House of leamon🍋

这是2017年CUIT校赛的压轴题,(我)第一次遇到的overwrite global_max_fast的手法,~(≧▽≦)/~

vulnerability

在Leamon的Leave Message操作中,作者本意应是0x10byte,但是可以Overwrite 0x20,从而覆盖Leamon的FD与BK指针。

覆盖指针后,寻找使用了BK,FD的位置即可触发漏洞
在Leamon指针delete时,没有做足够的判断或过滤(对比unlink),导致arbitrary memory write。

unexpected

非预期的解法十分简单,这确实是作者比较大的失误。

  1. 泄露Libc后.
  2. 溢出将BK,FD指针通过Overwrite覆盖BK,FD指针为__free_hook.
  3. delete操作会将qword_202040的BK指针overwrite 成__free_hook.
  4. 再次构建leamon,编辑即可覆盖__free_hooksystem.
  5. Getshell

expected

house of leamon

作者的预期做法是比较精彩的,简单总结就是 overwrite global_max_fast && main_arena overflow

设计的思路是写global_max_fast,这个值位于glibc的bss段上,初始时为0在堆经过初始化后会被赋为0x80(x64)。Fastbin是存在一个大小边界的,只有小于这个边界值的堆块才会使用fastbin的机制管理,一般来说x86上是0x40,x64上是0x80。其实这个边界就是global_max_fast,如果我们修改了这个边界值会导致归属于fastbin块的范围发生变化。

_int_free中,首先验证了释放块的大小与global_max_fast的关系,之后使用fastbin_index由chunk size计算下标,然而fastbin_index宏只是简单的根据size大小计算index值

这样free一个很大的值,max_globle_fast的修改导致它按照fastbin的规则进行freefastbin_index计算的值很大,就可以越过FastbinY向后面的LIBC地址写,造成main_arena overflow

main_arena_overflow 后,能够向一个地址写入可控的heap_address,这个heap address的内容可控,即可伪造成fake IO_FILE,之后_IO_FILE_stdout 或者 _IO_FILE_stdin 的vtable为one_gadget即可。

PS: max_globle_fast 不在libc的符号表中,需要手动去找,大概位置在__free_hook上方。

hack _IO_jumps

采取的方式首先是将堆地址写入__GI__IO_file_jumps,那必须是one_gadget。
one_gadget 找libc.so却一直报错,大概是libc.so格式导致ruby parser elf解析失败。
手动打开libc.so,竟然在libc中发现了one_gadgets的后门:-D,看来是作者是重新编译的一份Libc。

脚本中注意需要根据fastbin的index计算得到malloc的大小为6064

hack _IO_FILE

另一个方法就是writeup所写的直接hack IO_FILE (PS:这本是一个多此一举的方法),但希望用system("/bin/sh")提权也算是一种完全之策。
按照一般_IO_FILE的构造方法构造,由于hack 的_IO_2_1_stdout的前16byte是chunk的metadata,无法填入"/bin/sh”字符串。

于是换了一个姿势伪造_IO_FILE的vtable为_IO_str_jumps,通过调用最终拿到SHELL。
关于将vtable 更改为_IO_str_jumps是2016年WCTF上Wannaheap提出的一种新的_IO_FILE利用链,该方式能够稳定利用,执行system("/bin/sh")

脚本如下:

如果题目如果没有非预期,可以说是一个非常好的heap题目了:)

发表评论

电子邮件地址不会被公开。