导语:今天我们要挖掘的是Edge绕过Sop限制的漏洞,但是漏洞利用的前提是,浏览器中的无域页面以及多余的数据标记都是可以访问到域内的页面的。
先通过视频看看这个漏洞的威力吧,在第一个59秒的视频中,我们使用用户名为:Charles Darwin发送推文。在第二个两分钟的视频中,我们通过Edge默认密码管理器进行发送推文甚至查看用户密码。Charles Darwin就是一个例子,这个漏洞允许攻击者在已经登录twitter的页面上进行关注,甚至产生更大的危害。
视频一:https://youtu.be/K3Ui3JxZGnE
视频二:https://youtu.be/PlxQBmLrnQA
如果你第一次了解sop绕过技术,建议你阅读之前两篇文章:Edge中无域页面进行绕过以及IE中无域页面绕过sop,在这篇文章中,使用了相同的想法,只是采用了不同的技术进行绕过。
先让我们快速的了解一个重要的概念:about:blank页面总是属于它来源的那个域。比如你在twitter页面的iframe标签就不可以访问属于google域中的about:blank页面。即使他们的名称都是about:blank,但是他们输出的document.domain是不同的。
在之前,我们已经创造出了无域的about:blanks页面。这些无域的页面可以访问任何域中的about:blank页面。比如我们在拥有一个主页面的about:blank,并且产生一个iframe指向twitter,另外一个指向google。这些iframe里面有一些空的子iframe,以及他们的域是twitter和google。所以在这种情况下,iframe的最顶端就可以访问域中的页面,也就是可以进入到google以及twitter的域中。
上述情况非常好,但是微软三个月前使用非常聪明的技巧修复了这个漏洞:无域about:blank页面不再是真正的域,微软为它们设置一个随机GUID作为域,如下所示:{53394a4f-8c04-
46ab-94af-3ab86ffcfd4c}。还有一些更有趣的东西(提示给边缘开发者):域将看起来好像是空白,但不是。换句话说,Edge将GUID隐藏并返回空,但在内部,它仍然是GUID。
那就让我们来试试吧,在Edege中按下F12打开调试器,然后在地址栏输入about:blank。这一步骤是用于产生一个无域的页面,现在看起来好像它和之前没有任何变化。但是Edge正在对我们作出防范。不过这对我们来说很轻易的就可以绕过~
我们可以看到,调试工具认为我们在一个空的域,但我们并不是。
绕过补丁,创造无域页面
就连调试工具都被微软的补丁所欺骗,那我们应该如何才能看到这里到底发生了什么改变呢?比预期的更容易,只要尝试加载任何具有相对路径的东西,或者改变这个窗口的位置,甚至使用document.write就可以发现这里改变了什么,让我们使用location.href=1,看看会发生什么?
data:uri方法被修复以及Flash没有开启
我们之前创造无域的about:blank页面的方法已经被修复。我们之前是在最顶层的窗口中使用data:uri。不过这个小伎俩已经被微软修补,甚至现在已经不能自动执行flash插件。在微软最近的更新后,每次执行flash之前,Edge都会对用户进行询问。
现在看起来,之前的POC(http://unsafe.cracking.com.ar/demos/edge-domainless-uxss/bing/index.html)看起来很丑。为Edge团队修复这一漏洞点赞。
发现新的无域页面
我们的data:uri的方法已经对这个攻击不起作用了,那么我们应该如何克服这一困难呢?首先,我将矛头指向了iframe标签, 而不是之前的顶部页面,因为就像我们之前看到的那样,Edge会将在主页面的data:uri拦截。
top.location.href = "data:text/html,SOMETHING"; // Fails badly, error page
但是设置一个data:uri作为iframe的位置很好。但是,这不是一个漏洞,而是从顶部隔离了iframe域。
正如我们在SOP阅读模式绕过这篇文章看到的,data:uri的隔离限制是非常琐碎的,只是一个document.write就可以访问到父级,但是我们现在不想这么做了。因为访问父级顶部对我们来讲并没有多大的作用了。我们现在想得一种方法是得到一个无域的页面,所以我们需要一个三重的组合:数据-元-数据。这将会让Edge返回我们想要的结果。
具体来说,我们将使用一个data:uri来设置iframe的位置,这个data:uri会重定向到另外一个data:uri进行刷新。获取无域页面步骤如下:
通过这一点小伎俩,我们就可以盗取Einsteins凭证,邮箱,paypal账户,设置以他的用户名发推文。让我们首先测试一下我们之前做的攻击是否成功。我们在bing.com进行测试,很简单的就进行了绕过,因为他有一个内部空白的Iframe,以及它没有使用XFO。
攻击预热:测试bing.com
我们将创建一个带有两个iframe的网页:一个指向bing.com和一个指向无域页面。从无域页面进行攻击,我们可以在bing的内部空白iframe中执行代码。 Bing中图片的选项是我们需要的解释模型。让我打开Chrome一秒钟,告诉你我的意思。
现在我们将借助我们的无域”数据-元-数据”来构建该页面并将代码注入到空白iframe中。但是有一些我没有说的话,你还记得我们在原始的无域SOP中与nature.com的命名问题吗?如果没有,让我给你一个很快的认识。
在这一点上,我们的无域iframe能够访问bing的空白iframe,但访问机制是非常重要的。我们不能直接访问DOM,我们必须使用window.open方法。换句话说,如果bing位于主页面的第一个iframe中,我们将无法以这种方式访问其内部iframe:
alert(top[0][0].document.cookie); // ACCESS DENIED
事实上,我们甚至不能执行这一条命令:
top[0][0].location.href = "javascript:alert(document.cookie)"; // ACCESS DENIED
那么我们该怎么办呢?很容易,在窗口中使用iframe的名字打开一个javascript url。如果bing的内部iframe名称是“INNER_IFRAME”,以下代码将会很好地工作:
window.open("javascript:alert(document.cookie)", "INNER_IFRAME"); // SOP BYPASSED!
但是很尴尬的一个问题,Bing中iframe没有命名!不过不要灰心,我们可以请求bing团队对这些iframe进行命名。或者我们可以继续挖掘绕过方法~
设置iframe名字
我们不能设置目前我们没有拥有的iframe名称,除非它与我们在一个域中。我们要在bing中产生一个空白的iframe。外部的iframe处于不同的域中,但是标签本身(元素,对象)是在我们的域中。所以,我可以设置任何名字:
<iframe name="ANY_NAME" src="http://bing.com"> <iframe src="about:blank"></iframe> </iframe>
但是内部的iframe是通过bing渲染的,所以即使他是空白页面,他的域照样是bing.com。惟一更改名称方法是先将iframe的位置设置到我们可以访问到的地方,然后才能更改它的名称。现在,如果我们改变about:blank的位置,所以我们需要先成为bing.com,,然后我们才能访问到无域的空白页面。这就像从脚下进行拍摄一样困难。
记住:我们的目标是从一个无域的页面到一个域中的页面。如果我们将域设置为要匹配的域,比如上述的bing,那么这个攻击毫无意义。所以我们将要做的是:设置位置,更改iframe名称,然后以这样的方式恢复位置,以保持原始域。听起来很复杂?下面是这个方法的总结:
1.iframe的位置设置为about:blank,将其域更改为我们控制的域:crack.com.ar 2.更改iframe名称 3.将其位置重新设置为about:blank,但这次使用一个元刷新,使得它的域名等于它的创建者:bing.com。
上述就是攻击的方法,他的域已经恢复到了bing.com,这是代码:
// Sets the location of Bing's inner iframe to about:blank // But now it is in our domain so we can set a name to it. window[0][0].location = "about:blank"; // Set the inner iframe name to "CHARLES" so we can later inject code // using a window.open("javascript:[...]","CHARLES"); window[0][0].name = "CHARLES"; // Restore Bing's domain to the about:blank that we've just renamed. window[0][0].document.write('<meta http-equiv="refresh" content="0;url=about:blank">'); window[0][0].document.close();
给你一个好消息,我们不需要about:blank页面的iframe,因为我们总是可以像上面那样做。换句话说,bing的内部iframe是不是about:blank并不重要,因为我们最后可以通过原始域对空白页面进行设置。
成功的大门为我们敞开,我们最后可以使用在iframe中的”数据-元-数据”执行一条命令。
测试这一漏洞的POC地址:http://unsafe.cracking.com.ar/demos/edgedatametadata/bing.html
视频地址:https://youtu.be/E_6OFcTi5kQ
关于PoC,一个重要事项:在上面的示例中,我们使用http(不安全)连接,因为在https(安全)中,数据的元刷新会被阻止,所以它不会重定向到最终的数据uri。Edge错误地认为重定向是不安全的。然而,这可以通过使用document.write而不是第一个data:uri来轻松绕过。所以代替”数据-元-数据”应该是document.write-元-数据。
我们没有在上述的PoC中使用它,因为在进行演示交互时(让你按下按钮来运行它)Edge检测https用了1/3的时间。所以,我选择在http和https自动使用以及可靠的PoC。但是无论如何,如下所示,它并不重要:我们的不安全(http)无域空白页面能够访问安全页面,所以让我们建立一个真实的例子。
是时候去进行真正的攻击了。Charles是一个比较具有安全意识的用户,他从来不在同一个页面打开相关链接,比如在twitter,gmail以及它的个人文档中。
让我们来看一看,他正在通过选项新建一个标签页打开链接。
他的心情很好,直到他用Twitter的账号打开了另一个标签,并为阿尔弗雷德·华莱士(Alfred Wallace)提供了关于谁先推送的消息。
几分钟后,华莱士的回应就包括了支持他的声明的证据。但是请记住,Charles不信任任何人,所以他复制了链接,以将其粘贴到一个新的窗口中,远离他拥有个人数据(gmail,twitter)的窗口。
没有任何一处地方是不可以出错的,像这个世界上的大多数网站一样,twitter同样有几个iframe。事实上,他有两个命名为about:blank的iframe。所以这次的攻击应该比bing简单一些。但是在回到我们的故事之前,我们使用调试工具找到一个合适的iframe攻击点。我在这里打开另外一个新的窗口,与Charles的会无关。
漂亮,dm-post-iframe是一个非常好的选择,所以我们有了盗取Charlie账户的所有条件。
Charlers打开了一个新的标签页,并加载了华莱士给他的网址。他不知道的是,即使在不一样的标签页,也可以相互通信。那么,如果我们在无域iframe中执行下面的代码,会发生什么?
window.open("javascript:alert(document.cookie)", "dm-post-iframe");
你是完全正确的,我们有Charlers的cookies~
警告:以下的概念证明将请勿做任何攻击。
漏洞执行Poc:http://unsafe.cracking.com.ar/demos/edgedatametadata/cookiesfromcharlie.html
请记住,我们真的不需要在窗口内部打开。上面的例子试图说明一个偏执的情景,但通常情况下更容易,因为人们点击链接,而不用完成Charles所做的所有工作来防止攻击。
作为Charles发送推文
为了建立一个更好的PoC。我们将以他的名字发推文,甚至尝试抓取他的密码,而不是阅读他的cookies。请记住,大多数用户(如查理)使用自动填写密码的密码管理员。
Edge密码管理器没有什么不同,所以如果Charles保存了他的密码,我们会得到它。这不是很难,只是强迫他注销,然后登录页面将被自动加载,所有的数据(用户名和密码)会被重放。事实上,在这种情况下,除非用户进行交互,否则窗体是隐藏的,但是Edge正在填充它,所以我们甚至可以设置窗体不可见。
在运行PoC之前,请考虑这是您的帐户,而不是Charles。没有任何东西被发送到网络,但如果你身后有人,他会在一个常规警报对话框中看到您的密码。
攻击视频1:https://youtu.be/K3Ui3JxZGnE(自备梯子)
攻击视频2:https://youtu.be/K3Ui3JxZGnE(自备梯子)
测试POC:http://unsafe.cracking.com.ar/demos/edgedatametadata/tweet-like-charlie.html