Light
LAST UPDATED FEB-2025 (p.s. pardon me, I'm still a rookie at CTFs)
Last updated
LAST UPDATED FEB-2025 (p.s. pardon me, I'm still a rookie at CTFs)
Last updated
I started on this challenge with minimal knowledge of SQL/SQLite commands and workings (just the basics as learnt from the TryHackMe course room detailed under the Web Hacking -> SQL Injection section in this gitbook: https://jarrettgxz-sec.gitbook.io/penetration-testing-ethical-hacking/web-hacking/sql-injection). I have gained ideas and insights from a few online resources and also from ChatGPT.
Note: ChatGPT was used to point myself towards the right direction on SQLite specific concepts such as commands to retrieve the table or columns names from the current database instance, but not on specific SQL injection concepts. The SQL injection commands were generated by myself based on multple trial-and-errors. For example, commands to query from sqlite_master
was generated by ChatGPT, however, the insertion of specific characters (eg. quotation marks, equal signs, etc.) within the final command sent to the vulnerable database application was added myself based on my own knowledge from past experiences.
The challenge presents a simple interface over the TCP connection at port 1337, prompting for the username, to which it will respond with the password. The goal is to find the name and password of the admin account, followed by a flag.
My first instinct was to perform a brute-force attack on the username. According to the results, I can identify the admin username, and retrieve the password from the application.
Bash script to brute force the password:
The following displays an attempt of using a bash script (not completed) to perform the brute-force attack. However, the script is not working as it simply pauses after the first input.
Python script:
The following shows a Python script that works:
Word-lists to try out:
/usr/share/wordlists/seclists/Usernames/Names/names.txt
/usr/share/wordlists/seclists/Usernames/Names/malenames-usa-top1000.txt
/usr/share/wordlists/seclists/Usernames/Names/femalenames-usa-top1000.txt
I found the username: alice. However this wasn't the admin username. Probably a rookie mistake on my part for not realizing sooner that the answer field for the admin username in the TryHackMe website is 14 characters long. An SQL injection is likely to be more feasible.
As mentioned before, I noticed that the input form length is very long, and realized that it's highly unlikely that I would be able to find the username with a simple brute-force.
As suggested from the challenge name, this database is likely to be a SQLite database application.
Possible SQL statements on the server side:
Attempts with common SQL injection inputs:
a) Potentially tricking the database to return all the users
1st attempt
Response: Error: unrecognized token: "' LIMIT 30"
From the error message, I understand that the query on the server side is as follows:
2nd attempt
The --
operator represents a single-line comment. This is used to tell SQL to ignore the comments after our input. In this case, it allows bypass of the ' LIMIT 30
command.
Hope to resolve to the following in the server side:
Reponse: For strange reasons I can't explain, any input containing /*, -- or, %0b is not allowed :)
This tells us that comment characters are banned.
3rd attempt:
Hope to resolve to the following in the server side:
This seems to return a password value (associated with the alice username).
a) Query the sqlite_master
database for more information
What is sqlite_master
?
Every SQLite database contains a single "schema table" that stores the schema for that database. The schema for a database is a description of all the other tables, indexes, triggers, and views that are contained within the database.
The schema table looks like this:
1st attempt to query the sqlite_master
schema table
This can be used to discover the name of the other tables available in the SQLite database
Response: Ahh there is a word in there I don't like :(
The full lowercase form for the UNION and SELECT operator in the query returns the same response too
After pondering for awhile on the error message returned from the statement in point 2 above, I got the idea of using non-standard SQL keyword commands, apart from the conventional fully capitalized, or fully non-capitalized versions (UNION
, union
).
Query 3.1
Response 3.1: Password: admintable
It appears that this method works
We have discovered that there exists a table with the name admintable
Query 3.2
Response 3.2:
Error: SELECTs to the left and right of UNION do not have the same number of result columns
This response tells us that the admintable table have more than one column
Thus, it causes a number of result columns mismatch from the original query (first part of the query before the UNION
keyword)
Note that the original query only returns one column
Query 3.3
We need a method to view the exact schema of the table, before selecting a single column to read the value directly
Response 3.3:
Password: CREATE TABLE admintable (
id INTEGER PRIMARY KEY,
username TEXT,
password INTEGER)
Query 3.4 (Answer to qn 1)
Now, with the information retrieved from the previous response, I can select a column value to read. In this case, it will be the username
column.
Response 3.4:
Password: TryHackMeAdmin
To answer question 1 "What is the admin username?": TryHackMeAdmin
Query 3.5 (Answer to qn 2)
Now that we know the admin username, we can find the password with the following query:
Response 3.5:
Password: mamZtAuMlrsEy5bp6q17
To answer question 2 "What is the password to the username mentioned in question 1?": mamZtAuMlrsEy5bp6q17
Query 3.6 (Answer to qn 3)
Response 3.6:
Password: THM{SQLit3_InJ3cTion_is_SimplE_nO?}
To answer question 3 "What is the flag?": THM{SQLit3_InJ3cTion_is_SimplE_nO?}
sqlite_master
schema tableQuery 4.1
Returns the same response as query 3.3 above
Query 4.2
Returns the same response as query 3.1 above
From the results, I have learnt that SQLite accepts variations of SQL keywords. This includes the following (non-exhaustive): Union
, uNion
, unIon
, uniOn
, UNion
, etc., which are treated as valid commands.
This is because SQLite follows the SQL standard, which states that keywords are case-insensitive. However, this only applies to keywords, not to identifiers like table names (unless quoted). This can allow attackers to bypass simple SQL injection filters that relies on specific standard keyword filters such as "UNION", "union", etc.