Detecting the database backend of a web application is one important step to go through to successfully exploit a SQL injection vulnerability.
Not only most of the common known injection vectors depend upon the DBMS (Database Management System) structure, also the algorithm syntax to perform a blind SQL injection attack and performance differs.
There are several ways to detect a web application database backend taking advantage of a SQL injection, the following fingerprint techniques are the ones I implemented so far on sqlmap:
Scenario
Let's assume that the remote web application is running on an unknown database backend, with a dynamic page (index.php) affected by a SQL injection on GET parameter id. The pseudo code of the page may be something like:
Inband DBMS error messages
The first test we could perform to detect the database backend is to pass to the id parameter random values with the aim to cause an error in the SQL syntax leading the application to leak information about the database backend.
Requesting http://example/index.php?id=1' it might show us:
There exist many passive SQL injection fuzz vectors, for a list see the OWASP Testing Guide Appendix C: Fuzz Vectors.
The pros of this technique is that it is neither invasive because we perform just a single HTTP request nor time consuming. The cons is that many web application approch to information leakage is security through obscourity, configuring their web server and removing from the web application code die (or similar function depending on the language) messages to simply avoid displaying any DBMS error message on the page or faking the result of malicious queries through web application firewalls or ad hoc input validation functions and filters.
Implementation on sqlmap code:
DBMS banner parsing
I consider the DBMS banner the version() function output or similar depending on the DBMS architecture.
Both MySQL and PostgreSQL have such function, Microsoft SQL Server banner can be considered the @@VERSION variable value and in Oracle the output of query select banner FROM v$version where banner like 'Oracle%'.
Assuming that we do not know yet from the only two HTTP requests which type of SQL injection is the page affected by, we can first check if it is an inband SQL injection, also referred as UNION query SQL injection. We request the page appending UNION SELECT NULL to the id parameter value requesting http://example/index.php?id=1+UNION+SELECT+NULL the output in our scenario is an error message:
Now that we know the number of columns is more that one, we have to know how many columns there are exactly so the second HTTP request will be http://example/index.php?id=1+UNION+SELECT+NULL,+NULL appending a ', NULL' as long as we do not get any DBMS error output in the page source.
In our scenario already at the second UNION SELECT request we know how many columns the table has, two. We can assert now that the target url is affected by an inband SQL injection vulnerability, to test if such issue is exploitable we can now request for instance http://example/index.php?id=1+UNION+SELECT+1234, NULL. If we are lucky the HTTP request output will be something like:
In our scenario the second column is a string (since its value is foo) so I will use it from now on.
Requesting http://example/index.php?id=1+UNION+SELECT+NULL, version() we get the banner of the web application database backend:
Implementation on sqlmap code:
More on DBMS fingerprint through SQL injection to come soon...
Not only most of the common known injection vectors depend upon the DBMS (Database Management System) structure, also the algorithm syntax to perform a blind SQL injection attack and performance differs.
There are several ways to detect a web application database backend taking advantage of a SQL injection, the following fingerprint techniques are the ones I implemented so far on sqlmap:
- Inband DBMS error messages
- DBMS banner parsing
- DBMS functions output comparison
- DBMS specific features
Scenario
Let's assume that the remote web application is running on an unknown database backend, with a dynamic page (index.php) affected by a SQL injection on GET parameter id. The pseudo code of the page may be something like:
<?Requesting http://example/index.php?id=1 the result page HTML is:
$link = sql_connect("localhost", "testuser", "testpass");
if (!$link) {
die(sql_error());
}
// Make 'testdb' the current database
$db_selected = sql_select_db("testdb", $link);
if (!$db_selected) {
die (sql_error());
}
// Perform query on current database
$query = "SELECT * FROM testtable WHERE id=" . $_GET['id'];
$result = sql_query($query);
if (!$result) {
die("Invalid query: " . sql_error());
}
// Print the results
print "<table>\n";
while ($line = sql_fetch_array($result, SQL_ASSOC)) {
foreach ($line as $col_value) {
print "<tr><td>";
print $col_value;
print "</td></tr>\n";
}
}
print "</table>";
// Free result set
sql_free_result($result);
// Close connection
sql_close($link);
?>
<table>
<tr><td>1</td></tr>
<tr><td>foo</td></tr>
</table>
Inband DBMS error messages
The first test we could perform to detect the database backend is to pass to the id parameter random values with the aim to cause an error in the SQL syntax leading the application to leak information about the database backend.
Requesting http://example/index.php?id=1' it might show us:
Invalid query: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1Now we know that the remote DBMS is probably MySQL.
There exist many passive SQL injection fuzz vectors, for a list see the OWASP Testing Guide Appendix C: Fuzz Vectors.
The pros of this technique is that it is neither invasive because we perform just a single HTTP request nor time consuming. The cons is that many web application approch to information leakage is security through obscourity, configuring their web server and removing from the web application code die (or similar function depending on the language) messages to simply avoid displaying any DBMS error message on the page or faking the result of malicious queries through web application firewalls or ad hoc input validation functions and filters.
Implementation on sqlmap code:
DBMS banner parsing
I consider the DBMS banner the version() function output or similar depending on the DBMS architecture.
Both MySQL and PostgreSQL have such function, Microsoft SQL Server banner can be considered the @@VERSION variable value and in Oracle the output of query select banner FROM v$version where banner like 'Oracle%'.
Assuming that we do not know yet from the only two HTTP requests which type of SQL injection is the page affected by, we can first check if it is an inband SQL injection, also referred as UNION query SQL injection. We request the page appending UNION SELECT NULL to the id parameter value requesting http://example/index.php?id=1+UNION+SELECT+NULL the output in our scenario is an error message:
Invalid query: The used SELECT statements have a different number of columnsThis means that the UNION SELECT statement is wrong which is another information leakage because know we know that the table has more than one column. However, in our scenario we could already assume that because the output of the normal HTTP request (id=1) has two fields in the output (1 and foo) but I personally prefer not to count on such sources of information because on the wild during penetration tests we are supposed to have as few information as possible from the customer about the web application we have to exploit, that's why testing the UNION SELECT statement ourselves provides better results than relaying on the normal HTTP request output parsing.
Now that we know the number of columns is more that one, we have to know how many columns there are exactly so the second HTTP request will be http://example/index.php?id=1+UNION+SELECT+NULL,+NULL appending a ', NULL' as long as we do not get any DBMS error output in the page source.
In our scenario already at the second UNION SELECT request we know how many columns the table has, two. We can assert now that the target url is affected by an inband SQL injection vulnerability, to test if such issue is exploitable we can now request for instance http://example/index.php?id=1+UNION+SELECT+1234, NULL. If we are lucky the HTTP request output will be something like:
<table>As you can see 1234 is there in the HTTP source so the inband SQL injection is exploitable. We can now use this information for any further SQL injection. The only thing to take into account is that the length of the first column of the table, in our scenario, is probably a number (since its value is 1 without any bracket) so if we request a string in the UNION SELECT statement, it might lead to a DBMS query syntax error being the "unified" fields of different types or the output too large. Fortunately MySQL is not that restrictive and the type casting is done automatically in such simple cases , but PostgreSQL and others DBMS are so pay attention to this inconvenient passing to use the second NULL and so on as long as you're sure that such field is a string.
<tr><td>1</td></tr>
<tr><td>foo</td></tr>
<tr><td>1234</td></tr>
<tr><td></td></tr>
</table>
In our scenario the second column is a string (since its value is foo) so I will use it from now on.
Requesting http://example/index.php?id=1+UNION+SELECT+NULL, version() we get the banner of the web application database backend:
<table>The pro of this technique is that it is not invasive because we perform just a single HTTP request once we know how many columns in the table there are. Another pro is that the output of a database function (version() for instance) or a database system variable (@@VERSION in Microsoft SQL Server) is by default accessible by all DBMS users, including the totally unprivileged ones. Last, but not least this output can be "hardly" faked at database backend side. The con is that common network intrusion detection systems (Snort for instance), network intrusion prevention system (IBM Proventia Network Intrusion Prevention System for instance) and, always more and more diffused, web application firewalls and IDS like PHPIDS, filter the HTTP requests containing malicious SQL requests, but there are some general evasion techniques and specific ones depending on the remote web server and database backend.
<tr><td>1</td></tr>
<tr><td>foo</td></tr>
<tr><td></td></tr>
<tr><td>5.0.38-Ubuntu_0ubuntu1-log</td></tr>
</table>
Implementation on sqlmap code:
More on DBMS fingerprint through SQL injection to come soon...

1 comments:
Great article, keep on with the good work! sqlmap code is just awsome and keeps getting better!
Post a Comment