在下面的代码中,我们有一个规模为104096的数组,首先访问它的两个元素array[34096],array[74096],这样,有这两个元素的页就被cache了。然后从array[04096]到array[94096]的值,测量读取内存花费的时间。代码中,1在内存读之前读CPU的时间戳(TSC),2在内存读之后读计时器。它们的差就是花费在内存读上的时间(CPU周期)。
需要注意,在cache block层次,cache过程已经完成,但是在byte层次还没有。一个典型的cache block大小是64字节。
我们使用array[k
4096],所以程序中用到的元素没有两个会在同一个cache block中

使用下列命令编译并运行

从结果可以看到,array[34096]和array[74096]的访问速度远高于其他元素。

假设现在有个漏洞函数使用secret value作为索引从数组中加载特定的值,同时假设secret value不能从外面访问。我们的目标是使用侧信道来获得这个secret value,我们将会使用的技术是FLUSH+RELOAD.

整个技术包括三步:
1.从cache memory中FLUSH整个数组,确保数组没有被cached
2.调用victim function,它会基于secret value访问数组的一个元素。这个动作会导致相应的数组元素被缓存
3.RELOAD整个数组,测量每个元素reload时的时间,如果某个特定的元素load的时间很快,它很有可能就是已经在缓存中的元素了。这个元素一定就是victim function访问的元素。因此,我们可以找到secret value究竟是什么。

下面的程序使用FLUSH+RELOAD技术找到包含在变量secret中的一字节的secret value
由于1字节的secret有256种可能,我们需要把每个值映射到一个数组元素。最简单的方法就是定义一个有256个元素的数组(array[256])。不过这不行。caching是在block层次完成的,而不是byte层次。如果array[k]被访问了,那么包括这个元素在内的一个block的元素都被缓存了。因此,在array[k]的邻接元素也会被缓存,这样就很难推断secret是什么了。为了解决这个问题,我们创建一个2564096字节的数组。在RELOAD步骤用到的每个元素是array[k4096],因为4096比典型的cache block size要大(64字节),所以不会有两个不同的元素array[i4096]和array[j4096]在同一个cache block中
既然array[04096]可能会和邻接的变量在同一个cache block中。因为我们应该避免在FLUSH+RELOAD方法中使用array[04096].
在程序中我们对所有的k值使用array[k*4096+DELTA],其中DELTA被定义为常量1024

编译并执行

成功了

内存隔离memory isolation是系统安全的基础,在大多数操作系统中,kernel memory并不是对use-space程序直接可访问的,这个隔离是通过处理器的一个supervisor bit实现的,它定义了kernel的一个memory page是否可以被访问。当cpu进入到kernel space时,这个bit会被置位,当其到user space时会被clear。通过这一特性,kernel memory可以被安全映射到每个进程的地址空间,所以当一个user-level的程序陷入kernel时,页表就不需要改变。然而,这种隔离特性被meltdown打破了,它允许非特权的user-level程序读任意kernel memory

为了简化攻击,我们在kernel space放一个secret data,我们将演示user-level program是如何找出secret data是什么的
我们使用kernel module存储secret data。
代码如下

有两个条件需要满足,否则meltdown攻击很难成功。
1.我们需要知道secret data的地址。在2中,kernel module将该地址保存到了kernel message buffer,这是公开可访问的,我们从其中获取地址。在实际攻击中,攻击者不得不找到一个方法来获取地址,否则只能猜测
2.Secret data需要被cached,否则攻击者的成功率会下降。为了实现这一点,我们需要使用secret一次。我们创建一个data entry /proc/secret_data(3),这会为user-level program与kernel module交互提供一个window。
当一个user-level program从其中读取时,kernel module中的read_proc函数会被唤醒,在其中,secret 变量将被加载(1),因此也就被CPU cached了。需要注意,read_proc()不返回secret data到user space,所以不会泄露secret data。我们仍然需要通过meltdown攻击来获取secret。

Make,编译kernel module

使用insmod安装kernel module

安装后,使用dmesg命令从kernel message 缓冲区中找到secret data的地址

现在我们知道secret data的地址了,我们来看看是否可以直接根据地址获取secret。
在diamante第一行,将地址替换为实际的地址。然后编译并运算看看是否可以

可以看到从user-space是无法访问的

在meltdown攻击中,在访问kernel memory后我们需要做一些其他事情才不会让程序crash。访问禁止的memory location会报出SIGSEV 信号;如果程序自身不处理的话,操作系统将会处理并终止程序。这就是为什么我们上个程序crash了
在程序中定义我们自己的signal handler的一种方法是捕获由carastrophic events抛出的异常。
不像C++或其他高级语言,C没有提供对错误处理(或称之为异常处理)的直接支持,比如try/cache
然而我们使用sigsetjmp()和siglongjmp()模拟try/cache。
下面的代码可以看到,程序如何在关键异常(内存访问异常)出现时继续执行。

编译并执行结果如下

上面代码中的异常处理机制比较复杂,所以进一步解释一下,
准备一个signal handler:我们在2注册了一个SIGSEGV signal handler,所以当SIGSEGV signal被抛出时,handler function catch_segv()就会被调用
准备检查点checkpoint:在signal handler处理好exception后,它需要让程序从特定checkpoint之后继续执行。因此我们首先需要定义checkPoint,这是通过3中的sigsetjmp()实现的。
Sigsetjmp(jbuf,1)保存栈的上下文/环境到jbuf,稍后被siglongjmp()使用,当checkpoint准备好后它会返回0
退到检查点:当siglongjmp(jbuf,1)被调用时,存在jbuf变量中的状态被复制回处理器,以及从sigsethjmp函数的返回点再次开始计算,但是sufsetjmp函数的返回值是siglongjmp函数的第二个参数,在我们的例子中是1.因此,在异常处理时,程序会从else分支开始继续执行
触发异常:4的代码将会触发一个SIGSEGV信号,由于内存访问隔离的原因

以下面的代码为例,我们知道第3行代码会抛出异常,因为该地址属于kernel
因此,执行将会在第3行中断,第4行就得不到执行,所以number变量将是0

但我们从CPU外部看的时候,这个分析是对的。
但是,当从CPU内部看的时候,这就不是完全对的。
我们来看看微架构层面的执行序列。我们会在第3行成功地得到内核数据,而第4行以及其后的序列指令也会得到执行。这是由于现代CPU采用的重要的优化技术。叫做乱序执行(out-of-order execution)
不像以原始的顺序严格执行指令,现代高性能处理器允许乱序执行以充分利用执行单元。一条接一条执行指令的话,性能比较差而且没有充分利用好资源,比如即使当前执行单元是空闲状态,当前的指令仍然要等上一条指令执行完成。有了乱序执行的特性,CPU在资源可用的情况下就会执行。
以上面的代码为例,在微架构层面,第3行涉及到两个操作。
加载数据(通常是到寄存器),以及检查数据访问是否被允许。
如果数据直接在CPU cache中,那么第一个操作是很快的,而第二个操作可能需要等一会儿。为了避免等待,CPU将会继续执行第4行以及后续的指令,同时会进行访问的检查。这就是乱序执行。
在访问检查结束前,执行结果不会被commit。
在我们的例子中,如果范文检查失败,那么执行结果就被丢弃,就像从来没有发生过一样。这就是为什么从外部看,我们看不到第4行被执行了。

但是intel以及一些CPU制造商在设计乱序执行时犯了一个严重的错误。
当执行行为不应该发生时,他们会把乱序执行对寄存器、主存的影响全部擦除,所以对外没有可见的影响。但是他们忘记对CPU cache的影响了。
在乱序执行中,被访问的内存不仅写到了寄存器,同时也被存到了cache中,如果乱序执行被抛弃,那么该行为造成的cache的影响也需要被清除。但是在大多数CPU中,并没有做到这一点。
所以通过前面提到的侧信道技术,我们可以观察到这种现象。Meltdown聪明地利用这种现象找出在kernel memory中的secret
下面的代码可以演示乱序执行的效果。
1会造成异常,所以2不会被执行。但是由于乱序执行的原因,2会被CPU执行,虽然结果被会丢弃。不过,array[7*4096+DELTA]被CPU cache了
我们看看是否可以观察到这一点。

注意替换掉3中的地址为自己实际的地址

CPU在乱序执行中可以走多远依赖于访问检查有多慢,他们是并行进行的
这是一个典型的条件竞争问题
前面我们已经得到了array[74096+DELTA].事实上,使用FLUSH+RELOAD技术,我们检查array[i4096+DELTA]对于i=0,255的时间。如果我们发现只有array[k*4096+DELTA]在cache中,我们可以推断kernel_data是k。

乱序执行越快,我们就可以执行越多的指令,我们就越有可能观察到可以帮助我们获得secret的现象。
那么怎么让乱序执行更快呢?
我们代码中乱序执行的第一步是加载Kernel data到寄存器中,在同时,对这种访问是否合法进行检查。如果数据加载比安全检查慢,比如当安全检查完成时,kernel data仍然在从memory到register的路上,乱序执行就会立刻被中断并被丢弃,因为检查失败。我们的攻击自然也就失败了。
如果kernel data已经在cpu cache中,那么加载kernel data到寄存器就更快了,我们也许就能达到关键指令(比如在检查失败终止乱序执行之前,加载数组)实际上,如果kernel data没有被缓存,使用meltdown来窃取信息是困难的,但是也不是不行,只不过需要更高性能的CPU和DRAM
在这次实验中,我们在发动攻击前,先让kernel secret data缓存好。我们让user-level的程序调用kernel module内部的函数,这函数将会访问secret data,并且不会将其泄露给user-level 程序。这样就可以使得CPU cache中缓存secret data。

在内存访问前加些汇编指令来提升成功率。
下面的汇编
做一个400次的循环,在循环中,简单地加0x141到eax寄存器。这其实是在做无效的计算,但是根据之前的讨论,这些代码“give algorihtmic units something to chew while memory access is being speculated。
这是增加攻击成功率的一个有效的trick

为了提供正确率,我们可以使用统计技术。创建一个score array,大小为256,一个元素对应一个可能的secret value。运行我们的攻击多次。每一次,如果程序说k是secret,那么就给scores[k]加1,在运行多次后,我们使用最高的k值作为我们对secret最后的估计。这比仅仅基于一次运行可以得到更可靠的结果

编译并运行

SEEDLAB2.0-Meltdown相关推荐

  1. Meltdown:Reading Kernel Memory from User Space 论文中英对照

    Meltdown:Reading Kernel Memory from User Space 翻译目录 摘要(Abstract) 一.简介(Introduction) 二.背景介绍(Backgroun ...

  2. Meltdown: Reading Kernel Memory from User Space论文翻译

    Meltdown: Reading Kernel Memory from User Space翻译 摘要(Abstract) The security of computer systems fund ...

  3.  Meltdown论文翻译【转】

    转自:http://www.wowotech.net/basic_subject/meltdown.html#6596 摘要(Abstract) The security of computer sy ...

  4. Meltdown 论文翻译

    摘要(Abstract) The security of computer systems fundamentally relies on memory isolation, e.g., kernel ...

  5. 估算带卷积核二分类0,3的网络的收敛时间和迭代次数

    制作一个网络分类minst的0和3求出这网络的迭代次数曲线表达式n(δ),和准确率表达式p-max(δ),用预期准确率去估算n,并推算需要的时间. 将minst的28*28的图片缩小到9*9,网络用一 ...

  6. 神经网络收敛标准与准确率之间的数学关系

    制作一个带一个3*3卷积核的神经网络,测试集是minst的0和2图片集,将28*28的图片缩小成9*9,隐藏层30个节点所以网络的结构是 S(minst0)-(con3*3)49-30-2-(1,0) ...

  7. 用共振频率去进行图片分类的尝试

    假设有一种物质,这种物质的原子核的质子数和电子数可以不同,允许质子的带电量不同,并且质子带负电,同时这个原子的电子不满足鲍利不相容原理,环境温度是 (1/1.3806505)*10^23k,电子波的频 ...

  8. 收敛标准对迭代次数影响

    制作一个n*n的网络,将收敛标准分别设定在,0.001,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,观察网络达到平衡时迭代次数的变化. 比如如图的 ...

  9. vue省市区三级联动mysql,js/json,html/jsp

    大家好,我是烤鸭: 省市区三级联动数据及页面: 测试的时候,发现少了几个地区,现在补上了,也优化了下排版. 如果你懒得复制和看的话,这里是打包的下载地址. 之前的资源地址也改了,http://down ...

  10. ZAM 3D 制作3D动画字幕 用于Xaml导出

    ZAM 3D 制作3D动画字幕 用于Xaml导出 原文:ZAM 3D 制作3D动画字幕 用于Xaml导出 原地址-> http://www.cnblogs.com/yk250/p/5662788 ...

最新文章

  1. JVM GC 日志详解
  2. 服务器报错:“/usr/local/var/run/nginx.pid”failed
  3. “约见”面试官系列之常见面试题之第五十二篇之标准模式和怪异模式(建议收藏)
  4. linux创建文件后会自动删除,linux会自动删除目录和文件的吗
  5. ~~spfa 算法(队列优化的Bellman-Ford算法)(附模板题)
  6. 用汉明距离进行图片相似度检测的Java实现
  7. 05【应用工具简介】PM 流程图,思维导图,原型图绘制?怎么绘制不被解雇?
  8. DGA 域名生成算法攻防
  9. 2012-7-19可樂词汇积累#9316;
  10. mysql临时表插入数据
  11. IOS 从项目学习Swift 开发(一)
  12. java 伊甸园_离伊甸园仅一步之遥
  13. 100个开源游戏-街机类、棋牌类、休闲益智类、教育类、音乐类、RPG和AVG、策略类开源游戏【转】...
  14. java 杨辉三角_JAVA实现杨辉三角的三种方式
  15. 记一次npm发包失败的经历
  16. 远程实时读取海康威视4G网络摄像头视频
  17. /bin/bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8)
  18. xbox360链接pc_如何在Windows PC上使用Xbox One控制器
  19. uint8array和string的互转(包括中文字符串)
  20. SpringCloud - 服务注册中心

热门文章

  1. 【附白皮书下载】专家黄正杰:从微笑曲线出发,思考制造业数字化转型方向
  2. s3c2440的时钟体系
  3. 为个人博客添加文章评论功能
  4. 浙江工业大学2020考研经验分享
  5. 硬币组合问题-非递归实现
  6. 2021-01-19 :在pycharm中创建包含anaconda中各种库的环境
  7. 18个最受欢迎的低代码开发平台【开源】
  8. 【CTF】buuctf web 详解(持续更新)
  9. 听课记录范文计算机基础,【教师听课记录范文】_听课记录范文三篇
  10. 181008 逆向-inctf(load3r、Decoy)