house_of_apple2
记录一下House of apple的总体过程,有一个例题House of apple 一种新的glibc中IO攻击方法 - LynneHuan - 博客园 (cnblogs.com)中的例题,例题的下载可以看那个文章。
一、原理
程序在abort或者exit时,会调用_IO_flush_all_lockp()函数,此函数会对_IO_list_all中的所有FILE结构体链进行处理,源码如下:
1 | //glibc-2.34 |
在_IO_OVERFLOW中,会调用到FILE结构体的vtable->_overflow。从_IO_OVERFLOW到vtable有一串宏定义链,可以在libioP.h中找到。这里不赘述。
在这里贴一幅用IDA看的此处的_IO_OVERFLOW的逻辑,chain就是fp:

假设我们可以通过LargeBin Attack让_IO_list_all写入堆块的地址,并且我们能够在堆块上伪造FILE结构体,同时伪造vtable的话,就可以执行我们想要的函数了。程序会执行fake_fp->vtable->_overflow指针指向的函数。
我们先从伪造FILE结构体开始。其中amd64的FILE结构体内部成员和对应的偏移如下:
1 | 0x0:'_flags', |
注意vtable并不是内部成员,但是是外包_IO_FILE_plus的内部成员,其紧跟在FILE结构体后,所以同样可以计算出偏移。
我们在堆上构造FILE结构体,让FILE结构体的_IO_write_ptr大于_IO_write_base,然后让vtable偏移处写入另一个伪造的vtable结构地址,在__overflow偏移处就是我们想要执行的函数的地址。但是很遗憾我们并不能随意的伪造vtable地址,在IDA的那张图也可以看到对vtable的地址进行了检查,如果不在一定范围内是会报错的。所以说这里的vtable地址就是要利用在可以通过检查的允许范围内去找哪些是可以用到的vtable地址,根据vtable不同,攻击方式也有不同的名字。在house of apple2中,是使用了_IO_wfile_jumps作为vtable的地址。当vtable是_IO_wfile_jumps时,在__overflow处的偏移存储的是__IO_wfile_overflow:
在_IO_wfile_overflow中,会调用_GI__IO_wdoallocbuf(fp),其中fp就是_IO_list_all,指向我们的伪造FILE结构体。

在这里,可以看到存在另一个函数指针:__doallocate(),其中它的offset是0x68。
fp->_wide_data的offset是0xA0,_wide_vtable的offset是0xE0,这里的vtable就不像之前一样需要绕过检查了。所以我们在FILE结构体中的wide_data处写入自己伪造的wide_data结构体地址,然后在这个伪造的wide_data结构体中的_wide_vtable偏移处写入伪造的_wide_vtable地址,在伪造的_wide_vtable中的__doallocate处写入gadget即可。要么使用onegadget,要么在可控rdi为sh字符串时直接写入system,要么使用栈迁移的方式进行rop,onegadget已经不是很好用了,比较稳妥的方式还是使用栈迁移的方式进行rop,这样是最稳定的。
本文介绍了House Of Apple2的一个利用原理,下一篇文章会进行实战,具体使用之前的PassWordBox_ProVersion和本片开头使用的例题进行实战。
