用侧信道读取特权内存(上)
字数 1620 2025-08-20 18:17:07

侧信道攻击:利用CPU推测执行漏洞读取特权内存

概述

本文详细介绍了三种利用现代CPU推测执行特性的侧信道攻击方法,这些漏洞被统称为"幽灵"(Spectre)和"熔断"(Meltdown)漏洞。攻击者可以利用这些漏洞跨安全边界读取特权内存,包括内核内存和其他进程的内存。

漏洞背景

现代CPU为了提高性能,采用了推测执行技术,即在分支条件尚未确定时就预先执行可能需要的指令。如果推测错误,CPU会丢弃这些执行结果,但某些副作用(如缓存状态变化)可能不会被完全清除,从而形成侧信道。

三种变体

变体1:边界检查旁路 (CVE-2017-5753)

原理

  • CPU在数组边界检查完成前就推测性地执行数组访问
  • 即使检查失败导致推测执行被丢弃,访问过的内存仍会留在缓存中
  • 通过测量缓存访问时间可以推断出越界读取的数据

攻击步骤

  1. 诱使CPU执行包含边界检查的代码
  2. 确保边界检查所需的数据不在缓存中,延长推测窗口
  3. 通过越界访问读取敏感数据
  4. 使用缓存时序分析推断读取的数据

防御

  • 在敏感边界检查后插入序列化指令
  • 编译器插入"lfence"指令阻止推测执行

变体2:分支目标注入 (CVE-2017-5715)

原理

  • 利用间接分支预测器污染攻击
  • 攻击者训练分支预测器使其在受害者上下文中预测错误的目标地址
  • 错误预测导致受害者执行攻击者控制的代码路径

技术细节

  • 分支预测器使用源地址低12位和分支历史缓冲区(BHB)状态
  • BHB混合了最近29个分支的信息
  • 攻击者可以精心构造分支序列来影响BHB状态

攻击步骤

  1. 识别受害者代码中的间接分支点
  2. 通过特定分支序列训练分支预测器
  3. 刷新目标地址缓存行以延长推测窗口
  4. 诱导受害者执行时分支到攻击者控制的地址
  5. 通过缓存侧信道泄露数据

防御

  • 使用retpoline技术替换间接分支
  • 启用间接分支限制推测(IBRS)
  • 启用单线程间接分支预测器(STIBP)

变体3:流氓数据缓存加载 (CVE-2017-5754)

原理

  • CPU在权限检查完成前就推测性地加载数据
  • 即使检查失败,加载的数据仍会留在缓存中
  • 通过缓存时序分析可以推断出特权内存的内容

攻击步骤

  1. 诱使CPU访问特权内存地址
  2. 确保权限检查所需的数据不在缓存中
  3. 通过用户空间地址访问缓存状态
  4. 测量访问时间推断特权内存内容

防御

  • 内核页表隔离(KPTI)
  • 在敏感权限检查后插入序列化指令

实际攻击示例

内核攻击(eBPF)

攻击流程

  1. 创建两个eBPF程序:
    • 第一个用于定位prog_map的内核地址
    • 第二个用于实际数据泄露
  2. 通过用户空间内存映射建立侧信道
  3. 利用边界检查旁路执行越界读取
  4. 通过缓存时序分析推断内核内存内容

优化技巧

  • 使用2^15个相邻用户空间映射覆盖大地址范围
  • 利用物理页面映射相同的特性减少检测次数
  • 通过二分法逐步缩小地址搜索范围

处理器内部机制

分支预测器细节

通用分支预测器

  • 使用源地址低31位的XOR折叠作为索引
  • 存储部分目标地址信息
  • 每个源地址对应一个预测目标

间接调用预测器

  • 使用源地址低12位和BHB状态
  • 每个源地址可存储多个目标
  • 依赖最近程序行为进行预测

分支历史缓冲区(BHB)

  • 记录最近29个分支的信息
  • 更新算法混合源地址和目标地址的特定比特
  • 用于提高间接分支预测准确性

防御措施总结

  1. 微代码更新:CPU厂商提供的补丁可以限制推测执行
  2. 编译器防护
    • 插入序列化指令(lfence)
    • 使用retpoline技术
    • 敏感检查后添加屏障
  3. 操作系统防护
    • 内核页表隔离
    • 减少攻击面(如限制eBPF)
  4. 运行时缓解
    • 禁用超线程
    • 限制侧信道精度(如降低时钟精度)

结论

这些漏洞揭示了现代CPU性能优化与安全之间的根本矛盾。虽然完全修复这些漏洞会影响性能,但通过组合硬件、软件和操作系统层面的防护措施,可以显著降低攻击风险。理解这些攻击的原理对于开发安全系统和编写安全代码至关重要。

侧信道攻击:利用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性能优化与安全之间的根本矛盾。虽然完全修复这些漏洞会影响性能,但通过组合硬件、软件和操作系统层面的防护措施,可以显著降低攻击风险。理解这些攻击的原理对于开发安全系统和编写安全代码至关重要。