Asis CTF 2015-Car_Market

发布者:Ox9A82
发布于:2016-10-29 01:28

恰好找到了这道题的bin文件,就来做一下。

这道题目是一个经典的选单程序但是具有三级选单,在bss段存在指针数组ptr,ptr中的值指向每个主结构,其中主结构如下所示。

[16]  model
[4]   price
[4]   padding;
[8]   pointer
共32byte

其中pointer会指向一个子结构customer

[32]  first_name
[32]  name
[8]   pointer
共72byte

这个pointer又会指向一个一块内存comment

[72] comment

 第一个漏洞存在于sub_400BFB中,这是自己实现的Read函数,这个Read函数在读取长度限制的最后一个字节之后还会把指针加1,并且又符了0值,从而造成NULL byte off-by-one。代码如下

__int64 __fastcall sub_400CC9(__int64 a1, int a2)
{
  int v2; // eax@3
  __int64 result; // rax@6
  int v4; // [sp+10h] [bp-10h]@1
  __int64 v5; // [sp+18h] [bp-8h]@1

  v5 = a1;
  v4 = 0;
  while ( v4 < a2 )
  {
    v2 = _IO_getc(stdin);
    if ( v2 == '\n' )
    {
      result = v5;
      *(_BYTE *)v5 = 0;
      return result;
    }
    if ( v2 != 0xD )
    {
      *(_BYTE *)v5++ = v2;
      ++v4;
    }
  }
  result = v5;
  *(_BYTE *)v5 = 0;
  return result;
}

这个漏洞可以说是比较难找的,主要是程序代码量比较大,很容易忽略这里。

 

拿到这个null byte off-by-one之后肯定就是围绕这个漏洞展开思考,首先想的是两种常用的利用方法,第一想到的肯定是去构造unlink,因为几乎是每次获取输入都使用了这个存在漏洞的Read函数,所以可以off-by-one的地方很多。想了一下可以在哪里unlink,因为unlink存在check,所以也就只有存在了指针指向的地方才可以用来构造unlink,经过一番查找缺发现这道题并没有提供这样的机会。

后来发现其实这道题的关键在于这里

__int64 __fastcall Add_custom(__int64 a1)
{
  __int64 v1; // rdx@5
  __int64 result; // rax@5

  if ( *(_QWORD *)(a1 + 24) )
  {
    if ( *(_QWORD *)(*(_QWORD *)(a1 + 24) + 64LL) )// [64]
                                                // [8] pointer
    {
      free(*(void **)(*(_QWORD *)(a1 + 24) + 64LL));
      memset(*(void **)(a1 + 24), 0, 72uLL);
    }
    free(*(void **)(a1 + 24));
  }
  v1 = Alloc_ZI_STRUCT();
  result = a1;
  *(_QWORD *)(a1 + 24) = v1;
  return result;
}

 实际是通过控制内存块来控制free函数的值,实现free全局指针域。然后紧接着的分配会重用这个块,控制了指针以进行任意地址读写。感觉这道题还是很有难度的,洞比较好找,但是想出利用却比较难。


声明:该文观点仅代表作者本人,转载请注明来自看雪