Bypassing web application firewalls using HTTP headers

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!

 

--------

 

Here at FoD we have a premium tier of our dynamic application testing service. In this tier we give the app a thorough grokking with one of our senior web penetration testers and our industry leading tools. It goes through an extensive methodology driven assessment. This vulnerability is akin to something that would show up on that tier of test. To learn more about Fortify on Demand’s dynamic assessments for web applications or mobile applications, visit the link below:

 

hp.com/go/fortifyondemand

 

 

 

Comments
g33cko(anon) | ‎03-20-2014 05:41 AM

Heh, nice catch.

I have not stumbled upon a similar thing but definately will keep in mind.

Thank you for sharing !

Kevinff(anon) | ‎03-21-2014 06:56 AM

This is an error of a WP security plugin i guess (so is the 418 error, i think it's of wp better security?).

I think (i may be wrong), this could happen with bad plugins that use the wrong headers to retrieve the real client ip, there might have many WP plugins (and other cms) out there that don't allow the user to specify which header to search for the real ip, and that try to get it from all possible headers.. This is so wrong!

I think that's always better to do it through the webserver instead of using those broken plugins, in nginx you can specify the header to look for the real ip, in apache rpaf too.

Great article.

Brian McHenry(anon) | ‎03-27-2014 10:54 AM

That's a pretty wildly bad mis-configuration.  There's no reason the WAF should have to explicitly trust itself, and moreover, a cache server should never be treated as a trusted source, in any event.  And there's no good reason to trust the XFF header (of any name) to enable a bypass.


Even when counseling customers using large CDN's, the only way to ensure some integrity of an XFF header is to restrict the network-level permitted sources to the CDN IP's, and then use the XFF for more advanced correlation and mitigation (like IP reputation or geolocation).

MixALot(anon) | ‎03-28-2014 10:36 AM

Great article!

 

Since this is your environment, can you tell us if the WAF in the test was used in a proxy configuration? This may be of no consequence for how the WAF determines how to block the source, but my question is whether the WAF will use the X-originating-IP to actually route traffic in any instance, or if this is decoupled with the TCP/IP info for the actual routing of the packets involved. I am wondering if a WAF as a proxy configuration would handle these blocks differently than an inline or promiscuous installation topology, or if this is of no real consequence? 

 

Or maybe I am looking at this all wrong :)

Wth2014(anon) | ‎03-29-2014 05:12 PM
You may want to check CDNs as they have their own headers which you can add to your list. Good stuff.
Leave a Comment

We encourage you to share your comments on this post. Comments are moderated and will be reviewed
and posted as promptly as possible during regular business hours

To ensure your comment is published, be sure to follow the Community Guidelines.

Be sure to enter a unique name. You can't reuse a name that's already in use.
Be sure to enter a unique email address. You can't reuse an email address that's already in use.
Type the characters you see in the picture above.Type the words you hear.
Search
Showing results for 
Search instead for 
Do you mean 
About the Author


Follow Us
The opinions expressed above are the personal opinions of the authors, not of HP. By using this site, you accept the Terms of Use and Rules of Participation