-
-
[原创]溢 出 大 师
-
发表于:
2020-8-11 17:03
8026
-
前几天跟着看了几场比赛的题,有两道PWN题印象很深刻,只有一次堆溢出写,限制很多,在这里分享一下思路。
比较典型的菜单题,堆块添加部分只能添加0x80
及以上大小的堆块,只能用calloc分配。给一个小sz的堆块会改成0x80,但是注意此时在sz_list[idx]
填的值仍为开始的sz。
view
只能用一次,当查看的对象的sz小于0x500时,调用malloc(0x500)
分配一个chunk并且把目标堆块内容拷贝过去并输出。这里可以使用add(0)
使得某个sz_list[idx]
为0,从而拷贝了个寂寞,输出malloc的堆块的内容。
edit
可以溢出写0x18个字节,delete正常删除并清空bss的数据。
目标系统是18.04,首先分配一个块,释放后把它摁进large bin,完事儿调用view的malloc得到这个块,memecpy的sz为0即可泄露出堆地址和libc地址。
由于只有一次溢出写,我们先用溢出写一个unsorted bin的bk,改为global_max_fast-0x10,从而让近乎所有大小的堆块都按照fastbin处理。随后释放某个sz
的堆块,让_IO_list_all
写入这个堆地址,原理是fastbin堆块的头指针会存放到main_arena->fastbinsY[10]
,由于我们改了global_max_fast
,大于0x80的堆块释放后也会依次放到fastbinY后面的地址处,计算这样一个sz出来,这里是0x1438
,分配的堆块最大为0x2333,因此在合法范围内。释放后即可改_IO_list_all。在glibc 2.24后有一套IO攻击的技巧,详情可以参考glibc 2.24 下 IO_FILE 的利用 ,布置一下布局,主要是在fp+0xe8
处布置system
,fp->_IO_buf_end
布置参数地址,还有几个检查绕一下。这里因为需要exit退出的时候触发,而exit前关闭了0/1/2,所以需要反弹shell,我本地起shell失败了,选择直接把flag输出回来
这个题的设计和上面很像,不过add时最大的sz大小改成了0x1000,这使得之前的解法直接失效了,不过给了个奇怪的后门函数,可以使用scanf输入大量数据。
这里的leak相对更简单,给了两个gift用来输出地址,分别得到堆地址和libc地址。
使用tcache stashing attck将_IO_2_1_stdin_->_IO_buf_end
改成main_arena+x
(我这里是+352),从而可以在scanf的时候输入数据到realloc_hook
和malloc_hook
,改成one_gadget
,调节下偏移即可。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)