访问时间快就能获取到secret的原因是因为漏洞导致&array2[array1[malicious_x]*512]这个地址中的数据已经在cpu缓存中了,同时在循环中清空了训练数(1~15)在cpu中的缓存(见图2.3-3)。Cpu访问array2时候会先访问cpu缓存中是否有,缓存没有数据再去读内存中数据,这是cpu缓存存在的意义,因为传统的内存访问速度慢,用这种缓存机制可以提升cpu的运算速度。然后我们的time2其实就是访问array2数据的时间差,如果这个时间差小于一个阈值(这个阈值在不同cpu不同系统不同解析器中肯定是不一样的),而且会有个时间上的规律,如果time2比这个阈值小于或者等于,就可以认为这个时候的array2的的访问时间比没在cpu缓存中的访问时间快,因为1~15在cpu缓存中被清空了,只剩下了留在cpu缓存中的malicous_X,如果他的访问时间快,那么这个时候的array2中的下标中就是我们的要们要找的secret了。
寻找secret的方法是array2[mix_i*512]中的mix_i就是我们要找的secret,因为array2[value(T) * 512],只不过需要时间上的判断到底哪个mix_i是secret,如果命中,给score打分加一,然后做了命中的筛选,可以看到高命中打分大于=2倍低命中加5,或者只有最高命中score=2时候就代表命中率达到我们需求了。
四 Javascript 攻击chrome上面的攻击过程是可以通过浏览器加载js脚本实现获取私有内存的攻击,当一个浏览器网页里嵌入攻击js恶意代码,就可以获取到浏览器中的私有数据,比如个人的登陆凭证密码等。在原英文版中提到的是在chrome浏览器中实现了这次攻击。而chrome中使用的是v8引擎,他在执行之前把javascript编译成了机器码来提高性能。
经过分析逻辑上应用上基本跟Spectre是一样的。index 先放入比simpleByteArray.length小的数,然后放入malicious_x,让cpu预测以为malicious_X比length小,然后推测执行后面的code,后面的计算和赋值只是放到了cpu的缓存中了,并没有真正的去执行,可以在判断后打印malicious_X试一下,肯定是没办法打印malicious_x的值的,这个原理跟上面是一样的,下面让我们通过结合汇编来分析具体的漏洞细节。
首先看看触发预测执行的函数
if (index < simpleByteArray.length)
{
index = simpleByteArray[index | 0];
index = (((index * TABLE1_STRIDE)|0) & (TABLE1_BYTES-1))|0;
localJunk ^= probeTable[index|0]|0;
}
V8 编译机器码后:
1 cmpl r15,[rbp-0xe0] ;
对比index和simpleByteArray.length的大小
2 jnc 0x24dd099bb870 ;
如果 index >= length后的分支
3 REX.W leaq rsi,[r12+rdx*1] ;
设置 rsi=r12+rdx= simpleByteArray 第一个字节的地址类似我们上面的ADDR(T)
4 movzxbl rsi,[rsi+r15*1] ;
从 rsi+r15 (= 基地址+index) 读取数据
5 shll rsi, 12 ;
rsi * 4096= TABLE1_STRIDE,使他左移12字节
6 andl rsi,0x1ffffff ;
这个是,清空rsi的前三位为0,目的是放入probeTable数据不能超过probeTable的length, 这里的probeTable跟Spectre中的array2一样的,不能超过probeTable(array2)中的长度,因为异常了就没办法推测执行把我们的malicious_X放入到cpu缓存中了
7 movzxbl rsi,[rsi+r8*1] ;
从probeTable里读数据,跟读array2一样
8 xorl rsi,rdi ;
XOR the read result onto localJunk
把读到的结果和localjunk做异或运算
9 REX.W movq rdi,rsi ;
再把localjunk 放到rdi寄存器中
五 总结:Spectria攻击利用了cpu的预测执行导致了提前把私有数据放到了cpu缓存中,但是因为保护机制并没有写入数据的能力,同时我们并没有直接读取cpu缓存中数据的权限,不过可以通过计算访问数组的时间上做判断获取到下标中的之前放入的私有数据。同样对于浏览器来说,漏洞触发原理跟C语言中的poc是一样的,只不过因为javascript语言是脚本语言有很多不足,需要换种形式去执行漏洞,比如可以看到每个数组下标都有和0去作或的运算,结果还是它本身,只不过在做数据类型转换成int了,不然javascript的数组下标是不能获取char类型的会出错的。