堆溢出——unlink漏洞攻击(bamboobox)

题目自取:

链接:https://pan.baidu.com/s/1S9xbAWhFw0xFqFyQTACqLA?pwd=vvud 
提取码:vvud

介绍:

终于学到Unlink了,不得不说和栈的难度相比确实大了很多,学起来确实很淦,一个unlink漏洞也确实花了我不少时间,稍加整理写一个博客

什么时候可以用到unlink漏洞攻击,需要满足什么条件? 

1. glibc的版本不能过高,我用的是glibc 2.23版本的,glibc2.26之前的版本都是存在unlink漏洞的
2.堆溢出漏洞。可以写到上一个chunk的size位
3.可以自由创建堆,且自由创建的堆在内存上是物理相邻的

漏洞原理:

先大概看看,一会儿在构造假chunk的时候还会再分析

/* Take a chunk off a bin list */
#define unlink(AV, P, BK, FD) {                                            
    FD = P->fd;                               
    BK = P->bk;
	//检查p和其前后的chunk是否构成双向链表
    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;
        //一般的unlink到这里就结束了,只有是large bin范围,才继续执行下面的代码。
        //如果 p 在largebin的范围  且 p->fd_nextsize不为空
        if (!in_smallbin_range (P->size) && __builtin_expect (P->fd_nextsize != NULL, 0)) 
        {
          //检查p和其前后的large chunk的nextsize域是否构成双向链表
          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;           
            }                               
          }                               
      }                                  
}

这就是当调用free函数时,系统就会取寻找相邻堆块是否已经被释放了,如果被释放的话,会进行合并操作,并且指向先前就被释放的chunk的指针会指向新释放的chunk(指向的位置被修改,这一步很危险),而在2.23glibc中存在漏洞,可以修改先前被释放的指针的指向其他地方,实现任意地址写的操作。

具体而言就是写入假的chunk绕过检查,具体的会在题目讲解时提到

开始:

这里推荐用ubuntu低版本打,我用20.04更换glibc攻击的时候经常报错,而且很难找到问题,浪费很多时间

首先查看保护措施,哦提一嘴,这题用unlink漏洞就是改got表,修改某函数的got指向system函数,再传入'/bin/sh'拿到shell
 

IDA里是什么内容就不说了,其他博客讲得很清楚,我重点谈谈构造fake_chunk我的理解
想要合并空闲的chunk,系统会进行检查
1.首先检查被合并的chunk的大小是否正确,程序会先检查被合并的chunk的size是否与其物理相连的下一个chunk的presize是否相符。

2.则是我们此次的重点,unlink检查

#define unlink(AV, P, BK, FD) {                                            
    FD = P->fd;                               
    BK = P->bk;
	//检查p和其前后的chunk是否构成双向链表
    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;

这里的P就是指向要被合并的chunk的指针(之前我一直理解错,浪费了很多时间)
具体原理在这里不做太多解释,很多博客讲得很好

看看题目

首先我们要找到存储这些堆的指针的地址(也就是指向这些chunk的指针的地址)
 

比如这里 ,在add_item函数这里,可以看到的是,itemlist结构体数组里存的就是申请到的chunk的首地址,也就是说申请到的malloc堆的首地址都放在了itemlist里,我们点进去看看 这里说明以下,由于IDA识别不了结构体指针数组,因此指针的形式往往以_DWORD的形式进行定义,并且一个元素是一个字节。

 由于是DWORD形式,也就是双字节,占4个byte,因此item[4*i+2]代表着其实是item[16*i+8],这里可能看我博客理解不了,但是不影响做题,就不再细说了

做个验证吧,看看itemlist里是否真的存着申请到的堆地址
这里申请了三个堆

由IDA我们可以看到itemlist的地址是在0x6020c0,我们看看它存着什么东东
 可以看到如之前所说的,itemlist存着都是指向申请到的chunk用户段的指针 

接下来就是构造假的chunk了

 

 这里的FAKE_presize和size可以随意,但是fake_fd和bk则有要求
fake_ptr = 0x6020c8
fake_fd = fake_ptr-0x18
fake_bk = fake_ptr-0x10
具体是为什么呢?

首先说一下unlink的P是怎么来的

#define unlink(AV, P, BK, FD) {                                            
    FD = P->fd;                               
    BK = P->bk;
	//检查p和其前后的chunk是否构成双向链表
    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;

当要free掉某个堆块时,如果其低地址的chunk是空闲的,那么这里的P就是被释放掉的堆块的地址减去自己的pre_size里的数值,这样就可以指向低地址的chunk的chunk头了,通过堆溢出修改掉被释放的chunk的pre_size和size,就可以达到释放该chunk时,unlink调用的P是是指向假chunk的chunk头。

ok,继续说为什么
fake_ptr = 0x6020c8(itemlist存指向chunk的地址的指针的起始地址)
fake_fd = fake_ptr-0x18
fake_bk = fake_ptr-0x10

按照unlink函数的定义,此时FD就是P->fd,即fake_ptr-0x18,那么接下来就是要判断是否
FD->bk=P
那么FD->bk=FD+0x18=fake_ptr-0x18+0x18(FD的bk在FD这个chunk头加上0x18)=fake_ptr 
成功绕过!
同理BK也是按照这样的方法去绕过
这样我们就欺骗了程序,将第一个chunk(也就是被假”free“的)与第二个chunk合并了,那么带来的后果是什么呢?
按照unlink的定义,就是使得FD->bk=BK   BK->fd=FD,也就是fake_ptr(P)指向了fake_ptr的位置,实现了对应地址任意写的操作。

OK,就写到这里了,后续无非就是泄露libc,修改got,拿到shell。 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在计算机安全领域,"unlink"是一种常见的溢出攻击利用技术。它利用了"Use-After-Free"漏洞,该漏洞在释放内存后仍然使用该内存的指针。 在具体的实现中,"unlink"攻击需要使用全局变量,并进行多次写入。攻击者通过修改上的数据结构,使得被释放的块的前后指针指向了攻击者想要控制的地址。 下面是"unlink"攻击的主要步骤: 1. 攻击者需要一个全局指针变量p,该变量指向一个块。 2. 攻击者通过修改p的fd和bk指针,将p链接到自身的前后块上。 3. 攻击者检查p->fd->bk和p->bk->fd是否都指向p,如果不是,则意味着块链表被破坏,攻击失败。 4. 如果上述检查通过,攻击者将p->fd->bk指向p的前一个块,将p->bk->fd指向p的后一个块,完成"unlink"操作。 5. 攻击者可以利用这个被解链的块进行任意的内存写入或执行其他操作,从而实现对程序的控制。 总结起来,"unlink"攻击利用了溢出漏洞中的"Use-After-Free"漏洞,并通过修改块的前后指针来实现对程序的控制。这是一种常见的攻击技术,需要仔细的结构分析和理解。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [【pwn学习】溢出(三)- Unlink和UAF](https://blog.csdn.net/Morphy_Amo/article/details/122631424)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [pwn unlink](https://blog.csdn.net/qq_37433000/article/details/103500857)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值