堆溢出----Fastbin Attack

学习资料:https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/fastbin_attack/

                  https://www.anquanke.com/post/id/85357

之前稍微了解了一波Use After Free ,运用了fastbin,这次继续学一下fastbin的其他攻击方式,希望能学会吧

简单的介绍如下,图片来自CTFWIKI

Use After Free还是要派上用场的,不错欸

其实Fastbin Attack最精髓的地方就是每一块在fastbin中的堆被释放以后会放在一个链表中,而且free之后,size的prev_inuse标志位不会被清空哦

下面开始学(zhao)习(nue)啦

1.Fastbin Double Free

字面意思就是chunk可以多次释放

看一下是个什么鬼

int main(void)
{
    void *chunk1,*chunk2,*chunk3;
    chunk1=malloc(0x10);
    chunk2=malloc(0x10);

    free(chunk1);
    free(chunk2);
    free(chunk1);
    return 0;
}

哇,连续释放两次chunk1,不会报错么,继续执行下去了,原因就是指针main_arena,这个就要涉及到arena的管理了,和线程个数有关

主线程使用main_arena,看一下main_arena的变化过程吧,如下

emmmm,不细说了吧,看得懂,主要就是利用了main_arena的检测机制,悄悄的漏过去了

注意因为 chunk1 被再次释放因此其 fd 值不再为 0 而是指向 chunk2,这时如果我们可以控制 chunk1 的内容,便可以写入其 fd 指针从而实现在我们想要的任意地址分配 fastbin 块,能改就出事啦,基本就是这么个操作

看一个具体的操作

typedef struct _chunk
{
    long long pre_size;
    long long size;
    long long fd;
    long long bk;
} CHUNK,*PCHUNK;

CHUNK bss_chunk;

int main(void)
{
    void *chunk1,*chunk2,*chunk3;
    void *chunk_a,*chunk_b;

    bss_chunk.size=0x21;
    chunk1=malloc(0x10);
    chunk2=malloc(0x10);

    free(chunk1);
    free(chunk2);
    free(chunk1);

    chunk_a=malloc(0x10);
    *(long long *)chunk_a=&bss_chunk;
    malloc(0x10);
    malloc(0x10);
    chunk_b=malloc(0x10);
    printf("%p",chunk_b);
    return 0;
}

用pwndbg动态调试一波

我们先执行两个chunk的malloc

第一次释放chunk1和chunk2之后,chunk2的fd指向chunk1,但chunk1的bk不指向chunk2,也侧面验证了fastbin是单链表

然后第二次free chunk1

你看,我们躲避main_arena的检查,double free之后,改变fastbin单链表里的指针

接下来malloc给chunk_a原先chunk1的堆空间,然后赋给了它bss字段0x601080

然后两次malloc不变,先是分配chunk2,然后再次分配chunk1,接着再分配chunk_b时,chunk_b的地址就变为了0x601080

那我们就成功修改了指向的堆,并能输出数据

理完之后,感觉有点强行的意思,想试试看use after free的操作能不能直接输出bss字段

改后的代码如下

typedef struct _chunk
{
    long long pre_size;
    long long size;
    long long fd;
    long long bk;
} CHUNK,*PCHUNK;

CHUNK bss_chunk;

int main(void)
{
    void *chunk1,*chunk2,*chunk3;
    void *chunk_a,*chunk_b;

    bss_chunk.size=0x21;
    chunk1=malloc(0x10);
    chunk2=malloc(0x10);

    free(chunk1);
    free(chunk2);
    //free(chunk1);

    malloc(0x10);
    chunk_a=malloc(0x10);
    *(long long *)chunk_a=&bss_chunk;
    chunk_b=malloc(0x10);
    printf("%p",chunk_b);
    return 0;
}

然后我们两次malloc,两次free,再两次malloc之后,可以看到,chunk1的fd又指向了bss字段

继续执行,按照原先的猜想应该还是可以输出0x601090,但是结果如下

就很迷,然后我们其实犯了个很白痴的问题,malloc之后修改堆的fd,bk也没啥用了,因为已经从链表里卸下来了,那就继续新开辟一个堆,那么问题又来了,那最后输出的不应该是0x602040

我们最后malloc之后,的确可以看到chunk_b的地址的确是0x602040

emmmm,最后知道地址指向的应该是数据段才对,要把16个字节的头部去掉,所以就是0x602050

2.House Of Spirit

上面一种方法chunk是真的,但被我们重复利用,现在更进一步,伪造一个chunk,不知道和frame stacking的原理相差大不大,下图来自CTFWIKI

哇,这一顿操作看上去容易,其实感觉不简单啊,光看原因感觉不是很友好,就去网上找了几个场景

你看现在我们妖王目标区域写数据怎么办呢,我们可以把可控区域伪造成fastbin,然后覆盖堆指针指向他们,然后释放掉,等再次调用他们的时候往目标区域写入数据,这样容易懂多了

场景搞定了,我们来看一下上面那些机制为什么要绕过

1.ISMMAP:mmap标志位不能被置上,否则会直接调用munmap_chunk函数去释放堆块

2.对齐:对齐就对齐吧,好像不对齐的确不靠谱

3.size:fastbin是一个单链表结构,遵循FIFO的规则,32位系统中fastbin的大小是在16~64字节之间,64位是在32~128字节之间,超过的话,就不会释放到fastbin里面了

4.next chunk:下一个堆块的大小,要大于2*SIZE_ZE小于system_mem,否则会报invalid next size的错误

例题:湘湖 note

试着做做看吧,我也不知道做不做得出

大概是这么个东西

比较奇怪的是输入5、6都会退出,也不知道为啥,分析一下功能

New_note:创建note,最多创建3个,规定了大小

Show_note:就是Show

Edit_note:

好累…………先咕咕咕了

猜你喜欢

转载自blog.csdn.net/qq_42192672/article/details/83316042