好像拖更了好久。。。实在是抱歉。。。。主要是fastbin attack包含了四个部分,后面的例题不知道都对应着哪个方法,所以做完了例题才回来写博客。fastbin attack应该也会分四篇文章分开写。学了这么长时间pwn给我最大的感受就是量变确实可以引起质变,现在做题或者学习新的技术的时候可以隐约的进行以点看面的思考,通过某一处问题会在心里想象可能会引发什么什么样的后果。总的来说不后悔入坑pwn,精确到字节之间的环环相扣让我为之着迷!

编写不易,如果能够帮助到你,希望能够点赞收藏加关注哦Thanks♪(・ω・)ノ

往期回顾:
好好说话之Use After Free
好好说话之unlink
好好说话之Chunk Extend/Overlapping

Fastbin Attack

简单的介绍一下,我们可以根据名字看出,这一类漏洞利用的方法主要基于fastbin机制的缺陷,其实fastbin attack并不是指某一种利用方法,而是一些。这类利用的前提是:

  • 存在堆溢出、use-after-free等能控制chunk内容的漏洞
  • 漏洞发生于fastbin类型的chunk中

如果细分的话,可以做如下的分类:

  • Fastbin Double Free
  • House of Spirit
  • Alloc to Stack
  • Arbitrary Alloc

前两种主要漏洞侧重于利用free函数释放的真的 chunk或伪造的chunk,然后再次申请chunk进行攻击,后两种侧重于故意修改fd指针,直接利用malloc申请指定位置chunk进行攻击。这篇文章主要讲解的是Fastbin Double Free,后几种会在之后文章中继续讲解

原理

fastbin attack存在的原因在于fastbin时使用单向链表来维护释放的堆块的,并且由fastbin管理的chunk即使被释放,其next_chunk的prev_inuse位也不会被清空。我们用一个例子来看一下fastbin是怎么管理空闲chunk的,并演示这两处问题:

  1 //gcc -g hollk1.c -o hollk12 #include<stdio.h>3 int main(void)4 {   5     void *chunk1,*chunk2,*chunk3;6     chunk1 = malloc(0x30);7     chunk2 = malloc(0x30);8     chunk3 = malloc(0x30);9     10     free(chunk1);11     free(chunk2);12     free(chunk3);13     return 0;14 }

这是一个非常简单的程序,创建了3个0x30大小的chunk,并且依次释放。因为在编译阶段使用-g参数,所以我们在第10行下断点,我们看一下在内存中三个chunk的部署情况:

接下来我们在第13行下断点,看一下释放之后内存以及fastbin中的情况:

可以看到,由于创建的三个chunk的大小为0x30,那么自然而然的在释放后进入fastbin。由于fastbin是以单向链表的形式管理释放chunk的,所以可以在图1中看到chunk只有fd位置具有指针,并且指向前一个chunk的prev_size

可以看一下图2的最后,会有一个白色的<-- 0x0的标识,这证明chunk1前面已经没有被释放的chunk了。那么就会存在一个疑问:在fastbin中后一个被释放的chunk的fd指向前一个被释放的chunk的prev_size,那么谁指向最后一个被释放的chunk3的prev_size呢?其实是main_arena指向了chunk3的prev_size

另外有一点需要注意,我们往前翻,看一下在你为释放阶段chunk的prev_inuse标志位为1,回来在看释放后的内存情况,chunk的prev_inuse位依然还是1不变

Fastbin Double Free

可以从名字上直译可以解读为fastbin中的chunk被释放两次,事实上并不仅限于两次,也可以多次,因此被释放的chunk可以在fastbin链表中存在多次。这样导致的后果是多次分配可从fastbin链表中取出同一个堆块,结合堆块的数据内容可以实现类似于类型混淆(type confused)的效果

Fastbin Double Free能够成功利用主要有两部分的原因:

  • fastbin的堆块被释放后next_chunk的prev_inuse位不会被清空
  • fastbin在执行free的时候仅验证了main_arena直接指向的块,即链表指针头部的块。对于链表后面的块并没有进行验证

演示说明

  1 //gcc -g hollk2.c -o hollk22 #include<stdio.h>3 int main(void)4 {5     void *chunk1,*chunk2,*chunk3;6     chunk1=malloc(0x10);7     chunk2=malloc(0x10);8 9     free(chunk1);10     free(chunk1);11     return 0;12 }

一个简单的小程序,创建了两个0x10大小的chunk,但是在释放的时候释放了两次chunk1,我们执行一下看结果:


可以看到在执行过程中程序会检测到SIGABRT信号,紧接着进入核心转储,程序中断。这是因为_int_free函数好检测到了fastbin的double free。如何检测的呢?我们前面说过fastbin在执行free的时候仅验证了main_arena直接指向的块,即链表指针头部的块。也就是说在释放chunk1后main_arena直接指向的就是chunk1,这个时候再去释放chunk1,无异于顶枪口搞事情,被抓理所应当

那么如果我们在释放两次chunk1中间添加一个释放chunk2呢?

  1 //gcc - g hollk3.c -o hollk32 #include<stdio.h>3 int main(void)4 {5     void *chunk1,*chunk2,*chunk3;6     chunk1=malloc(0x10);7     chunk2=malloc(0x10);8 9     free(chunk1);10     free(chunk2);11     free(chunk1);12     return 0;13 }

编译好后,使用gdb调试,首先在第11行下断点,我们一起看一下fastbin中的情况:

可以看到在释放chunk2之后main_arena直接指向的是chunk2而不是chunk1,但是由于_int_free只检查main_arena前面的chunk是否被释放,即chunk2是否是释放状态,所以我们再一次释放chunk1的时候_int_free就会放行,我们在12行下断点,使程序再一次释放chunk1,一起看一下会有什么样的结果


可以看到,chunk1再一次被释放,并且又重新被挂进fastbin链表中。我们在前面讲过gdb中fastbin链表中最后白色的标识证明chunk2前面还是存在一个释放后被挂进fastbin中的堆块的

需要注意的是chunk1再一次被释放,此时你可以将chunk1看作一个新的块,也就意味着chunk1作为chunk2的后一个块被释放,那么此时chunk1的fd的值并不是0,而是指向chunk2。那么这个时候如果我们可以控制chunk1的内容,就可以修改fd指针,从而实现在任意地址分配fastbin块。

为了更好的看到上面描述的样子,我们再看一个例子

  1 //gcc -g hollk4.c -o hollk42 #include<stdio.h>3 4 typedef struct _chunk5 {6     long long pre_size;7     long long size;8     long long fd;9     long long bk;10 } CHUNK,*PCHUNK;11 12 CHUNK bss_chunk;13 14 int main(void)15 {16     void *chunk1,*chunk2,*chunk3;17     void *chunk_a,*chunk_b;18 19     bss_chunk.size=0x21;20     chunk1=malloc(0x10);21     chunk2=malloc(0x10);22 23     free(chunk1);24     free(chunk2);25     free(chunk1);26 27     chunk_a=malloc(0x10);28     *(long long *)chunk_a=&bss_chunk;29     malloc(0x10);30     malloc(0x10);31     chunk_b=malloc(0x10);32     printf("%p",chunk_b);33     return 0;34 }

简单的描述一下这个程序,首先创建了一个CHUNK结构体,每个结构体成员都是以long long类型创建的,分别是prev_sizesizefdbk。接着定义了一个size大小为0x21大小的结构体指针bss_chunk,然后申请了两个0x10大小的堆块chunk1、chunk2。接着依次释放了chunk1和chunk2,并再一次释放chunk1。这个时候重新申请一个0x10大小的堆块chunk_a,并且将chunk_a的fd位置设置为bss_chunk结构体指针。接着连续申请三个0x10大小的chunk,第三个chunk指针付给chunk_b,接着打印出chunk_b的地址

在编译好这个程序后,使用GDB打开,我们在23行下断点查看一下内存中的部署:

可以看到内存中存在chunk10x555555758000和chunk20x555555758020两个堆块,这里需要注意的是bss_chunk这个结构体其实并不是在内存中的,由于结构体指针是以全局变量的形式被创建的,所以结构体指针会被放置在bss段。我们用用ida打开这个程序看一下:


可以看到结构体指针bss_chunk所在位置为bss段,并且偏移为0x201040,这个偏移的基地址为代码段起始,所以我们在gdb中输入命令vmmap查看一下代码段的起始位置:


可以看到最上面绿色框中就是代码段的起始地址,那么:

0x201040 + 0x555555554000 = 0x555555755040

我们在gdb中查看一下0x555555755040这个地址:


可以看到结构体bss_chunk确实是在这个位置的

接下来,我们在第27行下断点查看一下在释放后fastbin中的情况:


由于在chunk1被二次释放了,所以chunk1在第二次释放后再一次被挂在了fastbin中,并且此时chunk1的fd指向的是chunk20x555555758020。接下来将断点下在28行:


可以看到在重新申请一个0x10大小的chunk_a的时候,被重新启用的是挂在fastbin最后面的chunk1而不是chunk2。记下来我们在29行下断点,这一步会将刚刚创建的chunk_a的fd位置改为bss_chunk结构体指针:


接下来连续的申请了三个0x10的chunk,首先申请的第一个0x10就应该是此时fastbin中最后main_arena指向的chunk2,第二个0x10就应该是此时fastbin中最后main_arena指向的chunk1。关键点在第三个0x10的chunk,我们将断点下载地址第31行:


可以看到此时是fastbin中还会有一个0x10大小的chunk,这个就是我们在bss段自定义的bss_chunk结构体,为什么会这样呢?

我们一起来看上面这张图,重新捋一遍这个流程:

  • 首先经过double free之后fastbin中的单向链表为chunk1_double --> chunk2 --> chunk1在经过一次malloc申请后main_arena指向的chunk1_double被重新启用,即chunk1倍重新启用,main_arena指向chunk2,并且将chunk1的fd从原来的指向chunk2修改为指向结构体指针chunk1 --> bss_chunk,也就是说在fastbin单向链表中bss_chunk已经作为chunk1前一个被释放的块的存在了
  • 接下来第二次malloc申请后main_arena指向的chunk2被启用,main_arena重新指向chunk1
  • 第三次malloc申请后chunk1再一次被启用,main_arena指向chunk的fd指向的bss_chunk
  • 那么在第四次malloc申请的时候此时main_arena指向的bss_chunk就会被启用

虽然bss_chunk并不是在内存中正常申请的chunk,但是由于我们可以修改chunk1的fd,使他指向bss_chunk,那么即使bss_chunk位于bss段,也会被当作一个chunk来被启用

那么在程序第31行代码中chunk_b其实被赋予的就是bss_chunk的结构体指针,所以在第32行输出的时候实际输出的是bss_chunk的chunk地址:

好好说话之Fastbin Attack(1):Fastbin Double Free相关推荐

  1. 好好说话之Tcache Attack(3):tcache stashing unlink attack

    tcache stashing unlink attack这种攻击利用有一个稍微绕的点,就是small bin中的空闲块挂进tcache bin这块.弯不大,仔细想想就好了 往期回顾: 好好说话之Tc ...

  2. 好好说话之Tcache Attack(2):tcache dup与tcache house of spirit

    这篇文章介绍了两种tcache的利用方法,tcache dup和tcache house of spirit,两种方法都是用how2heap中的例题作为讲解.由于tcache attack这部分的内容 ...

  3. 好好说话之Tcache Attack(1):tcache基础与tcache poisoning

    进入到了Tcache的部分,我还是觉得有必要多写一写基础的东西.以往的各种攻击手法都是假定没有tcache的,从练习二进制漏洞挖掘的角度来看其实我们一直模拟的都是很老的环境,那么这样一来其实和真正的生 ...

  4. 好好说话之IO_FILE利用(1):利用_IO_2_1_stdout泄露libc

    前言 本来是在做tcache attack的例题的,但是wiki上的challenge2考察的重点不仅仅是在tcache.题目程序中没有输出的功能,所以无法像往常一样去泄露libc,这个时候就需要进行 ...

  5. 好好说话之House Of Einherjar

    前言 又鸽了好久,抱歉哈~ 总的来说House Of Einherjar这种利用方法还是挺简单的,有点像chunk extend/shrink技术,只不过该技术是后向,并且利用top_chunk合并机 ...

  6. CTF(pwn) Fastbin Attack

    Fastbin Attack Fastbin Double Free 其中linux中会有一个校验对于double free 即会判断当前 fastbin链表的头部,是否和当前释放的fastbin 是 ...

  7. linux堆内存管理深入分析,【技术分享】Linux堆溢出之Fastbin Attack实例详解

    1. 摘要 在近几年各大CTF比赛中,看到有很多次pwn类别题中出现fastbin攻击的情况,例如今年的defcon,RCTF,胖哈勃杯,0CTF final等等 ,fastbin attack是堆漏 ...

  8. 好好说话之Use After Free

    到了Use After Free啦,总体来说这种手法并不复杂,特征也很明显,就是在静态分析阶段观察释放chunk之后指针是否置空.本以为参加hw会往后拖更,没想到这么快就写完了.如果前面一直跟着学的话 ...

  9. 好好说话之unlink

    堆溢出的第三部分unlink,这可能是有史以来我做的讲解图最多的一篇文章了累死 .可能做pwn的人都应该听过unlink,见面都要说声久仰久仰.学unlink的时候走了一些弯路,也是遇到了很多困扰的问 ...

最新文章

  1. 创建MySQL数据库
  2. 【Elastic Stack学习】ELK日志分析平台(一)ELK简介、ElasticSearch集群
  3. Intel汇编语言程序设计学习-第二章 IA-32处理器体系结构-上
  4. PyTorch 实现经典模型4:GoogLeNet
  5. 【译】Facebook 开源 Detectron
  6. trove mysql 镜像_trove 基于 centos7 制作 mysql5.6 镜像
  7. 阿里 P8 Java高级架构师,都需要掌握哪些技术栈?
  8. web项目中图标的前端处理方案
  9. 软件项目管理大作业_《软件工程》软件项目管理实验
  10. 将Jquery EasyUI中DataGird的数据导入Excel中
  11. Spring中整合Quartz插件【一】基于MethodInvokingJobDetailFactoryBean实现任务管理
  12. 数字电路与逻辑设计——组合逻辑篇
  13. 表格/列表法之分部积分
  14. 浅谈企业知识资产管理及建设思路
  15. mysql通过视图插入数据_数据库视图 sql
  16. 计算机英语口语app,最实用五大英语口语app,强烈推荐
  17. 鸿蒙和小米哪个值得入手,鸿蒙系统能够吸引小米的优势是什么
  18. Arcgis更换布局模板_PPT模板到底怎么用呢?
  19. SageX3和车辆排队系统、地磅系统集成方案
  20. Android:RecycleView基本使用(瀑布流)

热门文章

  1. MATLAB拟合函数使用说明
  2. Github Page 个人主页——自定义域名
  3. 安霸Ambarella三款CV系列芯片对比--CV2S、CV22S、CV25S
  4. 【玻璃心,碎一地】快来用人工智能技术测测有几个微信好友删除你
  5. 泛型---上界通配符和下界通配符
  6. 如何画一块标准的PCB板?SMT工艺PCB要求
  7. Matplotlib 设置支持中文的默认字体
  8. 0基础python笔记str/list/tuple/dict
  9. react基础之--样式设置
  10. HTML小案例-使用CSS3实现网页加载loding动画