HTB HackTheBoo 2022 - (Web) Horror Feeds writeup
‘Horror feeds’ was a web challenge (day 3 out of 5) from HackTheBox’s HackTheBoo CTF.
Getting the flag involved exploiting a SQL injection vulnerability on an INSERT statement.
What we got
Like the other web challenges from this CTF, we got access to a Docker container running a web app and the source code of that web app.
Running the webapp locally
First, let’s take a look at the Dockerfile
Dockerfile (click to expand)
We are going to need Flask and some other modules (flask_mysqldb, pyjwt, bcrypt, colorama).
We also have to install the ‘libmysqlclient-dev’ package (at least that’s how it is called on Ubuntu).
And we have to prepare a MySQL server to be used be the app. For this part, I started a MariaDB container using docker.
After the database server is up, we have to create the DB and the table used by this app. You can use the SQL queries from the entrypoint.sh file.
We access the application and we have two options: login and register.
First we register a new account and then we login using it.
We see that the application displays 4 .mp4 files and … that’s everything.
Since we couldn’t find anything that looked interesting, let’s look at the app’s code.
Code analysis. Identifying SQL injection
We find out that the flag is referenced in the templates/dashboard.html file.
The flag is part of a table that is being rendered only if the current user’s name is ‘admin’.
So now we know that we have to login as the ‘admin’ user or at least trick the server into thinking that we did.
An obvious choice would be to register the ‘admin’ account, but that account was already created as part of the initial setup (in the entrypoint.sh file).
We can also see why we can’t create duplicate accounts by reading the code from the database.db file.
By reading that file, we also see that one of the queries is vulnerable to SQL Injection.
Nearly all the queries made in this file use query_db, which will prevent SQL Injection attacks if they are detected.
However, when registering a new user, the INSERT query is using an f-string to add variables to the query instead of the usual method of using the second argument of db_query in order to transmit variables.
Testing for SQL injection
First, we add a print statement that prints the SQL query that gets executed. This will help us with troubleshooting our payloads.
Then, I tried to add another user named ‘admin’ by modifying the query to insert two users instead of one.
The payload that I used for this was
This way, the SQL query became
We can use the print statement that we added to confirm that the query was modified.
But this will fail because the ‘admin’ user already exists. When trying this, I haven’t noticed that the ‘username’ flag had the UNIQUE flag set and I was hoping that I could create multiple users with the same name.
At least we know that the attack works like we expect. We just need a different payload.
New payload
While looking for solutions, I found this blogpost: https://labs.detectify.com/2017/02/14/sqli-in-insert-worse-than-select/
It describes methods for exploiting SQL injection in insert statements and in ‘duplicate key-based insertion’ we can see a method that updates existing fields by using the “ON DUPLICATE KEY UPDATE” statement.
You can read more about that SQL statement here. Basically, when you attempt to insert a row that already exist, it will update the existing row instead of inserting a new one.
We can use this in order to either change the admin’s password to a known one and then use it to login or to change the admin’s username so that we’re able to create an ‘admin’ user.
I went with the later and chose to update the username field.
For that, my payload looked like this
And the resulting SQL query looked like this
Again, I could see that the query was the expected one in the application’s output
And the server returned a 200 status this time.
We can also verify that the user was update by looking directly at the database.
Getting the flag
Now that we changed the name of the existing account, we can create an account named ‘admin’ and use it for logging it.
After that, we reproduce the attack on the ‘production’ version of the app (the one from their docker container) and we get the real flag.
Other web challenges from this CTF
This CTF released a challenge in each of its 5 categories each day.
I have posted writeups for all the web challenges. Here are some links to them:
- Day 1 - Evaluation Deck
- Day 2 - Spookifier
- Day 3 - Horror Feeds (you are here)
- Day 4 - Juggling Facts
- Day 5 - Cursed Secret Party