VulnNet: Node (Node.js deserialization + /npm privesc and services privesc)
THM Writeup โ VulnNet: Node

After the previous breach, VulnNet Entertainment states it wonโt happen again. Can you prove theyโre wrong?
Room: VulnNet: Node
Difficulty: Easy
Operating System: Linux
Author: SkyWaves
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.
This is again an attempt to recreate some more realistic scenario but with techniques packed into a single machine. Good luck!
Add IP address to your hosts file:
Scan the target machine โ find open ports first:
Get more details about open ports:
Enumeration
Explore the web application โ browse to http://node.thm:8080/

I viewed the page source, but found nothing interesting, then I noticed a cookie, that looks like Base64 encoded:

Grab the cookie and paste it e.g. to the BurpSuiteโs Decoder โ first URL decode it and then Base64 decode it:

This looks great โ a JSON that says the app what user are we โ letโs try to bypass authentication completelly.
Take the JSON, modify it, Base64 encode it and finally URL encode it:

Now take the encoded text and modify the cookie via developer console, then refresh the page:

Do you see the difference? There is โWELCOME, ADMINโ instead of โWELCOME, GUESTโ, however the app still asks us for credentials. Hm nevermind, I remember I did a box few weeks ago where I exploited nodejs deserialization vulnerability. This app definitely uses deserialization, otherwise how would it know we changed the cookie to be Admin? We can even prove itโฆ
Change the cookie again, but this time set the cookie value to some gibberish (random text) and refresh the page:

Here we have the proof.
Use this script to generate a payload:
You can find the original script here โ the above is modified version so it can be run with python3 and the output is Base64 encoded.
Save it to a file e.g. nodejsshell.py
Generate the payload:
Copy generated payload, paste it to the BurpSuiteโs Decoder and URL encode it:

Run a listener on your attacking machine:
Now take the URL encoded payload, paste it as value of the cookie and refresh the page:

And we received a reverse connection โ simple shell.
User flag
We need to stabilize the shell:
Look around a little bit:
Ok, we are www user and we are in its home directory, there is no user flag and we donโt have permissions even to look into serv-manageโs home directory.
Letโs try to find how to escalate our privileges:
We can run npm as serv-manage user.
Check GTFOBins how to exploit it:

Now exploit it:
As you can see we need to set full permissions before we run sudo npm as serv-manage user.
Read the user flag:
Root flag
Spawn a shell:
Letโs find a privilege escalation vector to root user:
We can start and stop vulnnet-auto.timer service as root without password.
Find the vulnnet-auto.timer service location and check the permissions:
This is great โ as user serv-manage we have write permissions to vulnnet-auto.timer
Check the content:
Hm, this service calls other service named vulnnet-job.service every 30 minutes.
First we have to check if we have write permissions also to vulnnet-job.service:
Great, so weโll use this misconfigurations to escalate our privileges to root โ actually it is a combination of misconfigurations:
we can restart (start/stop) the
vulnnet-auto.timerservicewe have write permissions to both services:
vulnnet-auto.timerandvulnnet-job.servicewe can reload the daemon (systemd files) โ we need to do this after we change the services definitions
See the content of vulnnet-job.service:
Here we need to change ExecStart parameter.
Ok, first change the content of vulnnet-auto.timer:
We change only OnCalendar value โ so the services runs every minute.
Now change the content of vulnnet-job.service:
Now stop vulnnet-auto.timer service, reload systemd files and start vulnnet-auto.timer:
Wait a minute and check if /tmp/bashroot was created.
If it was, execute and youโre root now:
Our effective permissions are rootโฆ
Read the root flag:
Last updated