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 |
转换策略的核心思路:
- 信息泄露优先:在尝试任何写操作前,先建立稳定的地址泄露
- 原语放大:将受限原语通过堆布局或对象伪造扩展为更强原语
- 避免副作用:转换过程应避免破坏关键数据结构导致系统崩溃
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 内核利用链包含以下阶段:
触发阶段:从用户态可达的入口触发漏洞
- 系统调用(syscall)
- 设备文件 ioctl
- Netlink 消息
- Binder 通信
堆布局控制:通过堆喷射将目标对象放置到可预测位置
- 选择与漏洞对象同大小的 kmalloc cache
- 使用可控内容的内核对象进行占位
信息泄露:获取内核基址或目标对象地址
- 泄露 KASLR 偏移
- 泄露目标内核结构地址
原语构建:将初始能力转化为 AAR/AAW
- 利用 UAF 构造伪造对象
- 利用 OOB 修改相邻对象指针
权限提升:修改进程凭证或覆盖关键内核数据
- 修改 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 页被释放后,页面可被其他子系统重新分配
利用步骤概述:
- 大量分配目标对象,填满多个 slab 页
- 释放特定 slab 页上的所有对象,使整页可被回收
- 触发页面分配的其他路径(如 pipe buffer、sk_buff)重新获得该页
- 此时可通过新路径控制原目标对象所在内存
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 补丁差异分析方法
系统化的补丁分析流程:
获取补丁:
# 从 AOSP 获取特定提交
git log --oneline --all --grep="CVE-XXXX-XXXXX"
git show <commit-hash>
# 或从 Android Security Bulletin 链接获取差异分析要点:
- 补丁修改了哪些代码路径?
- 修复策略是什么?(添加检查、修改生命周期、移除功能)
- 是否引入新的攻击面?
- 修复是否完整覆盖所有变种?
补丁分类:
- 边界检查:添加长度/索引验证
- 生命周期修复:修正引用计数、添加锁保护
- 输入验证:过滤非法输入
- 逻辑修复:修正算法或状态机错误
6.3 回归测试策略
功能回归:
- 正常业务路径是否仍然工作
- 边界情况是否正确处理
- 性能是否有明显下降
安全回归:
- 补丁是否可被绕过
- 是否引入新漏洞
- 相似代码模式是否存在同类问题
测试方法:
- 构造补丁前可触发的 PoC
- 在补丁后环境运行 PoC,验证漏洞被修复
- 运行正常功能测试套件
- 使用 fuzzer 对修改区域进行针对性测试
6.4 验证补丁
- 补丁前:可稳定触发
- 补丁后:触发路径被修复或被硬化拦截
- 回归检查:正常功能路径不受影响
参考(AOSP)
- https://source.android.com/docs/security/overview/kernel-security — 内核侧安全机制与加固方向入口(用于对照"链路被哪层阻断")。
- https://source.android.com/docs/security/app-sandbox — 应用沙盒与纵深防御(seccomp/SELinux 等)官方入口。
- https://source.android.com/docs/security/features/selinux — Android SELinux 的官方总览入口(域/策略/版本演进)。