SQL InjectionBoolean-Based Blind

Boolean-Based Blind SQL Injection: Extracting Data One Bit at a Time

When an injectable endpoint displays no database output, it can still answer yes-or-no questions through response differences. Learn how the oracle works, when it is reliable, and how parameterization removes it.

SelfSec Team4 min read
Part 2 of 8from theSQL Injectionseries
42 AND 1=1

At a glance

CWE-89
Interpreter
SQL database engine
Required condition
An injectable condition causes a stable true-versus-false response difference.
Potential impact
Blind extraction of sensitive values despite no database output being displayed.
Primary defense
Parameterize every value and remove attacker control over query structure.

Safe practice: use benign proof only, in a disposable local lab or on a system you are explicitly authorized to test.

On this page

Most introductions to SQL injection show the data appearing right on the page through a UNION SELECT. Real targets are rarely that generous. Often the query result is never echoed back: the endpoint returns the same product, the same "OK", the same redirect no matter what you inject. That does not make it safe — it makes it blind.

Boolean-based blind SQL injection is the technique for these endpoints. Instead of asking the database to show you data, you ask it true/false questions and read the answer from how the page responds. This post covers how inference works, how to distinguish a real oracle from ordinary page variation, and why a harmless true/false pair is enough to prove the flaw.

When this technique applies

Boolean-based testing needs three conditions: an injectable expression, a predicate the database evaluates, and a repeatable difference between true and false. The difference may be a status code, redirect, row count, word, header or response length. If both branches produce the same observable result, this technique has no channel and a tester must stop or use a different authorized method.

Caching, personalization and rotating content can imitate a boolean signal. Compare normalized responses across repeated baseline, true and false requests before concluding that the condition reached SQL.

How it happens

The root cause is identical to classic SQLi — input concatenated into a query — but the output is gone. Consider an endpoint that loads an article by id and concatenates that id straight into SQL:

$id = $_GET['id'];
$row = $db->query("SELECT title, body FROM articles WHERE id = $id AND published = 1")->fetch();

if ($row) {
    render_article($row);
} else {
    http_response_code(404);
}

The page never prints the query's internals. But it has two clearly distinguishable states: a 200 with the article, or a 404. That binary difference is the entire side channel an attacker needs.

A concrete attack: true/false inference

First, confirm the parameter is injectable by forcing each branch. A condition that is always true should return the article; an always-false one should not:

42 AND 1=1
42 AND 1=2

If those two requests differ consistently, the parameter may be a reliable oracle. For a safe lab proof, attach a question about a fixed constant rather than production data:

42 AND ASCII(SUBSTRING('A', 1, 1)) = 65

If the article renders, the database evaluated the expression and confirmed that A has byte value 65. Pair it with = 66; the false response should be stable. This proves that attacker-supplied SQL logic controls the branch without selecting any private row.

The endpoint never returns query data. It returns one decision bit. That is enough to prove the boundary failure, and in a real attack repeated decisions could infer values the database account can read.

Why one bit is still serious

An attacker can ask ordered questions and use binary search to reduce the number of requests needed for each character. The important defensive point is not the extraction algorithm; it is that a stable yes/no response can expose any value readable by the vulnerable database account. An authorized assessment should record the paired proof and stop rather than infer real credentials or personal data.

Per-engine nuances

The shape of string functions changes with the database, so detection must understand the deployed dialect:

SUBSTRING('ABC', 1, 1)
SUBSTR('ABC', 1, 1)
ASCII('A')
UNICODE('A')

The true/false signal also varies: a numeric context may need no quote, a string context needs ' and a comment terminator, and some endpoints leak the boolean through response length, a header, or timing rather than the status code. Identifying the correct oracle for the target is most of the work.

Signals that are not proof

  • One response differs once but not on repetition.
  • Both 1=1 and 1=2 produce the same changed page.
  • The difference disappears when cache-busting and session state are controlled.
  • The parameter changes normal application filtering without entering SQL syntax.
  • A WAF blocks one payload but the application never evaluates either condition.

The fix: parameterize and constrain

Boolean-based blind SQLi dies the same way every other injection does — the input must never be parsed as SQL. Bind the id as a value so 42 AND 1=1 becomes a (failed) lookup for the literal string 42 AND 1=1:

using var cmd = new SqlCommand(
    "SELECT title, body FROM articles WHERE id = @id AND published = 1",
    connection);
cmd.Parameters.Add("@id", SqlDbType.Int).Value = id;

Cast the id to its real type at the boundary, so non-numeric input is rejected before it reaches the database. Then run the query under a least-privilege account that cannot read the users table at all, so even a missed sink cannot reach the secrets the oracle was built to extract.

How SelfSec finds it

SelfSec's SQL injection engine covers 19 database families and treats every parameter as a potential blind oracle: it pairs always-true and always-false conditions, measures the response difference across status, length, content or timing, and requires the contrast to repeat before reporting a finding. Each result includes a reproduction request you can replay. Core scan processing runs locally on 127.0.0.1.

References

SelfSec is intended strictly for authorized security testing of systems you own or are explicitly permitted to assess.

Do both things about SQL Injection

SelfSec covers this class from both sides — the scanner confirms it in your own app, the firewall blocks it in front of your origin while the fix ships.

The SQL Injection series

  1. 01OverviewSQL Injection, Explained: From Login Bypass to Full Data Extraction6 min
  2. 02Boolean-Based BlindBoolean-Based Blind SQL Injection: Extracting Data One Bit at a TimeReading
  3. 03Error-BasedError-Based SQL Injection: Turning Database Errors Into Data4 min
  4. 04Out-of-BandOut-of-Band SQL Injection: Confirming a Blind Flaw Through DNS5 min
  5. 05Second-OrderSecond-Order SQL Injection: When Stored Input Detonates Later4 min
  6. 06Stacked QueriesStacked Queries: Running Multiple Statements Through One Injection4 min
  7. 07Time-Based BlindTime-Based Blind SQL Injection: Reading a Database Through the Clock5 min
  8. 08UNION-BasedUNION-Based SQL Injection: Appending Your Own Result Set4 min

Related reading