Flash CTF – Second Breakfast

Challenge Overview

This challenge was a Second Order SQLi, you had control over a database entry, your username, that could later be used to inject into a SQL query on the profile page. The final solution was to register with a username similar to ' UNION select flag, CURRENT_TIMESTAMP from flags where 'metactf_is_awesome'='metactf_is_awesome, then login and view your profile to trigger the second order SQLi, thus getting the flag.

Finding the Injection

Browsing through the provided source code, we see several endpoints that interact with SQL: 

/register, /login, and /profile. Looking at the /register and /login queries, they appear to be proper parameterized queries:

query = "INSERT INTO users (username, password, salt) VALUES (%s, %s, %s)"
cursor.execute(query, (username, password, salt))

However, this is not the case on the /profile endpoint:

query = f"SELECT username, created_at FROM users WHERE username='{username}'"
cursor.execute(query)
user = cursor.fetchone()

Solving

We can inject into this query to return a value in place of our username! One thing to note is that although we can put almost anything into username, we need to get a timestamp into created_at, otherwise the page will error before giving us output. We can easily get a timestamp by using the built in CURRENT_TIMESTAMP. With all of this, we can use the injection ' UNION SELECT GROUP_CONCAT(table_name), CURRENT_TIME FROM information_schema.tables WHERE table_schema=DATABASE() AND 'metactf_is_awesome'='metactf_is_awesome to enumerate tables. In our case, since the challenge is whitebox, we know that we need the flag out of the flags table, so our final injection will be ' UNION select flag, CURRENT_TIMESTAMP from flags where 'metactf_is_awesome'='metactf_is_awesome, we simply register with that username, login, and then view our profile.

Flag: MetaCTF{Ill_h4v3_7h47_s3c0nd_0rd3r_0f_SQLi_pl3453}