Bypassing WAFs with non-alphanumeric XSS.

This post is an attempt to expand what we already discussed on Patricio’s blog, but with a focus on security in web applications. Although this post will not be a shocker, I will try to make it as interesting and entertaining as possible. If you have not read what Patricio and I wrote on his blog you should go there before continuing, otherwise you may not understand properly some of the references I will be making.

Cross site scripting attacks

As some of you may know, the common security method to prevent XSS is by escaping attacker controlled input (which ultimately becomes webserver output, assuming a persistent web form attack for example), so having a template engine doing this automatically is the best practice. Unfortunately not everybody follows this recommendation, and when manually escaping, people are really prone to making mistakes. So, to overcome this, Web Application Firewalls (WAFs) and Intrusion Detection/Prevention Systems (IDS/IPS) do their part mitigating what has been left behind.

So from an attacker’s point of view we have three stages to bypass, user input sanitization (due to manual escaping mistakes), WAF filtering (by rules such as those provided by modsecurity), and browser protections (which are not covered in this article).

Bypassing WAF filters

Basically, the purpose of a network-based application layer firewall is to monitor and block user content which violates pre-defined policies. In our case, these polices are patterns of user input which can potentially end up in an attack.

The main idea of bypassing a WAF is to craft requests semantically equivalent to a XSS attack for example, while avoiding the security policies.

For XSS, you usually make use of JavaScript’s common methods to steal user information, such as: eval(), Function(), document.write(), document.cookie(), alert(), etc. The problem is, the majority of the WAFs will filter the request immediately if one of these methods are found in a request. Also, if you know the target’s browser, with the help of its API you can use non-standarized methods to extend the attack, which can lead to an easier bypass since most of non-standarized methods are not taken into account by most policies.

But applying what we have learnt about encoders like hieroglyhphy (my python port), jsfuck, and others, we can obfuscate our attack and payload properly. The downside would be that the encoding will increase considerably the amount of characters used on the original request (a friend’s research has shown inflation rates of between 600 and 1000 times, with 650-850 being typical when obfuscating an entire script, such as for exploitation), but we don’t really need to fully encode it, we can just encode parts of it, like half of a method’s name or sensitive parts for exploitation.

Here’s a simple example that you can test in your browser’s interactive console:
eval("aler"+(!![]+[])[+[]])("xss")

If you have not had any luck yet don’t get sad, there are still other ways to try to trick the security measures. Since JavaScript has two different syntactic forms to access properties, you can access an Object method like a dictionary: object.method(arguments) === object["method"](arguments)

An example with document.cookie() would be: document["cookie"], where cookie is passed as a string which you can obfuscate like this:
document[({}+[])[!+[]+!![]+!![]+!![]+!![]]+({}+[])...]

I didn’t include the entire obfuscated representation as it is very long (2727 characters to be exact).

There are also alternate ways of accessing them too, in case the document word is also filtered. Since this is a reference to the current window you can use it as a “dictionary” too: this["document"]["cookie"]

Same thing with the rest, like alert():
this["alert"]("xss")
window["alert"]("xss")

Combining them you can get different results, also applying hex encoding is useful, some WAFs get bypassed just with that.

window[(+{}+[])[+!![]]+(![]+[])[!+[]+!![]]+([][+[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]]

this['ale'+(!![]+[])[-~[]]+(!![]+[])[+[]]]()

this['\x64\x6f\x63\x75\x6d'+([][+[]]+[])[!+[]+!![]+!![]]+([][+[]]+[])[+!![]]+(!![]+[])[+[]]][({}+[])[!+[]+!![]+!![]+!![]+!![]]+({}+[])[+!![]]+({}+[])[+!![]]+'kie']

document['\x63\x6f\x6f\x6b\x69\x65']
Here you can find more examples.

Playground

If you already feel like playing a little with this, I made a playground for the anxious people that want to apply what have learnt above. It’s a little script with different kind of vulnerabilities with a basic simulation of a simple WAF ruleset. The goal is to retrieve the cookies from anybody who visits the site, bypassing the security measures with the above. Consider doing it manually.

Click here to go to the playground.

Pyronbee

“We should accept WAFs for what they really are: a method of increasing the cost of attacks, but not necessarily one that might repel every attacker.”
Sometimes you find yourself doing a pentest and the security (WAF, IDS, IPS) starts to block certain requests you perform, for example the ones for an SQL injection. Knowing that a WAF does not see the same as a web server, tweaking our request a little can cause the security mechanisms to ignore it, but the webserver may understand it as a successful request.

One thing that you always must keep in mind is impedance mismatch: “you’re interpreting the stream of data in one way, but there’s a danger that whatever you are protecting is interpreting the same data differently”. Web servers tend to fix malformed requests, and there are modules to correct some urls to specific documents and paths, such as mod_spelling. So you can try to send “broken” requests hoping that the WAF will consider it harmless and the web server interpret it correctly.

So to accelerate the process, I’ve made pyronbee, a tool based on a project titled waf-research (IronBee) on github by Ivan Ristic, creator of ModSecurity, in which you can automate and make custom requests to a certain host to check which formatted requests get filtered and which ones get past the WAF.
(I’m currently making a script to port the test files made for IronBee to JSON syntax in order to use it with mine.)
“In fact, bypassing network-centric security tools is bound to be easier because in general, they perform less HTTP processing (parsing) than web application firewalls.”
In this case, we would use pyronbee to see which .test files are not filtered by security rulesets, using encoded requests for pyronbee with tools like hieroglyphy.
Despite we are trying to bypass a WAF, we are not really doing it in a low-level protocol, since the idea of doing so is to replicate the bypass on foreign browsers as a CSRF/XSS attack. If you want to go any further with this, you can format pyronbee requests to fulfill your needs at that level, but that would be another whole story.

As for the playground, pyronbee won’t be of any help because it’s a php script simulating a WAF with just a str_replace. However yon can host it on your site and play a little with it. Here’s the playground source code, and maybe you might want to use the test/playground/ folder .test files for that.

On pyronbee’s main folder you will find another folder named ‘extra’ where you have a script which can craft standarized HTTP/1.1 GET requests from a list of your own, choosing a desired prefix, in pyronbee’s .test file format.

Side notes and aknowledgments

Just to clarify, hieroglyphy was just an example, there are multiple ways of doing encodings, with more or less characters, but you always have the trade-of between encoding size and charset length. And remember to use url encoding when needed on pyronbee .test files, because for example for the + , the webserver interprets it as a space, and you will generating false positives.

I’d like to thank kernelsmith, an user I met on IRC that was porting hieroglhyphy to ruby with the idea to include it on metasploit as an obfuscator. In the meanwhile we realized that older versions of IE (< 9) and JS in IE9 on ‘quirksmode’ do not support some stuff, like accessing a string as an array, unless the site is using a standarized DOCTYPE. Take this as a side note in case you want to develop obfuscated exploits to bypass AVs. Besides from that, he was really supportive and enthusiastic all the time.

Finally, I will also like to thank snf, a friend, who was very supportive to my ideas during the development of pyronbee.

The quotes I’ve made are from the following paper: Protocol-Level Evasion of Web Application Firewalls.
Post a Comment
Thanks for your comment