作者 akihi(白帽攻防录讲师),某甲方网络安全工程师,合合 SRC 年度第一、腾讯 SRC 连续三年前十,单漏洞赏金 4w+,擅长 Web/App/PC 客户端漏洞挖掘。专注浏览器安全、V8 引擎逆向、沙箱逃逸技术。本文基于公开 CVE 信息与技术原理深度复盘,供安全研究与防护参考。
一、漏洞时间线
2026 年 4 月,Google Chrome 发布了一个安全更新,修复了 V8 引擎里的一个严重类型混淆漏洞 CVE-2026-6307。这个漏洞被安全研究者称为"Longinus"------一根长矛刺穿了两道边界:它不仅能在 V8 沙箱内执行代码,还能进一步逃逸到原生内存。最巧妙的是,这个漏洞不是普通的内存破坏,而是优化编译器 Turbofan 的一个元数据合并 bug------两个不同签名的 FrameState 被错误地合并成了一个,导致惰性反优化时类型完全错乱。
| 时间 | 事件 | 影响版本 |
|---|---|---|
| 2026-04-15 | 研究者公开技术分析(Part 1) | Chrome 147.0.7727.101 之前 |
| 2026-05-04 | 研究者发布 Part 2 深度分析 | ------ |
| 2026-05-21 | 研究者发布 Part 3 沙箱逃逸 | ------ |
| 2026-06-27 | 安全社区发布漏洞分析报告 | ------ |
| 2026-06-29 | 完整 writeup 公开 | ------ |
| 2026-09-24 | 公开 exploit 代码发布 | ------ |
这个漏洞最可怕的地方在于:它是一个"编译器优化 bug"------不是运行时的内存错误,而是编译器在优化阶段犯了逻辑错误。普通的内存破坏漏洞是"写错了内存",而这个漏洞是"编译器搞错了类型"。更可怕的是,它给了攻击者完整的 64 位 addrof/fakeobj 原语------而且这些指针不是压缩指针(cage-compressed),是完整的原生地址,直接就能用来逃逸沙箱。
二、攻击链全景
让我们先用一张流程图还原完整的攻击路径:
攻击者制作特制的 HTML 页面
│
▼
第一步:诱导用户访问
│ 方式一:水坑攻击
│ 攻陷目标常访问的网站
│ 嵌入恶意 JS 代码
│
│ 方式二:钓鱼链接
│ 给目标发邮件/消息
│ 里面有恶意链接
│
│ 方式三:广告投放
│ 在广告里嵌入恶意代码
│ 用户浏览网页时自动执行
▼
第二步:触发 JS-to-Wasm 调用
│ 恶意 JS 代码做的事情:
│ 1. 定义一个 Wasm 函数
│ 返回 i64 类型
│ 2. 在 JS 里多次调用这个 Wasm 函数
│ 3. 让 Turbofan 把这些调用内联优化
│ 4. 构造两个不同返回签名的调用
│ 让它们的 FrameState 看起来一样
▼
第三步:Turbofan 错误合并 FrameState
│ Turbofan 优化阶段:
│ - CSE(公共子表达式消除)
│ - GVN(全局值编号)
│
│ 问题出在:
│ JSToWasmFrameStateFunctionInfo
│ 的相等比较函数
│ 漏掉了 Wasm 签名的比较!
│
│ 结果:
│ 两个不同签名的 FrameState
│ 被错误地合并成了一个
│ 编译器以为它们是一样的
▼
第四步:惰性反优化触发类型混淆
│ 优化后的代码运行时:
│ 某个条件触发了惰性反优化
│ (比如类型检查失败)
│
│ 反优化时需要重建栈帧
│ 用的是合并后的 FrameState
│ 但这个 FrameState 的签名是错的
│
│ 结果:
│ Wasm 返回的 i64
│ 被当成了 JS 的 externref
│ (或者反过来)
│ 类型完全错乱了
▼
第五步:获得 addrof/fakeobj 原语
│ 类型混淆带来的能力:
│ - addrof:把任意 JS 对象
│ 转成原生地址
│ - fakeobj:把任意地址
│ 伪装成 JS 对象
│
│ 关键点:
│ 这里的指针是完整的 64 位
│ 不是 V8 的压缩指针
│ 直接就是原生地址!
▼
第六步:逃逸 V8 沙箱
│ 有了原生地址读写能力:
│ 1. 找到 V8 沙箱的边界
│ 2. 通过 WasmFX 机制
│ 突破沙箱隔离
│ 3. 获得整个进程的
│ 任意地址读写
▼
第七步:执行任意代码
│ 有了任意地址读写:
│ - 找到系统函数地址
│ - 覆盖函数指针
│ - 执行 shellcode
│ - 完全控制浏览器进程
▼
攻击者完全控制目标浏览器
│
├─ 窃取浏览历史和密码
├─ 读取所有网页内容
├─ 监控用户输入
└─ 进一步攻击操作系统
**关键结论:**这个漏洞的本质是"编译器元数据相等性判断错误"------JSToWasmFrameStateFunctionInfo 的相等比较函数漏掉了 Wasm 签名的比较,导致 CSE/GVN 优化阶段错误合并了两个不同签名的 FrameState。这种"编译器优化 bug"非常隐蔽,因为它不是运行时的内存错误,而是编译时的逻辑错误------普通的模糊测试很难触发。
三、V8 与 Turbofan 原理
3.1 什么是 V8
V8 是 Chrome 的 JavaScript 引擎:
| 组件 | 功能 |
|---|---|
| V8 | Chrome 的 JavaScript 引擎 |
| Turbofan | V8 的优化编译器 |
| Ignition | V8 的解释器 |
| Wasm | WebAssembly,高性能二进制指令格式 |
| V8 沙箱 | 隔离 V8 堆内存,防止逃逸到原生 |
3.2 什么是 Turbofan 优化
Turbofan 是 V8 的优化编译器:
// Turbofan 工作流程
// 1. 解释执行(Ignition)
// 先快速解释执行 JS 代码
// 收集类型反馈
// 2. 优化编译(Turbofan)
// 热点函数被 Turbofan 优化
// 生成高效的机器码
// 3. 反优化(Deopt)
// 如果运行时类型和预期不符
// 就退回解释执行
// (惰性反优化)
// 优化阶段做的事情:
// - 内联函数调用
// - 消除公共子表达式(CSE)
// - 全局值编号(GVN)
// - 类型特化
// 漏洞就在这里:
// CSE/GVN 阶段
// 错误合并了两个 FrameState
3.3 什么是 FrameState
FrameState 是反优化时的元数据:
// FrameState 是什么?
// 为什么需要 FrameState?
// - 优化后的代码运行很快
// - 但如果类型不对,要退回解释执行
// - 退回时需要重建原来的栈帧
// - FrameState 就是用来重建栈帧的元数据
// FrameState 里有什么?
// - 每个变量的类型
// - 每个变量的值
// - 函数调用的上下文
// - 反优化后要执行的位置
// 漏洞在哪里?
// - 两个 JS-to-Wasm 调用
// - 返回签名不同
// - 但 FrameState 的相等比较
// 漏掉了签名比较
// - 被错误合并了
// - 反优化时用了错误的签名
// - 类型就错乱了
四、漏洞深度分析
4.1 漏洞根因:相等比较漏掉签名
根据安全研究者的分析,漏洞的根本原因是 JSToWasmFrameStateFunctionInfo 的相等比较函数:
// 有缺陷的逻辑(伪代码)
// FrameState 的相等比较:
// 优化编译器用这个来判断
// 两个 FrameState 是否可以合并
// 正常应该比较:
// - 函数信息
// - 变量数量
// - 变量类型
// - Wasm 返回签名 <-- 漏了这个!
// 实际代码:
bool JSToWasmFrameStateFunctionInfo::Equals(...) {
// 比较了很多字段
// 但漏掉了 Wasm 签名!
// return this->signature == other.signature;
}
// 后果:
// 两个 FrameState
// 只有 Wasm 签名不同
// 其他都一样
// 相等比较返回 true
// CSE/GVN 把它们合并了
// 但实际上它们是不同的!
// 反优化时就用错了签名
// 类型就错乱了
4.2 为什么是 JS-to-Wasm
为什么漏洞只在 JS-to-Wasm 调用时触发:
// 为什么是 JS-to-Wasm?
// 纯 JS 调用:
// - 所有类型都是 JS 类型
// - FrameState 的类型信息完整
// - 相等比较不会出错
// JS-to-Wasm 调用:
// - Wasm 有自己的类型系统
// - i32, i64, f32, f64, externref 等
// - 跨边界时有类型转换
// - FrameState 需要记录 Wasm 签名
// - 就是这里漏了比较
// 具体场景:
// 两个 Wasm 函数:
// - func1() -> i64
// - func2() -> externref
//
// 它们的 FrameState 除了签名
// 其他都一样
// 相等比较返回 true
// 被合并了
// 反优化时
// i64 被当成 externref
// 或者反过来
4.3 从类型混淆到 addrof/fakeobj
类型混淆怎么变成内存读写原语:
// 利用链分析
// 第一步:i64 当成 externref
// Wasm 函数返回一个 i64
// 这个 i64 是攻击者控制的
// 比如是一个对象的地址
//
// 反优化时
// 这个 i64 被当成了 externref
// 也就是一个 JS 对象指针
//
// 结果:
// 攻击者可以构造任意地址
// 然后当成 JS 对象来读
// 这就是 addrof 和 fakeobj
// 第二步:为什么是完整 64 位?
// 正常的 V8 对象指针
// 是压缩指针(cage-compressed)
// 只有 32 位
//
// 但 Wasm 的 i64 是完整 64 位
// 直接就是原生地址
// 不需要解压缩
//
// 这意味着:
// 攻击者直接拿到了原生地址
// 可以读写整个进程的内存
// 不需要先逃逸沙箱!
4.4 影响范围
| 项目 | 详情 |
|---|---|
| CVE 编号 | CVE-2026-6307 |
| 漏洞类型 | 类型混淆(Type Confusion) |
| 影响产品 | Google Chrome V8 引擎 |
| 影响版本 | Chrome 147.0.7727.101 之前 |
| 发现者 | 匿名安全研究者 |
| 利用条件 | 诱导用户访问恶意网页 |
| 用户交互 | 需要访问恶意页面 |
| CVSS 评分 | 8.8(高) |
| 影响 | V8 沙箱内代码执行,可逃逸沙箱 |

五、修复方案分析
Google 在 Chrome 147.0.7727.101 中修复了这个问题:
| 修复项 | 修复方式 |
|---|---|
| FrameState 相等比较 | 补上 Wasm 签名的比较 |
| CSE/GVN 合并 | 不同签名的 FrameState 不合并 |
| 反优化类型检查 | 增加类型安全检查 |
5.1 浏览器安全设计原则
// 浏览器引擎安全原则
// 1. 元数据完整性
// 编译器元数据必须完整准确
// 任何字段都不能漏比较
// 2. 类型安全
// 跨边界调用时
// 类型转换必须严格检查
// 3. 沙箱隔离
// V8 沙箱是最后一道防线
// 即使引擎有漏洞
// 也不能逃逸到原生
// 4. 快速补丁
// 发现漏洞后快速修复
// 及时推送更新
5.2 浏览器安全最佳实践
// Chrome 安全检查清单
// 1. 及时更新
// 开启自动更新
// 不要延迟安全补丁
// 2. 不要访问可疑网站
// 不要点击陌生链接
// 不要下载不明来源的文件
// 3. 开启安全功能
// 开启安全浏览
// 开启沙箱
// 开启站点隔离
// 4. 减少攻击面
// 禁用不需要的扩展
// 禁用不需要的插件
// 5. 监控异常行为
// 注意浏览器异常崩溃
// 注意内存异常占用
六、SRC 审计启示录
6.1 浏览器漏洞审计清单
在 SRC 挖洞过程中,针对浏览器的审计清单:
| # | 检查项 | 检测方法 |
|---|---|---|
| 1 | 是否有 JS 引擎漏洞 | 测试 V8 的优化编译器 |
| 2 | 是否有 DOM 漏洞 | 测试各种 Web API |
| 3 | 是否有 Wasm 漏洞 | 测试 JS-to-Wasm 交互 |
| 4 | 是否有沙箱逃逸 | 测试沙箱边界 |
| 5 | 是否有扩展漏洞 | 测试浏览器扩展 API |
6.2 常见浏览器漏洞类型
// 常见的浏览器漏洞
// 1. 引擎内存破坏
// 类型混淆、UAF、越界读写等
// 就是本次漏洞的类型
// 2. DOM 漏洞
// Web API 的内存错误
// 比如 use-after-free
// 3. 跨边界漏洞
// JS-to-Wasm、JS-to-native 等
// 跨语言边界的类型错误
// 4. 沙箱逃逸
// 从渲染进程逃逸到浏览器进程
// 5. 扩展漏洞
// 浏览器扩展的权限问题
6.3 暴露面分级
| 暴露级别 | 情况 | 风险 |
|---|---|---|
| 严重 | 无需交互的远程代码执行 | 完全控制浏览器 |
| 高 | 需要诱导访问恶意页面 | 钓鱼配合可攻破 |
| 中 | 沙箱内代码执行 | 需要进一步逃逸 |
| 低 | 信息泄露 | 辅助攻击 |
七、防护建议
- 立即更新:升级 Chrome 到 147.0.7727.101 以上版本
- 开启自动更新:确保浏览器自动下载和安装安全更新
- 警惕可疑页面:不要访问不熟悉的网站,不要点击陌生链接
- 开启安全功能:开启安全浏览、站点隔离等安全功能
- 减少攻击面:禁用不需要的扩展和插件
- 企业部署 MDM:企业环境用 MDM 强制更新浏览器版本
八、总结
CVE-2026-6307 是一个典型的"优化编译器 bug"------它提醒我们:现代浏览器引擎已经复杂到极致,优化编译器里的一个元数据错误,就能变成一个完整的沙箱逃逸漏洞。在浏览器安全领域,"编译器优化 bug"是最高价值的漏洞类型之一:它们不像普通的内存破坏那样容易被模糊测试发现,而是需要深入理解编译器的优化逻辑才能找到。在 SRC 挖洞实践中,浏览器漏洞是赏金最高的方向之一------一个 Chrome 0day 的市场价可以到几百万美元,因为它可以被用来监控高价值目标。
