Web application firewalls are usually placed in front of the web server to filter the malicious traffic coming towards server. If you arehired as a penetration tester for some company and they forgot to tell you that they are using web application firewall than you might get into a serious mess. The figure below depicts the working of a simple web application firewall: As you can see its like a wall between web traffic and web server, usually now a days web application firewalls are signature based.
What is a signature based firewall?
In a signature based firewall you define signatures, as you know web attacks follow similar patters or signatures as well. So we can define the matching patterns and block them, i.e.
Payload :- <svg><script>alert`1`<p>
The payload defined above is a kind of cross site scripting attack, and we know that all these attacks can contain following substring -> “<script>”, so why don’t we define a signature that can block a web traffic if it contains this sub string, we can define 2-3 signatures as defined below:
First signature will block any request that contains substring, and second one will block alert(any text). So, this is how signature based firewall works.
How to know there is a firewall?
If you are performing a penetration test and you didn’t know that there was a firewall blocking the traffic than it can waste a lot of your time, because most of the time your attack payloads are getting blocked by the firewall not by your application code, and you might end up thinking that the application you are testing have a secure good and is good to go. So, it is a good idea to first test for web application firewall presence before you start your penetration test.
Most of the firewalls today leave some tracks about them, now If you attack a web application using the payload we defined above and get the following response:
HTTP/1.1 406 Not Acceptable Date: Mon, 10 Jan 2016 Server: nginx Content-Type: text/html; charset=iso-8859-1 Not Acceptable!Not Acceptable! An appropriate representation of the requested resource could not be found on this server. This error was generated by Mod_Security.
You can clearly see that your attack was blocked by the Mod_Security firewall. In this article we will see how we can develop a simple python script that can do this task detecting firewall and bypassing it.
Step 1: Define HTML Document and PHP Script!
We will have to define our HTML document for injection of payload and corresponding PHP script to handle the data. We have defined both of them below.
We will be using the following HTML Document:
<html> <body> <form name="waf" action="waf.php" method="post"> Data: <input type="text" name="data"><br> <input type="submit" value="Submit"> </form> </body> </html>
<html> <body> Data from the form : <?php echo $_POST["data"]; ?><br> </body> </html>
Step 2: Prepare malicious request!
Our second step towards detecting the firewall presence is creating a malicious cross site scripting request that can be blocked by the firewall. We will be using a python module called ‘Mechanize’, to know more about this module please read the following article :
If you already know about Mechanize, you can skip reading the article. Now that you know about Mechanize, we can select the web form present on any page and submit the request. Following code snippet can be used to do that:
import mechanize as mec maliciousRequest = mec.Browser() formName = 'waf' maliciousRequest.open("http://check.cyberpersons.com/crossSiteCheck.html") maliciousRequest.select_form(formName)
Lets discuss this code line wise:
- On the first line we’ve imported the mechanize module and given it a short name ‘mec’ for later reference.
- To download a web page using mechanize, instantiation of browser is required. We’ve just did that in the second line of the code.
- On the first step we’ve defined our HTML document, in which the form name was ‘waf’, we need to tell mechanize to select this form for submission, so we’ve this name in a variable called formName.
- Than we opened this url, just like we do in a browser. After the page gets opened we fill in the form and submit data, so opening of page is same here.
- Finally we’ve selected the form using ‘select_form’ function passing it ‘formName’ variable.
As you can see in the HTML source code, that this form have only one input field, and we are going to inject our payload in that field and once we receive response we’re going to inspect it for know strings to detect the presence of the web application firewall.
Step 3: Prepare the payload
In our HTML document we’ve specified one input field using this code:
input type="text" name="data">
You can see that name of this field is ‘data’, we can use following bit of code to define input for this field :
crossSiteScriptingPayLoad = "<svg><script>alert`1`<p>" maliciousRequest.form['data'] = crossSiteScriptingPayLoad
- First line saves our payload in a variable.
- In a second line of code, we’ve assigned our payload to a form field ‘data’.
We can now safely submit this form and inspect the response.
Step 4: Submit the form and record Response
Code I am going to mention after this line will submit the form and record the response:
maliciousRequest.submit() response = maliciousRequest.response().read() print response
- Submit the form.
- Save the response in a variable.
- Print the response back.
As I currently have no firewall installed, the response I got is :
As you can see that payload is printed back to us, means no filtering is present on the application code and due to the absence of firewall our request was also not blocked.
Step 5: Detect the Presence of firewall
Variable named ‘response’ contains the response we got from server, we can use the response to detect presence of firewall. We will try to detect the presence of following firewalls in this tutorial.
- Dot Defender.
Let see how we can achieve this with python code:
if response.find('WebKnight') >= 0: print "Firewall detected: WebKnight" elif response.find('Mod_Security') >= 0: print "Firewall detected: Mod Security" elif response.find('Mod_Security') >= 0: print "Firewall detected: Mod Security" elif response.find('dotDefender') >= 0: print "Firewall detected: Dot Defender" else: print "No Firewall Present"
If Web Knight firewall is installed and our request got blocked, response string will contain ‘WebKnight’ inside it some where, so find function will return value greater than 0, that means WebKnight firewall is present. Similarly we can check for other 2 firewalls as well. We can extend this small application to detect for as many number of firewalls, but you must know there response behavior.
Using Brute force to bypass Firewall filter
I’ve mentioned in the start of the article that mostly firewall these days block requests based on signatures. But there are hundreds and thousands of ways you can construct a payload. Java script is becoming complex day by day, we can make a list of payloads, and try each of them, record each response and check if we was able to bypass the firewall or not. Please note that if firewall rules are well defined than this approach might not work. Let see how we can brute force using python:
- On the first line we’ve defined a list of 3 payloads, you can extend this list and add as many payloads as you require.
- Then inside the for loop we did the same process we did above, but this time for each payload in a list.
- Upon receiving response we again compare and see see if firewall is present on not.
As I’ve had no firewall installed, my output was:
Convert HTML Tags to Unicode or Hex Entities
If for example firewall is filtering html tags like . We can send their corresponding Unicode or Hex Entities and see if they are being converted to there original form, if so, than this could be an entry point as well. Code below can be used to examine this process:
listofPayloads = ['<b>','u003cbu003e','x3cbx3e'] for payLoads in listofPayloads: maliciousRequest = mec.Browser() formName = 'waf' maliciousRequest.open("http://check.cyberpersons.com/crossSiteCheck.html") maliciousRequest.select_form(formName) maliciousRequest.form['data'] = payLoads maliciousRequest.submit() response = maliciousRequest.response().read() print "---------------------------------------------------" print response print "---------------------------------------------------"
Each time we will send the encoded entry and in the response we will examine if it got converted or printed back without conversion, when I ran this code I got the this output :
Means none of the encoded entry got converted to its original form.
The purpose of this article was to train you in advance so that you can penetrate your firewall before a hacker can do. It is always a good choice to self test your network infrastructure for vulnerabilities, because our first concern always is to get our application up and running and we overlook the security part. But it must not be over looked, because later it can be a huge headache. Complete source code can be downloaded from this link.
Usman Nasir, founder, and author of Cyberpersons is a Computer Science student. I also worked as a technical support staff at various hosting companies and love to write about Linux and web application security.