Bypassing Cloudflare's WAF for XSS atacks (for open redirect)

Hello there,

Today i'll show you how I found a XSS bypass for Cloudflare's WAF that allows a tag to cause open redirect.

Introduction:

It all started when I randomly came across on Twitter with the account of an American university (who's name I wont reveal for obvious reasons) that was advertising their study plan on their website. As I was bored I decided to follow the ancient tradition of submitting “><img> in every form I see from every website I visit. Surprisingly I was able to successfully inject the tag into the response so I decided to escalate it to actually execute some code in my browser. My next step was to inject <svg onload=“alert(1)”> but it got instantly blocked by the website's WAF. In that very moment I knew that even if the website had an obvious vulnerability, things weren't going to be that easy for me to inject some code on it. My first step was to identify what was actually blocking my petitions and if there was any kind of public unfixed bypass for it, so I ran a very known python script called Wafw00f (https://github.com/EnableSecurity/wafw00f) to see what was going on. After that, things were pretty clear for me, I had to deal with Cloudflare's WAF and all public XSS bypasses were already fixed, so I had to create my own.

Messing with the WAF and finding the bypass:

For testing the WAF I started with the most known payloads in order to see how it blocks them while I slowly remove or replace components. While doing this I discovered that the <script> tag is always blocked, however the <svg> and <img> tags are allowed. Other important thing is that any event inside a <svg> tag is always blocked if it has quotes on it, but since quotes are not necesary because most modern browsers autocompletes them, we can avoid that block. Example: <svg onload=“thisIsNotEvenJS”> Blocked <svg onload=thisIsNotEvenJS> Not blocked

From this point, I only had to obfuscate the content of the onLoad() function. Obviously the alert(1) was blacklisted and any kind of similar alternative was also forbidden, “ale”+“rt(1)”, al\x65rt\x2814\x29``, alert;throw 1337 (this last one was harder to pull off because of the space between the “throw” and the “1337” was breaking the quotes autocomplete from the browser). I also tried using JSFuck (http://www.jsfuck.com/) but the WAF was blocking the brackets and the square brackets () []. Note: Brackets were only blocked if they were opened and closed “( )”, single brackets were allowed “(” or “)”. The same goes for square brackets and diacritical accents. Finally after some testing I came up with this payload that doesn't uses brackets in order to redirect the user to a malicious website from the attacker:

<svg onload=document.location=“https://example.com">

Getting a POC:

Lucky for us, Cloudflare has a vulnerable web for testing their WAF, so you can see how the bypass works (as long it's not fixed), even though if you are interested in working aside Cloudflare's knowledge, keep in mind they probably store everything is tested in this web. https://waf.cumulusfire.net/xss?globalHtml=

https://waf.cumulusfire.net/xss?globalHtml=<svg+onload=document.location="https://example.com">

See you next time and remember, a WAF will never be a patch to a security flaw.