Authorization disclaimer. This walkthrough applies only to the intentionally vulnerable PortSwigger Web Security Academy lab linked below. Test only systems you own or have explicit permission to assess.
Overview
This lab contains blind SQL injection in the TrackingId cookie. Successful and unsuccessful queries do not produce useful content differences, but a database exception causes a distinct HTTP error. By triggering that exception only when a tested proposition is true, the error becomes a one-bit oracle that can reveal the lab’s synthetic administrator password.
Lab objective/setup
The objective is to determine the password for the synthetic administrator account and sign in. The back end is Oracle, which matters because a standalone SELECT requires a table such as dual, and the injected expression must be compatible with the surrounding string column.
What I observed
I intercepted a normal request and changed only the TrackingId cookie. Appending one quote caused an internal error, while appending two quotes restored the normal response. That paired test is stronger evidence than an isolated error: the first value disrupts SQL syntax and the second balances it again.


Oracle-specific probes then established usable syntax. A UNION SELECT null form failed, whereas the equivalent selection FROM dual succeeded.


Why it is vulnerable
The useful lab-only payload pattern is:
1 | ' UNION SELECT CASE WHEN (<condition>) |
When <condition> is true, Oracle evaluates 1/0, raises ZERO_DIVIDE, and the application returns its error response. When it is false, the empty string branch is selected and the request completes normally. TO_CHAR makes the error-producing branch type-compatible with the selected text value.


Walkthrough in the authorized PortSwigger lab
With the oracle validated, I tested candidate lengths against the single synthetic administrator row. In Burp Intruder, the candidate integer occupied one payload position in a condition equivalent to LENGTH(password)=N. The response associated with N=20 entered the error state, establishing a 20-character password for this lab instance.


Recovering each synthetic character
For each position from 1 through 20, I tested candidate characters using an Oracle expression equivalent to SUBSTR(password, position, 1)='candidate'. Each position had exactly one candidate that triggered the error response. Sorting or filtering Intruder results by status and length made those matches straightforward to identify.


The recovered value is ephemeral lab data and is intentionally not reproduced as a reusable credential. Entering the extracted value for administrator completed the exercise.

Verification
Three controls support the conclusion: quote balancing changes error behavior predictably; true and false predicates reliably select different HTTP outcomes; and the 20 extracted character tests produce a credential accepted by the lab. Together, these observations distinguish a conditional SQL error channel from random server instability.
Impact and defensive lesson
Suppressing query output does not make SQL injection harmless. Status codes, timing, connection resets, and custom error pages can all leak boolean results. Production applications should use parameterized queries, avoid concatenating cookie values into SQL, return uniform external errors, and monitor repeated near-identical requests. Uniform errors reduce leakage but are only defense in depth; eliminating the injection sink is the primary fix.
Provenance
This article is a publication-quality English rewrite of the author’s notes for the reserved PortSwigger migration item the internal migration record. Figures were retained from that lab session and stored locally under the manifest-reserved image route.