In this lab, we are dealing with a Blind SQL Injection vulnerability that exists in a web application using a tracking cookie for analytics purposes. The value of this cookie is directly included in a backend SQL query, making it a potential injection point.

Although the application does not return query results or visibly behave differently based on the outcome of the query (whether it succeeds or fails), the backend still processes the query synchronously. This behavior opens the door for blind SQL injection techniques, where information can be inferred indirectly rather than observed directly.

The database contains a table named users, which includes the columns username and password. The objective of this lab is to exploit the vulnerability in order to retrieve the password of the administrator user and successfully authenticate as them.

Getting Started

To begin with, I started by exploring the application to identify any obvious input points that could be manipulated. I initially tested a few URL parameters for potential injection vulnerabilities by injecting a single quote ('), but there was no noticeable change in the application's behavior or any error messages

None

Since no parameters appeared immediately interesting, I moved on to intercepting the application's traffic using Burp Suite. After logging into the application and navigating to the "My Account" section, I captured the HTTP request and sent it to Repeater for further testing.

None

While analyzing the request, one particular value caught my attention: the TrackingId cookie. I began testing it for SQL injection by injecting a single quote, but again, there was no visible error or response change.

None

To further validate whether this could be a boolean-based injection point, I attempted to inject a conditional expression (' AND 1=1), but the application's response remained unchanged. This suggested that neither error-based nor boolean-based injection was immediately observable.

None

At this stage, I considered the possibility of a time-based blind SQL injection. I injected a time delay payload (pg_sleep(5) equivalent behavior),

TrackingId=x';SELECT pg_sleep(5)-- -
None

and after sending the request, I observed a noticeable delay of approximately 5 seconds in the server response. This confirmed that the database was processing the injected payload, and that a time-based blind SQL injection vulnerability was present.

At a deeper level, this works because the injected single quote closes the original string in the SQL query, while the semicolon (;) starts a completely new query. Instead of relying on logical operators like AND, this approach allows the execution of an independent statement. This is particularly useful in time-based attacks, where the goal is not to retrieve data but to force the database to perform a measurable action such as a delay.

After confirming that the application was vulnerable to time-based blind SQL injection, I moved on to building a reliable way to infer data from the database using conditional time delays.

To validate the technique, I first constructed a simple test condition to ensure that the delay behavior was functioning as expected. I used a basic boolean expression that triggers a delay when the condition evaluates to true:

TrackingId=x'; SELECT CASE WHEN (1=1) THEN pg_sleep(10) ELSE pg_sleep(0) END--
None

As expected, the response was delayed by approximately 10 seconds, confirming that the injected condition was being executed by the database.

The use of CASE WHEN is critical here, as it allows us to simulate conditional logic inside the database. Since the application does not return any output, we rely on time as a side channel. By linking a true condition to a delay and a false condition to no delay, we effectively transform the database into a system that answers yes/no questions based on response time.

To further verify this behavior, I tested the opposite condition:

TrackingId=x'; SELECT CASE WHEN (1=2) THEN pg_sleep(10) ELSE pg_sleep(0) END--
None

In this case, the response returned immediately, which confirmed that the delay was strictly dependent on the condition being true. This allowed me to confidently rely on time-based inference for data extraction.

With the technique validated, I then targeted the administrator user in the users table to confirm its existence:

TrackingId=x'; SELECT CASE WHEN (username='administrator') THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users--
None

The response delay confirmed that the user existed in the database.

Rather than retrieving the username directly, this approach asks the database a question: does a record exist that satisfies this condition? If the answer is true, the delay is triggered. This is the essence of blind SQL injection, where data is not extracted directly but inferred through indirect signals such as response timing.

Next, I focused on determining the length of the administrator's password. I gradually increased the length condition until the response time behavior changed:

TrackingId=x'; SELECT CASE WHEN (username='administrator' AND LENGTH(password)>19) THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users--
None

The application still delayed the response, indicating that the password length was greater than 19 characters. However, when increasing the value further, the delay stopped, confirming that the password length was exactly 20 characters.

This step demonstrates how the attack evolves from simple detection into structured data extraction. Instead of guessing blindly, we reduce the search space by asking incremental questions about the data, narrowing down the exact value step by step.

Once the length was identified,I proceeded to extract it character by character using the SUBSTRING function combined with time-based inference.

';SELECT CASE WHEN (username='administrator' AND SUBSTRING(password,1,1)='a') THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users--

The SUBSTRING function isolates a single character at a specific position, allowing precise testing of each character. By combining this with conditional checks, the extraction process becomes a sequence of controlled yes/no questions driven entirely by timing differences.

Since manual testing would be inefficient, I automated the process using Burp Suite Intruder to systematically brute force each character of the password.

The attack was configured using a Cluster Bomb strategy with two defined payload positions:

The first payload position represented the character index within the password, ranging from 1 to 20.

None

The second payload position represented the character set, consisting of lowercase letters and digits.This allowed me to test every possible character for each position in the password.

None

Once the attack was launched, the results were analyzed based on response time differences. A delayed response of approximately 10 seconds indicated a correct guess, while an immediate response indicated an incorrect character.

None

To make the analysis clearer, I filtered the results in Burp Suite to highlight only the requests with delayed responses, which significantly simplified the process of identifying valid characters.

None
None

By correlating the payload positions with the highlighted responses, I was able to reconstruct the password sequentially, one character at a time.

None

After successfully extracting all characters, I used the recovered credentials to log in as the administrator user, successfully completing the lab.

None

This lab highlights how even in the absence of visible output, applications can still leak critical information through side channels such as response time.

This demonstrates why relying solely on hidden responses is not a sufficient defense against SQL injection vulnerabilities.

Keep hacking, stay curious — the next vulnerability is just one request away