Skip to content

8x02 - Exploit Development

从发现漏洞到实现利用的跨越。

本章聚焦"利用链评估与可利用性分析",目标是把漏洞从"能崩"推进到"可定级、可验证修复、可解释影响面"。具体攻击细节与可直接复用的利用步骤不在本笔记范围内。

1. 利用链抽象(通用模型)

一条漏洞链通常包含:

  • 触发:输入如何到达 bug
  • 原语:bug 能提供什么能力(信息泄露、越界读写、UAF 等)
  • 对抗缓解:ASLR/CFI/MTE/SELinux/seccomp/进程拆分如何影响链路
  • 影响达成:越权、信息泄露、持久化、DoS 等

这个模型可以同时用于用户态与内核态。

2. 利用原语

利用原语是漏洞能力的抽象表达。理解原语类型及其强弱转换是利用评估的核心。

2.1 常见原语类型

信息泄露原语

  • 栈泄露:泄露返回地址或保存的寄存器,可用于推断代码段基址
  • 堆泄露:泄露堆对象地址或堆上存储的指针,用于绕过 ASLR
  • 内核地址泄露:泄露内核符号或对象地址,是内核提权的前置条件

内存破坏原语

  • 任意地址写(AAW):可向任意地址写入任意值,是最强的写原语
  • 受限写:只能写特定范围或特定值(如写零、写固定偏移)
  • 任意地址读(AAR):可读取任意地址内容,常用于信息收集
  • 越界读写(OOB R/W):读写超出对象边界的内存,强度取决于可控偏移范围

对象生命周期原语

  • Use-After-Free(UAF):对已释放对象的引用仍可访问,可通过堆喷射重新占位
  • Double Free:同一对象被释放两次,可导致堆元数据破坏

类型混淆原语

  • 将对象 A 的指针当作对象 B 使用,若两者布局不同可导致字段错位访问
  • 在面向对象语言(如 Java/Kotlin 的 native 层)中较常见

2.2 原语强度转换

弱原语可通过组合或放大转化为强原语:

弱原语转换方法强原语
单字节溢出覆盖相邻对象的 size 字段扩展为更大范围的 OOB
受限写写入函数指针低位部分控制流劫持
堆地址泄露结合 OOB 读泄露其他对象完整 ASLR 绕过
UAF(不可控内容)堆喷射占位构造的对象可控内容的 UAF

转换策略的核心思路

  1. 信息泄露优先:在尝试任何写操作前,先建立稳定的地址泄露
  2. 原语放大:将受限原语通过堆布局或对象伪造扩展为更强原语
  3. 避免副作用:转换过程应避免破坏关键数据结构导致系统崩溃

3. 用户态可利用性评估

3.1 关注点

  • 是否存在稳定的信息泄露(影响 ASLR、对象地址推断)
  • 是否存在稳定的写原语(决定影响面上限)
  • 目标进程的权限与隔离(应用进程 vs 系统进程;SELinux domain)

3.2 信息泄露技术分类

根据泄露来源和利用方式,可将信息泄露技术分为以下类型:

直接泄露

  • 未初始化内存读取:新分配的缓冲区未清零,包含残留数据
  • 格式化字符串:控制格式化参数导致栈内容泄露
  • 越界读:数组索引可控导致的邻接数据读取

侧信道泄露

  • 时序侧信道:通过操作耗时差异推断内存布局或缓存状态
  • 错误消息泄露:异常处理路径暴露的地址信息

结构化泄露

  • 对象指针泄露:通过序列化、日志或调试接口泄露对象地址
  • 元数据泄露:堆块头部、vtable 指针等管理结构的泄露

3.3 与现代缓解的关系

ASLR 绕过评估

  • ASLR 提高地址预测成本,信息泄露会削弱其效果
  • 评估维度:是否存在独立的泄露原语?泄露的是代码段、堆还是栈地址?泄露精度如何?

CFI/PAC 绕过评估

CFI(Control Flow Integrity)和 PAC(Pointer Authentication)显著提升控制流劫持成本:

  • CFI 绕过评估点

    • 目标进程是否启用 CFI?(检查编译选项或二进制特征)
    • 间接调用点的类型签名是否足够严格?
    • 是否存在 CFI 未覆盖的间接跳转(如 JIT 代码、汇编片段)?
    • 是否可转向"数据流攻击"绕过 CFI(不劫持控制流,直接篡改关键数据)
  • PAC 绕过评估点(ARM64 设备):

    • PAC 密钥的作用域(每进程 vs 全局)
    • 是否存在 PAC 签名/验证不一致的代码路径
    • 是否可利用签名后的指针进行重放
    • 侧信道是否可用于推断或伪造 PAC

MTE 对利用稳定性的影响

MTE(Memory Tagging Extension)在 Android 14+ 的部分设备上启用,对内存安全漏洞的利用产生显著影响:

  • 标签检查机制:每个内存分配携带 4-bit 标签,访问时硬件校验标签匹配
  • 对 UAF 的影响:释放后对象获得新标签,旧指针访问大概率触发 SIGSEGV
  • 对堆溢出的影响:相邻对象标签不同,越界访问被检测概率约 93.75%(15/16)
  • 利用稳定性评估
    • MTE 模式(sync/async)影响检测时机
    • 标签碰撞概率(1/16)意味着利用需要更多尝试或侧信道
    • 评估时需明确目标设备是否启用 MTE 及其配置模式

4. 内核态可利用性评估

内核态的关键差异在于:攻击面更依赖设备与驱动实现,且缓解机制与配置差异更大。

4.1 关注点

  • 触发是否可由低权限稳定达成(入口:syscall/ioctl/netlink 等)
  • 原语强度与可重复性
  • 是否被 seccomp/SELinux/进程拆分显著限制

4.2 现代内核利用链步骤

典型的 Android 内核利用链包含以下阶段:

  1. 触发阶段:从用户态可达的入口触发漏洞

    • 系统调用(syscall)
    • 设备文件 ioctl
    • Netlink 消息
    • Binder 通信
  2. 堆布局控制:通过堆喷射将目标对象放置到可预测位置

    • 选择与漏洞对象同大小的 kmalloc cache
    • 使用可控内容的内核对象进行占位
  3. 信息泄露:获取内核基址或目标对象地址

    • 泄露 KASLR 偏移
    • 泄露目标内核结构地址
  4. 原语构建:将初始能力转化为 AAR/AAW

    • 利用 UAF 构造伪造对象
    • 利用 OOB 修改相邻对象指针
  5. 权限提升:修改进程凭证或覆盖关键内核数据

    • 修改 task_struct 中的 cred 指针
    • 覆盖 selinux_enforcing
    • 修改 addr_limit(旧版本内核)

4.3 Cross-Cache Attack

当目标对象和可控对象不在同一 kmalloc cache 时,cross-cache attack 提供了一种跨 slab 利用的方法:

基本原理

  • Linux 内核的 SLUB 分配器将相同大小的对象放入同一 cache
  • 不同大小对象位于不同 cache,直接堆喷射无法占位
  • Cross-cache 利用页级回收机制:当整个 slab 页被释放后,页面可被其他子系统重新分配

利用步骤概述

  1. 大量分配目标对象,填满多个 slab 页
  2. 释放特定 slab 页上的所有对象,使整页可被回收
  3. 触发页面分配的其他路径(如 pipe buffer、sk_buff)重新获得该页
  4. 此时可通过新路径控制原目标对象所在内存

msg_msg 利用技术

msg_msg 是内核中常用的利用对象,因其具有以下特性:

  • 可从用户态通过 msgsnd() 系统调用分配
  • 大小在一定范围内可控(48 字节头部 + 用户数据)
  • 头部包含链表指针,可用于信息泄露或伪造
  • msgrcv() 可读取数据,配合越界读可泄露相邻内存

4.4 竞态条件利用的稳定化

竞态条件(Race Condition)漏洞的利用面临时序窗口小、成功率低的问题。以下技术可提高稳定性:

增大竞态窗口

  • 利用 userfaultfd 在页错误时暂停内核执行(需要特权,受限于 Android 配置)
  • 利用 FUSE 文件系统延迟内核的文件访问
  • CPU 亲和性绑定,减少调度引入的不确定性

提高命中率

  • 多线程并发触发,增加竞态发生概率
  • 统计分析确定最佳延迟参数
  • 减少系统负载,降低调度干扰

检测成功条件

  • 设计可检测的竞态成功标志
  • 失败时安全退出,避免系统崩溃
  • 实现重试逻辑

4.5 输出形式

更可复用的输出往往是:

  • 可利用性分级(高/中/低)与理由
  • 被哪个缓解机制阻断(或未阻断)的证据
  • 修复验证(补丁前后行为变化)

5. 实际案例分析框架

分析真实 CVE 利用链时,可采用以下结构化框架:

5.1 分析框架模板

## CVE-XXXX-XXXXX 分析

### 1. 漏洞概述
- 漏洞类型:[UAF/OOB/整数溢出/竞态条件/...]
- 影响组件:[内核子系统/驱动/用户态服务]
- 触发条件:[所需权限/入口点]
- 影响版本:[受影响的 Android/内核版本]

### 2. 漏洞成因
- 根本原因分析
- 触发路径描述
- 代码片段标注(如有)

### 3. 利用链分析
- 原语类型与强度
- 信息泄露方法
- 缓解绕过策略
- 最终影响达成方式

### 4. 缓解措施影响
- KASLR/ASLR:[是否被绕过/如何绕过]
- SELinux:[是否限制/限制程度]
- seccomp:[是否阻断入口]
- MTE/CFI/PAC:[是否生效]

### 5. 修复分析
- 补丁内容概述
- 修复是否完整
- 是否存在变种风险

6. 复现与修复验证

6.1 复现最小化

  • 固定输入与环境
  • 缩小到最小触发路径
  • 记录可重复证据(日志、堆栈、状态差异)

6.2 补丁差异分析方法

系统化的补丁分析流程:

获取补丁

bash
# 从 AOSP 获取特定提交
git log --oneline --all --grep="CVE-XXXX-XXXXX"
git show <commit-hash>

# 或从 Android Security Bulletin 链接获取

差异分析要点

  • 补丁修改了哪些代码路径?
  • 修复策略是什么?(添加检查、修改生命周期、移除功能)
  • 是否引入新的攻击面?
  • 修复是否完整覆盖所有变种?

补丁分类

  • 边界检查:添加长度/索引验证
  • 生命周期修复:修正引用计数、添加锁保护
  • 输入验证:过滤非法输入
  • 逻辑修复:修正算法或状态机错误

6.3 回归测试策略

功能回归

  • 正常业务路径是否仍然工作
  • 边界情况是否正确处理
  • 性能是否有明显下降

安全回归

  • 补丁是否可被绕过
  • 是否引入新漏洞
  • 相似代码模式是否存在同类问题

测试方法

  • 构造补丁前可触发的 PoC
  • 在补丁后环境运行 PoC,验证漏洞被修复
  • 运行正常功能测试套件
  • 使用 fuzzer 对修改区域进行针对性测试

6.4 验证补丁

  • 补丁前:可稳定触发
  • 补丁后:触发路径被修复或被硬化拦截
  • 回归检查:正常功能路径不受影响

参考(AOSP)