CVE-2021-38001复现
环境搭建
1 |
|
可能是因为版本过于久远,试了网上很多的版本,都没法正常运行poc,最后这个版本9.5.172.10
是正常的,可以拿到shell
前置知识
原型链
了解即可
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
Inline Cache
https://mathiasbynens.be/notes/shapes-ics
v8堆喷
仅作记录
代码分析
1 |
|
下图红框处为堆内存
步过之后,这块内存增长了0x23000
简单的看下结构
1 |
|
漏洞分析
基本信息
此处为该cve的commit
对此commit的详细分析https://github.com/vngkv123/articles/blob/main/CVE-2021-38001.md
poc分析
首先有两个文件,分别是1.mjs
和2.mjs
1.mjs
的内容如下
1 |
|
2.mjs
的内容如下
1 |
|
这个poc定义了一个函数,函数内存在一个C类,C类中有一个m方法。接着定义了一个zz的对象,同时又定义了trigger
函数,函数内对于C的原型链进行了修改,同时为C添加了x0``x1
……x4
的属性,res保存c执行完m方法的值,最后通过最后的一个for循环来调用trigger
看一下执行完这个poc的效果
卡在了给r8d
寄存器赋值的位置,此时r8
的值就是poc里添加的几个变量的值,前面多出来的前缀是由于指针压缩,真实的值=r8-r14=0x42424242
分析下这个poc里调用c.m()
时的原型链
被trigger函数修改之前:{} -> C.prototype -> Object.prototype -> null
被trigger函数修改之后:{} -> C.prototype -> zz -> module -> {} -> y.prototype -> Object.prototype -> null
这里可以把zz给精简掉,不影响最后的效果
1 |
|
一样的效果
任然阻塞
但是此时的0x42424242
被写入成功了,555819297也就是0x42424242/2
继续修改poc
这里添加一个array1
的对象,然后对象数组的键值赋值为0x42424242
,接着c.x0 = array1;
改动代码如下
1 |
|
完整代码
1 |
|
调试效果
此时任然是卡住了,卡在了0x42424242
这个值
但是此时此处是一个可控可访问可伪造的对象
job看下
那么此时的思路就有了,可以伪造一个对象数组,这样就可以控制R8的值,让其等于一个合法的地址
添加如下代码
1 |
|
可控的对象
那么思路其实就明确了,通过array1可以伪造出一些地址,达到非法读写的效果
下面直接这样修改array1['x'+i] = 0x4040404040404040;
1 |
|
可以发现这里已经成功伪造了evil的地址
漏洞利用
这里参照了
[Loora1N](https://loora1n.github.io/)
师傅的方法,通过利用poc伪造element和map,但这里的element和map都是已经存在的结构,也就是在内存中存在,可以通过代码控制
首先就是一些准备工作,先获取double_array_map和object_array_map的地址,这里可以创建一个double 的数组对象和一个对象
1 |
|
需要的数值,其中element_addr就是数组a1的element,fake_elements_addr就是数组a2的element
这样就可以通过a2来控制evil的element
a1就是用来伪造对象
通常的对象结构如下
1 |
|
1 |
|
接着通过poc触发,打印evil看下
1 |
|
此时的evil起始地址是a1+8,然后elements地址是a2
这样就可以编写addressOf
和fakeObj
1 |
|
wasm code 的准备工作
1 |
|
泄露wasmInstance的地址
1 |
|
构造一个fake_array,来实现AAR/AAW
1 |
|
泄露fake_array的地址,然后跟踪到fake_array.elements的位置,不同版本不太一样这个(高版本不太清楚了
fake_array的结构
然后fake_obj的地址也就是要到达fake_array[1]的地址,也就是得在fake_array的基础上+0x24
1 |
|
有了fake_obj就可以写AAR/AAW了
1 |
|
下面就是读出来wasm的rwx段,这个版本的instance偏移是0x60
1 |
|
p就是封装了下debugprint
找wasm的instance
找rwx段
接着通过dataview写入shellcode
流程是先泄露dataview的地址,然后计算得出其backing_store_addr,接着修改backing_store_addr为rwx_page_addr,然后就可以写入shellcode
1 |
|
dataview,通过buffer找backing_store_addr
此时的backing_store_addr已经被修改为rwx_page_addr
然后就是拿shell
exp
1 |
|
参考文章
https://loora1n.github.io/2024/09/20/%E3%80%90V8%E3%80%91HeapSpary/
https://loora1n.github.io/2024/10/17/%E3%80%90V8%E3%80%91CVE-2021-38001-2/?highlight=cve+2021+38001
https://staticccccccc.github.io/2024/03/10/V8/V8%E5%88%A9%E7%94%A8(4)-CVE-2021-38001/
https://github.com/vngkv123/articles/blob/main/CVE-2021-38001.md
https://a1ex.online/2021/12/02/cve-2021-38001-%E5%88%86%E6%9E%90/
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain