探秘之旅:为何打开书签会导致Chrome崩溃
字数 1902 2025-08-09 18:44:03

Chrome书签UAF漏洞(CVE-2021-21167)分析与教学文档

漏洞概述

CVE-2021-21167是Chrome浏览器中的一个Use-After-Free(UAF)漏洞,存在于89.0.4389.72版本之前。远程攻击者可以通过特制的HTML页面触发书签功能中的UAF漏洞,导致堆损坏。该漏洞位于书签的"打开所有标签页"功能中,当用户尝试打开大量书签时,在特定条件下会导致已释放的内存被重新访问。

漏洞复现

环境准备

  • 使用ASAN版本的Chrome浏览器(如win64 822987版本)
  • 确保浏览器有15个以上的标签页

PoC代码

<html>
<head>
<button id="triggerButton">Trigger</button>
<script>
triggerButton = document.querySelector('#triggerButton');
triggerButton.addEventListener('click', async event => {
    setTimeout(()=>{window.close();},5000);
});
</script>
</head>
</html>

复现步骤

  1. 将PoC代码保存为poc.html
  2. 在PoC所在目录运行python -m SimpleHTTPServer搭建HTTP服务器
  3. 使用命令chrome.exe "http://localhost:8000/poc.html" "about:blank"打开浏览器
  4. 点击"Trigger"按钮
  5. 右键单击工具栏,选择"打开所有标签页"
  6. 在PoC页面关闭后点击确认对话框
  7. ASAN版本的Chrome会崩溃并显示UAF错误信息

漏洞分析

对象生命周期分析

对象分配

  1. 浏览器启动时调用StartupBrowserCreatorImpl::OpenTabsInBrowser
  2. 创建Navigate对象并最终调用WebContentsImpl::Create创建WebContentsImpl对象
  3. 对象被保存到TabStripModelcontents_data_变量中

调用链:

StartupBrowserCreatorImpl::OpenTabsInBrowser
    → Navigate
        → CreateTargetContents
            → WebContents::Create
                → WebContentsImpl::Create
                    → WebContentsImpl::CreateWithOpener

对象释放

  1. PoC调用window.close()后,消息通过IPC机制发送
  2. 最终调用content::WebContentsImpl::Close关闭页面
  3. 通过TabStripModel::CloseWebContentsesDetachWebContentsImpl获取要关闭的WebContents对象
  4. 调用SendDetachWebContentsNotifications释放对象

关键释放路径:

WebContentsImpl::Close
    → Browser::CloseContents
        → chrome::CloseWebContents
            → TabStripModel::CloseWebContentsAt
                → TabStripModel::InternalCloseTabs
                    → TabStripModel::CloseWebContentses
                        → TabStripModel::DetachWebContentsImpl
                            → TabStripModel::SendDetachWebContentsNotifications

对象使用

  1. 右键书签栏时调用ContextMenuController::ShowContextMenuForView
  2. 创建BookmarkContextMenuController对象
  3. 通过browser_->tab_strip_model()->GetActiveWebContents()获取WebContents对象
  4. 该对象被保存为BookmarkContextMenuControllernavigator_成员变量

UAF触发条件

  1. 用户点击"打开所有标签页"时调用BookmarkContextMenuController::ExecuteCommand
  2. 最终调用chrome::OpenAll函数
  3. 如果要打开的标签页≥15个,会弹出确认对话框
  4. 对话框在UI线程中循环等待用户响应
  5. 在此期间如果页面被关闭(如PoC中的window.close()),navigator指针变为悬垂指针
  6. 用户确认后,函数继续执行并解引用已释放的navigator指针,触发UAF

漏洞修补

补丁链接:58ae65c7f9a276777e611db69633b2ff8ed32cb7

主要修改:

  1. 使用chrome::OpenAllIfAllowed替换chrome::OpenAll函数
  2. 新函数直接返回,如需用户确认则使用异步方式打开标签页
  3. 不再直接持有content::PageNavigator指针,而是通过回调方式获取
  4. 确保总是使用有效的PageNavigator

关键点总结

  1. 漏洞类型:Use-After-Free (UAF)
  2. 触发条件
    • 打开≥15个书签链接
    • 在确认对话框出现期间关闭相关页面
  3. 影响对象content::PageNavigator接口的WebContents实现
  4. 根本原因:同步对话框导致UI线程阻塞,期间对象可能被释放
  5. 修复策略:将同步操作改为异步,避免持有可能失效的指针

教学建议

  1. 漏洞分析技巧

    • 关注对象生命周期管理
    • 注意同步操作中的资源管理问题
    • 特别警惕UI线程阻塞期间的资源状态变化
  2. 安全开发实践

    • 避免在可能阻塞的操作中持有资源指针
    • 考虑使用弱引用或回调机制管理可能失效的资源
    • 对用户确认等耗时操作采用异步设计
  3. 调试方法

    • 使用ASAN等内存检测工具
    • 分析调用栈时关注对象分配/释放点
    • 注意多线程环境下的资源竞争条件
Chrome书签UAF漏洞(CVE-2021-21167)分析与教学文档 漏洞概述 CVE-2021-21167是Chrome浏览器中的一个Use-After-Free(UAF)漏洞,存在于89.0.4389.72版本之前。远程攻击者可以通过特制的HTML页面触发书签功能中的UAF漏洞,导致堆损坏。该漏洞位于书签的"打开所有标签页"功能中,当用户尝试打开大量书签时,在特定条件下会导致已释放的内存被重新访问。 漏洞复现 环境准备 使用ASAN版本的Chrome浏览器(如win64 822987版本) 确保浏览器有15个以上的标签页 PoC代码 复现步骤 将PoC代码保存为poc.html 在PoC所在目录运行 python -m SimpleHTTPServer 搭建HTTP服务器 使用命令 chrome.exe "http://localhost:8000/poc.html" "about:blank" 打开浏览器 点击"Trigger"按钮 右键单击工具栏,选择"打开所有标签页" 在PoC页面关闭后点击确认对话框 ASAN版本的Chrome会崩溃并显示UAF错误信息 漏洞分析 对象生命周期分析 对象分配 浏览器启动时调用 StartupBrowserCreatorImpl::OpenTabsInBrowser 创建 Navigate 对象并最终调用 WebContentsImpl::Create 创建 WebContentsImpl 对象 对象被保存到 TabStripModel 的 contents_data_ 变量中 调用链: 对象释放 PoC调用 window.close() 后,消息通过IPC机制发送 最终调用 content::WebContentsImpl::Close 关闭页面 通过 TabStripModel::CloseWebContentses 和 DetachWebContentsImpl 获取要关闭的WebContents对象 调用 SendDetachWebContentsNotifications 释放对象 关键释放路径: 对象使用 右键书签栏时调用 ContextMenuController::ShowContextMenuForView 创建 BookmarkContextMenuController 对象 通过 browser_->tab_strip_model()->GetActiveWebContents() 获取WebContents对象 该对象被保存为 BookmarkContextMenuController 的 navigator_ 成员变量 UAF触发条件 用户点击"打开所有标签页"时调用 BookmarkContextMenuController::ExecuteCommand 最终调用 chrome::OpenAll 函数 如果要打开的标签页≥15个,会弹出确认对话框 对话框在UI线程中循环等待用户响应 在此期间如果页面被关闭(如PoC中的 window.close() ), navigator 指针变为悬垂指针 用户确认后,函数继续执行并解引用已释放的 navigator 指针,触发UAF 漏洞修补 补丁链接: 58ae65c7f9a276777e611db69633b2ff8ed32cb7 主要修改: 使用 chrome::OpenAllIfAllowed 替换 chrome::OpenAll 函数 新函数直接返回,如需用户确认则使用异步方式打开标签页 不再直接持有 content::PageNavigator 指针,而是通过回调方式获取 确保总是使用有效的PageNavigator 关键点总结 漏洞类型 :Use-After-Free (UAF) 触发条件 : 打开≥15个书签链接 在确认对话框出现期间关闭相关页面 影响对象 : content::PageNavigator 接口的WebContents实现 根本原因 :同步对话框导致UI线程阻塞,期间对象可能被释放 修复策略 :将同步操作改为异步,避免持有可能失效的指针 教学建议 漏洞分析技巧 : 关注对象生命周期管理 注意同步操作中的资源管理问题 特别警惕UI线程阻塞期间的资源状态变化 安全开发实践 : 避免在可能阻塞的操作中持有资源指针 考虑使用弱引用或回调机制管理可能失效的资源 对用户确认等耗时操作采用异步设计 调试方法 : 使用ASAN等内存检测工具 分析调用栈时关注对象分配/释放点 注意多线程环境下的资源竞争条件