When the application returns nothing - no error, no length delta, no status change - the only oracle left is the database clock. The attacker crafts a query that sleeps for a long time when a predicate is true, returns immediately when it is false. The response time is the only signal.
- L8Blind injection overview
- Use
SLEEP()andpg_sleep()to convert a boolean predicate into a delay. - Choose a delay long enough to clear network jitter (typically 5 seconds in MySQL, 2 in PostgreSQL).
- Recognise when time-based extraction is the only oracle left.
- Explain why time-based extraction is the slowest of the three blind channels.
- Time oracle
- A side channel where the attacker observes how long the server takes to respond. The only oracle available when the application is fully opaque (same status, same body, no length delta).
- SLEEP(n)
- MySQL function that pauses execution for n seconds. The PostgreSQL equivalent is pg_sleep(n). SQL Server uses WAITFOR DELAY '00:00:05'.
- IF()
- MySQL and PostgreSQL conditional expression. The pattern IF(condition, SLEEP(5), 0) is the canonical time-oracle primitive.
- Jitter
- Network and application noise that smears response times. A 5-second delay is the typical lower bound so that jitter (usually <500ms) does not pollute the signal.
When the only signal is the clock
Time-based extraction is the technique of last resort. It works when every other channel is closed - same status code, same body length, no errors, no reflected output. The attacker uses the database scheduler itself as the oracle.
-- MySQL
?id=1 AND IF((SELECT SUBSTRING(user(),1,1))='a', SLEEP(5), 0)
-- PostgreSQL
?id=1 AND (SELECT CASE WHEN SUBSTRING(current_user,1,1)='a' THEN pg_sleep(5) ELSE pg_sleep(0) END)
-- SQL Server
?id=1; IF SUBSTRING(system_user,1,1)='a' WAITFOR DELAY '00:00:05'
-- Oracle
?id=1 AND DECODE(SUBSTR(user,1,1),'a',DBMS_PIPE.RECEIVE_MESSAGE('a',5),0)=0The delay must be long enough to clear network jitter. Most scanners default to 5 seconds for MySQL/PostgreSQL and 2 seconds for SQL Server, where the implementation is more accurate. Anything below the jitter ceiling produces false positives and is the #1 reason time-based scanners report incorrect results on production networks.
Recover a string with the clock
The sandbox simulates a server that sleeps for ~1 second when the predicate is true and returns immediately when it is false. The binary search half-interval updates after every probe. Watch the range and the wall-clock delay evolve.
SELECT id FROM products WHERE id = 1 AND IF((ASCII(SUBSTRING(secret,1,1)) > 78), SLEEP(1), 0)-- The slow lane that every scanner uses
Most bug bounty payouts for time-based SQLi are 50–80% of the value of an equivalent UNION or error-based finding. The reason is throughput. A 5-second delay per request at 1 bit each is 0.2 bits per second per thread. Recovering a 32-character hash takes 7 × 32 × 5 = 1,120 seconds (almost 19 minutes) on a single connection. Real-world attackers run dozens of parallel connections and target the slowest findings only when the data justifies it.
Time-based extraction is also noisy at the network layer. A volumetric SQLi burst that holds database connections open for minutes is visible to any WAF or rate-limiter; defenders are usually tipped off before the dump completes.
The fix is unchanged
Parameterised queries make time-based extraction impossible - the conditional expression becomes a typed boolean, the sleep function is never reached, and every request returns in the same number of milliseconds regardless of the input.
// SAFE - the predicate is data, not code
const query = 'SELECT id FROM products WHERE id = $1 AND $2::boolean';
await db.query(query, [id, predicate]);What to remember
- Time-based extraction is the oracle of last resort - used only when status code, body, and length are all identical.
- The canonical primitives are
SLEEP()in MySQL,pg_sleep()in PostgreSQL,WAITFOR DELAYin SQL Server. - The delay must clear network jitter - typically 5 seconds in MySQL/PostgreSQL, 2 seconds in SQL Server.
- Time-based extraction is the slowest blind technique. Parallelise and prefer UNION or error-based extraction when the target allows.
Knowledge check
0/3 answered · 0 correct1.When is time-based blind SQLi the right technique to use?
2.Why is the typical delay set to 5 seconds in MySQL and PostgreSQL?
3.Why is time-based extraction noisier than boolean at the network layer?