RWCTF2022 svme
类别:clone-and-pwn
新的类别,是挖现实里的项目的洞,贴近实战,还是挺有意思的,就自己做了一遍
关键词:虚拟机,数组越界
源码
提供了main.c和Dockerfile,根据Docker File可以直接找到仓库simple-virtual-machine-C ,mian.c的逻辑很简单
1 |
|
因为vm_create的第三个参数nglobals是0,所以我当时下意识认为用不到全局操作,这也算是教训吧
然后因为调用了free,当时觉得可以打free_hook
VM的结构体如下
1 | typedef struct { |
主要需要分析的部分在头文件的vm_exec里,所有的数据类型都是int
1 | void vm_exec(VM *vm, int startip, bool trace) |
很明显,对于数组的操作未做任何检查
这里有两个指针可以关注:
code指针指向栈上的数组,只能读不能写(相当于text段嘛)。
globals指针指向堆块,可读(GLOAD)可写(GSTORE)。
⽤load和store可以越界修改vm结构体, 而进行GSTORE和GLOAD的时候,都是通过global指针来确定global的位置的,此时如果global改成code指针,就可以利用GSTORE和GLOAD进行栈上的任意地址读写。
由于LOAD是借助我们输入的索引来寻址的,我们可以直接任意读,将code先行读到globals上
1 | POP, |
看一下code和rbp的距离,是0x210
那我想着push上去一个0x210,然后IADD不就得到rbp地址,然后就可以ret2libc了吗
但是要注意小端序的问题,高地址在高位,和sp相邻的是高位,想要加上去只能先加
1 | POP, |
栈上就这么一个libc地址它的偏移是0x270b3,与code的偏移是0x218
既然还得用到之前的栈地址来算,不如一开始就存到stack上来计算(反正不涉及进位),利用STORE来写入更方便
EXP
1 | from pwn import * |
总结
虚拟机pwn的难度主要是调试起来比较抽象,这题给了一个trace,还是比较友好的。
考察点应该算是汇编?总之这题要从汇编层面去理解。