heap exploit tips

1. common tips:

  • environ指向的地址 -30*size 为 main函数的返回地址的栈地址

  • 申请分配large chunk时,会进行 malloc_consolidate,清空fastbins表,进行合并

  • scanf, printf当输入、输出过长时,会调用mallocfree

  • addr(main_arena)-0x10 = addr(__malloc_hook)

  • unsorted bin泄露libc

    • 64bit: libc_addr = leak_addr - 0x68 - libc.sym['__malloc_hook']

    • 32bit: libc_addr = leak_addr - 0x48 - libc.sym['__malloc_hook']

  • malloccallocrealloc区别

    • calloc 在分配后会自动进行清空,libc 2.23版本如果设置 is_mmap不会清空
    • realloc(ptr,size)的size不等于ptr的size时
      • 如果申请size>原来size
        • 如果chunk与top chunk相邻,直接扩展这个chunk到新size大小
        • 如果chunk与top chunk不相邻,相当于free(ptr),malloc(new_size)
      • 如果申请size<原来size
        • 如果相差不足以容得下一个最小chunk(64位下32个字节,32位下16个字节),则保持不变
        • 如果相差可以容得下一个最小chunk,则切割原chunk为两部分,free掉后一部分
    • realloc(ptr,size)的size等于0时,相当于free(ptr)
    • realloc(ptr,size)的size等于ptr的size,不进行任何操作
  • check_action & 2 = 0 时,堆错误不会退出,只会打印错误信息,同时设置 main_arena->flags | 0x100

  • free_pertube 调用发生在向前合并和向后合并之前,所以如果设置了pertube位,不会将合并后增加的堆区域的内容设置为pertube

2. Heap exploit

  • 条件:

    • 存在堆溢出,可以伪造堆块和控制下一个堆块的头部
    • 存在全局指针ptr指向堆块
  • 方法:

    • 伪造堆块
      • fake_size = (current_size - size*2) | 1
      • fd=ptr-size*3
      • bk=ptr-size*2
    • unlink成功之后
      • ptr=ptr-size*3
      • 编辑ptr指向的内容,修改ptr指向got表,再编辑ptr即可overwrite got表
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    chunk0                malloc返回的ptr           chunk1        malloc返回的ptr
    | | | |
    +-----------+---------+----+----+----+----+----+------+------+----+----+------+
    | | |fake|fake|fake|fake| D | fake | fake | | | |
    | | |prev|size| FD | BK | A | prev | size&| | | |
    | prev_size |size&Flag|size| | | | T | size | flag | | | |
    | | | | | | | A | | | | | |
    | | | | | | | | | | | | |
    +-----------+---------+----+----+----+----+----+------+------+----+----+------+
    |--------new_size--------|

fastbin attack

  • house of spirit

    • 伪造chunk,free之后再次申请chunk进行攻击
  • double free
    • 重复释放同一个chunk,实现类似类型混淆的效果
    • f86cf21b984d249fae8e07f3758a1643.png
  • Arbitrary Alloc(分配的堆块大小为0x70,限64位)

    • 利用:__malloc_hook地址-0x28+5 作为伪造的fd指针(地址错位 ),填充0x13字节+ onegadget_addr

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      $2 = (void *(**)(size_t, const void *)) 0x7ff5dd109b10 <__malloc_hook>
      pwndbg> dqs 0x7ff5dd109b10-0x28+5
      00:0000│ 0x7ff5dd109aed (_IO_wide_data_0+301) ◂— 0xf5dd108260000000
      01:0008│ 0x7ff5dd109af5 (_IO_wide_data_0+309) ◂— 0x7f
      02:0010│ 0x7ff5dd109afd ◂— 0xf5dcdcae20000000
      03:0018│ 0x7ff5dd109b05 (__memalign_hook+5) ◂— 0xf5dcdcaa0000007f
      04:0020│ 0x7ff5dd109b0d (__realloc_hook+5) ◂— 0x7f
      05:0028│ 0x7ff5dd109b15 (__malloc_hook+5) ◂— 0x0
      ...
      07:0038│ 0x7ff5dd109b25 (main_arena+5) ◂— 0xc7604a04a0000000
    • 利用堆漏洞触发堆异常调用 malloc_printerr 打印堆错误,会调用malloc函数,执行one_gadget

      • 满足下列条件的one_gadget 触发更稳定

      • 1
        2
        3
        0xf02a4 execve("/bin/sh", rsp+0x50, environ)
        constraints:
        [rsp+0x50] == NULL

unsorted bin attack

  • 条件:
    • 能够控制 Unsorted Bin Chunk 的 bk 指针(bk = target_addr - 0x10)。
  • 效果:
    • 实现修改任意地址值为一个较大的数值(unsorte bin地址),例如 global_max_fast,例如_IO_list_all(house of orange)

House of Lore(small bin attack)

  • 条件:
    • 能够修改small bin中的bk指针
  • 方法:
    • 修改small bin中的bk指针指向伪造的chunk,同时令fake chunk的fd指针不等于small bin中的最后一个chunk
  • 效果:
    • 任意地址写

House Of Einherjar (small或large bin attack, top chunk)free时触发

  • 条件:
    • 需要有溢出漏洞可以写物理相邻的高地址的 prev_size 与 PREV_INUSE 部分。
    • 我们需要计算fake_chunk与 被覆盖大小的chunk 地址之间的差,所以需要泄漏地址
      • prev_size = &fake_chunk - & overwritten_prev_size_chunk_addr
    • 我们需要在目的 chunk 附近构造相应的 fake chunk,从而绕过 unlink 的检测
      • fake_chunk->fd = &fake_chunk
      • fake_chunk->bk = &fake_chunk
  • 方法:
    • 覆盖相邻到地址的prev_size与PREV_INUSE标志位
  • 效果:
    • 任意地址写

House Of Force (top chunk)

  • 条件:
    • 能够以溢出等方式控制到 top chunk 的 size 域
    • 能够自由地控制堆分配尺寸的大小
  • 方法:
    • 修改top chunk size域为-1,然后分配指定大小的堆块(计算偏移)
  • 效果:
    • 能够在任意地址分配堆块,实现任意地址写

House Of Orange (top chunk + unsorted bin + FILE attack)

  • 条件:
    • 首先需要目标漏洞是堆上的漏洞
    • 不存在free函数或其他释放堆块的函数
  • 方法:
    • 伪造top chunk的size,满足
      1. 伪造的size必须要对齐到内存页
      2. size要大于MINSIZE(0x10)
      3. size要小于之后申请的chunk size + MINSIZE(0x10)
      4. size的prev inuse位必须为1
  • 效果:
    • control the world

参考: