堆溢出

  • 原理非常简单
  • 数据溢出并覆盖下一个区域
  • 如果下面有认证信息或重要数据,则可以破坏/覆盖
  • 如果溢出目标是函数指针,则可以进行pwn
    • func_ptr overwrite
    • 当函数被调用时,则变成了调用system
  • 如果下面是free chunk,则管理数据会被破坏
    • heap管理变得奇怪的话,进程可能会crash
  • 以之前的例子1进行尝试
    • 正常运行是上面这样的
    • 过长数据破坏heap管理区域是下面这样的
1
2
3
4
5
$ ./a.out TESTTESTTESTTESTTESTTEST TESTTESTTESTTESTTESTTEST

$ ./a.out TESTTESTTESTTESTTESTTESTTEST TESTTESTTESTTESTTESTTESTTEST
*** Error in `./a.out': free(): invalid next size (fast): 0x00000000006de010 ***
Aborted (core dumped)

Use After Free

  • 顾名思义,heap内存释放后再次使用
  • 假设用户已经通过new获取了可以读取写入的内存
  • 假设已进行delete ptr操作
    • 这时候,原本的ptr已经不能使用
    • 但是,由于Use After Free问题,仍然可以直接读取和写入此地址
  • 假设通过new获取了ptr2
    • 它恰好和之前的ptr指向同一个地方,需要考虑到这种情况
    • 堆释放后可能被再次利用,就是因为这个
  • 如果ptr2是object,它通常有一个虚函数表
  • 指向这个虚函数表的的指针叫做vptr
  • 因为ptr可能还会使用,从ptr进行覆盖可能会改变vptr
  • vptr overwrite
  • vptr指向可控区域,并将内容设置为system地址等
  • 这样当调用函数时,实际调用的是system
  • Use After Free很难找到
    • 阅读大部分代码,如果不了解整体行为,通常无法找到它
      • 通常,对应的malloc和free可能跨越多个函数,需要准确掌握具体的调用位置
        • 另外,你必须找出Use After Free的调用顺序
      • 重点关注使用malloc/free或者new/delete较多的的二进制
  • 这样的二进制文件就很可疑
    • 用户输入可以自由创建object
      • 笔记管理类
      • 购物车系统
    • 自己实现的内存管理机制
  • 这种也是可能的
    • func_ptr overwrite + ROP
      • 预先将ROP等加载到stack上的变量中(前提是能够加载)
      • 通过Use After Free,在vptr之前,写入pop×N; ret之类的代码
      • 当调用该函数时,pop×N去除其他的参数,之后触发ROP