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.
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.
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:
- String eval() – passes the payload into the eval function.
- Base64 – uses atob() to pass the base64 payload into eval.
- 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.
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.
Add these all together and we end up with something pretty complex looking, which might have taken a bit of time to create manually:
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!