常规检查

HCTF-2016-fheap 堆技巧use-after-free

逆向分析

  题目程序较为简单,功能是创建字符串和删除字符串,其中创建字符串用 create ,删除字符串用 free 。

create 函数

HCTF-2016-fheap 堆技巧use-after-free

  当输入的字符串大于 0xf 字符时会另外开辟内存来存储字符串,否则存入 ptr 指针的地址中。通过分析我们还可以得到

  • *ptr :在小于等于 0xf 字符时是string的地址,在大于 0xf 字符时是 dest 的指针, dest 指针指新开辟用来存储 stirng 的内存
  • *(ptr+3):这个地方存储的是 free 函数地址,当小于等于 0xf 字符时只 free 指针,当 大于 0xf 字符时 free 指针和内容,但是都没有对指针和内容置 0 ,这里就会导致 use-after-free 和 double-free 漏洞
  • *(ptr+4):存储 string 的长度。
  • *(&unk_2020C0 + 2 * i + 1):存储的是字符串的地址
  • *(&unk_2020C0 + 4 * i):通过置 1 说明第 i 个 string 已创建

  同时 create 函数 c 层面有个比较难理解的地方
HCTF-2016-fheap 堆技巧use-after-free

  free2 是一个 void 函数,哪里来的返回值呢?我们看下汇编
HCTF-2016-fheap 堆技巧use-after-free

lea 指令,所以这个语句的意思是将 free2 函数的起始地址赋给 *(ptr+3) 。

delete 函数

HCTF-2016-fheap 堆技巧use-after-free

  *(&unk_2020C0 + 2 * i + 1) 是字符串地址,加上 24 即为 free 函数地址,所以这个语句相当于 free(string) 。同时把 *(&unk_2020C0 + 4 * i) 置 0 说明已经 string 删除。

利用思路

  我们首先可以构造两个小的 chunk ,并释放它们,然后 create 大于 0xf 的字符串,这样刚刚被 free 的两个 chunk 又使用到了。同时里面的拥有 free 函数的指针,我们可以覆盖这个指针,泄露出程序运行的基址。虽然程序开启了 PIE ,但是 PIE 是无法改变地址后三位的。
HCTF-2016-fheap 堆技巧use-after-free

HCTF-2016-fheap 堆技巧use-after-free

  注意到 call put 指令与 free2 函数地址偏移在后三位之内。我们只要把 string 内容中 free2 的地址后三位修改一下为 call put 地址,这样 delete 字符串的时候相当于运行 put 打印出字符串地址开始的内容, call put 的地址就在这串内容里,这样可以泄露程序基址。
  线路程序基址后,我们可以获得 printf_plt 的地址,重复上述步骤,利用格式化字符串可以泄露 libc 函数的地址。
  最后,根据泄露的 libc 函数地址通过偏移计算 system 与 binsh 的地址,覆盖 free2 函数指针为 system 函数即可 get shell 。

来源

2016 hctf fheap 题解

相关文章: