This post will help you to evade some of those tricky cross site scripting restrictions with the help of a new tool I’ve pushed to our XSS Payloads repository.
There are times during a web application penetration test when Cross Site Scripting (XSS) has been identified with a trivial payload such as <script>alert(1)</script>
or via a Burp Suite scan result and you want to take it further, but for various reasons it’s not as easy as you would like to inject a useful JavaScript payload. This could be due to output encoding or character blacklisting, which might turn all your single and double quotes into their HTML entity equivalent, or it could be that simply by a quirk of where the injection occurs only non-letter characters can be used. In these cases we usually turn to encoding to build up an obfuscated string which will hopefully bypass these restrictions and that the application can interpret and execute.
For example, an application might block certain keywords in a string, so you encode your payload as base64 and then execute it by decoding with atob()
and passing that into eval()
, assigned to the “onerror” event of an image, to bypass restrictions on scripts:
<img src=x onerror=eval(atob('YWxlcnQoJ0kgb25seSB3cml0ZSBsYW1lIFBvQ3MnKQ=='))/>
Burp Suite includes a few options for this, such as the “Decoder” tool, which can convert strings to and from base64, URL encoding, ASCII hex etc, and the often overlooked “Construct string” function which includes “Construct string in JavaScript” to create a string purely by using the String.fromCharCode()
method.
This is fine for doing a quick fire and forget payload, but what happens when it doesn’t work and you want to make some changes? You slowly find yourself getting caught in your browser’s Developer Tools and making tweaks, then laboriously having to re-encode them to make your chosen bypass method work, then re-encapsulating them into whatever delivery method you were able to use to execute the XSS payload. It’s time consuming, boring and ends up leading to difficult to spot errors because you’re no longer looking at readable source code.
When the injection method becomes more complex, such as when testing blind XSS with something like 0xsobky’s XSS polyglot, having to encode a simple payload into a string begins to quickly become non-trivial.
There were no time-saving options for solving this problem so I decided to make one, and added it to our XSS Payloads repository. It works by setting three basic options for the payload you want to generate which combine to create an encoded string. They should be fairly logical once you get started, but in brief, they are as follows.
XSS Payload
This is what you want the actual action to be when the XSS is executed and includes two methods for inserting an external script (JQuery and document.createElement
), two methods for invoking a URL request (XMLHttpRequest
and Image
), which are good for establishing execution has occurred when testing for blind XSS, and finally the option to simply write your own JavaScript snippet for when you just gotta have alert(1)
.
Selecting one of the two load script payloads automatically gives you the option of choosing from the scripts in the XSS payloads repository.
Obfuscation
The next option contains a series of basic obfuscation methods. These are designed to simply bypass filters. By default “None” is selected which simply puts the XSS payload verbatim into the resulting injection string. We also have the option of:
- String
eval()
– passes the payload into theeval
function. - Base64 – uses
atob()
to pass the base64 payload intoeval
. - Reverse – hides the payload by reversing it before passing to
eval
. String.fromCharCode()
– builds the string by ordinal values.- Hex codes – uses hex notation to create a string.
Injection type
This is how the XSS payload actually ends up being interpreted by a browser and is where an app pentester should be spending their time. A basic polyglot that we all know and love is to assume the string is being output unescaped within an element attribute or textarea
, and simply attempts to break out of those:
'"></textarea><script>
We’ve included other examples for different situations as well, such as within an svg element onload
event or, my personal favourite – 0xsobky’s XSS polyglot, which is included in Daniel Miessler’s excellent SecLists repository. If the application can take the input that lengthy and it’s at all vulnerable to XSS, then there’s a good chance this payload will find it.
Output
If that didn’t work then you can simply tweak some of the options and the XSS payload will be regenerated automatically for you.
If you’ve used one of these payloads in a new and interesting way or you’ve thought of a new payload, obfuscation or injection option to add to the configuration, let me know – I’m @strawp on Twitter. Enjoy!