5.6. Exploiting Blind SQL Injection

 

Exploiting Blind SQL Injection differs from the techniques discussed earlier. The main difference between SQLi and Blind SQLi is that usually, the results of SQL queries are not returned by the server. Typically, the server returns one of two states. It could be another page or an additional element on the page, or it could be a server error or another HTTP response code.

To hack an application with Blind SQLi vulnerability, various techniques are employed, some of which we will discuss in this article.

 

Generating responses based on specific conditions

To simulate Blind SQLi vulnerability, we will use the DVWA (Damn Vulnerable Web Application) application. To log in to the application, use admin/admin, then select the SQL Injection (Blind) option. On the opened page, enter 1 or any other digit in the input field:

Observing normal operation of webpage in DVWA

The displayed result indicates that the entered value exists on the server. If you enter a value greater than 6 or any text characters, the server will not return any response. This behavior is often encountered when Blind SQLi vulnerability exists, meaning the server displays one of two options: either an existing value or nothing. A prime example of such a reaction is the vulnerability in the Cookie header. As you know, servers use Cookies to identify authorized users. If the Cookie value is found on the server, the application identifies and authorizes the user. Additional control elements and the user's data will be displayed on the page. However, if you slightly modify the Cookie value or enter unauthorized characters, the server will simply fail to identify the user. Instead, it will display a regular page intended for unauthenticated users.

If you enter quotation marks, apostrophes, or any other characters to test for vulnerabilities, the server will display the initial page without any errors. Therefore, we will use a different technique. Let's introduce an additional AND condition to create identical expressions, for example, like this:

11’ AND 1=1 #1’ AND ‘a’=’a

Testing and geting Blind SQL confirmation

In the expressions provided above, the AND condition always signifies TRUE, and therefore, it does not affect the outcome of the SQL query. However, if we apply a false condition, the result of the SQL query will immediately change. For example, when entering one of the following expressions, the server will not return any values:

1’ AND 1=2 #1’ AND ‘a’=’b

This is based on the principle of exploiting the Blind SQLi vulnerability. Let's try to use this method to retrieve the name of the current database.

Since MySQL is used on the server, we'll use the following expression:

1' AND SUBSTRING(DATABASE(), 1, 1)='a'

where

DATABASE() - retrieves the name of the current database,

SUBSTRING('string', position_of_character, length_of_substring) - extracts a substring of a specified length from a given position in the input string. In our case, we are extracting one character at a time, starting from the beginning of the desired string, and then comparing the obtained character with each letter of the alphabet, numbers, and other characters. Once TRUE is met in the condition, we will immediately notice it.

In this way, we send a series of requests, changing the compared characters and the position number in the string. Let's use Burp Suite to perform this operation, but first, create a text file that contains all the letters of the Latin alphabet (both uppercase and lowercase) and numbers (from 0 to 9).

In Burp Suite, intercept the required request and send it to Intruder, where you can insert the prepared SQL query:

Applying Blind SQLI payload in Intruder

In the "Payloads" tab, select the pre-prepared file containing Latin letters and numbers:

Payload configuration in Intruder for Blind SQLi

Start the attack and in the opened window, select the query whose length differs from the others:

Review of Successful Blind SQLi attack

The first letter is ready; now we change the position number and launch the attack again:

Changing parameters Blind SQLi payload

Since we don't know how many characters are in the name of the database, we can use the following query to estimate the number of characters:

1' AND LENGTH(DATABASE()) < 10 #

Using this exploitation method, you can extract practically any information from the database.

 

Calling for an execution delay

In many applications, database requests happen sequentially and synchronously, meaning that after sending a query, the browser essentially pauses and waits for the server's response. We can use this property to generate a delay on the server and thus confirm and exploit the SQLi vulnerability.

Once again, we will use the DVWA application. To confirm the vulnerability, enter the following query:

1' AND SLEEP(10) #

With the sleep() function, the database "sleeps" for the specified number of seconds in the parentheses. If you enter the above expression, the server's response will come in approximately 10 seconds, clearly indicating the presence of the vulnerability.

Now, let's try to construct an SQL expression to retrieve the name of the current database. The structure of the expression will look like this:

1' AND IF(condition, option_1, option_2)='option_2'

If the condition is TRUE, option_1 is executed, and if it's FALSE, option_2 is executed. We will use the condition SUBSTRING(DATABASE(), 1, 1)='a'. In other words, we will use a series of queries in which we change the letters of the alphabet and the position number in the desired string. The final expression will look like this:

1' AND IF(SUBSTRING(DATABASE(),1,1)='a', SLEEP(10), 'a')='a'

A similar option is available in other systems as well:

DBSM

Function

Example

MySQL

SLEEP(seconds)

SELECT SLEEP(10);

SELECT IF(condition,SLEEP(10),'a');

SELECT * FROM (SUBSTRING(version(),1,1)=5,SLEEP(10),null)

BENCHMARK(number_of_iterations, any_function)

IF(condition,BENCHMARK(5000000, ENCODE('HELLO')), 'a')='a'

Oracle

DBMS_PIPE.RECEIVE_MESSAGE('any_string',seconds)

SELECT CASE WHEN (condition) THEN 'a'||DBMS_PIPE.RECEIVE_MESSAGE(('a'),10) ELSE NULL END FROM dual

UTL_HTTP.REQUEST (‘http://non_existing_website/’)

SELECT UTL_HTTP.REQUEST (‘http://10.0.0.0/’) FROM DUAL;

PostgreSQL

PG_SLEEP(seconds)

SELECT PG_SLEEP(10);

SELECT CASE WHEN (condition) THEN PG_SLEEP(10) ELSE NULL END

MS SQL Server

WAITFOR DELAY '00:00:10'

IF (condition) WAITFOR DELAY '0:0:10'

WAITFOR TIME '00:00:10'

IF (condition) WAITFOR TIME '0:0:10'