【Linux堆利用】Fastbin Double Free

Double Free是针对fastbin的攻击,字面意思就是重复释放内存,也就是两次free()同一块内存导致的漏洞。

由于fastbin的机制,在满足fastbin的chunk在被释放后它下一个chunk的P位不会被置为0,也就是说即使当前chunk被释放掉了,但是他的next_chunk的P为还依然为1(1表示前一个chunk正在使用中),但他却是已经被free()掉了,这样做的目的是为了防止chunk被合并(因为现实证明,就是程序通常会申请小内存块比较频繁,如果每次申请释放都重复分割合并,会导致性能非常低下,这也是为什么将P为置1的原因,P位为1代表前一个chunk正在使用中,就无法合并了,然后当我们申请的小内存满足fastbin,就会直接从fastbin中直接返回chunk给我们),对于fastbin的ptmalloc实现而言,在我们free的时候仅仅验证了main_arena直接指向的块,也就是链表指针头部的块。当我们两次重复free同一块内存,就会触发ptmalloc的验证机制直接报错double free(_int_free函数的检测)

ptr = malloc(0x10);
free(ptr);
free(ptr); // 两次连续重复释放同一块内存,就会报错
// _int_free的检测机制

但是要绕过这个检测也非常简单,因为上面说了ptmalloc只验证main_arena指向的块,也就是头部块(就是每次释放的chunk都和上一次释放的chunk进行比较,如果发现是同一块就会报错)

ptr = malloc(0x10);
ptr1 = malloc(0x10);
free(ptr);
free(ptr1);
free(ptr); // 这样也达到了重复释放ptr指向的chunk的目的,但是不会触发检测机制,因为上一次的释放的事ptr1, 现在释放的事ptr,只要ptr != ptr1 就会通过检测,这样的代码不会有任何异常

正是因为这样,问题来了。
还要回到chunk的结构,我们知道chunk的free释放以后,它本来的用户空间会存放它的上一个释放的chunk的指针,也就是fd指针(fastbin只使用了fd指针,释放的chunk通过fd指针构成单链表,且满足后进先出)会存放在size域的下一个字段fd,因为这样的结构,fastbin中的指针永远指向最进一次释放的chunk,申请的时候也是分配fastbin指向的chunk,所以就是一种典型的后进先出(最后释放的chunk最先被申请)的结构。

第一次我们释放ptr时候,fastbin指针指向ptr,此时fastbin中不存在已经释放过的chunk,所以ptr的fd指针指向0
在这里插入图片描述
第二次释放ptr1的时候,由于已经存在之前释放的ptr,所以ptr1的fd指针就会存放ptr的指针,而且fastbin同时修改指针指向ptr1
在这里插入图片描述
第三次当我们又再一次free释放ptr的时候,虽然之前已经free过了,但是现fastbin指向的chunk是ptr1,(也就是前面说得上一次释放的chunk),并不会触发_int_free的检测机制,所以当又一次释放完了ptr的时候,此时的结构就变成了,fastbin指向ptr,ptr指向ptr1,ptr1指向ptr,而ptr又指向ptr1
在这里插入图片描述
当我们重复释放ptr,就会形成上面的结构

ptr = malloc(0x10);
ptr.fd = 0x1234; // 修改ptr的fd指针指向0x1234

当我们指向完上述的代码后,现在又会变成什么样?

在这里插入图片描述
当我们再次分配内存的时候

malloc(0x10); // 分配到ptr1
malloc(0x10); // 分配到ptr
ptr_0x1234 = malloc(0x10);	// 再一次分配,内存就分配到了我们指定的位置了 	

这样的话就可以实现任意地址写了…

猜你喜欢

转载自blog.csdn.net/weixin_43833642/article/details/106780060