SQL Injection Attacks
SQL injection (SQLi) is a code-injection vulnerability in which attacker-controlled input is concatenated into a SQL query, causing the database to execute unintended commands. Because SQL makes no real distinction between the control plane (query structure) and the data plane (literal values), metacharacters in user input can break out of their intended context and alter the query’s logic. 1
SQLi is listed in the OWASP Top 10 under “A03:2021 – Injection.” A successful exploit can read sensitive data, modify or delete data, bypass authentication, execute administrative operations, read files from the DBMS filesystem, and in some cases issue commands to the operating system.
Detection
The canonical test is submitting a single quote (') and watching for errors or anomalies. PortSwigger’s systematic methodology adds:
- Quote characters —
',", and backtick, depending on context - Boolean conditions —
OR 1=1vsOR 1=2; look for systematic response differences - Time-delay payloads —
SLEEP(10),pg_sleep(10),WAITFOR DELAY '0:0:10'; measure response time deltas - Out-of-band (OAST) payloads — trigger DNS/HTTP interactions to an attacker-controlled listener
SQL values can be enclosed in parentheses (treated as sub-queries), so injection contexts are not always simple string literals. Test all three quote types and parenthesized contexts. 2
Comment truncation
Most SQLi payloads end with a comment sequence to neutralize the remainder of the original query:
| Database | Comment syntax |
|---|---|
| MySQL | -- (note trailing space), #, /* */ |
| PostgreSQL | --, /* */ |
| Microsoft SQL Server | --, /* */ |
| Oracle | -- |
URL-encoded variants (--+, --%20, --+-) are often needed because a trailing space may be stripped. If the developer filters trailing comments, append anything after the -- — it’s all a comment anyway. Sometimes no comment is needed when injecting at the end of a statement.
Types of SQLi
Error-based (in-band)
The database returns error messages containing query output. Requires verbose errors to be shown to the user. Microsoft SQL Server’s conversion errors and PostgreSQL’s cast errors are classic vectors; MySQL’s EXTRACTVALUE() and UPDATEXML() XPath errors serve the same role.
Union-based (in-band)
Abuses the UNION keyword to append attacker-controlled SELECT results to the original query. First determine the column count by iteratively adding NULL columns until the query succeeds:
' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--Then probe column types by replacing NULL with a string literal one position at a time. Useful MySQL functions: database(), user(), @@version, GROUP_CONCAT() (aggregates multiple rows into one string), CONCAT() with 0x3a for colon separators.
Boolean-based blind
No query output is returned, but the application’s response differs based on a true/false condition. Inject conditional logic (e.g., AND (SELECT COUNT(*) FROM users) > 0) and observe differences in HTTP status codes, page content, or redirect behavior. Some frameworks try to defeat this with uniform redirects; Burp Suite can follow redirects and diff responses.
Time-based blind
No output and no boolean differential — only timing. Inject a conditional delay:
' AND IF(SUBSTRING(password,1,1)='a', SLEEP(5), 0)-- -- MySQL
'; IF (1=1) WAITFOR DELAY '0:0:5'-- -- MSSQL
' AND (SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END)-- -- PostgreSQLA measurable delay confirms the condition is true. Extract data one bit at a time.
Out-of-band (OOB)
The database makes an external network call (DNS, HTTP, SMB) carrying exfiltrated data. Requires the DBMS to support network-accessible functions and the network to permit outbound traffic. DNS is the most reliable OOB channel because it typically traverses firewalls. Oracle’s UTL_HTTP, MSSQL’s xp_dirtree, and MySQL’s LOAD_FILE() with UNC paths are common vectors.
Authentication bypass
Login forms query the database for matching credentials; injecting a tautology returns true without knowing a password. Sometimes multiple fields must be injected simultaneously. Tack on LIMIT 1 when the application expects a single row.
Injection contexts beyond WHERE
Most SQLi occurs in WHERE clauses of SELECT queries, but injection can also land in:
UPDATEvalues orWHEREclauseINSERTvalues- Table or column names (rare, requires allow-listing)
ORDER BYclause (cannot use parameterized queries for identifiers — a common developer mistake)
Defense
Two complementary strategies:
- Parameterized queries (prepared statements) — the primary defense. The query structure is sent to the database separately from the data, making injection impossible. Stored procedures provide similar guarantees when implemented correctly.
- Contextual output encoding / escaping — escape user input for the specific SQL context (string literal, identifier, numeric). Know which context your data lands in and escape when crossing boundaries. Escaping alone is fragile; always prefer parameterization.
Additional controls: least-privilege database accounts, WAF rules, input validation as defense-in-depth, and avoiding dynamic SQL construction entirely.
Common language/database stacks
Certain pairings appear frequently in the wild and shape which payloads to try first:
| Language / Framework | Typical Database |
|---|---|
| PHP | MySQL / MariaDB |
| .NET (ASP.NET) | Microsoft SQL Server |
| Python (Django, Flask) | PostgreSQL, MySQL, SQLite |
| Java (Spring, J2EE) | Oracle, PostgreSQL, MySQL |
| Ruby on Rails | PostgreSQL, MySQL, SQLite |
SQLi is historically most common in PHP apps due to the prevalence of older functional interfaces; J2EE and ASP.NET’s programmatic interfaces make SQLi less likely but not impossible. 3
Sources
- SQL Injection — OWASP
- SQL injection — PortSwigger Web Security Academy
- SQL injection cheat sheet — PortSwigger
- Examining the database in SQL injection attacks — PortSwigger
- SQL Injection Prevention Cheat Sheet — OWASP
See also
- sqlmap — automated SQLi detection and exploitation
- test-for-sqli — detection methodology
- database-fingerprinting — identify the backend DBMS
- enumerate-database-schemas — information_schema and Oracle equivalents
- mysql-hexadecimal-strings — bypass quote filters with hex literals
- mysql-ascii-function — case-sensitive extraction via ASCII values
- common-sql-variables — useful server variables for recon
- mysql-into-outfile-webshell — escalate SQLi to RCE via file write
- rogue-mysql-server — flip the trust direction: a malicious MySQL server reading files from the client
- oracle-sql-server — Oracle-specific enumeration, fingerprinting, and PL/SQL injection
- xss-attacks — sibling injection class
- burp-suite — interception and response diffing for blind SQLi