在本文中,我们将与读者一道,深入考察浏览器中与UI相关的安全漏洞。
提取私人信息
在介绍这个漏洞之前,让我们先了解一下占位符。众所周知,当我们与自动填充建议的用户界面互动时,如果将鼠标悬停在每个建议的条目上,都会发生一些有趣的事情。一个占位符值将被放置在我们试图填写的任何输入中。不过,这个占位符的值不应该允许网页随意访问:只有当用户明确选择了他们认为合适的条目后,浏览器才能读取自动填充数据。除此之外,占位符将被设置为所有具有匹配名称的输入。这意味着信用卡号码、地址、用户名、全名等都可以被提取出来。
我第一次意识到这个微妙的安全问题是因为这个漏洞(作者Mark Amery),它使用CSS/字体技巧来提取占位符数据。
现在回到这个漏洞本身。在试图找出我之前提到的问题(关于浏览器用户界面的伪造)的解决方案时,我偶然发现了一个有趣的行为。在研究问题(2)时,我在自动填充出现时切换了输入的类型,结果导致自动填充的用户界面一直存在。在这个例子中,我所做的不是改变输入类型,而是在第一个自动填充建议的用户界面出现时,让另一个自动填充用户界面出现:
1.用户与一个输入元素“A”互动
2.自动填充建议出现在输入元素“A”上
3.让自动填充建议出现在输入元素“B”上
4.从文档中删除输入元素“B”。
这样一来,最后剩下的只有输入元素“A”(包括来自自动填充建议的占位符值),而实际的建议用户界面并不存在。这对攻击者来说是好事,因为现在他们有充分的时间来提取数据,而以前,一旦自动填充建议消失,占位符值就会被删除。
下面是针对这一特定行为的小型PoC:
hit down arrow < Br >< br >< form id="qsub" > < input id="qa" name=email placeholder="tester" type=text autocomplete=email >< /form >< form name="addr1.1" id="paymentForm" action="" method="post" > < input type="text" id="nameInput" name="name" autofocus >< /form >< script > nameInput.onkeydown = (e) = > { setTimeout((g) = > { qa.click(); qa.focus(); document.execCommand("insertText", false, "\u0000"); qa.remove(); }, 215); }; < /script >
我发现有两种方法可以提取这些数据并将其暴露在网页上,具体如下所示。
CVE-2021-21177:拖放占位符的值
一个有趣的函数是document.execCommand('selectAll'),其作用就是选择一个可编辑文档中的所有文本(我们可以通过contenteditable=true属性将所有元素设置为可编辑)。我注意到,当占位符停留在输入中时,如果执行这个命令,它将被选中。不够,由于我们无法自动复制和粘贴所选的值(没有剪贴板使用权限),所以,我使用了另一种方法:拖放!
所以,漏洞利用过程变为:
1.让用户点击页面
2.触发占位符持久性故障
3.诱使用户拖放页面的一部分
前面,我们已经介绍了完成任务(1)的方法,对于任务(2),我的方法是放置一个冒充iframe的图片,当用户试图使用不存在的滚动条向下滚动时,他们会在不知不觉中拖放他们的自动填充占位符值。
演示视频:
基于拖放方法的原始PoC可以从这里找到。
在这个漏洞的相关报告中,最初的讨论似乎是为了防止拖放适用于占位符的值。实际上,已经有一个CSS可以做到这一点“ -webkit-user-select: none;”。但这还不够,主要问题是自动填充数据的持久性。
实际上,拖放已经是一种经常遇到的用户互动了,所以我想看看是否可以用一个更好的提取占位数据的方法来代替它。CSS和字体似乎根本不适用于占位符数据,所以,经过一番折腾,我最终发现了一个不同的方法。
CVE-2021-21177:使用window.find()提取占位符的值
这个函数一出现在我的脑海中,我就对它抱有很大的期望,结果确实如此。
众所周知,window.find()是一个非常有用的API,网页通过它对自身的内容进行搜索。假设我们有一个只有Hello World文本的文档,那么window.find("Hello")==true,window.find("World")==true,当然window.find("doesntexist")==false。
现在,完整的漏洞利用过程如下所示:
1.用户按下向下箭头
2.触发占位符故障
3.使用window.find提取占位符
这意味着,用户只需要在一个恶意的页面上按下方向键,我就能提取很多私人信息,其中最危险的是信用卡信息。
演示视频:
原始PoC可以从这里找到。
CVE-2021-21216:隐藏自动填充建议的用户界面
我们知道,有一些UI应该始终显示给用户。其中,最受欢迎的是当我们进入全屏时出现的“You are now in fullscreen”的信息。由于进入全屏后,由于浏览器的头部会消失,因此,攻击者可以轻易通过伪造的信息来代替它来欺骗用户的。
我清楚地认识到,自动填充建议的用户界面和全屏用户界面一样重要。这是因为,在它从未显示出来的情况下,攻击者就可以让用户按下某些键盘按钮,并神不知鬼不觉地用自动填充值来填充隐藏的输入元素。关于这一点,我也是从一个漏洞利用代码中领悟到的:相应的PoC是一个游戏,以获得提取数据所需的用户手势。
使用一个类似于之前讨论的本地浏览器伪造的漏洞,我注意到:可以让自动填充建议的UI“出现”在用户屏幕之外。因此,换句话说,攻击者可以让用户看不到自动填充的用户界面,尽管该界面确实存在。
利用这个漏洞的方法非常简单:
1.诱骗用户访问恶意页面,设法让他们点击向下的箭头。
2.让隐藏的自动填充出现在屏幕外的某个地方,并选择第一个建议的结果,随后用占位符的值填充多个隐藏的输入。
3.让恶意页面诱导用户点击“Enter”键。
这样的话,就能让用户会在不知不觉中用自动填充数据填写一个隐藏的表单。
演示视频:
原始PoC可以从这里找到。
自动挖掘UI安全漏洞
我开发了一个审查UI安全问题的工具,当然,这只能算是我学习Fuzzer工作原理的副产品,因为我在加入目前团队之前,从未真正使用过Fuzzer。这是一个非常简陋的工具,几乎都不能算作Fuzzer,之所以这么说,是因为Fuzzer通常能够发现内存问题。通常来说,浏览器的崩溃是出现安全问题的明确信号,但检测用户界面问题却没有这样明确的信号。所以,我为该工具设置了一个模式,以观察的用户可以手动选择某个东西看起来是不是很奇怪。
结果是,我既能发现内存问题的漏洞,也能发现与UI有关的设计缺陷。在继续之前,让我先介绍一下这个简单的自动测试器是如何工作的。
⚪使用普通Web内容可调用的UI列表及其相应的PoC,我创建了一个测试用例,以随机的顺序随机地显示这些用户界面。当测试用例运行时,我就进行某种导航操作:
-在历史中导航
-导航到一个新标签
-打开一个弹出式窗口
-在一个iframe中运行测试案例 + (可选)呈现两个按钮,看看是否出现某些奇怪的东西
-如果出现:保存测试用例,并开始新的迭代
-如果没有出现:直接开始新的迭代
这个实验确实找到了一些有趣的结果,具体如下所示。
smartscreen:FlyoutShower中的堆使用后释放漏洞(仅限Edge浏览器)
这个内部漏洞是我最先发现的,该漏洞与Smartscreen有关。Smartscreen是Edge浏览器特有的一种功能,相当于谷歌的安全浏览功能:进行相应的检查,以确保下载的文件和访问的网站没有被标记为恶意的。
然而,它们的区别在于Edge处理被标记为潜在网络钓鱼网站的网站的具体方式。如果我们使用Edge浏览器导航到这种类型的网站,就会看到:
因此,这自然成为我实现自动化的UI调用命令之一。不久后,我发现Edge崩溃了,原来是浏览器进程崩了。
< html > < body > < script > const blob = new Blob( [ `< iframe id="qss" src="https://nav.smartscreen.msft.net/other/areyousure.html" target="_blank" rel="noreferrer noopener" >< /iframe >`, ], { type: "text/html" } ); var test = window.open(window.URL.createObjectURL(blob)); var blank = window.open("about:blank"); setTimeout(function() { blank.close(); test.close(); }, 1400); < /script >< /body > < /html >
之所以出现这种情况,是因为SmartScreen UI没有安全地处理指向WebContents对象的指针所致。在Chromium和Edge浏览器中,WebContents对象是直接与标签的寿命挂钩的。由于标签可以自行关闭,考虑到它们有一个开启器,我们可以滥用调用这个用户界面的自行关闭的标签,并可靠地令其崩溃。
使用这种技术,我们在Edge和上游浏览器中还发现了其他一些与UI相关的漏洞,这些漏洞要么还没有被完全修复,要么没有那么有趣,因此,这里就不介绍了。
CVE-2020-26953:绕过Firefox中的全屏UI
作为BVR团队的一员,我们被鼓励对其他浏览器中进行相关的安全测试。虽然Chromium的代码库与Firefox不同,但两者可能具有相同的设计缺陷。这样做的另一个好处是:可以了解Firefox是如何处理某种行为的,并从中获得启示。
在一个周末,我决定修改自己的工具,看看对Firefox的效果如何,结果发现一个UI设计缺陷不断出现,但并不稳定。这个漏洞会导致浏览器进入全屏时,通知用户进入全屏的UI完全不可见。
最初报告的PoC中有一个谜团:似乎只有在建立websocket连接并失败的情况下,它才会起作用。不仅如此,你还必须不断地把它改变到另一个无效的位置(假设是为了绕过任何缓存)。
原始PoC可以从这里找到。
一位Mozilla员工(Gijs)指出,PoC中神秘的websocket部分可以用卸载处理程序中的console.log()调用代替。这个变化对我来说是个谜,console.log与全屏UI显示与否有什么关系?如果您想了解其中的缘由,请参阅Bugzilla的相关报告。
按照上述报告给出的建议,我用卸载处理程序替换了websocket连接,还添加了一个blob导航,而不是导航到同一个页面,最终得到了一个更可靠的PoC。
关于修订版的PoC,可以从这里找到。
演示视频:
对我来说,这具有很重要的意义,因为这个漏洞是以半自动的方式发现的,从而让我看到了自动挖掘逻辑/设计漏洞的潜力。
与标签相关的安全漏洞
标签是用户界面的一部分,可以说是浏览器中比较复杂的用户界面之一。因此,当我注意到标签页中的一个安全漏洞被修复时,我觉得这个代码中一定还有更多的漏洞尚未发现。例如,通过标签,我们可以将它们添加到组中,进行拖放,将一个窗口中的标签转换成另一个窗口中的标签,反之亦然,等等。正如之前提到的,标签是可以自行关闭(如果它们有一个开启器的话)的,这意味着网页内容可以控制标签的寿命。
我所做的事情,只是创建了一个脚本来打开标签,而这些标签会自行关闭;然后,在这个连续的打开和关闭标签的过程中,对标签的不同功能进行了相应的处理。
以下安全漏洞已被上报并随后得到了修复。
CVE-2021-21197:TabStrip的堆缓冲区溢出
这里被利用的主要标签功能是将标签拖放到自己的窗口中的能力。当一个标签在拖动另一个标签到自己的窗口时关闭,就会发生崩溃。
相关的PoC可以从这里找到。
演示视频:
CVE-2021-21192:标签组中的堆缓冲区溢出漏洞
这里再次利用了拖放技术,只不过,这次拖动的不是一个普通的标签,而是在标签关闭时将标签组拖出并拖入主窗口。
相关的PoC可以从这里找到。
演示视频:
CVE-2021-21154:页签列(Tab Strip)中的堆缓冲区溢出
您猜对没错:在一些标签关闭时拖动一组标签会导致这种崩溃。在这个例子中,用到了通过按住shift键+选择范围来选择标签的主要标签功能。
相关的PoC可以从这里找到。
演示视频:
CVE-2021-21180:标签搜索功能中UAF漏洞
该漏洞与一个相对较新的功能有关,该功能使用户能够搜索自己的活动标签。我发现,这个新的标签搜索用户界面实际上就是一个位于chrome://tab-search.top-chrome/的WebUI。
在这个标签搜索用户界面中,我们可以关闭标签,但是,当我们在自己的窗口中打开“chrome://tab-search.top-chrome/”,然后试图使用标签搜索用户界面的关闭机制来关闭自己时,就会触发UAF漏洞。
演示视频:
小结
我们希望本文能够帮助读者了解UI安全的相关知识,正如您所看到的,这并不是一个单纯的逻辑/设计问题,因为有时还会掺杂内存损坏问题。另外,UI安全的审计工作,是很难实现自动化和模糊处理的,即使是围绕着标签的内存问题也需要进行拖放操作,但是几乎没有Fuzzer会模拟这些操作。由此看起来,UI安全是自动化漏洞挖掘领域中的一块处女地,一旦获得突破,将曝出更多的安全漏洞。
本文翻译自:https://microsoftedge.github.io/edgevr/posts/ui-security-thinking-outside-the-viewport/如若转载,请注明原文地址