
在现代计算的舞台上,安全问题已经超出了操作系统(OS)漏洞和软件错误的范围。在抽象层的深处,我们的处理器已经发展出了复杂的微架构——流水线、缓存、缓冲区和执行引擎——这些都是为追求最大性能而设计的。讽刺的是,这些特性引入了新的和微妙的安全风险,促成了所谓的微架构攻击。这种攻击利用了同时执行的应用程序之间微架构状态的非预期共享和泄露,有时甚至在完美安全的软件中也会发生。
这篇综合性博客文章旨在解密微架构攻击,涵盖以下内容:
无论您是初学者、研究人员、软件开发人员还是网络安全专业人士,这本指南都将帮助您了解这些强大的现代攻击以及如何防御它们。
微架构攻击是利用处理器硬件低级设计中的非预期信息泄漏的攻击技术。
与典型的软件漏洞不同,微架构攻击不需要程序或操作系统中的程序错误。相反,它们利用现代CPU尝试最大化性能的方式,比如共享缓存或重新排序指令。
现代CPU在应用程序甚至虚拟机之间共享关键硬件结构,例如:
由于这些结构并未完美地隔离,一个进程通常可以观察或推断另一个进程的效果。攻击者利用这种隐式共享通过观察间接的物理效果(如内存访问时间的微小变化)来提取秘密。
主要分为两个大类:
隐蔽通道创建了两方(发送方和接收方)之间不在系统设计之中的通信路径。一个应用程序调节某些共享资源,而另一个应用程序观察这些修改以重建消息。
示例:
侧信道攻击泄露敏感信息而无需直接通讯。相反,它们利用了受害者活动“溢出”的信息。
示例:
两种通道都能让一个进程推断关于另一个进程的信息——有时甚至跨容器、虚拟机或用户边界。
异构计算系统由一个平台上的多种处理器类型(通用CPU、GPU、FPGA、AI加速器等)构成,通常共享一些内存和/或微架构状态。
假设GPU和CPU共享一个缓存区域。运行在GPU上的低特权进程可以“填充”缓存,而运行在CPU上的高特权进程可能在其内存访问中无意间透露出秘密。然后,低特权进程可以观察变化,推断受保护的信息。
RISC-V是一个开源、模块化的指令集架构,迅速在研究和商用嵌入式系统中流行起来。尽管在x86和ARM上微架构攻击研究非常深入,最新研究显示RISC-V同样易受攻击。
**关键结论:**没有指令集或开源硬件是免疫的——如果没有专门的硬化措施,任何具有共享微架构的CPU都可能是脆弱的。
一个新的领域:堆栈引擎攻击(来源)
如果攻击者和受害者共享一个CPU,通过执行精心设计的堆栈操作并观察结果的计时,攻击者可以推断出受害者最近进行了哪种类型的堆栈活动。
Spectre和Meltdown(2018)让全世界明白微架构攻击不再是理论,它们影响着数十亿的计算机。
[受害者进程] [攻击者进程]
在秘密数据上执行 填充缓存,计时访问
的指令 解码因受害者活动导致的变化
---[物理共享缓存]---
Prime+Probe是一种经典的攻击,过程如下:
就像把硬币放在剧院所有的座位上(prime),然后让别人进来(victim),再检查哪些座位是空的(probe)——无需直接观察他们即可揭示他们坐在哪里。
最近攻击目标是堆栈引擎优化:
需要强调的是:在生产系统上执行真实攻击是非法的,未经同意。然而,在自己的测试机器上进行性能测量以揭示时间侧信道是可行的,用于研究和防御。
简单时间测量探头,检查缓存共享(例如,在虚拟机中)。
#!/bin/bash
buffer=/tmp/testmem
size=1024000
# 分配一个大缓冲区
dd if=/dev/urandom of="$buffer" bs=1K count=1000
# 反复访问内存以“填充”缓存
function prime_cache {
for i in $(seq 1 $size); do
tail -c +$i "$buffer" | head -c 1 >/dev/null
done
}
# 计时一次访问
function time_access {
/usr/bin/time -f "%e" dd if="$buffer" of=/dev/null bs=1K count=1000 2>&1
}
echo "填充缓存..."
prime_cache
echo "计时读取访问..."
time_access
# 现在让另一进程运行一个内存密集型的负载并重复
# 比较以观察是否时间变化,这可能表明存在缓存争用!
将重大变化解释为与其他进程的缓存争用的证据——可能启用Prime+Probe攻击。
使用Python的time模块和numpy数组进行更精确的方法,以重复内存访问模式。
import numpy as np
import time
# 分配一个大数组
arr = np.zeros((1024 * 1024 * 10,), dtype=np.uint8)
def probe_access():
ts = time.time()
# 访问所有元素以强制缓存加载
for i in range(0, len(arr), 64):
arr[i] += 1
te = time.time()
print(f"访问时间:{te - ts:.6f} 秒")
# 首次运行:可能是冷的(可能缓存未命中)
probe_access()
# 第二次运行:缓存可能热的
probe_access()
现在,在第二个终端(或单独的进程)中,运行一个内存密集型脚本(例如,stress-ng或类似),它将驱逐缓存行。再次运行probe_access(),观察时间增长。
如果您在另一进程运行后看到访问时间增加,这意味着您的系统缓存对时间攻击是易感的。
鉴于微架构攻击的持久性,安全防护人员可以做些什么?
# 检查与刷新相关的CPU功能
grep . /proc/cpuinfo | grep -E 'flush|clflush|clwb'
# 可能显示:clflush,表示可用指令用于软件清除缓存
许多CPU供应商正在引入诸如:
然而,大多数部署的CPU仍然易受攻击,特别是在云环境或复杂硬件中。
微架构攻击不再是“理论上的奇珍异宝”。随着我们的处理器更优化——更共享——其内部设计的细微之处成了熟练攻击者手中强大的工具。
特别是在异构系统中,CPU、GPU和加速器共享微架构状态,隐蔽和侧信道不仅可能——而且普遍存在。最近针对RISC-V CPU和堆栈引擎的攻击展示了这些风险的普遍性和持续相关性,即使是针对新架构和优化。
保持更新,测试你自己的环境,并要求更好的隔离——在软件和硬件中。
本文仅用于教育目的。请始终在安全、受控的环境中测试。