借着 how2heap 这个专题,我们来研究一下 glibc2.25 中的 malloc_consolidate
0X00 例子
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
int main() {
void* p1 = malloc(0x40);
void* p2 = malloc(0x40);
fprintf(stderr, "Allocated two fastbins: p1=%p p2=%p\n", p1, p2);
fprintf(stderr, "Now free p1!\n");
free(p1);
void* p3 = malloc(0x400);
fprintf(stderr, "Allocated large bin to trigger malloc_consolidate(): p3=%p\n", p3);
fprintf(stderr, "In malloc_consolidate(), p1 is moved to the unsorted bin.\n");
free(p1);
fprintf(stderr, "Trigger the double free vulnerability!\n");
fprintf(stderr, "We can pass the check in malloc() since p1 is not fast top.\n");
fprintf(stderr, "Now p1 is in unsorted bin and fast bin. So we'will get it twice: %p %p\n", malloc(0x40), malloc(0x40));
}
这个例子就是告诉我们,在分配 large bin chunk 的时候,会调用 malloc_consolidate(),这个函数会遍历所有的 fastbin 把里面的 chunk 该合并合并,该清楚使用就标志清楚使用标志,然后全部插入 unsorted bin 中。
在下一次 free 的时候,判断是不是 double free 仅仅根据从同一个大小的 fastbin 中拿出第一个 bin,比较地址是不是相同
而我们的 chunk 早到 unsorted bin 中去了。所以为 0。所以现在 fastbin 和 unsorted bin 中都有同一个 chunk
也就是我们可以把它 malloc() 出来两次
0X01 动手调试
调试一下,做个纪念
直接进入 malloc(400) 中:
进入 _int_malloc 中:
重点来了,进入 malloc_consolidate 中:
maxfb 是最大 size 的 fastbin 的地址,fb 是最小 size 的 fastbin 的地址,下面那个循环正是开始遍历,所有的 fastbin
由于现在就一个 fastbin 中间很多的代码都没有执行
大致意思就是把 fastbin 中所有的 chunk 拿了出来,该合并合并,该消除标记就消除标记。然后插入 unsorted bin 中
最后从 top_chunk 中分配一个 large bin chunk
我们再来看看 double free:重点都在这里
从相同大小的 fastbin 中拿出上一个被释放的 chunk,但是显然这里的 chunk 已经不存在了,在 unsorted bin 中了。所以 double free 被绕过了。
所以就会有一个 chunk 既在 unsorted bin 中又在 fastbin 中。
完结撒花。