从0开始学V8漏洞利用之starctf 2019 OOB(三)
我是从starctf 2019的一道叫OOB的题目开始入门的,首先来讲讲这道题。
FreeBuf上有一篇《从一道CTF题零基础学V8漏洞利用》,我觉得对初学者挺友好的,我就是根据这篇文章开始入门v8的漏洞利用。
环境搭建
1 | $ git clone https://github.com/sixstars/starctf2019.git |
或者可以在我之前分享的build.sh
中,在git reset
命令后加一句git apply ../starctf2019/pwn-OOB/oob.diff
,就能使用build.sh 6dc88c191f5ecc5389dc26efa3ca0907faef3598 starctf2019
一键编译。
漏洞点
源码我就不分析了,因为这题是人为造洞,在obb.diff中,给变量添加了一个oob函数,这个函数可以越界读写64bit。来测试一下:
1 | $ cat test.js |
使用gdb进行调试,得到输出:
1 | x is 0x16c2a4382ed9 |
可能是因为v8的版本太低了,在这个版本的时候DebugPrint
命令只会输出变量的地址,不会输出其结构,我们可以使用job来查看其结构:
1 | pwndbg> job 0x242d7b60e041 |
我们能发现,x的值为变量a的map地址。浮点型数组的结构之前的文章说了,在value之后就是该变量的结构内存区域,所以使用a.oob()
可以越界读64bit,就可以读写该变量的map地址,并且在该版本中,地址并没有被压缩,是64bit。
我们继续运行代码:
1 | pwndbg> x/8gx 0x242d7b60e029-1 |
发现通过a.oob(2.1);
可以越界写64bit,已经把变量a
的map地址改为了2.1
。
套模版写exp
想想我上篇文章说的模板,我们来套模板写exp。
编写addressOf函数
首先我们来写addressOf
函数,该函数的功能是,通过把obj数组的map地址改为浮点型数组的map地址,来泄漏任意变量的地址。
所以我们可以这么写:
1 | var double_array = [1.1]; |
编写fakeObj函数
接下来编写一下fakeObj
函数,该函数的功能是把浮点型数组的map地址改为对象数组的map地址,可以伪造出一个对象来,所以我们可以这么写:
1 | function fakeObj(addr_to_fake) |
完整的exp
好了,把模板中空缺的部分都补充完了,但是还有一个问题。因为模板是按照新版的v8来写的,新版的v8对地址都进行了压缩,但是该题的v8缺没有对地址进行压缩,所以还有一些地方需要进行调整:
首先是读写函数,因为map地址占64bit,长度占64bit,所以elements
的地址位于value-0x10
,所以读写函数需要进行微调:
1 | function read64(addr) |
copy_shellcode_to_rwx
函数也要进行相关的调整:
1 | function copy_shellcode_to_rwx(shellcode, rwx_addr) |
fake_array
也需要进行修改:
1 | var fake_array = [ |
计算fake_object_addr
地址的偏移需要稍微改改:
1 | fake_array_addr = addressOf(fake_array); |
获取rwx_addr
的过程需要稍微改一改偏移:
1 | var wasm_instance_addr = addressOf(wasmInstance); |
偏移改完了,可以整合一下了,最后的exp如下:
1 | var wasmCode = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,0,4,109,97,105,110,0,0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,42,11]); |
执行exp:
1 | $ ./d8 exp.js |
从0开始学V8漏洞利用之starctf 2019 OOB(三)