V8 EXPLOIT ONE
Last Update:
Word Count:
Read Time:
V8初探
前言
以前早就在ctf上看见过类似的v8引擎题,比如sctf,Downunder Ctf等等,这篇文章就来复现一下underdown ctf中的一个d8 pwn题,这也是个历年谷歌浏览器漏洞的一个cve,本篇参考faith的文章来学习一下v8。
ref: https://faraz.faith/2019-12-13-starctf-oob-v8-indepth/
题目: 下载
下载好之后有几个文件如下:
1 |
|
编译 v8
首先先下载谷歌的depot_tools
1 |
|
设置环境变量
1 |
|
下载v8源码,这里需要翻墙下载
1 |
|
有点大,有3个多G
1 |
|
在ubuntu16下进行编译
编译debug版
1 |
|
编译release版
1 |
|
下载还有编译过程需要时间有点长,耐心等待下,这里我就编译debug版本的,编译出来的文件会放在 v8/out.gn/x64.debug/d8
.
1 |
|
Patch文件
oob.diff文件如下
1 |
|
这个patch中修改了src/bootstrapper.cc,src/builtins/builtins-array.cc, src/builtins/builtins-definitions.h,src/compiler/typer.cc文件,然而变动最大的就是
src/builtins/builtins-array.cc文件,漏洞也在这个文件中,作者呢也强烈要求读者去自己尝试把漏洞标记出来,下面注释就是我做的一些解释,如下
1 |
|
下面贴下作者的原话:
I urge the reader to take a look at the code added to src/builtins/builtins-array.cc
and try to spot the vulnerability. Even without any further context, it should be easy to spot.
- The function will initially check if the number of arguments is greater than 2 (the first argument is always the
this
argument). If it is, it returns undefined. - If there is only one argument (
this
), it will cast the array into aFixedDoubleArray
before returning the element atarray[length]
. - If there are two arguments (
this
andvalue
), it will writevalue
as a float intoarray[length]
.
Now, since arrays start with index 0, it is evident that array[length]
results in an out-of-bounds access by one index at the end of the array.
那么按照作者介绍js中的三种类型,v8采用一种pointer taggin的机制去分辨pointer,double还有smis类型,都代表一种快速小的整数,这些信息可以在src/objects.h中找到。三种类型分别分别定义如下:
* Double: Shown as the 64-bit binary representation without any changes
* Smi: Represented as value << 32, i.e 0xdeadbeef is represented as 0xdeadbeef00000000
* Pointers: Represented as addr & 1. 0x2233ad9c2ed8 is represented as 0x2233ad9c2ed9
还有一 注意的是,v8泄漏任何信息都以浮点数进行打印,也没有任何方式去正常表达64位的整型变量,所以的采用js的某些特殊手段将内存中的float类型以16进制方式打印出来,下面是作者提供的转换函数。
1 |
|
ftoi: 将浮点类型转换为BigInt类型,用于泄漏内存
itof: 将BigInt类型转换为浮点类型,用于写入到内存,因为d8都是采用浮点类型进行储存的,采用一定转换后的格式才能正确在内存中写入值。
将上面保存为file.js
可以运行d8如下去执行,可以通过脚本实现转换。
1 |
|
输出
1 |
|
数组末尾储存的是什么?
可以通过到谷歌官方source code https://source.chromium.org 查看源代码,但是不推荐,除非要有深刻的理解v8的代码才能知道内存的布局是什么。有另一种方法可以去知道内存布局。
通过debug版本的d8,可以实时的打印数组的内存布局,执行命令如下:
1 |
|
若想进入到某些调试函数的话,可以采用%DebugPrint()
采用gdb调试效果如下:
1 |
|
然而发现上面创建了4个线程,不方便调试通过设置UV_THREADPOOL_SIZE环境变量来改d8启动的线程数
1 |
|
尝试了,不行。
在调用数组oob()函数的时候崩溃。。。Arch linux与Ubuntu执行效果一样,出现了内存错误。。。
1 |
|
Downunder ctf [is-this-pwn-or-web]
查看diff文件与之前一样,下面为作者具体利用思路。
更新中…
exp
1 |
|
1 |
|