美文网首页CTF-PWN
fastbin_attack中fake chunk 的size的

fastbin_attack中fake chunk 的size的

作者: pu1p | 来源:发表于2018-04-24 22:38 被阅读10次

背景

复现 0ctf_2018 的 babyheap是碰见了十分奇怪的情况:
经过一系列操作之后, 我需要fastbin attack 在main_arena中伪造一个fake chunk, 进而修改top chunk的值, 从而达到任意地址写的目的.
经过一系列操作, 我之一使得fast bin中0x50项中的指针指向0x7f707e3bfb45, 其指向空间如下:

0x7f707e3bfb45 <main_arena+37>: 0x00ca23e0d000007f  0x0000000000000055
0x7f707e3bfb55 <main_arena+53>: 0x0000000000000000  0x0000000000000000
0x7f707e3bfb65 <main_arena+69>: 0x0000000000000000  0x0000000000000000
0x7f707e3bfb75 <main_arena+85>: 0x00ca23e1a0000000  0x00ca23e130000056

照理说我接下来调用一次alloc(0x40)就可以得到一个以0x7f707e3bfb45开始的chunk了吧, 但是却直接得到个错误.

原因分析

经过漫长的debug之后我终于发现问题出在fake chunk的size上了......0x55是不行滴.
经过一系列的测试, 我发现当fake chunk 的size为0x54, 0x55, 0x5c, 0x5d的时候, 调用alloc(0x40)都会报错, 而其它的值则都没有问题.
那么这些值有什么共同点呢?

0x54 = 0101 0100b
0x55 = 0101 0101b
0x5c = 0101 1100b
0x5d = 0101 1101b

观察它们的二进制值发现它们的低数第3位都是1, 而根据定义: 这一位置1表示这个chunk不属于main_arena. 而为什么这么就会报错的原因还是要看看libc源码(省略了一些不必要的):

#define arena_for_chunk(ptr) \
  (chunk_main_arena (ptr) ? &main_arena : heap_for_ptr (ptr)->ar_ptr) //根据chunksize地书第三位判断是否属于main_arena
  
void *
__libc_malloc (size_t bytes)
{
  mstate ar_ptr;
  void *victim;
  arena_get (ar_ptr, bytes);
  victim = _int_malloc (ar_ptr, bytes);   //经过debug可确定问题出在_int_malloc之后
  
  assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
          ar_ptr == arena_for_chunk (mem2chunk (victim)));  //如果低数第三位置一, 则arena_for_chunk返回的肯定不是&main_arena
  return victim;
}

因为低数第三位置一, 所以arena_for_chunk返回的肯定不是&main_arena, 所以 ar_ptr == arena_for_chunk (mem2chunk (victim)))false, 由于三个判断之间为或关系, 所以当chunk_is_mmapped (mem2chunk (victim))返回true(即低数第二位置一)时, 也不会报错. 所以只有上面四个值会报错.

更新: 利用fastbin attack时构造fakechunk 的size时又遇到了一个坑, 也卡了挺长时间的

背景:

这次是在线程中调用malloc(), 然后我在bss段有64字节的可读写段(称其为A, 设其地址为 0x6020000), 我也知道这段的地址. 而且我也已经可以覆盖线程的heap_info 和 malloc_state了, 我的目的就是在A中构造一个fakechunk, 从而可以覆盖A后面的一些关键数据. 示意图如下:

 bss: 0x602000(可写)              heap info(可写)
+----------^+-----------------+    +-----> +-----------------+
            |                 |            |                 |
            +-----------------+            |                 |
            |                 |    malloc state(可写)        |
            +-----------------+    +-----> +-----------------+
            |                 |            |                 |
            +-----------------+            |                 |
            |                 |            |                 |
            +-----------------+            |                 |
            |                 |            |                 |
            |                 |            |                 |
            |                 |            |                 |
            |                 |            |                 |
            +-----------------+            |                 |
                                           +-----------------+

我的目的是malloc一个0x60大小的chunk. 所以我就将0x602000的8字节覆盖为0x65:
这很合理, 将因为是线程分配的fast bin, 所以将A 和 P位设为1, 其余为设为0. 然后得到了SIGSEGV , 经过debug发现_libc_malloc()中有一个检测:

//return_ptr 是调用 int_malloc返回的指向chunk内容的指针
if ( return_ptr )
{
prev_size_ptr = *(_QWORD *)(return_ptr - 8);
if ( prev_size_ptr & 2 ) //检测是否为 mmap的
  return return_ptr;
v6 = &dword_7F5FC1CEAB20;
if ( prev_size_ptr & 4 ) //检测是否为子线程的
  v6 = *(int **)((return_ptr - 16) & 0xFFFFFFFFFC000000LL); //如果为子线程则计算该线程的heap info 的地址
if ( v6 == (int *)_RBX )  //检测chunk的heap_info的地址是否合法(具体检测原理不懂)
  return return_ptr;
((void (__fastcall *)(const char *, const char *, signed __int64, const char *))assert)(
  "!victim || chunk_is_mmapped (mem2chunk (victim)) || ar_ptr == arena_for_chunk (mem2chunk (victim))",
  "malloc.c",
  2927LL,
  "__libc_malloc");

程序会在第9行报SIGSEGV错误, 因为因为该地址不可读.

通过观察第5行可知如果把fakechunk的size的M位也设为1的话就可以通过检测了.
于是乎将0x602000的8字节覆盖为0x6f: 在设置一下对应的fastbin, 成功得到fakechunk.

关于heapinfo可以参考这篇文章

相关文章

网友评论

    本文标题:fastbin_attack中fake chunk 的size的

    本文链接:https://www.haomeiwen.com/subject/dlvslftx.html