探秘之旅:为何打开书签会导致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>
复现步骤
- 将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_变量中
调用链:
StartupBrowserCreatorImpl::OpenTabsInBrowser
→ Navigate
→ CreateTargetContents
→ WebContents::Create
→ WebContentsImpl::Create
→ WebContentsImpl::CreateWithOpener
对象释放
- PoC调用
window.close()后,消息通过IPC机制发送 - 最终调用
content::WebContentsImpl::Close关闭页面 - 通过
TabStripModel::CloseWebContentses和DetachWebContentsImpl获取要关闭的WebContents对象 - 调用
SendDetachWebContentsNotifications释放对象
关键释放路径:
WebContentsImpl::Close
→ Browser::CloseContents
→ chrome::CloseWebContents
→ TabStripModel::CloseWebContentsAt
→ TabStripModel::InternalCloseTabs
→ TabStripModel::CloseWebContentses
→ TabStripModel::DetachWebContentsImpl
→ TabStripModel::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等内存检测工具
- 分析调用栈时关注对象分配/释放点
- 注意多线程环境下的资源竞争条件