自从数字经济2019线下赛之后,体验了一把小白难度的Real World,虽然一道题没出来,但是至少给学习带来了前进的方向
遂想要复现当时赛场的一道chrome的题目,于是着手开始学习v8的利用
starCTF 的 oob很简单,是个不错的选择
题目链接:Github
参考:https://www.freebuf.com/vuls/203721.html
建议先把大佬的文章看完,然后本文权当补充以及自我总结
下载编译v8
因为墙的缘故,下载v8会很烦人。在我感叹利用朋友搭的VPS也不能在国内愉快地下载v8的源码的时候,不得已买了个vpn,我才发现,原来下载慢只是钱不到位
下载depot_tools
1 | git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git |
下载V8
1 | fetch v8 |
安装所需依赖
1 | cd v8 |
导入gdb脚本
1 | $ #在 ~/.gdbinit 中添加 |
编译
通常的教程的编译过程是这样的
1 | tools/dev/v8gen.py x64.release |
此法不管release版本还是debug版本都不适合做题,因为release版本无法使用v8的指令,而debug版本在运行漏洞函数的时候会因为dcheck而报错终止。解决办法就是设置好编译选项,或者干掉dcheck的宏(我没成功)
于是我找到了另一种方法
1 | tools/dev/gm.py x64.release |
gm.py脚本中定义了一些编译选项,我发现它们刚好可以符合外面的要求,即在release版本中使用它定义的一些gdb指令
关于debug
1 | path/to/d8 --allow-natives-syntax path/to/js |
输入 --allow-natives-syntax
参数可以使用v8的一些调试函数,作为新手,我接触到的有
1 | %DebugPrint(obj); |
函数作用顾名思义
关于exp
寻常方法
在本文开始的链接中,作者共介绍了两种方法,一种是寻常pwn题的思路,即读取got地址,读出libc地址,算出libc函数地址,最后覆盖__free_hook
或者__malloc_hook
exp
该exp对应的偏移均是在out.gn/x64.release/d8
中计算的偏移,即通常编译过程的release版本
1 | var buf = new ArrayBuffer(0x10); |
注意
该exp我只在d8中实现了,在题目所给的chrome中,可能由于编译选项的不同,导致偏移不同,但我目前也没有办法得到在chrome中v8的代码段地址
所以这种方法具有很大的局限性,只能自娱自乐
覆写wasm代码段
该方法是利用了wasm代码段可读可写可执行的特性。但是在生成wasm代码的时候,不能够调用libc的函数,所以只能先导入wasm代码之后再找到它的地址,再把它修改成我们的shellcode来执行
wasm代码在线生成网址:https://wasdk.github.io/WasmFiddle/
编写shellcode
由于无法确定libc基址,所以采用系统调用的方式来执行shellcode
shell.asm
1 | global _start |
执行
1 | $ nasm -f elf64 ./shell.asm |
就得到了shell.o文件
执行
1 | ld -o shell shell.o |
就得到了名为shell的可执行文件,执行它,测试我们编写的shellcode是否正确
执行
1 | objcopy -O binary ./shell.o code |
就得到了一个名为code的文件,该文件中只有汇编代码,没有其他无用的信息
执行
1 | xxd -i ./code |
就会得到
1 | unsigned char __code[] = { |
如果是内联在c代码中,还可以用以下的形式来测试:
1 | unsigned char __code[] = { |
但是我测试的时候失败了,原因是__code位于bss段,该段不可执行
编写exp
先写一段无关的wasm代码,将其导入
然后在内存中就会存在一块可读可写可执行的区域,将shellcode放到这片区域然后执行wasm的函数指针就会触发shellcode
1 | var buf = new ArrayBuffer(0x10); |
这样执行就可以get shell了
当然,一般做题的时候会让你弹出计算器,将shellcode改为如下即可:
1 | var shellcode = new Uint8Array([ |
这段代码相当于执行了execve('/usr/bin/xcalc','xcalc','DISPLAY=:0')
我现在也不晓得为啥是这样
总之直接用execve('/usr/bin/xcalc',NULL,NULL)
是不行的
注意
若想在chrome中弹出计算器,一定要用path/to/chrome --no-sandbox
这样的方式打开,不然无法正常执行shellcode
其他大佬的骚操作
泄露elf基地址,libc地址,再通过libc地址泄露栈地址,然后构造ROP链,接着劫持返回地址……
这种方法不适用于我所遇到的情况……即chrome中的v8的各种偏移与我编译的不一样……
总结
这道题似乎并没有什么难度,但是对于我这样的菜鸟来说又充满了挑战与趣味性(v8编译的问题我就整了3天)
接下来就准备看一下队友要到的大佬的数字经济的exp,尝试去复现了
话说今天的360个人赛的pwn真简单……但是我也意识到了除了pwn其他的我啥也不太了解……
是太专了么?