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 |