# 探究利用 Sentinel Value 突破 Chrome V8 防护机制Sentinel value 是算法中一种特殊值,通常用作循环或递归算法的终止条件。Chrome 源码中存在多种 Sentinel value。之前有研究表明,通过泄露 TheHole 对象可实现某些 CVE 的沙箱内任意代码执行。谷歌团队在我们发文阐述该缓解绕过约一周后,迅速将相关 CVE 更新到了 GitHub 上。从 Chrome 源码可以看到针对 TheHole 对象导致任意代码执行的缓解修复。但实际上,V8 中还有很多其他不应泄露到 JS 中的原生对象。本文将讨论 Uninitialized Oddball 对象,该绕过方法最早出现在 Issue1352549 中。值得注意的是,目前该方法仍可用于最新版 V8,谷歌尚未针对此进行修复。该方法具有较强通用性:1. Issue1216437(CVE-2021-30551)中首次给出的 POC 即为泄露 internal uninitialized oddball。2. Issue1314616(CVE-2022-1486)中的 POC 也直接泄露了 UninitializedOddball。3. Issue1352549(NoCVE)的影响不容忽视。这些都充分说明了有必要重新审视可能受 PatchGap 影响的软件。## V8 中的 Sentinel ValueV8 的大部分原生对象定义在 v8/src/roots/roots.h 文件中,它们在内存中相邻排布。一旦这些不应泄露的原生对象被泄露到 JavaScript 中,就可能导致沙箱内任意代码执行。为验证该方法在最新版 V8 中的有效性,我们可以修改 V8 的原生函数 %TheHole(),使其返回 Uninitialized Oddball。## 绕过 HardenType Issue1352549 中给出了完整代码,我们对其进行提取和简化后,在 V8 11.0.0 中测试仍可实现相对任意读。对优化后的 JavaScript read 函数反汇编,可以看到在检查 obj.prop 时,没有检查以 obj.prop 为 key 的 Value,而是直接按 JavaScript 语义计算偏移获取数组值。这导致了在计算时发生类型混淆,实现任意读。当传入 uninitialized_oddball 时,以 obj 为起点计算,最终在 vmovsd xmm0,[r9+r11*8+0x7] 指令中完成任意读,数据保存在 xmm0 寄存器中。由于 uninitialized_oddball 在 V8 内存中排序靠前且更原始,伪造更容易,是绕过的首选方法。任意写可参考 Issue1352549 构造分析。修复建议是在优化后的函数返回数组元素时,添加对数组 map 的检查,避免直接计算偏移返回数组值。## PatchGap 警告分析 Issue1352549 后,我们排查了可能存在 PatchGap 的软件,发现 Skype 至今未修复该漏洞。x86 下的任意读写略有不同,由于没有地址压缩,是直接相对整个进程的。在 Skype 的利用中,虽然开启了 ASLR,但由于文件过大,黑客只需对某个固定地址读写,就很可能读写到 Skype 文件内容。结合 PE 解析等传统思路,不难完成整个漏洞利用链。这次 PatchGap 不仅涉及 Issue1352549,新绕过方法的公开还导致类似 Issue1314616 和 Issue1216437 的利用难度大幅降低。黑客几乎无需研究成本,就可实现以往任何泄露 uninitialized_oddball 漏洞的完整利用。## 总结本文简要讨论了通过泄露 uninitialized_Oddball 实现任意读原语。V8 中还有很多其他 Sentinel value,测试时也容易遇到非 int3 的崩溃。既然 Uninitialized_Oddball 和 TheHole 均可绕过 V8 防护,其他 Sentinel value 也可能存在类似问题。这给我们一些启示:1. 其他 uninitialized_Oddball 泄露是否也可轻松实现 V8 的 RCE。2. 谷歌迅速修复了 TheHole 绕过,但利用垃圾回收绕过 ASLR 的问题长期搁置,说明类似 issue 是否被视为正式安全问题仍存在模糊边界。3. 如果将其视为正式安全问题,fuzzer 中是否有必要考虑将 %TheHole/uninitialized_Oddball 等 Sentinel value 作为变量加入,以挖掘其他利用原语。无论该类问题是否被正式视为安全问题,它都会大大缩短黑客实现完整利用的周期。
V8引擎Sentinel Value漏洞探究:绕过防护实现任意代码执行
探究利用 Sentinel Value 突破 Chrome V8 防护机制
Sentinel value 是算法中一种特殊值,通常用作循环或递归算法的终止条件。Chrome 源码中存在多种 Sentinel value。之前有研究表明,通过泄露 TheHole 对象可实现某些 CVE 的沙箱内任意代码执行。谷歌团队在我们发文阐述该缓解绕过约一周后,迅速将相关 CVE 更新到了 GitHub 上。
从 Chrome 源码可以看到针对 TheHole 对象导致任意代码执行的缓解修复。但实际上,V8 中还有很多其他不应泄露到 JS 中的原生对象。本文将讨论 Uninitialized Oddball 对象,该绕过方法最早出现在 Issue1352549 中。值得注意的是,目前该方法仍可用于最新版 V8,谷歌尚未针对此进行修复。
该方法具有较强通用性:
Issue1216437(CVE-2021-30551)中首次给出的 POC 即为泄露 internal uninitialized oddball。
Issue1314616(CVE-2022-1486)中的 POC 也直接泄露了 UninitializedOddball。
Issue1352549(NoCVE)的影响不容忽视。
这些都充分说明了有必要重新审视可能受 PatchGap 影响的软件。
V8 中的 Sentinel Value
V8 的大部分原生对象定义在 v8/src/roots/roots.h 文件中,它们在内存中相邻排布。一旦这些不应泄露的原生对象被泄露到 JavaScript 中,就可能导致沙箱内任意代码执行。
为验证该方法在最新版 V8 中的有效性,我们可以修改 V8 的原生函数 %TheHole(),使其返回 Uninitialized Oddball。
绕过 HardenType
Issue1352549 中给出了完整代码,我们对其进行提取和简化后,在 V8 11.0.0 中测试仍可实现相对任意读。
对优化后的 JavaScript read 函数反汇编,可以看到在检查 obj.prop 时,没有检查以 obj.prop 为 key 的 Value,而是直接按 JavaScript 语义计算偏移获取数组值。这导致了在计算时发生类型混淆,实现任意读。
当传入 uninitialized_oddball 时,以 obj 为起点计算,最终在 vmovsd xmm0,[r9+r11*8+0x7] 指令中完成任意读,数据保存在 xmm0 寄存器中。
由于 uninitialized_oddball 在 V8 内存中排序靠前且更原始,伪造更容易,是绕过的首选方法。任意写可参考 Issue1352549 构造分析。
修复建议是在优化后的函数返回数组元素时,添加对数组 map 的检查,避免直接计算偏移返回数组值。
PatchGap 警告
分析 Issue1352549 后,我们排查了可能存在 PatchGap 的软件,发现 Skype 至今未修复该漏洞。x86 下的任意读写略有不同,由于没有地址压缩,是直接相对整个进程的。
在 Skype 的利用中,虽然开启了 ASLR,但由于文件过大,黑客只需对某个固定地址读写,就很可能读写到 Skype 文件内容。结合 PE 解析等传统思路,不难完成整个漏洞利用链。
这次 PatchGap 不仅涉及 Issue1352549,新绕过方法的公开还导致类似 Issue1314616 和 Issue1216437 的利用难度大幅降低。黑客几乎无需研究成本,就可实现以往任何泄露 uninitialized_oddball 漏洞的完整利用。
总结
本文简要讨论了通过泄露 uninitialized_Oddball 实现任意读原语。V8 中还有很多其他 Sentinel value,测试时也容易遇到非 int3 的崩溃。既然 Uninitialized_Oddball 和 TheHole 均可绕过 V8 防护,其他 Sentinel value 也可能存在类似问题。
这给我们一些启示:
其他 uninitialized_Oddball 泄露是否也可轻松实现 V8 的 RCE。
谷歌迅速修复了 TheHole 绕过,但利用垃圾回收绕过 ASLR 的问题长期搁置,说明类似 issue 是否被视为正式安全问题仍存在模糊边界。
如果将其视为正式安全问题,fuzzer 中是否有必要考虑将 %TheHole/uninitialized_Oddball 等 Sentinel value 作为变量加入,以挖掘其他利用原语。
无论该类问题是否被正式视为安全问题,它都会大大缩短黑客实现完整利用的周期。