I dislike most XSS cheat sheets out there. Many attempt to be copy-and-paste sources (and never clean up things that stopped working 10 years ago) while ignoring that in most instances where you’re doing more difficult than trivial injection literally none of it will work for one reason or another (be it WAF or a XSS filter), and if it is trivial XSS then you just need one vector and not a million.
So I wanted to make a different kind of cheat cheet. A cheet sheet of techniques and tips and a brief list of examples for them all. My goal is that even if you encounter a weird filter or WAF, something in here will likely help you or give you ideas on how to proceed in attempting injection against it. There is no way to cover literally every possible thing you can do, but I believe what I’ve managed to cover is a vast majority of the techniques still in use in 2020.
Creating this has taken 10x longer than I initially expected, but I know that this list has been useful to me, so hopefully it will be useful for you as well.
Tag-attribute separators
Sometimes filters naively assume only certain characters can separate a tag and its attributes, here’s a full list of valid separators that work in firefox and chrome:
Decimal value | URL Encoded | Human desc |
---|---|---|
47 | %2F | Foward slash |
13 | %0D | Carriage Return |
12 | %0C | Form Feed |
10 | %0A | New Line |
9 | %09 | Horizontal Tab |
Usage
Basically, if you have a payload that looks like:
|
|
You can try to replace the space between ‘svg’ and ‘onload’ with any of those chars and still work like you expect it to:
So, these are all valid HTML and will execute (demo: valid html ):
|
|
JavaScript event based XSS
Good reference for more events: More HTML events
Standard HTML events
(0-click only)
Name | Tags | Note |
---|---|---|
onload | body, iframe, img, frameset, input, script, style, link, svg | Great for 0-click, but super commonly filtered |
onpageshow | body | Great for 0-click, but appears only usable in Non-DOM injections |
onfocus | most tags | for 0-click: use together with autofocus="" |
onmouseover | most tags | if possible, add styling to make it as big as possible. It’s technically a 0-click if you don’t have to click, right? /s |
onerror | img, input, object, link, script, video, audio | make sure to pass params to make it fail |
onanimationstart | Combine with any element that can be animated | Fired then a CSS animation starts |
onanimationend | Combine with any element that can be animated | Fires when a CSS animation ends |
onstart | marquee | Fires on marquee animation start - Firefox only? |
onfinish | marquee | Fires on marquee animation end - Firefox only? |
ontoggle | details | Must have the ‘open’ attribute for 0-click |
Examples:
|
|
HTML5 events
(0-click only)
Name | Tags | Note |
---|---|---|
onplay | video, audio | For 0-click: combine with autoplay HTML attribute and combine with valid video/audio clip |
onplaying | video, audio | For 0-click: combine with autoplay HTML attribute and combine with valid video/audio clip |
oncanplay | video, audio | Must link to a valid video/audio clip |
onloadeddata | video, audio | Must link to a valid video/audio clip |
onloadedmetadata | video, audio | Must link to a valid video/audio clip |
onprogress | video, audio | Must link to a valid video/audio clip |
onloadstart | video, audio | Great underexploited 0-click vector |
oncanplay | video, audio | Must link to a valid video/audio clip |
Examples:
|
|
CSS-based events
Unfortunately, true XSS through CSS appears dead. All the vectors I’ve attempted only work on extremely old browsers. So what we’ve got is XSS that triggers based on CSS unless you feel like arguing with devs that an IE8 or old opera vulnerability is still a valid risk.
Note: Below uses style tags to set up keyframes for animation(start|end), but you can also check for already included CSS to reuse what’s already there.
|
|
|
|
Weird XSS vectors
Just some odd/weird vectors that I don’t see mentioned often.
|
|
XSS Polyglots
I use several XSS polyglots because sometimes you only have a certain # of characters to input and need a DOM or non-DOM based one.
Don’t rely on these as there are circumstances they will fail, but if you’re fuzzing everything then polyglots can give okay coverage.
# chars | Usage | Polyglots |
---|---|---|
141 | Both | javascript:"/*'/*`/*--></noscript></title></textarea></style></template></noembed></script><html \" onmouseover=/*<svg/*/onload=alert()//> |
88 | Non-DOM | "'--></noscript></noembed></template></title></textarea></style><script>alert()</script> |
95 | DOM | '"--></title></textarea></style></noscript></noembed></template></frameset><svg onload=alert()> |
54 | Non-DOM | "'>-->*/</noscript></ti tle><script>alert()</script> |
42 | DOM | "'--></style></script><svg onload=alert()> |
Frameworks
To attack JS Frameworks, always do research on the relevant templating language.
AngularJS
|
|
That payload works in most cases, but this great resource has a bunch of other recommendations for various versions you may want to try.
Mavo
|
|
XSS Filter Bypasses
Parenthesis filtering
Abusing HTML parsers and JS Syntax:
|
|
Restricted charset
These 3 sites will transform valid JS to horrible monstrosities that have a good shot at bypassing a lot of filters:
Keyword filtering
Avoiding keywords:
|
|
mXSS and DOM Clobbering
It’s basically impossible for XSS filters to correctly anticipate every way that HTML will be mutated by a browser and interacting libraries, so what happens is that you can sometimes sneak a XSS payload in as invalid HTML and the browser will correct it into a valid payload… which bypasses the filter.
mXSS paper with lots of details: here
Talk with good info on clobbering: here
mXSS payload that bypasses one of the most commonly used filters:
DOMPurify <2.0.1
|
|
Double encoding
Simple enough, sometimes an application will perform XSS filtering on a string before it’s decoded once more, which leaves it open by filter bypasses. It’s pretty rare, but some bug hunters I know swear by it so I’m including it for reference.
Char | Double encoded |
---|---|
< | %253C |
> | %253E |
( | %2528 |
) | %2529 |
" | %2522 |
' | %2527 |
General tips
- VaRy ThE capItaliZatiOn. Sometimes a regex or other custom-made filters do case sensitive matching.
- Practice your XSS skills on CTFs like Pwnfunction’s XSS CTF . You will likely learn techniques you did not know existed.
Resources
Great other resources:
Fantastic collection of somewhat old XSS stuff
Portswigger XSS cheatsheet
Portswigger XSS through Frameworks