HacktheBox Cyber Apocalypse CTF 2023 — Web Solutions
HacktheBox CA2023 just ended, and my team, DELTAxSYNDICATE, solved 36/74 challenges, scoring a whopping 10,550 points! These are the solutions for the web challenges we solved.
Web: Trapped Source (Very Easy)
Description: Intergalactic Ministry of Spies tested Pandora’s movement and intelligence abilities. She found herself locked in a room with no apparent means of escape. Her task was to unlock the door and make her way out. Can you help her in opening the door?
Sensitive info in webpage source:
This challenge was simple: We are presented with a lock, and we need to enter the correct code to get the flag.
Take a look at the <script>
tag in the page source code:
The correct pin is right there! Entering it gives the flag:
FLAG: HTB{V13w_50urc3_c4n_b3_u53ful!!!}
Web: Gunhead (Very Easy)
Description: During Pandora’s training, the Gunhead AI combat robot had been tampered with and was now malfunctioning, causing it to become uncontrollable. With the situation escalating rapidly, Pandora used her hacking skills to infiltrate the managing system of Gunhead and urgently needs to take it down.
OS command injection:
This web application is written in PHP, and has a panel where commands can be executed:
In the source code, we can see that the ping command is vulnerable to command injection since the user-supplied IP address is not sanitized before being passed into the shell_exec()
function:
With some simple command injection:
/ping 127.0.0.1; cat /flag.txt
We get the flag!
FLAG: HTB{4lw4y5_54n1t1z3_u53r_1nput!!!}
Web: Drobots (Very Easy)
Pandora’s latest mission as part of her reconnaissance training is to infiltrate the Drobots firm that was suspected of engaging in illegal activities. Can you help pandora with this task?
SQL injection login bypass:
We are presented with a login page:
Looking at the source code, we see that the login page is vulnerable to SQL injection because our user input isn’t sanitized before being passed into the MySQL database query:
Some simple SQLi should allow us to bypass the login page:
Username: test
Password: “ OR 1 = 1-- -
This will make the resulting query look like this:
SELECT password FROM users WHERE username = "test" AND password = "" OR 1 = 1-- -"
We successfully bypass the login page and the flag is right there!
FLAG: HTB{p4r4m3t3r1z4t10n_1s_1mp0rt4nt!!!}
Web: Passman (Easy)
Pandora discovered the presence of a mole within the ministry. To proceed with caution, she must obtain the master control password for the ministry, which is stored in a password manager. Can you hack into the password manager?
Changing admin password with GraphQL API IDOR:
Looking at the source code (entrypoint.sh
) shows us that the (dummy) flag is stored as a phrase in the admin’s password manager account:
So, if we gain access to the admin account, we get the flag!
We can create our own account for this password manager and then log in, which presents us with a dashboard:
In this dashboard, we can create our own phrases to store our login info for different services.
What’s more interesting is how our queries are sent to the server and how they are processed server-side. The package.json
file in the source code shows that this web app is using GraphQL (query language for APIs) and a MySQL database.
Adding a phrase in my account results in this query being sent to the web app’s API:
A POST request with a GraphQL query is sent to the /graphql
endpoint which will then parse my query and add my new phrase to the SQL database.
Further analysis of the files database.js
and GraphqlHelper.js
shows how it all works. The database.js
file defines the functions which modify the database, such as loginUser(), registerUser(), addPhrase(), and more. On the other hand, the GraphqlHelper.js
file defines how to interact with the graphQL API, and how each query for the functions listed in database.js
should be structured. It also, after receiving a query, runs the corresponding function from database.js
supplied with user arguments (from the query) to fulfill the query.
After looking through the functions in database.js
, a hidden function stands out (not present in the user dashboard):
The updatePassword() function changes the password for ANY user in the database. Looking at its corresponding query object in GraphqlHelper.js
shows that this function is vulnerable to IDOR:
This code only checks if you’re a user in the database, and not if you’re the same user that you’re changing the password for (or at least even some admin-level user), which means that we can effectively change the password for any user we want, including admin!
In order to exploit this IDOR vulnerability, we craft a GraphQL query for UpdatePassword (which I copied from the LoginUser query and changed up a bit):
{
"query":"mutation($username: String!, $password: String!) { UpdatePassword(username: $username, password: $password) { message, token } }",
"variables":{
"username":"admin",
"password":"hacked"
}
}
Then, we paste our user’s session cookie into a POST request (to prove we’re a real user) and put our GraphQL query in there too:
After sending it, we get success response!
Now let’s log in as admin and get the flag!
FLAG: HTB{1d0r5_4r3_s1mpl3_4nd_1mp4ctful!!}
Web: Orbital (Easy)
In order to decipher the alien communication that held the key to their location, she needed access to a decoder with advanced capabilities — a decoder that only The Orbital firm possessed. Can you get your hands on the decoder?
SQL injection to dump database:
Quickly looking at the source code shows us definite SQL injection in the login page of the web app:
Since the password is checked after the SQL query, we can’t bypass the login page, but we can probably do some blind injection to extract password hashes from the backend database.
Manual blind SQL injection is a pain, so I will use SQLmap with a generic request file (saved from burpsuite) to the login page:
# This is the req_burp request file to the vulnerable /api/login endpoint.
POST /api/login HTTP/1.1
Host: 178.62.9.10:32438
Content-Length: 37
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.5563.111 Safari/537.36
Content-Type: application/json
Accept: */*
Origin: http://178.62.9.10:32438
Referer: http://178.62.9.10:32438/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close
{"username":"test","password":"test"}
sqlmap.py -r req_burp # Let SQLmap detect the blind injection.
SQLmap successfully detects the blind injection. Now we will run SQLmap again but this time we’ll tell it to dump the users
table, which is made in the entrypoint.sh
setup file:
sqlmap.py -r req_burp -T users --dump
And we successfully dump the database and get the admin’s md5 password hash.
Putting the hash in crackstation.net gives us this cleartext password:
The admin pass is ichliebedich
.
LFI to get the flag:
Now that we can log in, we can take a look at the routes.py
file to check for any other endpoint vulnerabilities. And behold, there’s a glaring LFI vulnerability in the /api/export
endpoint:
As you can see, the user-supplied path to the exported file is not being sanitized, which means we can literally download the flag file, which is renamed “signal_sleuth_firmware” in the challenge Dockerfile.
We craft a curl POST request with the path to the flag file as the value for the name
parameter, and with our session cookie:
curl -X POST http://127.0.0.1:1337/api/export
-H "Content-Type: application/json"
-H "Cookie: session=eyJhdXRoIjoiZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SjFjMlZ5Ym1GdFpTSTZJbUZrYldsdUlpd2laWGh3SWpveE5qZ3hORGcwT1RRMWZRLjZiZzdoa2tsR2pyQ19XVVdZcS1hNXRNb3JZME5nOXRMSVU3dlU5LWhyelUifQ.ZDkYMQ.i9q9XjAUlonb1V2vwiAACpmm1KU"
-d '{"name":"../../signal_sleuth_firmware"}'
And sending this command gives us the flag!
FLAG: HTB{T1m3_b4$3d_$ql1_4r3_fun!!!}
Web: Didactic Octo Paddles (medium)
You have been hired by the Intergalactic Ministry of Spies to retrieve a powerful relic that is believed to be hidden within the small paddle shop, by the river. You must hack into the paddle shop’s system to obtain information on the relic’s location. Your ultimate challenge is to shut down the parasitic alien vessels and save humanity from certain destruction by retrieving the relic hidden within the Didactic Octo Paddles shop.
JWT manipulation to access admin page:
In this challenge, we are greeted with a login page:
Looking at the source code, we can see that there is a /register page:
We access the registration page and create an account, after which we see that we have a JWT token assigned to the account:
The source code for the creation of the JWT token looks secure, but what’s interesting is the code for the /admin page shown in the routes file (index.js
):
It uses the AdminMiddleware.js
file to moderate access to this /admin endpoint. A quick look at the AdminMiddleware.js
file shows a glaring vulnerability in the JWT verification logic:
The first highlighted segment is an if
statement that checks if the algorithm type for the JWT token is literally none
and the second highlighted segment is an else
statement that verifies the JWT token with no algorithm. So if we can bypass that first if
statement, we can modify the JWT payload however we want since it’ll be verified with no algorithm!
We change the alg type to None
since the code only checks for the literal string none
, so the capital N bypasses the first check, and it’s still a valid alg type. Now, we change the id
value to 1 because, according to the source code, that’s most likely the id
value for the admin account. Remember, this will work because the code is now verifying out JWT token with the None algorithm, so we can modify the JWT and it will still be authentic!
We put in our modified JWT into the session cookie value and successfully access the admin page:
RCE with SSTI in admin page:
The admin page shows the active users on the site (we created the “test” user). Looking at the source code for this page in admin.jsrender
, we see that there’s some unsafe templating going on:
The routes file index.js
also shows that the usernames in the database are all directly rendered into this HTML page without any input sanitization. We can definitely get RCE with this obvious SSTI vulnerability in the jsrender templating engine.
We use a jsrender SSTI payload that I found on HackTricks (I modified the shell command to grab the flag) and make a user account with it:
And then we log in as the new user and change our session cookie back to the modified JWT. Finally, we reload the /admin
page and get the flag!
FLAG: HTB{Pr3_C0MP111N6_W17H0U7_P4DD13804rD1N6_5K1115}
Thanks for Reading!
If this post was beneficial to you, consider dropping a follow and liking the post! Make sure to leave any comments or questions down below!
CTF Team Info:
If you would like to join my CTF team, then please visit my About Page, and you can find more information there!