Exploiting Truncation
Sanitizing
filters often perform several operations on user-supplied data, and
occasionally one of the steps is to truncate the input to a maximum
length, perhaps in an effort to prevent buffer overflow attacks, or
accommodate data within database fields that have a predefined maximum
length.
Consider a login function which performs the following SQL query, incorporating two items of user-supplied input:
SELECT uid FROM tblUsers WHERE username = 'jlo' AND password = 'r1Mj06'
Suppose the application employs a sanitizing filter, which performs the following steps:
Doubles up quotation marks, replacing each instance of a single quote (‘) with two single quotes (“)
Truncates each item to 16 characters
If you supply a typical SQL injection attack vector such as
the following query will be executed, and your attack will fail:
SELECT uid FROM tblUsers WHERE username = 'admin''--' AND password = ''
Note that the doubled-up
quotes mean that your input fails to terminate the username string, and
so the query actually checks for a user with the literal username you
supplied.
However, if you instead supply the username
which contains 15 a's
and one quotation mark, the application first doubles up the quote,
resulting in a 17-character string, and then removes the additional
quote by truncating to 16 characters. This enables you to smuggle an
unescaped quotation mark into the query, thus interfering with its
syntax:
SELECT uid FROM tblUsers WHERE username = 'aaaaaaaaaaaaaaa''
AND password = ''
This initial attack results
in an error, because you effectively have an unterminated string: Each
pair of quotes following the a's represents an escaped quote, and there
is no final quote to delimit the username string. However, because you
have a second insertion point, in the password field, you can restore
the syntactic validity of the query, and bypass the login, by also
supplying the following password:
This causes the application to perform the following query:
SELECT uid FROM tblUsers WHERE username = 'aaaaaaaaaaaaaaa'' AND
password = 'or 1=1--'
When the database executes this query, it checks for table entries where the literal username is
aaaaaaaaaaaaaaa' AND password =
which is presumably always
false, or where 1 = 1, which is always true. Hence, the query will
return the UID of every user in the table, typically causing the
application to log you in as the first user in the table. To log in as a
specific user (e.g., with UID 0), you would supply a password such as
the following:
Other Truncation Attacks
Truncation of user-supplied
input in SQL queries can lead to vulnerabilities even when pure SQL
injection is not possible. In Microsoft SQL Server, parameterized
queries must specify a maximum length for each string parameter, and if
longer input is assigned to the parameter it is truncated to this
length. Furthermore, SQL Server ignores trailing whitespace when
comparing strings within a WHERE
clause. These features can lead to a range of problems in vulnerable
applications. For example, suppose an application allows users who have
forgotten their password to submit their e-mail address and receive
their forgotten password via e-mail. If the application accepts overly
long input which gets truncated within the SQL query, an attacker can
submit the following input:
In the resultant
query, this input will retrieve the password for [email protected],
because the trailing whitespace in the truncated input is ignored:
SELECT password FROM tblUsers WHERE email = ' [email protected]'
When the application then
sends the password to the originally supplied e-mail address, a copy is
also sent to the attacker, enabling him to compromise the victim's
account. For further details of this and similar attacks, see the paper
“Buffer Truncation Abuse in .NET and Microsoft SQL Server,” written by
Gary O'Leary-Steele and available at www.scoobygang.org/HiDDenWarez/bta.pdf.
|
Bypassing Custom Filters
Web
applications are extremely varied, and you are likely to encounter all
kinds of weird and wonderful input filters in the wild. You frequently
can bypass these filters with a little imagination.
Oracle Application
Server provides a useful case study in poorly devised custom filters.
This product provides a Web interface to database procedures, enabling
developers to quickly deploy a Web application based on functionality
that is already implemented within
a database. To prevent attackers from leveraging the server to access
the powerful procedures that are built into the Oracle database, the
server implements an exclusion list, and blocks access to packages such
as SYS and OWA.
Blacklist-based filters
of this kind are, of course, notoriously susceptible to bypasses, and
Oracle's exclusion list is no exception. In the early 2000s, David
Litchfield discovered a series of defects in the filter, each involving
ways of representing blocked packages that appear benign to the
front-end filter but are still processed as intended by the back-end
database.
For instance, whitespace can be placed before the package name:
https://www.example.com/pls/dad/%0ASYS.package.procedure
The Y character in SYS can be replaced with a URL-encoded ÿ character:
https://www.example.com/pls/dad/S%FFS.package.procedure
The package name can be placed within quotation marks:
https://www.example.com/pls/dad/“SYS”.package.procedure
A programming goto label can be placed before the package name:
https://www.example.com/pls/dad/<<FOO>>SYS.package.procedure
Although these
examples are specific to a particular product, they illustrate the kinds
of issues that can arise with custom input filters, and the techniques
that you need to try when attempting to circumvent them.
Using Non-Standard Entry Points
Sometimes you
will encounter situations where application-wide defenses are in place
(such as WAFs) which implement effective input filters and prevent the
usual means of exploiting vulnerable code. In this situation, you should
look for non-standard entry points into the application, which may be
vulnerable to SQL injection and which the applicationwide filters may
have overlooked.
Many WAFs inspect the
values of every request parameter, but do not validate the parameter
names. You can, of course, add arbitrary parameter names to any request.
If the application incorporates arbitrary parameter names into dynamic
SQL queries, you may be able to perform SQL injection despite the
presence of the filter.
Consider an
application function which saves user preferences. The preferences page
has a large number of input fields, which are submitted to a URL such as
the following:
https://www.example.org/Preferences.aspx?lang=en®ion=uk¤cy=gbp…
Requesting this URL causes the application to make a number of SQL queries of the form:
UPDATE profile SET lang='en' WHERE UID=2104
UPDATE profile SET region='uk' WHERE UID=2104
UPDATE profile SET currency='gbp' WHERE UID=2104
…
Because the fields used
for preferences change over time, the developers decided to take a
shortcut and implemented the functionality as follows:
IEnumerator i = Request.QueryString.GetEnumerator();
while (i.MoveNext())
{
string name = (string)i.Current;
string query = “UPDATE profile SET ” + name + “='”
+ Request.QueryString[name].Replace(“'”, “''”) +
“' WHERE uid=” + uid;
…
}
This code enumerates all of
the parameters supplied in the querystring, and builds an SQL query
using each one. Although quotation marks in parameter values are being
escaped, in an attempt to block SQL injection attacks, the parameter
values are embedded directly into the query without any filtering.
Hence, the application is vulnerable, but only if you place your attack
into a parameter name.
A similar vulnerability
can arise if the application contains a custom logging mechanism which
saves to the database all requested URLs, including the querystring. If
the input filters validate parameter values but not parameter names, you
can place payloads into a parameter name to exploit the vulnerability.
Another entry
point which applicationwide input filters typically overlook is the
headers within HTTP requests. Application code can process HTTP headers
in arbitrary ways, and applications frequently process headers such as
Host, Referer, and User-Agent in application-level logging mechanisms.
If the values of request headers are incorporated into SQL queries in an
unsafe manner, you may be able to perform SQL injection by attacking
these entry points.
Injection via Search Query Referers
In addition
to custom mechanisms for logging requests, many applications perform
traffic analysis functions, providing administrators with data regarding
the navigational paths followed by users within the application, and
the external sources from which users arrive at the application. This
analysis usually includes information about the search queries performed
by users which led them to the application. To determine the terms used
in these queries, applications check the Referer header looking for the
domain names of popular search engines, and then parse out the search
term from the relevant parameter in the Referer URL. If these terms are
incorporated into SQL queries in an unsafe manner, you can perform SQL
injection by embedding your attack in the query parameter of a search
URL, and submitting this within the Referer header. For example:
GET /vuln.aspx HTTP/1.1
Host: www.example.org
Referer:http://www.google.com/search?hl=en&q=a';+waitfor+
delay+'0:0:30'--
This kind of attack
vector is pretty obscure, and is likely to be missed by many
penetration testers and automated scanners (except for Burp Scanner,
which checks for this attack against every request scanned).