AT FIRST
最近在ISCC上做到一道PWN题,其中高版本的largebin attack后的利用手法,很明显是house_of_apple,通过两次largebin attack变可以控制了_IO_list_all的值为堆地址,但是后面上模板老是有问题,这就是这篇文章编写的原因,捋清和加强对FSOP的理解
House Of Apple
基本上是高版本堆题或者在限定条件下很常用的利用手法,利用的条件是程序以libc_start_main函数或者以exit函数退出
通过exit函数会调用fcloseall函数实现FSOP攻击,控制攻击流程
1 | exit ---> fcloseall ---> _IO_cleanup ---> _IO_flush_all_lockp ---> _IO_OVERFLOW |
最后会遍历_IO_list_all存放的每一个IO_FILE结构体,如果满足条件的话,会调用每个结构体中的vtable->_overflow函数指针指向的函数
如果我们利用largebin attack等修改任意内存的攻击就可以劫持_IO_list_all变量,将其替换为伪造的IO_FILE结构体
House OF Apple 主要利用思想是IO_FILE中的_wide_data的利用
总结利用条件为:
1 | 程序从main函数返回或能调用exit函数 或者可以触发FSOP等函数 |
FSOP高版本限制说明
libc-2.24之后加入了vtable check机制,我们无法伪造vtable
如何控制程序执行流程
我们知道现在无法直接伪造vtable,但是总有几个系统定义好的IO_FILE没有直接对它们定义的vtable进行检查,所以我们可以间接的控制它
在house of apple文章中,也阐明了利用思路是_wide_data的_wide_vtable,其原因是_IO_wide_data结构体没有对它的_wide_vtable进行范围检查,而在调用_wide_vtable虚表里面的函数的时候,同样也是使用宏来调用
1 |
_IO_wfile_overflow
函数的调用链如下:
1 | _IO_wfile_overflow |
分析_IO_wfile_overflow函数
1 | wint_t |
首先要满足f->_flags & _IO_NO_WRITES == 0 并且f->_flags & _IO_CURRENTLY_PUTTING == 0
其次我们要满足f->_wide_data->_IO_write_base == 0
然后我们步进到_IO_wdoallocbuf函数
1 | void |
这里则需要满足fp->_wide_data->_IO_buf_base == 0 且 fp->_flags & _IO_UNBUFFERED == 0
依照以上条件,我们需要进行以下设置:
_flags设置为~(2| 0x8 | 0x800),如果不需要控制rdi,通常为0就可以vtable设置为有_IO_wfile_overflow的vtable即可,然后记得加减偏移_wide_data设置为可控制的内存地址(即堆地址 A),满足*(fp + 0xa0) = A_wide_data->_IO_write_base设置为0,满足*(fp + 0x18) = 0_wide_data->_IO_buf_base设置为0,满足*(fp + 0x30) == 0_wide_data->_wide_vtable设置为可控内存地址(即堆地址B),满足*(A + 0xe0) = B_wide_data->_wide_vtable->doallocate设置为地址C用于劫持RIP,满足*(B + 0x68) = C
所以我们基本上的模板是
1 | FP = fake_io_addr |
还有 打malloc_assert的模板,但在2.37后不可使用 移除了fflush(stderr);:
1 | FP = fake_io_addr |