An injectable login service returns no query results at all. How would an attacker still read the admin's password out of it, and what does that cost?
Ask one yes/no question per character and read the answer off the clock: inject a conditional SLEEP, and a slow response means "that guess was right". Automated, it recovers the whole value — at roughly one request per guess.
* One yes/no question per character, answered by the clock — a slow reply confirms the guess, and the loop walks the value out. *
The injected statement pairs a guess with a delay, so the database only pauses when the guess holds:
SELECT USERNAME, PASSWORD FROM USER WHERE USERNAME = 'test123'
UNION
SELECT IF(SUBSTRING(PASSWORD, 1, 1) = 'A', SLEEP(5), NULL), NULL FROM USER
WHERE USERNAME = 'admin';
If the response takes five seconds, the admin password starts with A. If it comes back at once, it doesn't — try B.
The procedure is just that, iterated:
- Fix a position (
SUBSTRING(PASSWORD, n, 1)). - Walk the candidate characters until one delays the response.
- Record it, move to position
n+1, repeat until a position yields nothing and the string is exhausted.
What it costs. Naively that's up to one request per candidate character — call it tens of requests per position, hundreds to low thousands for a full password, each paying its delay when it hits. Attackers cut it down with a binary search over the character range (> 'M'?), turning ~60 guesses per position into about 6. Either way it is far too tedious by hand, which is why blind extraction is always driven by a script.
Two things follow for the defender. First, "the page shows no data, so injection is harmless here" is false — silence slows an attacker down, it does not stop them. Second, this attack has an unusually loud signature for something called blind: a burst of near-identical requests to one endpoint, differing by one character, with response times clustering at a suspiciously round number. Rate limiting and query timeouts blunt it; only parametrization removes it.