用侧信道读取特权内存(上)
字数 1620 2025-08-20 18:17:07
侧信道攻击:利用CPU推测执行漏洞读取特权内存
概述
本文详细介绍了三种利用现代CPU推测执行特性的侧信道攻击方法,这些漏洞被统称为"幽灵"(Spectre)和"熔断"(Meltdown)漏洞。攻击者可以利用这些漏洞跨安全边界读取特权内存,包括内核内存和其他进程的内存。
漏洞背景
现代CPU为了提高性能,采用了推测执行技术,即在分支条件尚未确定时就预先执行可能需要的指令。如果推测错误,CPU会丢弃这些执行结果,但某些副作用(如缓存状态变化)可能不会被完全清除,从而形成侧信道。
三种变体
变体1:边界检查旁路 (CVE-2017-5753)
原理:
- CPU在数组边界检查完成前就推测性地执行数组访问
- 即使检查失败导致推测执行被丢弃,访问过的内存仍会留在缓存中
- 通过测量缓存访问时间可以推断出越界读取的数据
攻击步骤:
- 诱使CPU执行包含边界检查的代码
- 确保边界检查所需的数据不在缓存中,延长推测窗口
- 通过越界访问读取敏感数据
- 使用缓存时序分析推断读取的数据
防御:
- 在敏感边界检查后插入序列化指令
- 编译器插入"lfence"指令阻止推测执行
变体2:分支目标注入 (CVE-2017-5715)
原理:
- 利用间接分支预测器污染攻击
- 攻击者训练分支预测器使其在受害者上下文中预测错误的目标地址
- 错误预测导致受害者执行攻击者控制的代码路径
技术细节:
- 分支预测器使用源地址低12位和分支历史缓冲区(BHB)状态
- BHB混合了最近29个分支的信息
- 攻击者可以精心构造分支序列来影响BHB状态
攻击步骤:
- 识别受害者代码中的间接分支点
- 通过特定分支序列训练分支预测器
- 刷新目标地址缓存行以延长推测窗口
- 诱导受害者执行时分支到攻击者控制的地址
- 通过缓存侧信道泄露数据
防御:
- 使用retpoline技术替换间接分支
- 启用间接分支限制推测(IBRS)
- 启用单线程间接分支预测器(STIBP)
变体3:流氓数据缓存加载 (CVE-2017-5754)
原理:
- CPU在权限检查完成前就推测性地加载数据
- 即使检查失败,加载的数据仍会留在缓存中
- 通过缓存时序分析可以推断出特权内存的内容
攻击步骤:
- 诱使CPU访问特权内存地址
- 确保权限检查所需的数据不在缓存中
- 通过用户空间地址访问缓存状态
- 测量访问时间推断特权内存内容
防御:
- 内核页表隔离(KPTI)
- 在敏感权限检查后插入序列化指令
实际攻击示例
内核攻击(eBPF)
攻击流程:
- 创建两个eBPF程序:
- 第一个用于定位prog_map的内核地址
- 第二个用于实际数据泄露
- 通过用户空间内存映射建立侧信道
- 利用边界检查旁路执行越界读取
- 通过缓存时序分析推断内核内存内容
优化技巧:
- 使用2^15个相邻用户空间映射覆盖大地址范围
- 利用物理页面映射相同的特性减少检测次数
- 通过二分法逐步缩小地址搜索范围
处理器内部机制
分支预测器细节
通用分支预测器:
- 使用源地址低31位的XOR折叠作为索引
- 存储部分目标地址信息
- 每个源地址对应一个预测目标
间接调用预测器:
- 使用源地址低12位和BHB状态
- 每个源地址可存储多个目标
- 依赖最近程序行为进行预测
分支历史缓冲区(BHB):
- 记录最近29个分支的信息
- 更新算法混合源地址和目标地址的特定比特
- 用于提高间接分支预测准确性
防御措施总结
- 微代码更新:CPU厂商提供的补丁可以限制推测执行
- 编译器防护:
- 插入序列化指令(lfence)
- 使用retpoline技术
- 敏感检查后添加屏障
- 操作系统防护:
- 内核页表隔离
- 减少攻击面(如限制eBPF)
- 运行时缓解:
- 禁用超线程
- 限制侧信道精度(如降低时钟精度)
结论
这些漏洞揭示了现代CPU性能优化与安全之间的根本矛盾。虽然完全修复这些漏洞会影响性能,但通过组合硬件、软件和操作系统层面的防护措施,可以显著降低攻击风险。理解这些攻击的原理对于开发安全系统和编写安全代码至关重要。