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
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=='))/>
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.
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 (
Selecting one of the two load script payloads automatically gives you the option of choosing from the scripts in the XSS payloads repository.
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:
eval()– passes the payload into the
- Base64 – uses
atob()to pass the base64 payload into
- Reverse – hides the payload by reversing it before passing to
String.fromCharCode()– builds the string by ordinal values.
- Hex codes – uses hex notation to create a string.
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:
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.
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!