一道2022的国赛堆题,用到了IO_FILE泄露libc的利用。
首先看一下程序的保护
熟悉的保护全开,libc版本为2.23,算是堆题中很低的了,没有double free检查,没有tcache三种攻击思路:
1、打malloc hook、freehook
2、泄露libc、environ打栈上的rop
3、FSOP
看一下程序逻辑:
main函数经典菜单题。只有add和free,没有edit和show。
add最多申请32个堆块,最大申请堆块0x78,都在fastbin里面。
heap全局数组用于存储堆块指针和size大小。
read像堆块中读入数据时有off by one漏洞,可以伪造堆块大小构造重叠堆块,也可用于扩展free堆块大小,得到Unsorted bin。
delete函数在free之后未置0,存在UAF,在2.23的libc下可以直接构造fastbin的double free,进而任意地址分配堆块(仍需过fastbin的size检查)
程序逻辑看差不多,理一下攻击思路:
1、由于程序没有show和edit,想泄露地址必须要利用IO的_IO_2_1_stdout来泄露。
2、利用off by one伪造堆块size,扩大堆块大小得到Unsorted bin,再利用fastbin的double通过fastbin attack来分配_IO_2_1_stdout附近堆块,
3、通过IO_FILE attack泄露得到libc地址。进而得到one_gadget地址、malloc_hook地址等
4、再次利用fastbin attack分配malloc hook附近堆块写入ogg,然后在程序分配新堆块时触发ogg来getshell。
笔者自行本地测试时发现,几个可用的ogg都无法通过malloc hook直接getshell,这里用到一个新trick,借助realloc来调栈。因为ogg的利用条件基本上都是要求栈上固定偏移位置为0啊或者是有效地址等等,因此可以利用realloc函数中的一些push和pop来调整栈,进而使ogg可用。
借助realloc布置栈需要:
5、写malloc hook为realloc,realloc_hook为one_gadget。realloc hook紧贴malloc_hook前,直接分配一个fake fast chunk一次写入两个hook。
6、程序分配新堆块时有如下调用链子:
malloc->malloc_hook->realloc(调整栈)->realloc_hook->one_gadget->getshell
完整攻击脚本如下:
脚本执行结果:
成功getshell。
By Del0n1x
Keyboard