首页
社区
课程
招聘
[原创]Chrome v8 issue 1234770( CVE-2021-30599)漏洞分析
发表于: 2021-11-18 10:55 31986

[原创]Chrome v8 issue 1234770( CVE-2021-30599)漏洞分析

2021-11-18 10:55
31986

环境:Ubuntu 18.04

GDB

V8 9.0.257.23

一般情况下,在Ubuntu上安装软件总是比在Windows上安装要麻烦一点,但是在安装Google家产品的编译环境时,情况则恰恰相反,一般是在Windows环境上会比在Ubuntu上麻烦一些。

究其原因个人认为有以下两个,

第一:Ubuntu上安装google产品编译环境的相关资料(无论英文还是中文)都比在Windows上的相关安装资料要容易找。

第二:Windows上配合代理下拉google的东西时,因为要使用代理的原因,总是会碰到奇奇怪怪的问题,这些问题还很难在网上找得到,即使在google官方搜到这问题的提问,google官方给的回复也是把代理关了。关键是关了代理我还怎么下拉他的东西,碰到这些难题时可能就要自己研究他的下拉脚本,这算是研究google家产品的天朝中人会碰到的独特的难题了。

       

                                                               图 1.1.1

图1.1.1是我在Windows上挂代理下拉v8时碰到的问题,反正网上对这个问题的解答是奇奇怪怪,五花八门,说什么的都有,让人越看越迷茫。我这里的解决方案是指定HTTP为HTTP/1.1协议,详细的设置命令可以看1.2.3部分。


如果是编译v8,则安装vs2019 和Windows 10 SDK,(version 10.0.19041 以上的版本)就可以了,如果是编译Chromium,需要在vs2019中添加一些别的组件,添加这些组件的相关命令如下。 

$ PATH_TO_INSTALLER.EXE ^

--add Microsoft.VisualStudio.Workload.NativeDesktop ^

--add Microsoft.VisualStudio.Component.VC.ATLMFC ^

--add Microsoft.VisualStudio.Component.VC.Tools.ARM64 ^

--add Microsoft.VisualStudio.Component.VC.MFC.ARM64 ^

--includeRecommended

本人的环境是将v8和vs2019都安装在虚拟机C盘下。

第一步:

架上代理,开启全局模式,或者在控制台设置代理,控制台设置代理命令如下。

set https_proxy=http://192.168.17.1:7890(IP和端口设置为你的代理服务器的IP和端口)

set http_proxy=http://192.168.17.1:7890

第二步:

下载depot_tools,解压在你想要安装的盘下,并把他安装路径加在环境变量中,这里有个细节要注意,需要把deptot_tool这个环境变量上移到环境变量顶部:

          

                                                      图:1.2.2.1

第三步:

在控制台上输入gclient命令,这个命令会帮你自动安装符合现在v8和Chrome要求的python和git版本。

如果没有出现意外的话会出现以下log:

C:\Users\XXX>gclient

Downloading CIPD client for windows-amd64 from https://chrome-infra-packages.appspot.com/client?platform=windows-amd64&version=git_revision:8e9b0c80860d00dfe951f7ea37d74e210d376c13...

WARNING: Your metrics.cfg file was invalid or nonexistent. A new one will be created.

Usage: gclient.py <command> [options]


Meta checkout dependency manager for Git.


Commands are:

  config   creates a .gclient file in the current directory

  diff     displays local diff for every dependencies

  fetch    fetches upstream commits for all modules

  flatten  flattens the solutions into a single DEPS file

  getdep   gets revision information and variable values from a DEPS file

  grep     greps through git repos managed by gclient

  help     prints list of commands or help for a specific command

  metrics  reports, and optionally modifies, the status of metric collection

  pack     generates a patch which can be applied at the root of the tree

  recurse  operates [command args ...] on all the dependencies

  revert   reverts all modifications in every dependencies

  revinfo  outputs revision info mapping for the client and its dependencies

  root     outputs the solution root (or current dir if there isn't one)

  runhooks runs hooks for files that have been modified in the local working copy

  setdep   modifies dependency revisions and variable values in a DEPS file

  status   shows modification status for every dependencies

  sync     checkout/update all modules

  validate validates the .gclient and DEPS syntax

  verify   verifies the DEPS file deps are only from allowed_hosts


Options:

  --version             show program's version number and exit

-h, --help            show this help message and exit

  -j JOBS, --jobs=JOBS  Specify how many SCM commands can run in parallel;

                        defaults to 8 on this machine

  -v, --verbose         Produces additional output for diagnostics. Can be

                        used up to three times for more logging info.

  --gclientfile=CONFIG_FILENAME

                        Specify an alternate .gclient file

  --spec=SPEC           create a gclient file containing the provided string.

                        Due to Cygwin/Python brokenness, it can't contain any

                        newlines.

  --no-nag-max          Ignored for backwards compatibility.

 

这样就完成了python和git环境的搭建。

完成上述步骤以后在控制台输入如下命令:

git config --global http.sslVerify false

set GYP_DEFINES=target_arch=x64

set DEPOT_TOOLS_WIN_TOOLCHAIN=0

set GYP_GENERATORS=msvs-ninja,ninja

set GYP_MSVS_VERSION=2019

git config --global http.version HTTP/1.1

然后:mkdir v8 && cd v8

fetch v8

git reset --hard bdaa7d66a37adcc1f1d81c9b0f834327a74ffe07(换成你需要的版本)

gclient sync

这里执行完以后就顺利在Windows 10上,下拉到指定版本的v8了。

下拉后开始编译v8,命令如下:

# 提供默认的gn参数给args.gn文件,帮助我们编译出debug版本和release版本

 python tools\dev\v8gen.py x64.release

 python tools\dev\v8gen.py x64.debug

 # 自动编译

 python tools\dev\gm.py x64.debug d8

 python tools\dev\gm.py x64.release d8

将编译出d8.exe到out文件夹中

至于为什么在Windows上编译v8和Chromium,本人的主要原因是想着在Windows上比较方便用IDA看v8和Chromium的符号。

该漏洞属于v8 优化(turbofan)的漏洞。

位于`src/compiler/machine-operator-reducer.cc` 文件MachineOperatorReducer类中

关于turbofan的知识可以参考

https://v8.dev/docs/turbofan


这次漏洞出现在比特位运算的优化中,对((x&A)==B)&((x&C)==D)这种结构的优化

上述两个产生漏洞的函数:

      第一个函数Detect(Node* node)是会将‘((x&A)==B)’ (A,B为常数,x为变量) 这种节点截断为Word32类型的节点,这点通过注释就能看到。

      第二个函数TryCombine(const BitfieldCheck& other)是对两个Word32节点进行`Word32And`的运算的,进行尝试合并为一个Word32节点。

 因为第一个函数Detect(Node* node)会将‘((x&A)==B)’这种节点标记为Word32类型,故而如果存在两个这种节点进行And运算,就会进入TryCombine(const BitfieldCheck& other)这个函数处理流程,尝试将这两个Word32节点合并为一个Word32节点。

 具体一点来说如果出现’((x&A)==B)&((x&C)==D)’这种节点,因为Detect(Node* node)会将(x&A)==B)‘子节点和’((x&C)==D)‘子节点标记为Word32节点,接下来就会进入TryCombine(const BitfieldCheck& other)这个函数流程,将(x&A)==B)‘子节点和’((x&C)==D)‘子节点会进行尝试合并,如果通过条件判断,就会合并为一个新的’(x&E)==F’节点代替原有的’((x&A)==B)&((x&C)==D)’节点。

里面常数A,B,C,D,E,F互相可能相等,也可能不相等。



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

最后于 2021-11-18 16:17 被苏啊树编辑 ,原因:
收藏
免费 7
支持
分享
最新回复 (8)
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
18f
2
感谢分享, 补充一点其它细节.

1. 那个地方其它样例不行是因为之前会做一个 range analysis(v8 好像叫做 typer-optimization...), 然后节点被直接折叠成 false节点了... 要避免这种情况 num&b == c, 需要保持 b >= c.
2. root cause那里如果是对数学推导不大熟悉的同学(因为我当时推导到某个case老是推不下去...), 可以尝试使用 z3来帮助完成数据构建. 可以找到一堆额外的反例, 比如:" let res = (((num & 24) == 17 ) & ((num & 21) == 17 ));  //  optimize error" 不过作者提到的satisfied 是我没接触过的内容, 感恩.
2021-11-21 10:33
0
雪    币: 5317
活跃值: (3348)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
3
18f 感谢分享, 补充一点其它细节. 1. 那个地方其它样例不行是因为之前会做一个 range analysis(v8 好像叫做 typer-optimization...), 然后节点被直接折叠成 ...
仔细看作者是说如果有可能发生的话,所以那两个例子其实没有验证。。。。您这里提到的这构建方法我也不太懂,感谢分享
2021-11-21 15:43
0
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
18f
4
苏啊树 仔细看作者是说如果有可能发生的话,所以那两个例子其实没有验证。。。。您这里提到的这构建方法我也不太懂,感谢分享

x, y1, y2, z1, z2 = BitVecs('x y1 y2 z1 z2', 32)

s = Solver()

m = y1 & y2

s.add((z1 & m) == (z2 & m))

a = ((x & y1) == z1)
b = ((x & y2) == z2)
c1 = (x & (y1 | y2))
c2 = (z1 | z2)

s.add(y1 > z1)
s.add(y2 > z2)

s.add(y1 == 24)  // [+] 这里可以替换不写也没关系

s.add(And(a , b) == False)
s.add(c1 == c2)

# exit()

print(s.check())
print(s.model())

把他的源码抽象成数学公式 用这个求解就可以了
2021-11-21 18:21
0
雪    币: 7
活跃值: (4331)
能力值: ( LV9,RANK:270 )
在线值:
发帖
回帖
粉丝
5
18f x, y1, y2, z1, z2 = BitVecs('x y1 y2 z1 z2', 32) s = Solver() m = y1 & y2 s.add((z1 & ...
不错,不愧是18f
2021-11-22 10:32
0
雪    币: 5317
活跃值: (3348)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
6
18f x, y1, y2, z1, z2 = BitVecs('x y1 y2 z1 z2', 32) s = Solver() m = y1 & y2 s.add((z1 & ...
感谢大佬解答
2021-11-22 10:41
0
雪    币: 70
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
999
7

请问在迭代器next访问arr数组超出三个元素后的数据都无法访问,得到的值是undefined是什么原因,代码是漏洞作者提供的exp

最后于 2022-3-23 16:38 被999编辑 ,原因:
2022-3-23 16:34
0
雪    币: 5317
活跃值: (3348)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
8
999 请问在迭代器next访问arr数组超出三个元素后的数据都无法访问,得到的值是undefined是什么原因,代码是漏洞作者提供的exp
请问你是是怎么访问的呀,这里他exp已经越界获取了第六个元素的值了。。。
2022-3-30 14:49
0
雪    币: 70
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
999
9

我的是因为环境问题,漏洞提交者给的是版本是92.0.4515.107对应的V8版本是9.2.230.20,我用的v8版本是在issue页面下commit为574ca6b71c6160d38b5fcf4b8e133bc7f6ba2387的上一个commit为27a517b8922915f53d479133205ee80b35ac2feb的版本(具体版本号忘记了)这个版本的v8也可以触发这个漏洞,但是在后续用iter.next()进行漏洞利用时是不成功的,应该是这种利用方法在30598中已经被修补了,而我用的这个版本正好在这之后

最后于 2022-4-8 15:53 被999编辑 ,原因:
2022-4-8 15:23
0
游客
登录 | 注册 方可回帖
返回
//