Image

Reminder: VERT Vuln School guides are published for educational purposes only.
In our last post, we demonstrated how an attacker could leverage a classical SQL injection vulnerability in a web application to leak database information (by reflecting the result of the database queries onto the web application itself). In this post, we are going to show how an attacker can exploit a slightly different variation of SQL injection, known as "blind SQL injection." Blind SQL injection is nearly identical to classical SQL injection. That is, attacker-tainted queries are still able to reach the backend DBMS interpreter and alter the result set of the queries. However, the result of the query is no longer displayed on the web application. Instead, the attacker only knows whether the tainted-query returned a result or not (using inference based on how the web application behaves with certain inputs). Let's see how this binary output can be leveraged to extract database information. To demonstrate the exploitation of a blind SQL injection vulnerability, we added a page, forgot.php, into our custom vulnerable web application, BankOfVERT.Image

Image

Image

Image

fakeusername'or'1'='1
, we see that the response of the page changes. Recall that by injecting 'or'1'='1
, we are effectively changing the original query from returning 0 results, to now returning all results whenever 1=1, which is always. However, unlike our previous examples, we are not able to directly see the output of the results. Therefore, we need to figure out a way to use this true/false output to leak details about the backend database.
Let’s take a look at one way this can be achieved…
Image

fakeusername' or mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1)='a
Notice that this seemingly complicated injection payload resulted in the query being true. Let’s break the query down and examine what is happening.
fakeusername' or
allows us to break out of the original query using a single quote.
mid((...),1,1)
is a MySQL built-in function which is an alias of substring(). It takes in 3 arguments: the original string, the start position of the substring, and the desired length of the substring. In this case, we are asking MySQL to return a substring of length 1 starting at position 1 (the first character).
(select group_concat(table_name) from information_schema.tables where table_schema=database())
is simply a nested MySQL query. In this example, we are asking for a list of tables in the current database.
='a
is comparing the result of the previous mid() function to the letter ‘a’. Note that the trailing single quote is left out because it will be completed by the original query hardcoded by the web application.
We see that the output of the page indicates the query resulted as true, which means the first letter of the list of tables is the letter ‘a’. Let’s see what happens if we compare it with the letter ‘b’...
Image

Image
