When dealing with filters, we need to determine how it is filtering our input in order to find a successful bypass technique.
Again we will work only with the event based payloads (on*=), because they represent more than 99% of all possible XSS payload constructions.
So, if we already can inject the tag part like “<anything”, we can simply set it as something with the minimum amount of chars like “<x” and start to test for the event handlers accepted.
That’s what I tried to summarize in this tweet (regarding WAFs – Web Application Firewalls):
#XSS vs WAF
1) use <x & jump to event handler
2) use onxxx=yyy & find number of x it accepts
3) test them & change tag accordingly
4) put js
— Brute (@brutelogic) October 10, 2015
The filter may be using a regex (regular expression) that flags a minimum number of chars after the “on” prefix and/or blacklists the known event handlers. If it does the latter, exclusively, there’s a great chance that they have missed one, and it will be just a matter of trying all of them.
But usually we have to test for how many chars it accepts after the “on” string, followed by a “=” sign. For this we will use the following pseudo-payload:
If it accepts it, we start to increase the number of X’s one by one, until we get a filter blocking.
<x onxxx=1 -> pass
<x onxxxx=1 -> pass
<x onxxxxx=1 -> block
From there we will have the maximum number of chars (6 in our example) that we can use to choose an event handler: the webGun tool has its event handlers list separated by number of chars to help on this task.
Event handlers with up to 6 chars:
oncut, onblur, oncopy, ondrag, ondrop, onhelp, onload, onplay, onshow
So the next step is just trying all event handlers allowed based on that number of chars; after finding one that does not get blocked, change the “<x” tag to one associated with it (no need if it’s one of the agnostic event handlers).
But if it does not accept the pseudo-payload above without blocking, with just 3 chars after “on”, it’s because we can’t inject even the shortest event handler so far, oncut.
In this case we will need to move to the following tricks to try to break the filter:
Encoding one or more key chars of the payload can be really tricky:
2) Mixed Case
Using uppercase in one or more chars may trick some poor filters:
Maybe the filter only looks for one occurrence of the pattern:
<x onxxx=1 onxxx=1
The following spacers can be used between the tag name and the event handler:
We may try to fool the filter with a quote before the handler using a tag pseudo-attribute:
The filter flow may allow us to pass a rule being disguised by allowed stuff:
<x </onxxx=1 (mimics a closing tag)
<x 1=“>” onxxx=1 (mimics a text outside of the tag)
<http://onxxx%3D1/ (mimics an URL)
We may combine some or all of the above: