Login
ChallengesLearn
Scoreboard
Teams
SPNZ

LearnSQL InjectionSQL Injection: Blind injection overview
SQL Injection·Lesson 8 of 20

SQL Injection: Blind injection overview

No errors, no output, no problem - but only if you can see the side channel. The taxonomy of response body, status, and time oracles.

Intermediate12 min
SQLiBlindSide Channel
Loading lesson…
PreviousSQL Injection: Error-based extractionNextSQL Injection: Boolean-based blind

© 2026 SPNZ.

Terms of ServicePrivacy PolicyCookie Policy

Lessons 1-4 assumed the application was generous: it echoed query results, displayed error messages, and gave the attacker something to look at. Production-grade applications are usually less cooperative. They render a generic “something went wrong” page, swallow the actual error, and only expose a single bit of information: success or failure. That single bit is enough.

What you'll be able to do
  • Explain why a hidden channel is not a safe channel - data still leaks through side effects.
  • Name three side channels: response body, status code, response time.
  • Reason about the cost: N characters = ~8N requests, parallelised in minutes.
  • Choose between boolean and time-based blind given a target application.
Key terms
Side channel
An observable effect of a database operation that the application did not intend to expose - response body, status, latency, headers, redirect target.
Boolean oracle
A pair of distinguishable responses (e.g. "Welcome back" vs "Invalid credentials") that lets an attacker learn one bit per request.
Time oracle
A measurable latency difference (SLEEP(3) returns in 3 seconds when true, instantly when false) that lets an attacker learn one bit per request even when the response body is identical.
Bisection
A binary-search technique that asks 7 questions per character (not 26) by testing 'is the char < m?', then '< g?', etc.
What is it?

One bit at a time

Blind SQL injection is the technique of asking the database yes/no questions and watching for any observable side effect. The two most common variants are boolean-based and time-based. In boolean-based, the attacker crafts a payload that makes the WHERE clause true or false depending on a condition, and the application returns slightly different HTML for each case. In time-based, the attacker forces the database to sleep for N seconds when the condition is true and respond immediately when it is false, and measures the response time. The next two lessons drill into each variant in detail.

Both techniques are slow. To extract a 32-character password hash, an attacker needs roughly 32 × 7 = 224 bisection probes per character set, which is on the order of a few hundred requests per byte. Automated tools fire thousands of requests in parallel and reconstitute the answer from the timing or boolean noise. It is a brute-force search expressed in HTTP, and it is the only option when the application refuses to display data.

Side channels: what the attacker sees
Mini Map
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
Try it

Time-based extractor in a hardened form

The form below fakes a login endpoint that returns only “Login OK” or “Invalid credentials”. It cannot display the database result. Below it, a separate time-based tester simulates a SLEEP() condition. Try ' OR IF(1=1, SLEEP(3), 0)-- and watch the response take three seconds. Then try ' OR IF(1=0, SLEEP(3), 0)-- . The latency is the channel.

prodacme-portal.app/auth/login
acme-portal
Login form blind endpoint

The endpoint only returns “Login OK” or “Invalid credentials” - no error details, no data.

Time-based blind tester

Payload is appended to the password field. Server response simulates a database SLEEP() when the IF condition is true.

Try IF(1=1, SLEEP(3), 0)-- (true → ~1500ms) vs IF(1=0, SLEEP(3), 0)-- (false → instant).
time-based blind tester ready

Tip - an attacker escalates each probe to: IF(SUBSTRING(password,1,1)='a', SLEEP(3), 0)-- to extract one character at a time.

Real-world relevance

The slow drip

Blind SQLi is rarer in headline breaches but more common in long-running targeted attacks. Nation-state actors and ransomware affiliates use it because it is quiet: a single boolean question per second, indistinguishable from normal traffic, blends in with the background noise of a busy application. The 2011 breach of HBGary (a US security firm) used a boolean-based blind SQLi through a status-code side channel on a public content form, then escalated into a full email dump. The cost is time, not feasibility. A modern tooling stack with 50 parallel connections can extract a 40-character secret in well under an hour, and the application logs will show nothing more alarming than slightly elevated latency and a few hundred extra requests on a search endpoint.

Mitigation

The same fix, plus discipline

Parameterised queries defeat blind injection just as effectively as UNION. The only additional defense is rate limiting and request-shape validation, which slows the attacker's question-asking rate and surfaces anomalies in logs. Suppressing error messages prevents the boolean variant. Throttling expensive queries or enforcing statement timeouts blunts time-based extraction.

javascriptparameterised
// VULNERABLE: input used in concatenation
app.post('/login', (req, res) => {
  const q = "SELECT id FROM users WHERE u = '" + req.body.u + "' AND p = '" + req.body.p + "'";
  db.query(q).then(rows => rows.length ? res.send('Login OK') : res.status(401).send('Invalid credentials'));
});

// SAFE: parameterised
app.post('/login', (req, res) => {
  db.query('SELECT id, password_hash FROM users WHERE u = $1', [req.body.u])
    .then(async rows => {
      if (rows.length && await argon2.verify(rows[0].password_hash, req.body.p)) {
        res.send('Login OK');
      } else {
        res.status(401).send('Invalid credentials');
      }
    });
});

// Defenses in depth (not the primary fix)
// * rate-limit /login to e.g. 5 attempts per 15 minutes per IP+user pair
// * statement_timeout = '2s' on the database role used by the app
// * never echo DB error text to the client
Further reading
  • Blind SQL injection (PortSwigger)(PortSwigger)
  • OWASP SQLi Prevention Cheat Sheet(OWASP)
Key takeaways

What to remember

  • Blind SQLi extracts data through side channels: response body, response length, status code, redirect target, response time.
  • Boolean-based needs two distinguishable responses per probe. Time-based needs a measurable latency difference.
  • Extraction is roughly linear in secret size: 32 characters = a few hundred probes. Parallelise and you finish in minutes.
  • Parameterise the query - always. Rate limit, time out, and log anomalies as defense in depth.
  • Suppressing verbose error messages is necessary, not sufficient - it slows the boolean variant only.

Knowledge check

0/2 answered · 0 correct
  1. 1.The application returns the same 200 OK and the same HTML for any input. Which blind variant is still viable?

  2. 2.A 40-character secret extracted via boolean blind with 7 bisection probes per character. Roughly how many HTTP requests?