Blind SQL injection with time delays and information retrieval
Overview of the Lab
This lab demonstrates a time-based blind SQL injection vulnerability in a PostgreSQL-backed web application, where no direct database output or error messages are returned to the user. Instead, information is extracted by observing response time differences caused by conditional database delays.
The attacker leverages PostgreSQL’s pg_sleep() function to force the database to delay responses when specific conditions evaluate to TRUE. By measuring these delays, sensitive information such as usernames and passwords can be extracted incrementally.
This type of vulnerability is especially important in real-world scenarios because:
- Applications often suppress errors completely
- No query output is reflected in responses
- Boolean-based inference may not be available
- Timing differences become the only observable signal
Understanding Time-Based Blind SQL Injection in PostgreSQL
In PostgreSQL, the function:
-
pg_sleep(seconds)
forces the database to pause execution for a specified number of seconds.
This behavior can be abused in SQL injection by embedding it inside conditional logic. If a condition is TRUE, the sleep function executes and delays the response. If FALSE, no delay occurs.
This creates a timing oracle, where:
- TRUE condition → delayed response
- FALSE condition → immediate response
By carefully controlling these conditions, an attacker can infer hidden database values without ever seeing them directly.
Step 1: Confirming Administrator User Existence
The first step is validating whether a specific user exists in the database. In this lab, the target is the administrator account.
The payload used is:
'|| (select case when(username = 'administrator') then pg_sleep(1) else pg_sleep(-1) end from users)--;
How it works:
-
The query checks if a row exists where
username = 'administrator' -
If TRUE →
pg_sleep(1)executes (delay occurs) -
If FALSE →
pg_sleep(-1)executes (invalid/ignored behavior depending on context)
Observations:
- A delayed response confirms that the administrator account exists
- No delay indicates the condition is false or not matched
Key insight:
This step confirms both:
- The existence of the target user
- That SQL injection is active and influencing backend logic
At this point, the attacker has validated a working time-based injection channel.
Step 2: Confirming Password Length Using Time Delays
Once the target user is confirmed, the next step is to determine the password length. This is critical for efficient extraction.
The payload is injected into the TrackingId cookie, which is commonly vulnerable in real-world scenarios:
Cookie: TrackingId=kkFXoXrQ6A0nRKi6'|| (select case when length(password) > 1 then pg_sleep(1) else pg_sleep(-1) end from users)--; session=PdazIHwDN6MztMCVo9YQ6WaVUs5zzx0e
Explanation:
-
length(password) > 1is evaluated for the administrator record - If TRUE → response is delayed by 1 second
- If FALSE → no delay occurs
Bruteforce logic:
The attacker increments the value:
- length > 1
- length > 2
- length > 3
- …
Until the delay stops being observed.
Result inference:
When testing reaches:
- The last value where delay still occurs → password length is confirmed
This transforms timing behavior into a binary measurement system for discovering hidden numeric values.
Step 3: Character-by-Character Password Extraction
After determining the password length, the attacker begins extracting the password one character at a time using substring-based comparison.
Payload used:
'|| (select case when SUBSTR(password,1,1) = 'a' then pg_sleep(2) else pg_sleep(-1) END FROM users WHERE username = 'administrator')--
How it works:
-
SUBSTR(password,1,1)extracts the first character of the password -
It is compared against a guessed character (
'a') -
If the guess is correct:
-
pg_sleep(2)is triggered → noticeable delay
-
-
If incorrect:
- No delay occurs
Why pg_sleep(2) is used here:
Using a longer delay (2 seconds) helps:
- Improve accuracy
- Reduce false positives caused by network latency
- Make results easier to observe visually
Iteration process:
The attacker repeats this process for:
- Position 1 → 20 (or discovered password length)
-
Each character position tests:
- a-z
- A-Z
- 0-9
- symbols
Each correct character produces a delay signal, allowing reconstruction of the full password.
Step 4: Understanding the TrackingId Injection Point
A key aspect of this lab is that the injection occurs in the TrackingId cookie, not a visible input field.
Example:
TrackingId=kkFXoXrQ6A0nRKi6'|| (payload)||; session=...
Why this matters:
- Many real-world applications store user tracking or session identifiers in cookies
- Developers often fail to sanitize cookie values
- Cookie-based injection is harder to detect through normal UI testing
This makes it a realistic attack vector commonly seen in production environments.
Step 5: Why Time-Based Blind SQL Injection Works
This attack works because:
- SQL logic is still executed even without output
- The database allows conditional function execution
- Response timing can be measured externally
- No visible output is required for inference
The attacker effectively turns the database into a timing-based oracle system.
Each request becomes a question:
- “Is this condition true?”
And the answer is encoded in time delay rather than visible output.
Step 6: Automation Considerations (Burp Suite Intruder)
Although this lab can be performed manually, automation is typically done using tools like Burp Suite Intruder.
Recommended configuration:
- Attack type: Cluster Bomb
- Payload set 1: character position (1 → password length)
- Payload set 2: character list (bruteforce dictionary)
How it works in practice:
For each request:
- Intruder injects a position and character guess
- Response time is measured
- Delay indicates correct guess
Advantage:
- Fully automates enumeration
- Eliminates manual repetition
- Scales to long passwords efficiently
Comments