🎈
Hacking for fun
GithubCV
  • About me
  • Friends
  • Technology
    • os折腾——Arch & Win11 双系统
    • 2024 Let's GoSSIP
    • 固件仿真
    • 安全随笔——安全到底是什么
    • 《信息安全论文写作》方法论
    • Heap Exploitation
    • 信息收集
    • GPT-4 初体验
    • 关于定向 fuzz 的总结
    • Beacon 实验
    • 对 AI 的认知
    • CSAPP —— lab1 datalab
    • 可视化入门学习
    • Python 爬虫入门学习
    • 对 UNIX 新的认识
    • Great works are connected
    • 开源与黑客
    • 搭建个人网站
  • Life
    • 一个悲观de乐观主义者的独白
    • 路在脚下
    • 法律学习初体验
    • 悟已往之不谏 知来者之可追
    • 在自训队,是一种什么样的体验
    • 支教
    • A passion for difficult and novel problems
    • 2022,我的年度总结
    • 1.21 大年三十
    • 1.20 打工日记
    • 浪漫的中国酒文化
    • 我的哲学批判
    • The review of The Grand Hotel
    • 暑假感想
    • 随想
  • Paper reading
    • Fuzzing
      • PDIFF
      • SyzVegas: Beating Kernel Fuzzing Odds with Reinforcement Learning
      • 1dFuzz: Reproduce 1-Day Vulnerabilities with Directed Differential Fuzzing
      • SyzDirect: Directed Greybox Fuzzing for Linux Kernel
    • Others
      • Cumulative Reasoning With Language Model
      • A Review of the F-Measure: Its History, Properties, Criticism, and Alternatives
      • Araña: Discovering and Characterizing Password Guessing Attacks in Practice
      • ChameleMon: Shifting Measurement Attention as Network State Changes
Powered by GitBook
On this page
  • 前言
  • 什么是堆?
  • 堆的实现有哪些?
  • glibc 实现
  • UAF
  • 附:Linux kernel heap feng shui in 2022 学习笔记
  • References

Was this helpful?

  1. Technology

Heap Exploitation

Previous《信息安全论文写作》方法论Next信息收集

Last updated 11 months ago

Was this helpful?

前言

笔者最近跟学委吴一起接了软件安全测试中的 Heap Exploitation Project,借此 blog 梳理学习思路。

什么是堆?

借 stackoverflow & geeksforgeeks 的回答,先大致了解一下堆是个什么东西,与我们所熟悉的栈又有怎样的区别和联系。

通过以上两张图片,相信读者已经能建立起对堆的初步印象。接下来就可以愉快地讨论堆的实现方式与利用。再次声明,以下讨论的堆,均指运行内存中的堆区域,该区域由程序员手动申请、手动释放,被同一个进程中的所有线程全局共享。

堆的实现有哪些?

从古到今,笔者了解到的堆实现方式有以下七种:

dlmalloc  – General purpose allocator
ptmalloc2 – glibc 
jemalloc  – FreeBSD and Firefox
tcmalloc  – Google
libumem   – Solaris
nedmalloc
Hoar

堆多种的实现方式,也间接提示我们 heap exploitation 不是件轻松活。那么 heap exploitation 究竟难在什么地方呢?

Heap-based vulnerabilities can be very dependent on how the internal implementation of the heap allocator actually works.

因此为了“不耍流氓”,定义讨论的范围为采用 ptmalloc2 的 glibc,接下来让我们去一睹 glibc 堆管理的实现吧!

glibc 实现

chunk 介绍

堆的最小单元为 chunk,由 metadata 与 userdata 组成。metadata 指下图中的 PREV_SIZE & CHUNK SIZE,用于记录 userdata 的元信息,方便 glibc 进行内存管理。

metadatas 中 PREV_SIZE 的作用:

  1. 给前一块 chunk 作为 userdata 存储数据使用(见 Fig.2);

  2. 在 bin 中表示前项 chunk 的大小。

metadata 中 CHUNK SIZE 记录了整个 chunk 的大小,其计算方式如下图所示。需要注意的是,glibc 中规定了 alignment 是 double word,即在 32bits 机器中要求 8bytes 地址对齐,64bits 机器中要求 16bytes 地址对齐。

chunk 释放策略与细节

glibc 对于被 free 掉的 chunk 都丢给了“小弟”——bin去管理。bin 要考虑的问题是:该把这块 chunk 改造成什么样,丢到哪里去,才方便后续分配嘞?

bin 根据用途分为了五类:small bin、large bin、unsorted bin、fast bin、tcache bin。其中发挥基础作用的是 small bin 和 large bin,small bin 实现对 512bytes 以下的 chunk 管理,large bin 实现对 512bytes 及以上的 chunk 管理。unsorted bin、fast bin 和 tcache bin 充当 cache layer 的作用。具体可参考下图以及联想存储器多级缓存的架构理解:

先从高空俯瞰一下 chunk 释放的策略:

if pointer is NULL “do nothing” else convert the pointer back to a chunk

→ Perform sanity checks on the chunk, and abort when fail

→ chunk fits into a tcache bin, store it there.

→ chunk has the M bit set, give it back to the os via munmap.

→ Otherwise we obtain the arena heap lock and then:

  1. fits into a fastbin, put it on the corresponding fastbin, and we’re done.

  2. size > 64KB, consolidate the fastbins, put the resulting merged chunks → unsorted bin.

  3. Merge the chunk with neighboring freed chunks in the small, large, and unsorted bins.

  4. Merge the result chunk if neighboring the top chunk.

  5. Otherwise store it in the unsorted bin

第一次看到这些策略,肯定是一头雾水,这时候就需要结合细节去理解。

sanity checks:

五类 bin 的具体实现:

  • bin 的整体管理是将各类 bin 放到一个数组中,包括 62 small bins, 63 large bins, 1 unsorted bin, 10 fast bins and 64 tcache bins per thread

  • small bin

    • Every chunk less than 512 bytes on 32-bit systems (or than 1024 bytes on 64-bit systems) has a corresponding small bin. (the size of allocated memory is stable)

  • large bin

    • 基于用户分配的空间趋向于小块的事实,large bin 倾向于作为 small bin 的补充。注意下图中 BETWEEN 是表 AMONG 的意思。

  • unsorted bin

    • cluster free & malloc 聚集在某一个时间段时,将其放入 unsorted bin,即拿即用。

  • fast bin

    • 为了减少内存碎片对系统的影响,fast bin 用于管理程序释放掉的较小的内存块(小于 88bytes)。

  • tcache bin

    • 因为堆是全局共享的,对于多线程的情况,则不可避免会遇上需要等待别的线程释放锁,才能申请资源的情况。为了避免此类开销,设计了 tcache。

chunk 分配策略与细节

为了避免频繁的系统调用,在程序第一次 malloc 过后(即便申请很小的内存,如 malloc(0)),os 会分配一块 0x21000 大小的内存给 glibc,并拍了拍 glibc 的肩膀说,“小老弟,拿去耍吧。这些应该足够你应付来申请内存的小鬼了,如果实在不够再来找我”。glibc 捧着这块 0x21000 大小的内存,屁颠屁颠得开始了它的打工生活——替 os 处理内存申请与释放的工作。

老规矩,先瞅一眼 chunk 分配的策略:

tcache

→ mmap

→ obtain arena heap lock → fast bin → small bin

→ unsorted bin,if suitable stop,otherwise put into small / large bin

→ large bin

→ merge unsorted bin、fast bin、small bin、large bin

→ sbrk

→ mmap

→ return NULL

想必你初见觉得晦涩难懂。没事,咱们 step by step 来瞅瞅看这究竟是怎么回事。

chunk 分配机制

  1. If all these strategies fail, the allocation can’t be serviced, and malloc returns NULL.

UAF

有了以上的基础,就可以愉快尝试一下 heap exploitation。笔者近期了解到的 heap exploitation 如下:

  • Heap Overflow(堆溢出): 攻击者通过向动态分配的堆内存写入超出分配的内存空间的数据,覆盖相邻内存的内容,可能导致程序崩溃或执行恶意代码。

  • Use-After-Free(释放后使用): 攻击者利用程序中已经释放的堆内存块,尝试重新使用这些内存块来执行恶意操作。

  • Double Free(重复释放): 这种攻击涉及重复释放相同的堆内存块,从而可能导致内存管理数据结构被破坏,以及潜在的漏洞利用机会。

  • Off-by-One Error(溢出一个字节): 攻击者试图溢出一个字节的内存,通常用于更细微的堆利用攻击。

  • Fastbin Attack(快速分配块攻击): 这种攻击针对 glibc 中的 fastbins,攻击者试图伪造 fastbin 链表,以便获取堆上的未分配内存块。

  • Tcache Attack(Tcache攻击): 这种攻击利用glibc 的 tcache 机制,攻击者试图伪造 tcache 链表,以获取未分配内存块。

  • Unlink Attack(取消链接攻击): 这种攻击涉及伪造一个被取消链接的堆块,以触发漏洞利用机会。

  • Poison Null Byte Attack(毒零字节攻击): 这种攻击利用零字节终止字符串,攻击者试图修改内存块的大小字段,以实现漏洞利用。

UAF 的实现机理是观察堆的分配与释放,构造合法的内存写入,利用 dangling pointer 访问原先分配的地址,通过这种未定义行为发起恶意攻击(如劫持控制流),其本质是如下 L4 所述的 “arbitrary effects”。

hacknote:hacknote.c
        gcc hacknote.c -m32 -no-pie -fstack-protector -o hacknote 

示例代码架构与利用步骤如下:

UAF 在此题的体现:首先申请两个 node,然后删除两个 node。两个 node 共计四块 chunk 被加入到 tcache 中管理。此时再申请一个新的 node,如果申请的 size 得当,glibc 就会将 node0 与 node1 的两块 printnote 分配给新的 node 使用,注意到 printnote 是一个函数指针!此时 content2 是从标准输入读入的,即可以被用户所控制的。那么先往 content2 写入 magic 函数地址,再利用 node0(此时为 dangling pointer)访问 content2 这块区域,RIP 就会访问 magic,成功实现控制流的劫持。

附:Linux kernel heap feng shui in 2022 学习笔记

该文内容较杂,因此采用分点记录的方式。

  1. 该文总结了 allocator 的实现机制对堆利用的影响;

  2. kernel 中两种常见的动态分配机制如下:

    1. General-purpose allocations performed using kmalloc/kzalloc/... API

    2. Special-purpose allocations via kmem_cache_create/kmem_cache_alloc

  3. Slab 是 Linux 内核中的一种内存分配机制,用于高效地管理内核数据结构和对象的内存分配和释放。Slab 分配器的主要目标是减少内存分配和释放的开销,以提高系统性能。Slab 分配器通过预分配一定大小的内存块并将它们组织成 slabs,然后在需要时分配这些内存块,从而减少了内存碎片和频繁的内存分配操作。Slab 分配器通常管理多个 slab 缓存,每个缓存用于不同大小的内存块。这些缓存通常包括三种类型:

    1. Slab缓存:用于保存已分配的内存块。

    2. Slab未分配缓存:用于保存已分配但尚未使用的内存块,以便后续分配。

    3. Slab空闲缓存:用于保存完全未使用的内存块。

  4. 对齐问题的潜在利用:攻击者可以利用对齐问题来修改数据结构的大小,进而改变其行为。例如,他们可能故意构造一个对象,以便它与某个通用缓存别名化,从而可以操纵通用缓存并导致不安全操作。但安全机制近年来也在不断地更新:

    • cred_jar 在 kernel version > 4.4 的情况下加入 SLAB_ACCOUNT 标签,使得其 standalone 免受其攻击。

    • 安全的函数(copy_to_user / copy_from_user)被逐步引入,更加严格的检测机制使漏洞利用难以下手。

    • A freelist pointer randomisation CONFIG_SLAB_FREELIST_RANDOM was introduced in 4.8 and is now enabled by default on most modern distributions.

References

A check that the allocation on an 8-byte (or 16-byte on 64-bit) boundary, since malloc ensures all allocations are aligned.

A check that the chunk’s size field isn’t impossible–either because it is , too large, not an aligned size, or .

A check the chunk lies .

A check that the chunk is by checking the corresponding “P” bit that lies in the metadata at the start of the next chunk.

Each bin contains a maximum of ranging from .

If there is a previously-freed chunk of memory, and that chunk is big enough to service the request, the heap manager will use that freed chunk for the new allocation.

Otherwise, if there is available space at the top of the heap, the heap manager will allocate a new chunk out of that available space and use that.

Otherwise, the heap manager will ask the kernel to add new memory to the end of the heap, and then allocates a new chunk from this newly allocated space.

mmap provides greater flexibility, can map files or anonymous memory, and can map memory to non-contiguous addresses. This helps overcome some limitations of brk, such as heap fragmentation.

以下借 ctf-wiki 的介绍 Use-After-Free(UAF)。

示例可通过链接获取,注意将 Makefile 修改成如下所示,将 PIE 保护关闭。温馨提示: exp.py中的 magic 变量值是通过反汇编(如,将可执行文件拖入 IDA) ,查看函数的起始位置得到的。其它具体的实现过程参照示例即可。

is aligned
too small
would overlap the end of the process’ address space
within the boundaries of the arena
not already marked as free
7 same-size chunks
24 to 1032 bytes on 64-bit systems and 12 to 516 bytes on 32-bit systems
示例
源码
系统理解 Arm Heap Exploitation
Understanding glibc malloc
glibc malloc source code
了解 linux kernel heap
对以往 linux heap 的研究总结
ctfwiki-UAF
深入理解 heap exploitation
glibc 对 chunk 的介绍
chunk 示意图
Fig.2
32bits 中的 chunk 组成
chunk 在 bin 中的样子
small bin
large bin
unsorted bin
fast bin
tcache bin
free in malloc.c
first contribution
https://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap
https://www.geeksforgeeks.org/stack-vs-heap-memory-allocation/#