绕过指针压缩
使用ArrayBuffer写入shellcode:
比较新的v8指针占4个字节,用寄存器+指针联合表示,而最后写shellcode时,需要写到rwx段,此时不能使用read_any(应该是由于浮点数以及Bigint等写入时的问题),此时可以使用ArrayBuffer
,ArrayBuffer的backing_store为8字节指针,将backing_store修改为rwx_page,此时使用data_view的setBigUint64就可以成功绕过
tips: 需要注意backing_store的偏移是0x14n。
泄露地址:
创建BigUint64Array,其中external_pointer和base_pointer可以泄露。并可以任意读。
CVE产生原因
漏洞成因详情可以见:https://bugs.chromium.org/p/chromium/issues/detail?id=1086890
POC:
1 | array = Array(0x40000).fill(1.1); |
简单来说,漏洞成因是新引进的’NewFixedArray’ 和 ‘NewFixedDoubleArray’ 缺少长度检查,但是这两个数组的长度有个最大值为67108862,此时,缺少长度
检查,还无法利用,但正好tuoque的代码优化中,会取数组的最大长度,不考虑实际长度,此时就会发生数组越界。
优化次数可以参考poc。这个POC中修改的偏移为长度,但是此时会将element一起修改,如果只是简单的本地复现的话,element可以修改为对应的element,也可以复现成功
思路
1.利用obj = {“a”: 2.1};并控制好偏移,从而修改length,不改变element
2.泄露array_map和double_map
3.伪造obj通过fake_obj写出write_any和read_any
4.需要在函数中编写泄露map之后的exp,这样不会影响原本的布局
5.使用wasm getshell
exp
1 | var f64 = new Float64Array(1); |
总结
这个CVE复现的难点在于修改全局变量等会改变原本的变量布局,产生segment fault,至于其他的关于偏移等问题,都可以通过调试解决,需要注意一下细节。