在正常情况下,当free掉一块大于max_fast的大小的chunk时,程序将会把他放至unsortedbins中,而由于unsorted是双向链表的结构,所以它有FD
和BK
两个指针,且当fastbin为空时,他的fd
和bk
指针将同时指向main_arena
中,一般也就是main_arena+88
的位置。
关于main_arena是什么,以我个人理解的来说他就是Doug lea用来分配空间时的一片进行中转的地方,具体的可以看华庭大佬的《glibc内存管理》,这里不做多讲解,只要知道可以拿他来泄露libc地址即可
此时只要通过再次申请该地址并填充8字节的数据即可将main_arena+88的地址带出来,进而泄露libc地址
当free掉两块不相邻的chunk时(且第二次free的chunk不能为最后一块,以避免被合并)
第一次free的bk指针指向第二次free的地址,这样就可以在bins的链表中找到chunk_1和chunk_2的地址(因为大于0x80的构成unsortedbins双向链表)表示他们已经被系统所回收,当我们再次申请时,便可以利用只填入0x8字节的数据来带出bk的地址。
进而通过减去距离堆地址的偏移来算出堆地址。
具体步骤和上面类似,这里要申请4个堆块,并分别free掉chunk_1和chun_3
在我们free掉第一个堆块时,由于这个堆块是0x80大小故不符合fastbin的标准,所以将被放在unsortedbins中,而此时被free的chunk_1的fd和bk指针则是main_arena+88的地址
但这只是第一次free,且仅泄露出了marin_arena的地址,所以我们继续下一次的free
可以看到由于双向链表的原因,两块bins的fd和bk都互相指向对方,且都有一个main_arena的地址,这时候我们只要再次申请堆块,并覆盖掉红框内的数据,之后通过打印功能便能直接输出堆块的地址和main_arena的地址
不过需要注意此时泄露出的堆块地址是chunk_2的地址距离堆的起始地址还有一段固定的偏移,计算一下就能得出
最后就可以通过再该堆块的地址上再次申请个0x8字节大小的数据即可带出后面的地址
或者是通过扩充chunk2的方式,将chunk-0x10的位置覆盖掉来带出地址