Bypassing web application firewalls using HTTP headers
jhaddix| March 19, 2014 - last edited March 20, 2014
1 Comments
1
2014-03-19_12-47-41.png
Web application firewalls (WAF’s) are part of the defense in depth model for web applications. While not a substitute for secure code, they offer great options for filtering malicious input. Below is a story from a real assessment where an enterprise deployment of such a device was vulnerable to being bypassed. The vulnerability is one of a bad design and/or configuration and as an attacker it was very useful. Read below to find out more!
Testing the security of an app in its production deployment is important. While this app might have been assessed in development or QA, when you deploy live you might introduce new attack vectors due to configuration issues. Such was the case with our fictional customer Heisenberg Bank.
While firing up the assessment I quickly ran into issues fuzzing all the application points I usually go after first, see below (screenshot approximated):
teapot.png
Well… that’s both humorous and unsatisfying.
After a bit of investigating I knew that I was up against a WAF that was triggering on a few things:
Rapid succession of POST request to forms
Rapid succession of GET requests to *most* pages
Lack of a CSRF token
*Bad* characters
After one of these conditions were met it would block me with said error code for 5 minutes.
So, how to proceed?
The normal method of encoding payloads to bypass WAF regexes is hit or miss these days. WAF’s have come a long ways. Still, I gave it a shot, no dice.
While waiting in one of my timeouts I decided to do some WAF research. While going through several WAF implementation guides I found a forum that mentioned integrating a WAF with your caching service/device. It described a user’s trouble with standing up something like Varnish or a proxy/accelerator appliance running on a different host, and that the WAF was blocking that server. Of course the vendor promptly replied that you can whitelist devices based on IP, allowing them not be inspected by the WAF.
At this point, everything is still fine. Below is where things went bad for Heisenberg Bank and the WAF.
After reading more, I found that instead of doing a real lookup on incoming requests (something akin to REMOTE_ADDR or something similar), the WAF was looking at a custom HTTP header.
This is how it’s supposed to work if a user or other server contacts the WAF:
supposed.png
Instead, the WAF checks the requests HTTP Headers. The specific implementation was checking the request for the header X-originating-IP.
So, who would this WAF be configured to trust? In this instance the default was… Itself!
Since I control all HTTP requests sent out of my browser I can easily add this header fooling the WAF to think I was itself, allowing me to bypass its protections completely:
wafreq.png
After further research there are several headers that can be defined for WAF’s to whitelist (instead of doing a proper lookup):
X-forwarded-for
X-remote-IP
X-originating-IP
x-remote-addr
There is also a hit-list of types of addresses/configurations that might be whitelisted/vulnerable. (some fictitious examples below):
headers.png
After figuring out the bypass, the rest of the assessment yielded many other vulnerabilities and was expedited due to the fact that I could bypass the WAF. It was as simple as having my inline interception proxy add the header to all requests.
A simple solution is having your frontend proxy strip all non-standard headers but then you’re still playing the cat and mouse game of blacklisting. Better yet, consult with your WAF vendor and see what headers are accepted and defaults are enabled. Then find a solution that doesn’t rely on information that the attacker can forge.
In general you can also audit the security of HTTP headers on your site using Gethead, a project from our dynamic testing team’s leader, Nathan LaFollette (@httphacker).
As always, feel free to reach out with any questions via Twitter (@jhaddix) or via email (jason.haddix@hp.com).
Happy hacking!