ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

深入解析Unsortedbin Attack堆漏洞利用技术

深入解析Unsortedbin Attack堆漏洞利用技术

1. Unsortedbin Attack概述

Unsortedbin attack是一种针对glibc堆管理器中unsorted bin机制的漏洞利用技术。在Linux系统的内存管理中,当程序释放一块较大的内存时,这块内存通常会被放入unsorted bin中,而不是立即归还给操作系统。unsorted bin作为glibc堆管理器中的一个重要数据结构,主要用于暂存最近释放的堆块,以便后续的内存分配请求能够快速重用这些内存空间。

这个攻击技术的核心在于利用unsorted bin双向链表操作时的写操作原语。当从unsorted bin中取出一个chunk时,glibc会执行unlink操作来将该chunk从链表中移除。在这个过程中,攻击者可以通过精心构造的内存布局,实现对特定内存地址的写操作。

2. 技术原理深度解析

2.1 glibc堆管理基础

glibc的堆管理器使用ptmalloc2算法,它将堆内存划分为不同大小的chunk。每个chunk都包含元数据信息和实际用户数据区域。关键的元数据包括:

  • size:当前chunk的大小
  • prev_size:前一个chunk的大小(如果前一个chunk是free状态)
  • fd/bk:前向(fd)和后向(bk)指针,用于连接free chunk

当chunk被free时,根据其大小会被放入不同的bin中:

  • fastbin:用于小尺寸chunk的单向链表
  • smallbin:中等尺寸chunk的双向链表
  • largebin:大尺寸chunk的双向链表
  • unsortedbin:最近释放chunk的暂存区

2.2 Unsorted Bin工作机制

unsorted bin是一个双向循环链表,具有以下特点:

  1. 当chunk被释放时,如果不符合fastbin的大小要求,会先放入unsorted bin
  2. 在后续malloc请求时,堆管理器会先遍历unsorted bin寻找合适大小的chunk
  3. 如果找到的chunk比请求的大小大很多,会进行分割操作
  4. unsorted bin中的chunk在被重新分配前会保持free状态

关键的数据结构操作发生在malloc时对unsorted bin的遍历过程中。当从unsorted bin中取出一个chunk时,会执行以下操作:

// 伪代码表示unlink操作 victim = unsorted_chunks(av)->bk; bck = victim->bk; unsorted_chunks(av)->bk = bck; bck->fd = unsorted_chunks(av);

2.3 漏洞利用原理

攻击者可以通过以下步骤构造利用条件:

  1. 控制一个free chunk的bk指针
  2. 确保这个chunk位于unsorted bin中
  3. 触发malloc操作使得该chunk从unsorted bin中取出
  4. 在unlink操作时,bck->fd = unsorted_chunks(av)会向bck+0x10的位置写入一个值

通过精心构造bk指针,攻击者可以实现向任意地址写入一个较大的值(通常是main_arena的地址)。这个写操作原语可以用于:

  • 修改关键函数指针
  • 覆盖全局变量
  • 破坏堆管理结构

3. 实战利用步骤

3.1 环境准备

要复现unsortedbin attack,需要准备:

  1. 存在堆溢出或UAF漏洞的程序
  2. 能够控制free chunk的bk指针
  3. glibc版本通常需要低于2.29(之后加入了更多保护措施)

3.2 具体操作流程

  1. 分配两个较大的chunk(避免进入fastbin):
void *chunk1 = malloc(0x400); void *chunk2 = malloc(0x400);
  1. 释放第一个chunk,使其进入unsorted bin:
free(chunk1);
  1. 通过漏洞(如堆溢出)修改chunk1的bk指针:
// 假设我们可以覆盖chunk1的bk指针 *(size_t *)(chunk1 + 0x8) = target_addr - 0x10;
  1. 触发malloc操作,使得chunk1从unsorted bin中取出:
void *chunk3 = malloc(0x400);
  1. 检查目标地址的值是否被修改:
printf("Target value: %p\n", *(void **)target_addr);

3.3 关键点说明

  • target_addr需要满足可写条件
  • 写入的值通常是main_arena的地址(一个较大的值)
  • 需要确保在修改bk指针时,chunk1确实在unsorted bin中
  • 可能需要绕过一些检查(如size字段的合法性检查)

4. 防御措施与绕过技术

4.1 glibc的保护机制

现代glibc版本增加了多项保护措施:

  1. unlink时的完整性检查:
if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0)) malloc_printerr ("corrupted size vs. prev_size");
  1. 对largebin chunk的额外检查
  2. 引入tcache机制改变了内存分配流程

4.2 可能的绕过方式

在某些特定条件下仍可能利用:

  1. 当程序使用较旧版本的glibc时
  2. 存在其他漏洞可以绕过检查时
  3. 结合其他攻击技术(如house of系列)

5. 实际应用场景

unsortedbin attack通常作为复杂漏洞利用链的一部分:

  1. 用于泄露libc地址(通过写入可预测的值)
  2. 修改全局变量(如global_max_fast)
  3. 为后续攻击创造条件(如FSOP)

一个典型场景是结合文件流操作(FILE *)进行利用。通过修改_IO_list_all等全局指针,可以导向攻击者控制的区域,最终实现代码执行。

6. 调试技巧与注意事项

6.1 调试方法

  1. 使用gdb+pwndbg插件观察堆状态:
heap bins # 查看各个bin的状态 vis_heap_chunks # 可视化堆chunk
  1. 关键断点设置:
b _int_malloc # 跟踪malloc内部逻辑 b unlink # 跟踪unlink操作
  1. 观察内存变化:
watch *(long *)target_addr # 监视目标地址变化

6.2 常见问题

  1. chunk没有进入unsorted bin:
  • 检查大小是否符合要求(大于global_max_fast)
  • 确认没有进入tcache(glibc 2.26+)
  1. unlink操作崩溃:
  • 检查伪造的bk指针是否合法
  • 确保size字段与prev_size匹配
  • 确认next chunk的prev_inuse位是否正确
  1. 写入的值不符合预期:
  • 检查目标地址计算是否正确(需要-0x10)
  • 确认main_arena地址是否如预期

7. 与其他堆利用技术的关系

unsortedbin attack常与其他技术结合使用:

  1. 与fastbin attack结合:先使用unsortedbin attack修改global_max_fast,扩大fastbin的范围
  2. 与house of orange结合:构造伪造的FILE结构体
  3. 与tcache poisoning结合:绕过现代glibc的保护

相比其他技术,unsortedbin attack的特点是:

  • 不需要泄露地址即可实现写操作
  • 但只能写入一个固定的较大值
  • 通常作为利用链的中间步骤而非最终目标
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进