在现场打比赛紧张得不行ORZ。
基本逻辑
add函数从ptr[0]和ptr[1]中找到一个空闲块,分配一个大小为size的块,用于存放信息。可见本题只有ptr数组中只有两个元素可用。
show函数输出信息。
dele函数很神奇,如果对应的dele_flag为1,代表已经删除过了,直接将指针置零;为1代表还未删除,调用free函数,并把dele_flag置一。这种方法能够防止double free,而且所有指针都只能free一次,之后的就只是把ptr置零。
一些知识
- 正常情况下,fastbin的inuse位为1,即使在释放时候也不会置零。其他类型的块都会把inuse位置零。
- 但是当其他类型的块释放并合并时,合并大小大于64KB时,会调用malloc_consolidate合并fastbin中的chunk到unsorted bin
1 | if ((unsigned long)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) { |
- 另外,在_int_malloc中也有对fastbins的合并:当申请的大小在smallbin范围内,但smallbin中还没有初始化,先对fastbins进行合并,放入unsortedbin(还不知道如何在应用层触发这个条件);或者是申请的大小在largebin范围内,判断fastbins中是否有chunk,存在则对fastbins合并。
1 | if (in_smallbin_range (nb)) |
- (与本题关系不大)当不能直接触发malloc函数时,可以通过double free触发malloc_printerr进而触发malloc函数,函数调用顺序如下:
另,在unsorted bin非空的情况下,malloc时会沿着unsorted bin寻找合适的块,如果能修改某块的BK指针,使之指向一个不是chunk的地址,同样会触发malloc_printerr,如下面这段代码:
1 | int main() |
漏洞分析
当第一次调用dele函数时,会使用free,而且不对ptr置零。此时调用show函数则会泄露出FD,即main_arena+88,进而泄露libc地址。
此外,add函数中向ptr[i]中输入info时,没有限制大小,会造成堆溢出。
漏洞利用
泄露libc地址
ptr[0]要求一个size为0x100的块,即指向大小为0x110的块,ptr[1]要求一个size为0x60的块,即指向大小为0x70的块。第一次dele *ptr[0],0x110块会放置在unsorted bin 中,FD指针指向main_arena+88,由此泄露libc地址。
覆写malloc_hook
释放*ptr[0]
之后释放*ptr[1]
,由于*ptr[1]
是一个fastbin,释放之后不会与top合并。释放两块并置零后,再次申请0x100大小的块,并向其中填充数据,溢出覆盖掉已释放的*ptr[1]中的FD指针,使它指向malloc_hook-35的位置,之所以选择这里是因为如果把这个地址看作一个chunk,size字段恰好为0x7f。达到的效果和fastbin attack一样,再次申请0x60大小的块时就会将malloc_hook-35分配出去,实现向malloc_hook中写入内容。
利用脚本
1 | from pwn import * |