2018年12月,Mozilla
通过mfsa2018-29
发布了Firefox 64
版本,该漏洞最初由Nils发现并报告。 此版本修复了几个安全问题,其中包括CVE-2018-18492
,该CVE为与select元素相关的UAF漏洞。 我们之前的文章汇总讨论过UAF漏洞,我们已经发现供应商已经实施全面保护以修复此类漏洞。 即使在今天,在Web浏览器中发现与UAF相关的漏洞也并不罕见,因此了解它们对于查找和修复这些漏洞至关重要。 在这篇博客中,我提供了有关此特定UAF漏洞的更多详细信息以及为解决该漏洞而发布的补丁。
以下POC可用于触发此漏洞:
在受影响的Firefox
版本上运行此POC可为读者提供以下碰撞和堆栈的痕迹跟踪:
如我们所见,取消引用填充0xe5e5e5e5
的内存地址时会产生读取访问冲突。 这是jemalloc
用来恶意释放内存的值。 这里poisoning的意思是用可识别的模式填充释放的内存以用于诊断。 更为优化的地方在于,填充模式不对应于可访问的地址。因此,取消引用从填充的存储器加载的值将立即导致系统的崩溃。
PoC由6行组成。 让我们逐行分解:
1)创建div元素。
2)创建选项元素。
3)option元素被附加到div元素。 div现在是option元素的父级。
4)将DOMNodeRemoved事件侦听器添加到div元素。 这意味着如果删除了选项节点,我们将调用我们放在这里的函数。
5)创建选择元素。
我们在这里进行深入讲解:
当在JavaScript中创建select元素时,函数xul.dll!NS_NewHTMLSelectElement
将接收控件。 它为这个select
元素分配一个0x118
字节的对象:
如我们所见,最后该跳转到mozilla::dom::HTMLSelectElement::HTMLSelectElement
函数。
在该函数内,初始化新分配的对象的各个字段。 请注意,这里还分配了另一个0x38字节的对象,并将其初始化为HTMLOptionsCollection
对象。 因此,默认情况下,每个select元素都将具有选项集合。 让我们来看最后一行。
6)在步骤2中创建的选项元素被移动到select元素的options集合。 在JavaScript中执行此操作将导致调用mozilla::dom::HTMLOptionsCollection::IndexedSetter
函数(我们可以看到此函数在图中所示的堆栈跟踪中进行调用)。
这里一些检查由浏览器完成。 例如,如果选项索引大于选项集合的当前长度,则通过调用mozilla::dom::HTMLSelectElement::SetLength
函数来扩大选项集合。 在我们的PoC中,由于第6行中的[0]为零。 然后在图中的蓝色块处进行检查。如果要设置的索引不等于选项集合的选项计数,则采用右分支。 在我们的PoC中,所需的索引值为0,选项计数也为零,因此采用左分支。 因此,执行到达nsINode::ReplaceOrInsertBefore
函数,如下面的红色块中所示:
在·nsINode::ReplaceOrInsertBefore·函数中,调用·nsContentUtils::MaybeFireNodeRemoved·函数以在父级正在侦听此类事件时通知父类对象。
当我们在PoC的第4行的div元素上设置DOMNodeRemoved
事件监听器时,我们放在那里的函数被触发。 在此函数中,首先将sel
变量设置为0。这将删除对select
元素的最后一个引用。 接下来,该函数创建一个巨大的数组缓冲区。 这会产生内存压力,导致垃圾收集器启动。由于不再有任何对它的引用,此时select
元素对象被释放。这个释放的内存将被0xe5e5e5e5
填充。 最后,该函数调用alert
以刷新挂起的异步任务。 从nsContentUtils::MaybeFireNodeRemoved
函数返回后,释放的select对象用于读取触发读取访问冲突的指针:
这里有一个有趣的注意事项是,如果采用了右分支,将调用完全相同的函数(nsINode::ReplaceOrInsertBefore
),但在此调用之前,AddRef函数将用于增加select对象的引用计数。 因此,不会发生任何UAF:
Mozilla通过changeset d4f3e119ae841008c1be59e72ee0a058e3803cf3
修补了此漏洞。 主要的变化是选项集合中对select元素的弱引用被强引用替换:
尽管这是一个众所周知的问题,UAF漏洞仍然是多个浏览器的问题。 就在几个月前,针对谷歌Chrome的攻击使用了UAF漏洞。 UAF也存在于浏览器之外。 Linux内核发布了一个补丁,用于解决由UAF引起的拒绝服务情况。 了解UAF的发生方式是检测它们的关键。 与缓冲区溢出类似,我们不太可能在软件中看到UAF的漏洞。 但是,正确的编码和安全开发实践有助于消除或至少减轻未来UAF的影响。
本文为翻译文章,来自:https://www.zerodayinitiative.com/blog/2019/7/1/the-left-branch-less-travelled-a-story-of-a-mozilla-firefox-use-after-free-vulnerability