WHEN YOU SEE IT!!! (or don't).

https://blue-zenith-web.challs.sekai.team

Since I don't have images of the challenge, this is my attempt at recreating the scene of the website.

Blue Zenith



First, let's try logging in.

  • If we input normal letters for username and password, we get a 401 Unauthorized response.
  • If we input a single quote "'" for username, we get a 500 Internal Server Error response.
  • Inputting anything for password doesn't seem to cause the error response.

From that, we can tell that there's a blind SQL injection vulnerability in the admin field.

  • This is also referenced by the challenge description.
  • WHEN YOU SEE IT!!! (or don't).
  • While we can use sqlmap to automate the SQL injections, I wrote my own solving scripts in Javascript.

Next, we'll determine the type of the database (the DBMS).

  • I probably got lucky by first checking if it's an SQLite database.
    1. Use the UNION operator to determine the number of values selected through the admin field.
    2. ' UNION SELECT 0, 0, 0 --

      Explanation:
      If we union select the same number of values, the response will be 401 Unauthorized.
      If we union select a different number of values, the response will be 500 Internal Server Error.

    3. Select from sqlite_schema.
    4. ' UNION SELECT 0, 0, 0 FROM sqlite_schema --

      Since this returns 401 Unauthorized, we have identified that the database type is SQLite.

  • Refer to swisskyrepo's PayloadsAllTheThings for several other methods to identify the database.

Now, we can extract the database using error-based SQLite injection.

  • This is the general payload we will use.
  • ' OR CASE WHEN [BOOLEAN_QUERY] THEN 1 ELSE load_extension(1) END --

    When [BOOLEAN_QUERY] is true, the response is 401 Unauthorized.
    When [BOOLEAN_QUERY] is false, the response is 500 Internal Server Error.

  • We'll use this boolean query to determine a table's content character-by-character.
  • (SUBSTRING((SELECT ${column_name} FROM ${tbl_name} LIMIT 1 OFFSET ${row_index}), ${char_index}, 1) >= '${char}')

    Explanation:
    It gets the string at the given table name, column name, and row index,
    extracts the character at the given index of the string,
    then checks if it is greater than the given character.

  • First, extract column sql, row 0 from table sqlite_schema.
  • CREATE TABLE users id INTEGER PRIMARY KEY AUTOINCREMENT username TEXT UNIQUE NOT NULL password TEXT NOT NULL
  • Next, extract column username, row 0 from table users. This gives us a username.
  • admin
  • Then, extract column password, row 0 from table users. This gives us the password (flag).
  • osu{wh3n_u_d0nt_s33_1t}

Logging in with the username and password we found, we'll be redirected to this osu! video where Cookiezi gets 727pp on "Blue Zenith".

As a result, we found the flag for web/blue-zenith.

Flag: osu{wh3n_u_d0nt_s33_1t}