Mozilla火狐浏览器中的一个Use-After-Free漏洞分析
字数 1777 2025-08-27 12:33:31

Mozilla火狐浏览器Use-After-Free漏洞分析教学文档

漏洞概述

CVE编号: CVE-2018-18492
漏洞类型: Use-After-Free (UAF)
影响组件: Firefox浏览器中的select元素处理机制
严重性: 高危
修复版本: Firefox 64(通过MFSA2018-29发布)

漏洞原理

Use-After-Free是一种内存安全漏洞,发生在程序释放了某个内存区域后,仍然保留了对该区域的引用并尝试使用它。在本案例中,漏洞出现在Firefox处理HTML select元素和option元素的交互过程中。

漏洞触发条件

PoC代码

1. var div = document.createElement('div');
2. var opt = document.createElement('option');
3. div.appendChild(opt);
4. div.addEventListener('DOMNodeRemoved', function() {
5.     sel = 0;
6.     var buffer = new ArrayBuffer(0x999999);
7.     alert('hi');
8. });
9. var sel = document.createElement('select');
10. sel[0] = opt;

触发流程

  1. 创建div元素和option元素
  2. 将option附加到div元素
  3. 为div添加DOMNodeRemoved事件监听器
  4. 创建select元素
  5. 将option移动到select的options集合中

技术细节分析

内存分配

  • 创建select元素时,xul.dll!NS_NewHTMLSelectElement函数分配0x118字节的对象
  • 同时创建0x38字节的HTMLOptionsCollection对象(每个select元素默认有options集合)

关键函数调用链

  1. mozilla::dom::HTMLOptionsCollection::IndexedSetter被调用
  2. 根据条件分支选择执行路径:
    • 左分支(索引等于集合计数):直接调用nsINode::ReplaceOrInsertBefore
    • 右分支(索引不等于集合计数):先调用AddRef增加引用计数,再调用nsINode::ReplaceOrInsertBefore

漏洞触发过程

  1. 执行PoC第10行sel[0] = opt时进入左分支
  2. nsINode::ReplaceOrInsertBefore调用nsContentUtils::MaybeFireNodeRemoved
  3. 触发DOMNodeRemoved事件处理函数:
    • 将sel变量设为0,移除对select元素的最后一个引用
    • 创建大ArrayBuffer触发垃圾回收
    • select元素对象被释放,内存被填充0xe5e5e5e5(jemalloc的"毒化"机制)
  4. 事件处理完成后,nsContentUtils::MaybeFireNodeRemoved返回时尝试使用已释放的select对象
  5. 导致读取访问冲突(访问0xe5e5e5e5地址)

补丁分析

修复提交: d4f3e119ae841008c1be59e72ee0a058e3803cf3

关键修改:

  • 将options集合中对select元素对象的弱引用改为强引用
  • 确保在操作过程中select对象不会被意外释放

漏洞利用防护

检测方法

  • 观察崩溃时的内存地址(0xe5e5e5e5是典型特征)
  • 检查jemalloc的"毒化"内存模式

防御建议

  1. 及时更新到修复版本
  2. 使用现代C++智能指针管理对象生命周期
  3. 实施严格的引用计数管理
  4. 考虑使用内存安全语言重写关键组件

教学总结

关键知识点

  1. Use-After-Free漏洞的本质和危害
  2. DOM事件处理与内存管理的交互风险
  3. 引用计数在浏览器安全中的重要性
  4. jemalloc的内存诊断特性

扩展思考

  1. 为什么右分支不会触发漏洞?
    • 因为右分支先调用了AddRef增加了引用计数
  2. 为什么创建大ArrayBuffer能触发垃圾回收?
    • 大内存分配会强制内存压力,触发GC

实践建议

  1. 在开发类似功能时,仔细管理对象生命周期
  2. 对可能触发事件的操作保持警惕
  3. 使用自动化工具检测UAF问题(如AddressSanitizer)

参考资源

  1. 原始漏洞报告: https://www.zerodayinitiative.com/blog/2019/7/1/the-left-branch-less-travelled-a-story-of-a-mozilla-firefox-use-after-free-vulnerability
  2. Mozilla安全公告: MFSA2018-29
  3. CVE详细信息: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-18492
Mozilla火狐浏览器Use-After-Free漏洞分析教学文档 漏洞概述 CVE编号 : CVE-2018-18492 漏洞类型 : Use-After-Free (UAF) 影响组件 : Firefox浏览器中的select元素处理机制 严重性 : 高危 修复版本 : Firefox 64(通过MFSA2018-29发布) 漏洞原理 Use-After-Free是一种内存安全漏洞,发生在程序释放了某个内存区域后,仍然保留了对该区域的引用并尝试使用它。在本案例中,漏洞出现在Firefox处理HTML select元素和option元素的交互过程中。 漏洞触发条件 PoC代码 触发流程 创建div元素和option元素 将option附加到div元素 为div添加DOMNodeRemoved事件监听器 创建select元素 将option移动到select的options集合中 技术细节分析 内存分配 创建select元素时, xul.dll!NS_NewHTMLSelectElement 函数分配0x118字节的对象 同时创建0x38字节的 HTMLOptionsCollection 对象(每个select元素默认有options集合) 关键函数调用链 mozilla::dom::HTMLOptionsCollection::IndexedSetter 被调用 根据条件分支选择执行路径: 左分支(索引等于集合计数):直接调用 nsINode::ReplaceOrInsertBefore 右分支(索引不等于集合计数):先调用 AddRef 增加引用计数,再调用 nsINode::ReplaceOrInsertBefore 漏洞触发过程 执行PoC第10行 sel[0] = opt 时进入左分支 nsINode::ReplaceOrInsertBefore 调用 nsContentUtils::MaybeFireNodeRemoved 触发DOMNodeRemoved事件处理函数: 将sel变量设为0,移除对select元素的最后一个引用 创建大ArrayBuffer触发垃圾回收 select元素对象被释放,内存被填充0xe5e5e5e5(jemalloc的"毒化"机制) 事件处理完成后, nsContentUtils::MaybeFireNodeRemoved 返回时尝试使用已释放的select对象 导致读取访问冲突(访问0xe5e5e5e5地址) 补丁分析 修复提交: d4f3e119ae841008c1be59e72ee0a058e3803cf3 关键修改 : 将options集合中对select元素对象的 弱引用 改为 强引用 确保在操作过程中select对象不会被意外释放 漏洞利用防护 检测方法 观察崩溃时的内存地址(0xe5e5e5e5是典型特征) 检查jemalloc的"毒化"内存模式 防御建议 及时更新到修复版本 使用现代C++智能指针管理对象生命周期 实施严格的引用计数管理 考虑使用内存安全语言重写关键组件 教学总结 关键知识点 Use-After-Free漏洞的本质和危害 DOM事件处理与内存管理的交互风险 引用计数在浏览器安全中的重要性 jemalloc的内存诊断特性 扩展思考 为什么右分支不会触发漏洞? 因为右分支先调用了AddRef增加了引用计数 为什么创建大ArrayBuffer能触发垃圾回收? 大内存分配会强制内存压力,触发GC 实践建议 在开发类似功能时,仔细管理对象生命周期 对可能触发事件的操作保持警惕 使用自动化工具检测UAF问题(如AddressSanitizer) 参考资源 原始漏洞报告: https://www.zerodayinitiative.com/blog/2019/7/1/the-left-branch-less-travelled-a-story-of-a-mozilla-firefox-use-after-free-vulnerability Mozilla安全公告: MFSA2018-29 CVE详细信息: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-18492