首页
社区
课程
招聘
[原创]4月13日 Chrome爆出的v8漏洞车祸原因分析(Issue 1196683,CVE-2021-21220)
发表于: 2021-5-12 16:00 15539

[原创]4月13日 Chrome爆出的v8漏洞车祸原因分析(Issue 1196683,CVE-2021-21220)

2021-5-12 16:00
15539

紧接着前文:https://bbs.pediy.com/thread-267128-1.htm#1687388

这里将前文的poc.js命名为poc1.js因为这篇文章会有其他该poc简单变种。

poc1.js


通过前面对v8优化poc1.js后生成指令的逆向分析,我们知道要了解这个漏洞的原因可以分解为以下两个问题:

第一:为什么v8poc1.js进行优化后生成的指令,对x计算会出现错误,使得随后可以获得长度为1的有效数组对象var cor = new Array(x)。(前面文章,我们通过逆向分析v8poc1.js进行优化后生成的指令的过程,是在x = Math.abs(x);这一条代码语句对应的指令执行中发现了x计算错误)。

第二:为什么在v8poc1.js进行优化后,数组对象cor.shift()操作后会直接写入0xFFFFFFFE到代表其数组对象长度的内存位置。

 

写在前面:

1v8优化的漏洞利用的核心就是获得可以越界读写的数组。

2v8优化的漏洞不能直接通过二进制逆向分析寻找漏洞的真正原因,是因为最后能调试的指令只是优化的结果生成的指令,而不是优化的本身,优化的本身是如何生成这些优化指令。所幸google提供了turbofan工具来分析v8优化的各个过程。

3v8运行poc1.js加上参数 --trace-turbo 会生成一个.json文件的,这个.json文件会记录优化的各个阶段,我们使用turbofan工具时打开该.json文件时,看到的图表只会显示某个优化过程的部分节点。

我们可以先找到显示的要分析的目标节点附近节点,再一步步追踪到我们需要关注的节点(如图 1.1.11.1.2操作)。用这操作可以用turbofan分析每个优化阶段的详细过程。

        

                                                                                图 1.1.1

      

                                                                             图 1.1.2


第一部分,模拟正确JIT优化过程

既然是车祸原因分析嘛,就先来个简单车祸现场模拟。

 

如果对计算机和v8符号数的处理机制,以及x64汇编指令有足够的了解的话,可以直接定位错误的位置,这一步可以省略应该,但本人对这些知识不太熟悉,因此用自己的思路解决问题。

这里主要的方式是通过对构造相似的js代码,模拟v8正确优化poc1.js的情况下生成指令,然后对该指令进行逆向分析。

1.1:v8优化错误的指令定位

车祸分析,最开始的是确定在那个路口出现问题。

 

在前面动态调试之中,我们是因为在v8在对poc1.js优化后的,其语句x = Math.abs(x); 对应的指令执行时,返回了其参数自身,从而发现其是将参数处理产生错误的。

                                                                              图1.1.3

如图1.1.3所示的ecx=0x80000001

这里是我们发现错误的位置,但这不代表这就是错误的开始位置。

这里列举2个可以想到的原因:

              a):v8poc1.js优化后,执行x = Math.abs(x)这一句代码对应的指令之前的部分就已经把他作为无符号数处理了,也就是这句代码的前一句,x = (_arr[0] ^ 0) + 1这句生成的对应的指令就已经是错误的,在往前就没有有代码了。

       b):v8poc1.js优化后,生成的x = Math.abs(x) 这一句代码对应的指令是错误的。

1.2:模拟v8正确的优化

  接下来是对错误指令位置的验证:

  这里采用的参照的方法 

  猜测poc1.js错误的优化和使用0这个自然数有关, 因此可以尝试将常数0用一个Uint32Array变量来存储,让(_arr[0] ^ 0) +1这句代码得到v8正确优化。(也可以尝试别的办法)


因此这里简单修改poc1.js构造poc2.js获得正确优化情况下的指令:

v8poc2.js优化后  x = (_arr[0] ^ _arr_0[0]) + 1;这一句代码对应的指令如下图所示                                                       

                                                                                 图1.2.1

                                                                                图1.2.2

如图1.2.2所示,v8poc2.js进行优化以后代码x = (_arr[0] ^ _arr_0[0]) + 1;这一句代码生成的对应的指令为:

xor ecx, dword ptr ds:[rdi]

movsxd rcx, ecx

add rcx,1

这里我们发现v8(可能是x64架构的别的软件也这么处理)将有符号32位数转移到64位寄存器中,正确的处理指令为movsxd

处理结果为:FFFFFFFF80000000,带有符号扩展,然后再add rcx,1,这样是得到的正确的结果,我们推测这个是v8期望的优化处理结果。


而在v8在优化poc1.js后,生成的x = (_arr[0] ^ 0) + 1; 这句js对应的指令如下

                                                                                  图1.2.3

如图1.2.3所示:

生成的指令为

mov ecx, dword ptr ds:[rcx]

       add rcx, 1

这里直接把_arr[0] ^ 0优化为一个值,然后传递值是采用了mov这个无符号扩展指令,也没有其他的任何符号处理措施,就进行将32位数ecx扩展为64rcx进行接下来的add rcx,1操作。

                                                                          图1.2.4

在这里我们发现车祸真正开始出现问题的路口了。


v8优化poc1.js后,生成的x = (_arr[0] ^ 0) + 1;这句代码对应生成的指令是将的_arr[0]^0优化为固定的结果放入内存中,但取出来进行接下来的操作时出现了问题。这里在传递过程中没有对符号位进行处理就直接进入接下来add rcx, 1运算,导致结果错误出现错误。

换句话说在poc1.js的优化中,v8应该采用movsxd这样带有符号扩展的传值指令,而不是使用无符号扩展的mov指令,这是导致我们看到的,在绝对值操作之后产生错误数值的根本原因。

但是为什么会这样呢,为什么v8优化poc1.js时对x = (_arr[0] ^ 0) + 1;这句代码的_arr[0]^0结果从32位扩展为64位时,选择错误的mov指令,而不是使用正确的movsxd来传递数据呢?这像是探索出现车祸背后的交通规则设计的缺陷。

单靠逆向优化后的指令是无法知晓这个问题的答案的。这里就要就要借助google提供的turbofan,对优化的重要阶段进行分析;

第二部分:对poc1.js优化过程的turbofan进行分析:

这里对poc1.js进行简单的修改,tubofan分析变得简单一点,这里将这新文件命名为poc3.js

2.1:TFTyper阶段分析

2.1.1在我这环境中用turbofan查看v8生成的.json文件是顺着70:Branch[None, NoSafetyCheck]节点往上看,可以找到v8优化后的poc1.jsx = (_arr[0] ^ 0) + 1; 这句代码对应的所有节点。(不同环境可能会不同)

                                                                          图2.1.1

接着我们从return节点往上找

                                                                       图2.1.2                 

2.1.22.1.2 162: StoreField[+12]该节点为重要节点,是cor.shift()这句代码优化的重要部分,StoreField[+12]也就是偏移12的位置存放数值,根据对这图表的分析可以知道这节点代表的是往cor数组对象的+12的位置存放数据,而这个内存位置代表的正是数组的长度。

我们需要的是知道是后面阶段是如何优化的,最后为什么会直接写进0xFFFFFFFE这个数值。

 

                                                                      图2.1.3


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2021-5-13 10:08 被苏啊树编辑 ,原因:
收藏
免费 4
支持
分享
最新回复 (1)
雪    币: 207
活跃值: (460)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
细致
2023-3-6 11:40
0
游客
登录 | 注册 方可回帖
返回
//