Chrome XSS Auditor – SVG Bypass

More than an year ago, in my private twitter account Brutal Secrets, I shared an interesting way to bypass Google’s Chrome anti-XSS filter called XSS Auditor. We will see now in details, from a blackbox perspective, a logical sequence of assumptions and conclusions that leads to our XSS vector responsible for the bypass.

We start with a known source of trouble for all XHTML parsers (browsers) out there: Scalable Vector Graphics or SVG. Without getting deeper into the explanation of what SVG can do (check here), all we need to know is that SVG markup is way more complex than simple XML/HTML and full of unexplored resources for an attacker.

Starting with a simple <svg> tag we proceed using an empty anchor, the <a> tag that creates an hyperlink. Nested to this anchor we will use a rectangle to create a larger clickable area, ending up with something like this:

<svg><a><rect width=100% height=100%>

check here

We are now looking for a way to interact with the element but we can’t use event handlers due to Auditor’s blocking. So we will try one of the tags used in animations, notably the <animate> one. The <animate> tag takes an attribute (with attributeName) of a parent element (in our case the <rect> one) and manipulates its value, like “width” for instance. It creates the animation effect with the help of its own attributes “from”, “to” and “dur” (duration).

<svg><a><rect width=100% height=100%><animate attributeName=width from=0 to=100% dur=2s>

check here

The interesting conclusion here is that we are in fact changing the original value of “width” attribute, in sequence. But what if we target a different attribute? Let’s take the href of the anchor (<a>) which is not set but is implicit. With some tweak in attributes and a self-closed <rect>, we are ready to go.

<svg><a><rect width=100% height=100% /><animate attributeName=href to=//>

check here


<svg><a><rect width=100% height=100%><animate attributeName=href from=// to=?>

check here

By clicking in our rectangle now, we are redirected to Google’s website. So to pop an alert box, we will just try to change it to “javascript:alert(1)”.

Not that easy. Even an attempt to fool Auditor using HTML encoding gets blocked.

<svg><a><rect width=100% height=100% /><animate attributeName=href to=javas&#99ript:alert(1)>

check here

We get back to SVG Attribute Reference and find an interesting alternative to “from” and “to”: animation elements can also use a “values” attribute which provides the same set of values for the animation.

By simply setting “values” to “javascript:alert(1)” we get blocked again. But, surprisingly, this time we pop an alert using the HTML encoded form, “javas&#99ript:alert(1)”. Strange enough, any other arbitrary attribute with our obfuscated payload will fire a blocking but that one seems “whitelisted”!

We change the <rect> for an <image> tag, more suitable to attract a victim’s click. A little addition of text/markup and… Boom!

<svg width=12cm height=9cm><a><image href=// /><animate attributeName=href values=javas&#99ript:alert(1)>

check here

This bypass was found in version 51, although it might work in several past versions. It currently works on Google Chrome v60, the latest version at the time of this publication.