VMpwn
VMpwn
VM Pwn就是题目自定义了一套指令系统,并且模拟了一套CPU的环境(寄存器、栈、数据缓冲区等结构)需要通过逆向分析题目给定的指令系统,并利用其中的漏洞进行攻击
大部分漏洞都是数组越界!!
分析的时候要结合全局分析,先把总体架构搞清楚,如果只看部分很容易懵逼
OVM
checksec
1 | [*] '/home/aichch/pwn/pwn' |
比较入门的一道vm类题目了
通过一个数组模拟寄存器
程序实现了加减乘除左移右移压栈弹栈等操作
可以自己输入指令起始地址,指令数,栈起始等
程序的指令都是四字节的
字节从高到低分别是:指令码,左操作数,右操作数1,右操作数2
循环主体,不断取出指令下标并判断执行
1 | while ( running ) |
利用的漏洞自然是指令没有对下标进行检查,能够覆写很多地方
在接收到结束指令后会打印所有寄存器的值,此时可以进行泄露
由于开启了FULL RELRO,因此选择覆写__free_hook
具体的利用步骤:
- 将got表中存储的libc相关地址分块存储到寄存器中,建议泄露stdin三个,距离__free_hook比较近
- 通过got表计算得到__free_hook-8的地址(不同libc不同偏移,要根据gdb调试判断)
- 覆写comment指针为__free_hook-8
- 向comment指针写入binsh字符串,并覆写__free_hook为system的地址
exp:
1 | from pwn import * |
由于程序只有一次写入和free的机会,并且写入和free用的是同一个指针
因此部署binsh和覆写system要在一次完成
故选择comment写为__free_hook-8,这样先写binsh,再写system,之后又触发free(comment)实际上就已经变成了system(‘/bin/sh’)
[GWCTF 2019]babyvm
一道逆向VM题,头大
初始化操作,前四个模拟寄存器,unk_202060存存储指令码
1 | nsigned __int64 __fastcall initt(__int64 a1) |
F1,F2等操作码各自对应着函数
0xF1 | 实现mov操作 |
---|---|
0xF2 | 寄存器1异或寄存器2 |
0xF5 | 读入并判断长度 |
0xF4 | nop |
0xF7 | 寄存器1乘寄存器4 |
0xF8 | 寄存器1交换寄存器2 |
0xF6 | 寄存器1=2寄存器2+3\寄存器3+寄存器1 |
提取出0x202060处的指令后脚本处理一下
1 | opcode=[0xF5, 0xF1, 0xE1, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, |
得到
1 | read |
从读入长度以及0x2020a8引用判断下面部分才是真正的逆向块
1 | unsigned __int64 sub_F00() |
真正的加密逻辑:
1 | flag = '' |
1 | check = [0x69, 0x45, 0x2A, 0x37, 0x09, 0x17, 0xC5, 0x0B, 0x5C, 0x72, |
wdb_2020_1st_boom2
checksec
1 | [*] '/home/aichch/pwn/boom' |
ida打开发现存在类似平坦化混淆的东西
不过影响不大
申请了两个0x40000得堆块分别用作栈和数据缓冲区,并且初始化栈:
1 | 1 30 |
vm题比较麻烦的点就是分析指令,以及确定各内存如何对应模拟环境
1 | 0 immcode: reg=[sp+immcode] |
因为栈中存储有真实的栈地址,所以我们可以利用它来覆盖返回地址
步骤:
- 首先进行一次pop将初始栈顶的bp pop出来,随便一个改变栈的指令就行
- 这时栈顶就是真实栈指针了,然后利用指令1将reg寄存器置为便宜0xe8,然后利用指令26,让栈指针减0xe8,并利用指令13将结果重新入栈
- 使用指令9取值,获取返回地址处的值(也就是libc_start_main+231的地址),并用13指令将获取到的值入栈
- 利用指令1将reg置为libc_start_main+231的偏移值offset,然后利用指令26让libc_start_main+231地址减偏移,得到libc的基址,并用13指令将获取到的libc基址入栈
- 利用指令1将reg置为onegadget的偏移offset,然后利用指令25计算出libc基址加onegadget偏移,也就是onegadget的地址
- 这时栈顶是之前步骤2入栈的返回地址指针,利用指令11将onegadget写入覆盖返回地址
- 然后直接发送即可。
exp:
1 | from pwn import * |
starvm
vm类题
checksec,没有PIE利用会稍微简单一些
1 | [*] '/home/aichch/pwn/starvm' |
代码有点难读,gdb动态调试参照
初始malloc申请了0x80的内存
1 | 0h *code_begin |
程序在读入command和cost后做出一些判断,然后进入虚拟机操作中
存在两个重要的变量分别负责指向当前code和当前cost
10号功能给寄存器赋值,溢出可以修改后面的mem指针
7号指令可以往mem指向处任意写,两者配合其他指令
具体实施:
- 10号指令覆写mem指针为setvbuf的got表地址,利用减法得到system,利用7号指令将其修改
- 10号指令覆写mem指针为malloc的got表地址,7号指令将其写为调用setvbuf的地址
- 10号指令覆写mem指针为stdin的地址,将其修改为bss段上另一处地址,并在该处写上sh字符串
- 10号指令覆写mem指针为0使得再次调用相关功能时启用malloc,总而执行以上布置的执行流
要注意指令是4字节Dword的,下标要对应
exp:
1 | from pwn import * |