检测地址(也是分析的来源):http://xlab.tencent.com/special/spectre/spectre_check.html
首先判断是否启用了window.SharedArrayBuffer,如果没有启用的话就直接输出不容易受到攻击
1 | function main() |
假如是chrome可以在地址栏输入下面的进行开启和关闭(google为了防止利用直接云端控制将这个flag默认关闭了——来自tk微博评论)
chrome://flags/#shared-array-buffer
关闭状态
开启状态
开启后即可检测出存在风险,并在16M缓存的时候可以成功泄露
第一步
新建一个Worker
1 | const worker = new Worker('/special/spectre/js/worker.js'); |
其中worker代码如下:
1 | self.addEventListener('message', function (event) |
其中message事件是处理postMessage的
Atomics.add方法原型
Atomics.add(typedArray, index, value)
更多请看
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/add
第二步
新建了一个SharedArrayBuffer,并作为普通Array的参数new了一下,之后postMessage触发Worker
1 | const sharedBuffer = new SharedArrayBuffer(10 * Uint32Array.BYTES_PER_ELEMENT); |
接下来是new了一个 num * 1024 * 1024的evictionBuffer(num一开始是8,失败后就将num*2再尝试利用,最多是256,即256M的缓存测试),利用这个buffer再new一个DataView,之后flush掉evictionView
1 | var offset = 64; |
之后初始化asmModule这个类(其中probeTable是0x3000000大小),并调用init方法
var asm = asmModule(this,{},probeTable.buffer)
asm.init();
init是初始化simpleByteArray
1 | function init() |
这是初始化后的结果
设置simpleByteArray偏移0x2200000+i的值分别为88,117,97,110,119,117(即Xuanwu的ascii码)
这是为了模拟在内存中存储的密码等信息
1 | var simpleByteArray = new Uint8Array(probeTable.buffer); |
第三步
最后通过侧信道的攻击方式“读取”0x2200000+i那边的内存,跟我们之前写进去的比较,如果“读”出来的是正确的,那说明我们可以成功泄露了
1 | for(var i=0;i<data_array.length;i++) |
我们具体看看readMemoryByteWrapper,实际这个函数是调用readMemoryByte进行“读取”,假如读取不成功便尝试继续读取
readMemoryByte
我们重点看下readMemoryByte函数,关键是这两个循环
1 | for (var j = 29; j >= 0; j--) |
对于第一个循环我们关注asm.vul_call(x,j);
1 | function vul_call(index, sIndex) |
这个其实跟meldown的利用方式是相似的,简化一下代码
1 | function vul_call(index, sIndex) |
首先读取simpleByteArray里面的值,作为index(索引)
1 | index = simpleByteArray[index]; |
之后将probeTable利用这个索引跟junk异或,这样probeTable[index]就被缓存下来了
1 | junk = (junk ^ (probeTable[index])); |
接下来看第二个循环,其中TABLE1_STRIDE为0x1000,跟上面是遥相呼应
1 | for (var i = 0; i < 256; i++) |
一旦读取出来probeTable[(mix_i * TABLE1_STRIDE)];的值的时间小于CACHE_HIT_THRESHOLD(就是可以去区分从cached和uncached读取时间的阀值,大于它就是uncached的,否则是cached)
一旦是cached的,说明当前的mix_i就是侧信道泄露出来的值,即Array中的这些值[88,117,97,110,119,117]
而results[mix_i]++就是储存100次尝试中成功泄露该位的次数
防护建议
禁用SharedArrayBuffer
既然都禁用这个了,那么含有这个利用的关键词就可以拦截了:
SharedArrayBuffer
references
http://xlab.tencent.com/special/spectre/spectre_check.html
https://segmentfault.com/a/1190000006061528