ROP攻与防

diting0x

ROP是一种代码复用攻击方式(Code Reuse Attack)。 ROP攻击劫持控制流后,复用内存中可执行的指令(gadget),这些gadgets以ret指令返回,攻击者利用这些gadgets以不同方式拼接并执行,完成攻击过程。

下面以几个图来展示ROP攻击(图来源于Blackhat 2013 Kevin Z.Snow, Luca Davi)

metaphor:




攻击过程:













代码复用攻击历史:




再次声明,以上六张图全部来源于(Blackhat 2013 Kevin Z.Snow, Luca Davi)

上图可以大致了解2010年前ROP的发展历程,而下文大多数介绍的是近三五年ROP的攻与防。

Ret2libc可以说是ROP的前身,有点接近ROP。其主要是复用libc的函数地址(而不是含有shellcode代码的栈地址)覆盖被利用栈的返回地址。如果攻击者想触发一个shell, 他会利用system()地址来覆盖返回地址并设置好system()在栈中需要的必要参数,以便能成功调用system()。

随着ASLR的出现,将程序的数据段、堆、栈以及共享库在内存中的位置随机化,使得Ret2libc和ROP变得更加困难。
道高一尺魔高一丈,一攻一防,近些年对ROP的研究越来越热,不断有研究者设计更高级的ROP来绕过系统中现有的防御机制(包括DEP,ASLR),又不断有研究者设计更安全的ASLR或其它安全机制来抵御ROP。

攻:JIT-ROP(IEEE S&P 2013),其主要思想是即时扫描有效内存,即时反汇编搜寻rop gadgets。具体过程是,利用内存泄漏(memory disclousure)获取一个运行时的代码指针,泄漏当前4K的内存页,再利用页中指向其它页的分支获取更多的页面。之后将当前页反汇编获取所需的gadgets,构造ROP链。

slides

防:ROPecker (NDSS 2014)

ROPecker是一个利用Intel LBR特性记录代码执行流来检测和防御ROP的工具,是第一个可以针对所有形式ROP攻击的一种general的,不需要源代码,二进制代码重写。

ROPecker分析了现有ROP攻击的特点,发现ROP的gadgets一般利用jmp与分支判断指令跳转,在代码段中会进行大幅度的跳转,且其调用链很长。基于这两个特点,ROPecker先对要检测的程序进行离线gadgets分析,利用LBR记录代码执行流的分析信息,将不在代码当前执行片段周围的代码(sliding window)设置为不可执行状态,执行sliding window以外的代码就会触发ROPecker对攻击的分析。基于离线gadgets分析,再加上LBR的分析信息(当前程序的过去和未来的执行情况),一旦发现程序的执行流不符则认为程序受到了ROP攻击,则强制终止程序。以上检测和防御机制假设DEP已经打开。
pdf

防:Kbouncer(Security’13) 也是利用LBR记录程序的执行分支信息,识别程序的控制流转移信息,在关键点监控程序的间接指令来检测并防御ROP,其在Windows 7中实现。Kbouncer基于两个发现,1) ROP攻击会返回到non-call-preceded地址,其相对应的防御机制是Call-Preceded原则,没有恶意的代码指令执行的时候,ret指令回到的地址的上一条指令一定是call;2)ROP是由许多短gadgets组成的长链序列,其相对应的防御机制是不允许许多短gadgets组成的长链序列
slides

攻: ROP is Still Dangerous:
Breaking Modern Defenses (Security’14 -Berkeley)
Abstract: 提出三种方法(Call-Preceded ROP, Evasion Attacks, History Flushing)攻破现有的ROP防御方法,包括kbouncer,ROPecker。
并对未来防御ROP的方式提出两点要求:1)将代码分类成gadgets与non-gadgets并非易事;2)防御机制需要集中关注正常执行与ROP攻击的基本不同点。

slides
pdf video

防:ASLR-Guard(ccs’15 Byoungyoung)
要实施code reuse attack,要满足两个条件:1.知道现有gadgets的地址,2.用这个地址覆盖被控制的数据。对2的防御有:stackguard,cfi,code pointer integrity,对1的防御有:ASLR,但是ASLR有个缺陷,信息泄露,比如代码指针的泄露导致可验获取代码地址(JIT-ROP,Blind ROP, “Missing the point”)
本文目标:阻止代码指针的泄露。方法:系统化的发现代码指针,两种技术来阻止代码指针的泄露,隔离与加密。将代码指针存储在隔离的内存区域,隔离还不够,还需进行加密。实现:gcc,gas,ld,ld.so 3000sloc,eglibc,glibc。
slides pdf

防:XnR (CCS’15)
里面关于rop,aslr,jit-rop等介绍的很详细
该文从代码泄漏的角度进行了防护:当代码在被执行期间,不允许对代码的读操作,从而能有效抵御JIT code reuse攻击,简称XnR。类似W^X(W⨁X)策略。 这一思路在无硬件支撑的条件下,通过软件MMU实现,
基本思路:要实现XnR策略,在硬件不支持的情况下,可通过修改MMU中处理过程,实现软体MMU。 目前架构中:mmu可以检测到写,但是无法检测到读;读只能通过内存页的non-present实现;但是一旦non-present的话,代码也将无法运行。解决方法:修改page fault handler,在handler中区分page fault产生的原因,并决定是否继续正常执行,还是发现代码内存读取行为,中止执行。 具体的,在代码运行期间,仅允许极少的代码可读,文中的实验数据表明,采用3页的sliding windows是一个比较好的选择,即当前代码页面的相邻两页。是否可读性的实现方式是通过设置页面的present位实现,非法的读取将陷入中断,在中断中判断中断原因是缺页还是非法读。
PDF 来自liangyu blog

防:No-Execute-After-Read:
Preventing Code Disclosure in Commodity Software (AsiaCCS’16)
文章提出最新的XnR技术不能防御just-in-time的代码复用攻击,并设计了一种No-Execute-After-Read(NEAR),针对just-it-time攻击进行强安全保证。NEAR允许所有代码被披露,但是阻止被披露的代码继续执行。
pdf


待续

Intel VT 页面修改记录(PML)

diting0x

Intel VT 2015年推出page-modification logging(PML),
VMM可以利用EPT监控虚拟机在运行期间物理页面的修改。

在没有PML前,VMM要监控xu虚拟机中物理页面的修改,需要将EPT的页面结构设置为not-present或者read-only,这样会触发许多EPT violations,开销非常大。

PML建立在CPU对EPT中的accessed与dirty标志位支持上。
当启用PML时,对EPT中设置了dirty标志位的写操作都会产生一条in-memory记录,报告写操作的虚拟机物理地址,当记录写满时,触发一次VM Exit,然后VMM就可以监控被修改的页面。

这是KVM 对支持PML的patch

这是XEN支持PML的patch

VMWare 也对PML开始有了支持

参考来源

Page Modification Logging for Virtual Machine Monitor White Paper

CacheKit 利用cache不一致性绕过内存监控

作者:diting0x

听了Prof Kun Sun的报告,略作总结。

CacheKit核心思想:利用Trustzone的cahce不一致性,将恶意代码加载一块系统预留的I/O空间重定向的cache中,绕过安全世界和正常世界的监控。





几个发现

  • 1),安全世界可以访问正常世界的内存、CPU寄存器,反之则不行。但是,安全世界无法访问正常世界的cache内容
  • 2),内存空间:0x80000000-0xFFFFFFFF
    I/O空间: 0x0 -0x7FFFFFFF,其中0x1300000-0x1500000属于系统预留
  • 3),NS(non-secure)位,置零则表示在安全世界的cache,否则表示正常世界的cache。
  • 4), cache flush: 在安全世界中,不管cache lind的NS位是什么,会flush所有的cache line;而在正常世界中,只会fulsh正常世界的cache, NS=1.
  • 5),cache不一致性:同一块物理地址可以在安全世界和正常世界对应不同的cache line。
  • 6),有两种获取系统物理内存的方法,一是从处理器中获取,二是利用DMA从外设中获取;而DMA获取的方法直接获取物理内存而不会获取处理器中的cache内容

利用过程

1)将恶意代码加载到正常世界的cache中,但不加载到RAM中;

2)利用ARM cache locking机制保证恶意代码能持续存在cache中,而不会被换出 ;

3)控制物理地址空间保证恶意代码的隐蔽性。

如何做到上述的利用过程?


三个挑战

1) cache加载:在DRAM初始化前,允许让BLOS代码将栈存储在cache中(cache-as-ram CAR系统)。cacheKit利用CAR将恶意代码存储在cache中。

处理器cache的设计是为了对系统软件透明,所以ARM架构不支持在正常操作过程中直接访问cache lines,要让处理器读写cache中的内容,必须让处理器读写虚拟内存。
可以分两步进行,第一步是要让内存能够进行caching,具体细节可以参考论文4.2.1;
第二步是要让代码中的所有比特填充cache,但要避免将加载cache本身的程序代码也放进cache。

2)cache locking: 硬件支持将cache 锁住,ARMv7允许系统软件锁住八组cache中的七组。

3) cache 隐藏: 保证cachekit绕过安全世界和正常世界的监控;

  • 绕过正常世界监控:在正常世界中,当获取物理内存工具(如LiME)从处理器中读取物理内存时,获取的过程也会显示cache中的值。解决方法是利用未使用的系统I/O地址区域的cache,而取证者不会扫描这块区域,就算取证者打算扫描这块区域,也很难辨认哪个地址是安全可读的,哪些要跳过的,一不小心读到特定的硬件控制位就会导致系统停机与崩溃

  • 绕过安全世界监控:发现1)2)5)。安全世界无法访问正常世界中cache的内容。

cache隐藏细节:直接使用cache locking会带来两个问题;
第一个问题就是,直接在正常世界的kernel中做introspection,使用kernel模块将每个内存页面映射到内核地址空间仍然可以读取cache的内容;第二,cache lines被锁住以后,仍然可以clean操作将其内容写入到内存中。要解决这两个问题,就是利用系统预留内存0x1300000-0x1500000.在部署cachekit之前,这块区域是直接被MMU重定向到外设总线的;部署cachekit之后,利用cache-as-ram技术将其这块区域配置为内存空间,对这块区域所有的读写操作都被重定向到处理器的cache中。这块区域不会被任何RAM或者I/O设备所支持,不会有任何物理设备对这块区域响应。


来源

CacheKit: Evading Memory Introspection Using Cache Incoherence - ES&P’2016 Kun Sun

神乎其神的Rowhammer:用比特位翻转实现云虚拟机夺权



来源于Freebuf,附上链接:http://www.freebuf.com/column/133871.html. 作者:欧阳洋葱

想一个简单的问题,Memory类的存储介质中,每一个栅格存储一个比特位(0或1)。如果因为外力,这个比特位发生翻转,情况会怎样?这并非传说,而且有专家觉得还能应用到针对云服务器的东西向攻击中!

我先前在FreeBuf的文章中介绍过一种名为Bitsquatting的攻击手法,这是一种超高端的钓鱼攻击:我们假定内存、CPU缓存由于环境,或者制造缺陷,产生内存的比特位翻转,就可能导致原本我们要访问某家网站,最终由于这种硬件错误,却访问了与这家网站域名相近的钓鱼站点。



其实我个人真正钟爱的领域是成像和半导体,在我去年也算是半只脚踏进神圣的安全行业之后,第一次听说比特位翻转这种听起来极为高端的攻击方式就有些惊呆的感觉。而且这还不是个传说,先前Sun所推的UltraSparc II处理器就存在这样的问题——简单来说,采用UltraSparc II CPU的服务器有些时候会毫无征兆地出现随机性错误,最后发现问题出在SRAM介质之上,据说在生产过程中SRAM存储部分被辐射物污染,可以导致Cache的比特位翻转。


Cache比特位如果出现这种随机的翻转,数据处理肯定会出问题,最终就是服务器崩溃。这个问题本身也是因为处理器SRAM缺乏错误检查和纠正机制。我个人在听说这种所谓的“BUG”之后的确是有点三观被毁。对半导体有研究的同学可以去看看这篇Paper:https://media.blackhat.com/bh-us-11/Dinaburg/BH_US_11_Dinaburg_Bitsquatting_WP.pdf


然而实际上,这种听起来很玄幻的攻击其实不算新鲜,虽然看起来具有很强的不可控性,但实际还是可以人为触发其中的“硬件”漏洞(只是据说!!!我很怀疑)。这个漏洞名为Rowhammer,前两年就有人提出了,可能是有史以来最理想化的漏洞。由于其不可控性,很多人认为Rowhammer停留在理论阶段。


去年9月份,有安全研究人员提出一种名为“风水翻转”的攻击技术,主要针对同处一个云环境下的其他虚拟机。其本质也是Rowhammer攻击,据说具备了“高准确性”和“可控”的特点,可从其他虚拟机盗取加密密钥。谁曾想,这种硬件级别的漏洞可以应用到听起来如此靠上的层级(云算是非常上层吧)。





颠覆攻击逻辑的Rowhammer技术


去网上查资料,会发现Rowhammer的描绘极为晦涩。但Rowhammer漏洞其实很容易理解,这里我用自己的话来科普以下,这是个特别针对Memory的攻击技术,但不是缓冲区破坏或溢出攻击。一般的计算机Memory介质中,每个存储单元(晶体管+电容器)存放1bit数据,这个比特位要么是0,要么是1——存储单元中充满电子表示1,清空表示0。内存就是由上亿这样的存储单元构成的,数据也因此得以存储。


不过电容器会泄露,一个电容器充满电子后,只需要几毫秒就会泄露殆尽。这就要求CPU(内存控制器)对电容进行充电,让“1”这个值能够保持住。整个过程是由内存控制器先读取电容器中的值,然后再把数据写回去。这种刷新操作,每秒会执行几千次。


这几年的内存容量正在大幅度上涨,所以存储比特位的电容器也就越来越小,排列越来越近。要防止相邻的电容之间相互干扰,难度也就变得更大。如果能够快速、反复访问一排电容,相邻行的电容更容易产生干扰错误和所谓的“比特位翻转”,也就是0变成1。


其实正常的数据读写一般是不会发生比特位翻转的,可是如果对某些行进行反复读写,问题就有可能产生。2014年卡内基梅陇大学的研究人员层发表过一篇论文,题为《无访问情况下的内存比特位翻转——DRAM干扰行错误的试验研究》,其本质是通过机器码指令CLFUSH或Cache Line Flush,强制进行这种比特位的读取和更新。据说利用这种方式,可引起大量比特位翻转。


利用比特位翻转,很多事情都可以做,比如说执行未经授权的代码。这就是所谓的Rowhammer。这是一种颠覆人类对安全认知的攻击技术,软件层面几乎解决无望。先前已经有研究人员演示,如何用Rowhammer来进行提权,以及打破安全沙盒。


不过看原理就知道,这种攻击实在有够理想化,存在诸多不确定性,因为攻击者根本无法精准控制比特位如何翻转。比如说,这种攻击对数据所在的内存位置首先就有要求,这样才能实施内存翻转:但敏感数据存储在这些位置的几率可能并不算高。




实现内存“风水逆转”


所以在去年9月,针对Rowhammer的内存位置限制,有人开发出一种名为Flip Feng Shui(风水翻转)的攻击技术,这本质上也是Rowhammer。这种攻击就是篡改deduplication操作——deduplication在云端主机中应用得很常见,这种技术可让两个或者更多虚拟主机共享特定的数据块,起到节约内存资源的作用。


Flip Feng Shui在物理内存上做手脚,可致加密密钥和其他敏感数据存储到内存特定的位置——这些位置就很容易受Rowhammer的影响了。所以才叫风水翻转,就是让数据在内存中的“风水”位置变更好,Rowhammer攻击变得更可靠。


这种技术是由阿姆斯特丹自由大学的一名研究人员Ben Gras提出的。他说:“先前就已经有攻击方法表明,共同主机的虚拟机彼此间是可以相互攻击的,比如说获取对方的加密密钥。不过这次的攻击更具破坏性,也是此类攻击的第一例。”


“我们可以相当高的精度和可控性,针对目标虚拟机的内存进行篡改。针对这种软件堆栈中看似随机化的数据破坏方式,我们首次以极高的准确性和可控的方式,对其进行了展示。”这里Gras所谓的“看似随机化的数据破坏方式”也就是Rowhammer攻击。




研究团队演示了攻击者如何利用Flip Feng Shui攻击,获取另一台VM虚拟机上的RSA加密密钥——当然这要求被攻击的虚拟主机与攻击者处在相同的云环境中。在他们进行的某一例实验中,进行攻击的虚拟机获取到可用于授权安全shell访问的密钥,这样一来,这台虚拟机就可以获取目标虚拟机的未授权访问了。


研究人员在报告中提到,进行攻击的虚拟机获取到GPG密钥——该密钥是Ubuntu系统开发者用来确认更新可靠性的。有了这个GPG密钥,攻击者就能迫使目标虚拟机下载和安装恶意更新。


其实整个攻击过程描述起来还是比较复杂的,首先需要获取目标公钥。发起攻击的虚拟机通过Flip Feng Shui,针对公钥的某个特定部分进行比特位翻转,也就是我们上面提到的Rowhammer攻击方式——这里实际上还利用了云环境的deduplication技术。就像前文提到的,这种技术在云端主机中很常见,这是一种相较数据压缩粒度更大、节约存储资源的技术。基于此,物理页才会在多个虚拟机用户间共享,针对共享数据块的比特位翻转才显得有意义。


在公钥的比特位发生翻转之后,就构造出了一个全新的公钥,这个公钥会非常简单(足以进行因式分解)。也就是说,Rowhammer攻击欺骗目标虚拟机,接受新的公钥;攻击者随后也就能够得到相对应的私钥,并进行未经授权的SSH访问,签署恶意Ubuntu更新了。




鉴于篇幅关系,这里没法细致详述每一环技术细节,有兴趣的同学可以前往翻阅研究人员发表的论文,题为《Flip Feng Shui: Hammering a Needle in the Software Stack》。Gras表示,这次的实验虽然只针对RSA密钥,但他预期未来这种攻击方式还能针对数字签名算法、Diffie-Hellman加密算法、ECC等等。这样一来,攻击者就不仅能够进行未授权访问量了,还能窃听合法会话。


另外,这种攻击也需要一些条件才能发起,比如说像前文提到的,要求虚拟机开启Deduplication;而且本次实验依赖于基于内核的虚拟机,以及Linux中的Kernel SamePage Merging特性。还有,内存芯片本身也需要具备比特位翻转的基础,先前有人做过相应的测试,129款DDR3内存中,110款存在攻击可行性,还有12款DDR4内存有8款也存在Rowhammer漏洞(对此,我也真的很震惊,为什么我总是震惊?)。


最后,研究人员还列出了一些可抵御Flip Feng Shui攻击的手段,硬件层面要求DRAM芯片制造商进行相应的Rowhammer测试,还有比如针对某些DDR4芯片实施的直接行刷新机制等;至于软件层面,包括禁用内存的deduplication,开发者和工程师也应该考虑加入额外的措施,比如检查安全敏感信息完整性。


“这种攻击不需要攻击者进行什么复杂的操作,就能完全控制共用主机的云虚拟机。同时,我们认为Flip Feng Shui还能通过更多的形式发起攻击,这就需要系统安全社区能够对这样的威胁引起足够的重视。”



不过说实话,我对这种所谓Rowhammer的攻击精度还是持怀疑态度,是一种“怎么可能”的惊叹。有兴趣的真的很建议去看原paper。如果说针对Memory(包括内存、Cache、Register)的这种比特位翻转攻击真的是可行的,那么任何提权、代码执行之类的操作何苦再从应用或者系统层面去搞定呢?而且它还不是缓冲区溢出攻击那样的层面,应用层的恶意程序更多的是种逆向的边信道攻击。


不过的不过,我对安全本身了解得相当浅层,所以或许其精度有什么特别实现方式。毕竟先前在看ARM的安全文档谈Lab Attack的时候也有点惊呆——即边信道(或者叫侧信道)攻击远比你们想象得复杂和高端,就是实验室里不计成本用到的所谓“电子探针”。突然觉得还有点小激动…


* 参考来源:Flip Feng Shui: Hammering a Needle in the Software Stack,转载请注明来自FreeBuf.COM及作者欧阳洋葱




谷歌Project Zero:通过“Row hammer”漏洞获取系统权限





本文转自安全客,附上链接:http://bobao.360.cn/learning/detail/302.html
本文原作者:Mark Seaborn,沙盒制作和逃逸。以及逆向工程师Thomas Dullien

概述

“Row hammer”是指,最近一些DRAM设备上反复访问一行内存可能造成相邻内存行的bit翻转问题。我们测试了一系列笔记本,并发现其中一部分存在这个问题。我们利用这个问题,开发了两套可用的提权溢出。一个溢出在64位Linux的Ring3受限用户进程中,使用“Row hammer——引导”bit翻转,来获得Ring0权限。当程序跑在存在“Rowhammer”问题的主机中时,进程可以在PTE中印发bit翻转。这可以用来获得内存页的写入权限,进而获得全部物理内存的读写权限。

我们还不确定到底有多少台计算机存在这个问题,也不知道有多少存在问题的主机可以修复。我们的溢出程序使用x86指令clflush来获得访问底层DRAM的权限,但是其他的技术是可以用在非x86系统上。

我们期望我们基于PTE修改的溢出可以在其他操作系统上使用;这个问题不是Linux独有的。引起PTE表中的bit翻转仅仅是溢出的一种方法;其他的通过bit翻转的溢出也同样有效。我们前文提到的另一个溢出将通过Native Client沙盒逃逸来证明不仅仅可以修改PTE

“Rowhammer”问题介绍

我们从Yoongu Kim等人的论文《Flipping Bits in Memory Without Accessing Them:

An Experimental Study of DRAM Disturbance Errors》(全部作者:Yoongu Kim,Ross Daly,Jeremie Kim,Chris Fallin,Ji Hye Lee,Donghyuk Lee,Chris Wilkerson,Konrad Lai,Onur Mutlu,Carnegie Mellon University,Intel Labs)

在论文中,他们演示,通过反复访问同一进程中的两个“敲击”内存地址,可以在被叫做“受波及”的地址引起bit翻转。这个地址很可能位于当前进程虚拟地址以外的内存空间——在与当前的“敲击”内存不同的行中,也就是存在于一个不同的4k内存页中(也是由于当前流行的内存Bank中每一行的容量都大于4k的缘故)

这个问题是由于存储单元(内存存储的最小计算单元)现在做的越来越小,也越来越紧凑。由于内存制造业不断改进芯片工艺以容纳更多的存储单元,这使得保护存储单元远离相互之间的电器性影响越来越难。因此,访问一个内存地址是会影响到周围的内存,引发电荷逃逸或进入相邻的存储单元。当进行了足够次数的访问,就可以将一个存储单元从0变为1或者从1变为0。

这篇论文解释道,下面这个简短的代码片就可以导致bit翻转。

code1a:

  mov (X), %eax  // Read from address X

  mov (Y), %ebx  // Read from address Y

  clflush (X)  // Flush cache for address X

  clflush (Y)  // Flush cache for address Y

  jmp code1a

两个引发bit翻转的的必要因素:

地址的选取:要使用代码片code1a来引发bit翻转,需要地址X和地址Y位      于同一个内存Bank的不同行中。

一些背景知识:每一个DRAM芯片都包含多个Bank,而每个Bank中很多   行的存储单元。每访问内存       中的1字节需要将对应行的数据读取至芯片的    “Row Buffer”中(这个过程会放掉对应行中每一个存储单元的电)读取/写入     “Row Buffer”的上下文,然后将“Row Buffer”的上下文写回原来的行中(只是      读取的具体操作的一种,其     他的可以参考豆丁文档  http://www.docin.com/p-639315446.html 1.2中的内容)

 在这个“激活”一行(放电、充电)的过程中可以干扰到相邻的行。如果,在  相邻的行进行自动刷新的时候(通常每64ms进行一次),进行了足够多的“激 活”操作,就可以引发相邻行的bit翻转

“Row Buffer”扮演了一个缓存的角色,如果地址X和地址Y指向了同一行,那么在执行代码片code1a的时候,只会对“Row Buffer”进行操作,而不会进      行“激活”操作(具体可以参考豆丁文档中1.2节中提到的第三种读取方式)

 此外,内存中的每一个Bank拥有一套独立的“Row Buffer”(同样参考文档)。所以,如果地址X和地址Y位于不同的Bank中,在执行代码片code1a的  时候,也只会读取X、Y所在的个子的Bank中的“Row Buffer”而不会进行激      活操作。

而然,如果地址X、Y指向了同一个Bank中的不同行,在执行代码片code1a     的时候,就会引发X、Y所在行之间不断的“激活”操作。这就叫做“Row     Hammering”

绕过缓存:如果没有代码片code1a中的CLFLUSH指令,那么内存操作(MOVs)将只会记录在CPU的缓存(Cache)中。使用CLFLUSH刷写缓    存可以强制将内存访问命令发送到底层的DRAM中。

 注意到Yoongu Kim等人论文中的代码片code1a版本,还包含了MFENCE    指令,但是我们发没有必要调用MFENCE指令而且事实上调用后反而减少  了被翻转的bit。Yoongu Kim修正过的memtest函数也同样从他的“Row      Hammering”代码中忽略掉了MFENCE指令。

为“锤子”提炼需要选择的地址

使用物理地址映射

那么,我们如何来挑选成对的地址,来满足这个“不同行同Bank”的要求呢?

一种可能性是利用CPU集成的内存控制器对于物理地址到存储单元、内存行、Bank的映射的知识,以及其他相关的知识:

 内存的绝对物理地址,我们有权访问。Linux通过/proc/PID/pagemap

内存的相对物理地址,我们有权访问。Linux通过支持2M的连续物理地址   空间的内存页。通常一个普通的内存页仅有4K小于1个内存行,但是一个 2M的内存页,通常将包含多个内存行,其中比部分将存在于同一个Bank   中。

Yoongu Kim等人通过这个方法。他们选择Y=X+8M基于Intel与AMD的CPU中内存控制器对于物理内存映射的知识。

随机地址选取

CPU的物理地址映射很难被确定,尽管一些特性例如:/proc/PID/pagemap、大型内存页并不是通用的。此外,如果我们关于地址映射的猜测是错误的,我们可能会挑选一个降低“Row Hammering”成功率的偏移(比如:Y=X+8k可能使得地址总是在不同的Bank中)

一个更简单的方法是随机的挑选一对地址。我们申请一大块内存(比如:1G)然后在这块内存中随机挑选虚拟地址。在一台拥有16个Bank的电脑上(例如我们的测试机拥有2个DIMM,每个DIMM拥有8个Bank),这样我们挑选的地址对就有1/16的概率位于同一个Bank中,这个概率已经很高了(当然,地址对位于同一行中的概率就微不足道了,一般一个Bank中有8k+个行)

此外,我们可以通过修改代码片code1a,使其在每次循环中“Hammer”更多的地址对来提高我们“Row Hammering”的成功率。我们发现每次一次“Hammer”2或者4个地址对并不会增加多少时间。

通过计时选择地址

另一种判断地址对时候满足“不同行同Bank”特性的方法是使用高精度计时(例如使用RDTSC 指令)记录非缓存访问这些地址所用的时间。拥有此特性的地址对的访问时间要长于其他情况地址对的访问时间。

双侧“Hammering”

我们发现通过“Hammering”行N-1、N+1相比“Hammering”一个相邻行和另一个相对比较远的行,可以增加行N的bit翻转的成功率。我们称之为双侧“Hammering”

对于很多机器,双侧“Hammering”是在合理的时间内引发bit翻转的唯一方法。而对于那些通过随机选择地址对就已经可以引发bit翻转的,双侧“Hammering”可以在被翻转的bit数上产生一个非常显著的提高。我们在一台非常脆弱的主机层观察到1内存行超过25个bit的翻转。

由于内存的几何结构使得执行双侧“Hammering”变得更加复杂。它需要攻击者了解或者能猜测到物理地址中同Bank相邻两行之间的偏移值究竟是多少。

通过我们的测试,我们能够直接推断第4台样本笔记本(详见下表面的表格)的内存行偏移值是256k。我们得出这个结论是通过观察被翻转的bit发生的可能性相对于被选中的内存页到受影响的内存页之间的距离。这个可能性在我们给定目标内存行的情况下在256k上下达到最大值。

“256k敲击内存区域,256k受波及内存区域,256k敲击内存区域”的设置被证明在同一厂商的其他笔记本上也同样有效。当然,对于其他厂商,这个设置很可能需要修改。

这256k的内存行偏移,可以被解释成一种产品的内存行的大小、Bank的数量、等等DRAM在这才电脑上的参数,不过这需要更深入的了解引荐是如何将物理地址映射成行、列编号的。

使用双侧“Hammering”需要我们获得物理上连续的内存页(比如:via /proc/PID/pagemap或者大型内存页)

溢出“Row Hammer” bit翻转

Yoongu Kim等人说“通过工程化的尝试,我们相信我们可以将code1a发展成干扰攻击,从而获得系统的控制权”,但是他们把这个当做未来的研究任务,而我们现在就做到了!

我们发现了存在bit翻转的各种主机(参考下面的实验结果),并写出了一下两个exp:

第一个是运行在Native Client(以下简称NaCl)沙盒中的程序,成功逃逸, 并实现直接调用我们本地系统调用。我们已经通过禁用NaCl沙盒中   的程序调用CLFLUSH指令来缓解攻击(我之所以首先选择NaCl沙盒做溢   出,是因为我在这个项目工作,并在之前写过概念性的沙盒逃逸代码)

第二个是运行在64位Linux系统中的正常进程,成功提权并获得了全部物    理内存的权限。这个在实体机器上很难做到有效的攻击缓解。

NaCl沙盒逃逸

NaCl是一个只允许运行部分x86-64指令的沙盒系统(包括其他构架)。在运行一个x86-64可执行程序前,NaCl会使用一个校验器来检验这个程序的代码是否都在NaCl所认为安全的指令集。

然而,NaCl假设硬件行为是正确的。它假设内存地址除非调用指令改写,否则是不会改变的!NaCl对于机器码的检验方法在bit翻转面前是非常脆弱的,因为:

 1bit的翻转在验证过的代码中就可以使得一个安全的指令变得不安全。

在NaCl沙盒中,程序的代码段是可读的。这意味着程序可以检是否发生了   bit翻转,并检查是否或者如何利用这个翻转。

我们的溢出目的是NaCl沙盒下的直接跳转指令序列,例如如下形式:

andl $~31, %eax // Truncate address to 32 bits and mask to be 32-byte-aligned.

addq %r15, %rax // Add %r15, the sandbox base address.

jmp %rax // Indirect jump.

溢出原理是通过触发这段指令序列的bit翻转。我们前文已经提到溢出会有13%的可能性造成bit翻转。在这里我们仅使用bit翻转来篡改所用的寄存器(通过进一步研究,还有其他的可利用的方法,比如:篡改操作码)举个栗子,如果在jmp %rax代表寄存器字节的最低bit发生翻转,这就变成了jmp *%rcx,此时由于rcx没有被审查,这就允许我们可以跳转到任意地址上。通常情况下NaCl只允许直接跳转到32字节对齐的地址(并且还要确保指令没有穿越32位约束的边界)当一个程序可以跳转到一个非对齐的地址时,它就可以从沙盒中逃逸。因为该程序可以将不安全的x86指令隐含在安全的x86指令中。例如:

20ea0: 48 b8 0f 05 eb 0c f4 f4 f4 f4 movabs $0xf4f4f4f40ceb050f,%rax

这里在地址0x20ea2上隐藏了一条SYSCALL指令(0f 05)

我们的NaCl溢出程序作了如下的工作:

它使用NaCl信任的直接调转指令填充了由NaCl自带函数dyncode_create声 明的250M的动态代码空间

在每次循环中,程序首先挑选随机地址对,对动态代码空间通过CLFLUSH  进行“Row Hammer”。再对动态代码空间进行搜索。如果发现可利用的bit翻     转,就使用它并跳转到隐藏在NACl认证过的指令中的ShellCode。如果,没     有引发可利用的bit翻转,那么继续循环。

我们已经通过修改在NaCl中禁用CLFLUSH的策略指令来缓解攻击。(用兴趣的可以跟踪CVE-2015-0565)然而,除了调用CLFLUSH也许还存在其他的方法来引发“Row Hammer”

在NaCl中禁用CLFLUSH,可能不仅束缚了NaCl的溢出,还能防止类似后面提到的系统提权,以至于让一个Chrome软件店中的软件仅仅通过一个底层的硬件Bug,就可以获得内核权限。据我们所知,目前Chrome软件店还没有这样的应用。PNaCl,一个在开源Web上面可用的框架,由于拥有一个特殊的保护层,溢出在调用CLFLUSH前,还需要先干掉PNaCl的指令解析器。

内核提权

我们的内核提权的原理是,使用“Row Hammer”引发PTE基址处的1bit翻转。这可以使得PTE指向一个包含攻击者进程页表的物理内存。这赋予了攻击者进程对于自身页表的读写全,进而控制全部物理内存。

以下两点可以帮助我们的bit翻转具有一个很高的可利用性:

 1、“Row Hammer”引发的bit翻转具有很大的反复测试的可能性。这意味着,      我们可以进一步讨论,当一个存储单元可能会翻转,其中的某个bit的位置 对于溢出是否有意义。

举个栗子:第51bit超过64位PTE中的最高位。如果这里从0变为1,这将 会产生一个比当前系统内存还要大的页号。而这对于我们的溢出是没有任何   意义的,所以我们可以跳过对于这个bit翻转的利用。然而,第12bit作为 PTE的物理页号的中间位。如果,我们将其翻转,那么PTE将依然指向一个       有效的物理内存页。

2、我们喷射大量带有页表的物理内存。这意味着,当PTE物理页号被篡改  的时候,将会有很大的可能性指向我们喷射的页表。

我们通过反复mmap相同的文件来达到喷射的效果。这个过程执行起来会迅 速,使用页表喷满3G内存在我们的测试机器上只需要3秒!

还有两点注意:

我们的溢出程序是一个正常的Linux进程。从沙盒中的溢出还需要进一步的  研究(例如:Chromium的渲染进程)

我们的测试是在一台没有占用过多内存的机器上进行测试的。如果想在一个 内存使用频繁的机器上溢出成功,还需要做更多的工作。

接下来:溢出步骤

第一步是

 调用mmap映射一大片内存

 通过“Row Hammering”随机地址对,找到可以对应的“攻击”地址/“受波及”地  址。我们通过搜索/proc/self/pagemap来找出刚刚跑出结果的物理地址。

 如果我们发现被翻转的bit不能用于我们的溢出,那么跳过这个地址

否则,释放掉出目标地址以外的全部内存页然后开始溢出攻击

为准备喷射内存页表,我们在/dev/shm (一个共享的内存区段)中创建一个文件。随后我们将频繁的映射它。(随后,我们将介绍如何确定这个文件的大小)我们在这个文件的每4k的开始写入一个标记数,当随后我们检查PTE的变动的时候,我们就可以非常容易的识别我们自己映射的内存页。

同时,我们也意识到我们的这些内存页不能被分配到连续的物理内存地址中。因为随后的当我们进行bit翻转的时候,很可能导致PTE的指针从一个我们的内存页指向另一个我们映射的内存页。

为避免这样的问题发生,我们首先要故意碎片化物理内存,这样系统从物理内存上分配出来的地址就随机的了:

调用mmap(使用参数MAP_POPULATE)从机器的物理内存上申请一大块 空间。

随后,我们通过调用madvise(使用参数MADV_DONTNEED)从这篇空间 中释放掉一个内存页,都会引起系统申请一个4k的内存页(例如:页表)

我们现在已经做好内存喷射前的所有准备工作。要进行内存喷射,我们需要反复的调用mmap来映射之前生成的文件:

我们希望每一次映射都会在以2M对齐的虚拟地址上,因此,每一个4k的    页表对应一个2M的虚拟地址空间。我们使用参数MAP_FIXED来达到这个      效果

我们通过访问相似的内存页来引导系统构建一些PTE。我们只需要对每个页 表构建一个PTE,因为我们知道我们的bit翻转会命中页表中的第N个PTE,    因为,为了效率,我们只对每一个2M内存区域的第N个4k内存页进行检 查。

 Linux对于每一个进程可以进性的mmap的数量作了限制(2^16)。这意味     着,我们之前在/dev/shm生成的文件必须足够大,以至于,当我们映射了2^16  此后,所申请的空间足够填充大部分的物理内存。但与此同时,我们希望保      持文件尽可能的小,这样就浪费掉本来可以用页表填充的内存。因此,在选 择这个文件的大小的时候,我们非常谨慎。

在喷射内存的过程中,我们调用munmap来释放掉可以进行bit翻转的内存   页。而系统就会有很高的可能性紧接着使用这片物理内存保存页表。我们虽       然不能直接操作这片内存页,但是我们可以通过“Row Hammering”来篡改它。

当完成喷射完成,接下来就是“Hammer”时间。我们通过“Hammer”攻击地址。      来期望它引发“受波及”地址的bit翻转。不同于前一个溢出例子,这次我们 不能直接观察bit翻转。

现在,我们来检查PTEs的改变是否可以利用。我们对我们映射的这一大片内存区域进行扫描,看看是否有PTE现在指向了我们申请的空间之外的内存。同样,为了效率,我们只需要检测每2M区域中的第N个内存页。我们可以检测我们之前写入的标记数。如果,我们发现如果所有的标记数都没有改动,那么我们的攻击失败了(胜败乃比家常事,大侠请从新来过)

如果,我们发现一个标记数被修改了,那么我们已经获得了非法访问一个物理内存页的权限。而且有希望是我当前地址空间的内存页。如果希望更谨慎一点,我们可以来验证一下这个内存页是否看上去像是我们的一个页表项。在这第N个内存页的64位应该看起来像一个PTE(对应的一些标志位是0还是1)。如果,不像那么我们的攻击失败了(胜败乃比家常事,大侠请从新来过)

能到达在这里,说明我们已经具备对一个很可能是我们自己进程的页表的写入权限。然而,我们还不知道这个页表对应的虚拟地址。我们可以动过下面的步骤来判断:

在这个内存页中写入一个PTE(比如PTE指向物理内存页0)

对地址空间做第二次扫描,去找第二个虚拟地址页同样没有指向我们的数据 文件。如果我们不能找到,说明我们的攻击失败(胜败乃比家常事,大侠请       从新来过)

用页表的写入权限溢出

我们现在已经拥有对于我们当前进程的一个页表的写入权。通过篡改这个页表,我们可以访问物理内存中的任意内存页。对于接下来的溢出,我们现在拥有许多的方法。这些方法在可移植性、简洁性和运行速度上有所不同。高可移植性的方法可以不依赖于对于系统内核数据结构的了解。更快的方法可以在O(1)时间内完成,尽管慢一点的方法啊可能需要扫描全部的物理内存来定位一个数据结构

一些方法,如下:

我们所使用的方法:篡改一个可执行程序,例如/bin/ping(以root权限运行   但不需要su的程序),使用我们的ShellCode来覆盖程序入口,然后执行程 序。这时我们的ShellCode就将运行在root权限下。这个方法非常迅速而且       方便移植,但是这需要访问“/proc/PID/pagemap”。我们载入/bin/ping(通过调 用open和以MAP_POPULATE为参数的mmap)并通过/proc/self/pagema查      询文件被载入了哪个物理页面

一个相似的方法是修改一个可执行程序的动态库例如      /lib64/ld-linux-x86-64.so.2(在一些系统上,像/bin/ping这些程序由于他们的     访问许可被锁死,会导致open调用失败)

其他,低可移植性的方法可以篡改系统内核代码和内核数据结构

我们可以篡改当前进程的UID。这需要定位当前进程的cred结构体,并 了解它的结构

我们可以篡改系统调用的处理代码。我们可以通过SIDT指令快速定位   到对应的物理地址。

引发“Row Hammering”的途径

我们的概念性的exp使用的x86指令CLFLUSH,因为这是最简单的发送强制内存访问到底层DRAM,并引发“Row Hammering”的方法

由于CLFLUSH指令在系统内核以及设备驱动以外,使用的概率是非常小的,因此CLFLUSH指令在用户层代码中可用是令人吃惊的。相比而言,ARM在用户层指令集中不存在这么一条缓存刷新指令。(Linux的ARM版本中JIT所使用的,确实有一个叫做cacheflush的系统调用。它被用来同步指令和数据缓存。而在x86版本中i-cache和d-cache是自动同步的,因此CLFLUSH对于刷新缓存是没有意义的)

我们已经修改了NaCl的x86校验器来屏蔽CLFLUSH指令。不幸的是,系统不能屏蔽来自用户层对于CLFLUSH指令的调用。当前,CLFLUSH不能被拦截或者屏蔽,即使使用了VMX(x86虚化技术)(例如RDTSC不用VMX支持就可以拦截。VMX允许拦截很多指令包括WBINVD和CPUID,但还不能拦截CLFLUSH)要拦截CLFLUSH也许需要修改x86构架。从一个安全工程师的角度来看,去掉不必要的受攻击面是好的习惯。

然而,不通过CLFLUSH也许还有其他的方法来引发“Row Hammering”,这也许可以使用在非x86构架上:

正常的内存访问:正常访问内存经过足够多的次数或者正确的方式,可以造 成大量的缓存未命中,从而引起“Row Hammer”的bit翻转吗?这需要使得每       一层缓存都未命中(L1、L2、L3等等)这是否可行取决于这些缓存之间的      关联性。

如果这个方法可行,这将会是一个严重的问题。因为,可能当打开网页执行 JavaScript时,通过JavaScript的数组就可以造成bit翻转。

绕过Cache的内存访问:在x86指令集中,有一类叫做非暂时移动指令(例 如:MOVNTI, MOVNTQ,MOVNTDQ(A), MOVNTPD, MOVNTSD and        MOVNTSS)和预读取指令(例如:PREFETCHNTA) (编者注:这些指令       是不同过Cache直接读写内存的)

原子内存访问:一些报告称无恶意的使用spinlock可以引发“Row     Hammering”,然而这些报告细节不够具体,我们也无从验证(论文《The   Known Failure Mechanism in DDR3 memory called “Row Hammer”》作者:  Barbara Aichinger)但这看上去在共享最高级缓存的多核心系统中不太可能实       现。然而,它可能在核心之     间没有共享Cache的多路系统中 实现。

未对齐原子内存访问:x86处理器可以保证使用LOCK前缀的指令对内存的 访问是原子级别的,即使要访问的地址是未对齐的,甚至超过了缓存界限。       (详见《Intel® 64 and IA-32 Architectures Developer's Manual》8.1.2.2节   “Software Controlled Bus Locking”。其中提到总线锁的完整性是不受地址是   否对齐的影响的)这个性质为了向后兼容而存在至今。在这种情况下,CPU   为了内存访问的原子操作而放弃使用缓存一致性机制。相反,CPU回到原始     的总线锁机制,我们相信CPU将使用非缓存的内容访问方式。(在一些多  路CPU非一致性内存访问的主机上,总线锁是通过QPI协议而不是物理      LOCK针脚)

如果非对齐原子操作产生了非缓存DRAM访问,那么这可能会引发“Row    Hammering”

初步调查表明这些原子操作确实绕过了缓存,但是这些访问太缓慢,以至于 不能在有效的时间(64ms的刷新间隔)内进行足够的内存访问操作,来产       生bit翻转

非缓存内存页:例如,Windows中CreateFileMapping函数使用参数  SEC_NOCACHE可以申请到一片非缓存内存页映射。

其他操作系统的接口:这可能发生在系统内核或者设备驱动中(例如GPU    驱动)可以在用户层代码中进行绕过缓存的内存访问。

实验结果

我们通过使用CLFLUSH随机地址对测试了一系列x86笔记本(都没有使用ECC内存)。我们发现其中大部分的机器存在“Row Hammer”引发bit翻转的现象。这个结果已经展示在下面的表格中

这个测试所使用的“rowhammer-test”测试程序可以从这里获得:

https://github.com/google/rowhammer-test

注意:

我们的样本空间还不足够作为一个严格的代表

一台给定电脑上的一个否定结果(没有bit翻转)并不意味着“Row Hammer” 在这台机器上不可能引发bit翻转了。我们没有进行足够的测试来证明一台      给定的机器是安全的。

作为结果,我们决定隐藏一部我们的数据

所有被测试的机器都使用DDR3内存。我们没有办法鉴别出所有的内存使用年限。

http://p2.qhimg.com/t013c34db03148aa6db.png

同时,我们也测试了一些桌面电脑,但是在它们上面没有发现任何bit翻转。这可能是由于,都是使用了ECC内存的高档电脑吧。ECC技术可以隐藏掉bit翻转。

测试你自己的电脑

用户可能希望通过上面提到的“rowhammer-test”测试程序来测试它们自己的电脑。如果一台电脑在测试的过程中产生了bit翻转,那么用户一定希望变得安全并信任关于机器的结果

与此同时在测试过程中没有bit翻转的机器也并不意味着安全。这个测试仅仅证明引发bit翻转在这台电脑上比较困难

攻击缓解

针对附近内存行的刷新

为防止“Row Hammer”引发bit翻转,一些方案提出改进DRAM,改进内存控制器,或两者兼而有之。

Yoongu Kim等人在他们的论文中讨论了。一个系统可以确保在一个给定的时间周期内,即使没有确定相邻的内存航是否正在刷新,也不会对给定的内存行进行过多次数的“激活”。他们的论文中提出“维护一组计数器”(无论保存在内存控制器中还是DRAM中),用来记录“激活”的次数。这篇论文建议另一个叫做“PARA”的概率性的方案。这个方案并不是很正规也因此不需要维护计数器。

有迹象显示一些较新的硬件已经具有缓解能力:

JEDEC近期发布的LPDDR4(“LP”代表低电压)将了两个“Row Hammer”攻击缓解技术列入说明书。这两个技术很可能将用于内存控制器中。(具体看以查看JEDEC  document JESD209-4,虽然从JEDEC官网注册后才能下载,但是注册是免费的)

“目标行刷新”模式(TTR),这允许内存控制器要求DRAM设备刷新指定行的周围行

“最大‘激活’计数”(MAC),这指定了一内存在其相邻内存行需要刷新前,所能承受的安全的“激活”次数

(LPDDR4的说明书并没有直接提到“Row Hammer”这一次,但是他们使用了术语“受波及的内存行”)

我们还发现至少一家DRAM生产商在他们的公开数据中表示他们不需要借助特殊的内存控制器的支持,已经在DRAM设备中加入了“Row Hammer”       攻击缓解方案。

我们测试的一些较新型号的笔记本确实没有出现bit翻转。一个很可能的解释是这些笔记本都具有了“Row Hammer”攻击缓解能力

BIOS升级与加快刷新频率

硬件生产商是不是已经悄悄的推出BIOS升级?通过修改BIOS对于CPU内存控制器的配置,缓解了“Row Hammer”问题。

举个栗(实)子(验),我们对第4台样本笔记本进行双侧“Hammering”来观察发生bit翻转所需要的时间。这个观察到时间都没有超过5分钟。随后我们将笔记本的BIOS更新到最新的版本,然后重新进行“Row Hammering”测试。

我们最初以为现在的BIOS已经修复了这个问题。然而,经过接近40分钟的连续“Row Hammering”测试,还是出现了bit翻转。

我们推测更新的BIOS提高了DRAM的刷新频率。这使得在DRAM的刷新间隔中造成足够多的干扰标的更加困难,但也还存在成功的可能性。这个与Yoongu Kim等人的论文中所提到的相符(参考论文第四个表格)在他们的论文中提到,对于一些DRAM型号,32ms的刷新周期是不足以将bit翻转概率降至0的。

我们没有大范围的对笔记本上的BIOS升级进行测试。

使用性能计数器监视“Row Hammering”

CPU性能计数器也许可以被用来检测“Row Hammering”攻击。为了有效地“Hammer”一片内存区域,攻击者必须在短时间内产生大量对底层DRAM的访问。不论攻击者使用CLFLUSH还是通过正常的内存访问,这都会产生大量的缓存未命中。

现代的CPU为性能分析提供允许监视缓存未命事件的方法。这些方法可以被防御方,有目的的用来监视系统突发的缓存未命中,因为正常的缓存未命中的访问方式在台式机和笔记本上都是极少发生的。通过记录每N个缓存未命中发生所需要的时间并监视不正常的变化,即使在系统繁忙的时候,我们也可以发现“Hammer”攻击。不行的是,即使我们检测到可能的“Hammer”攻击时,我们即无法做出明确的响应,也不知道正常的缓存未命中如何确定。

与此同时,攻击者也可以使他们的攻击规避这些这种检测,这将增工程量,让这个监控程序变成了一个指令检测程序。

揭露真相

计算机行业(谷歌也是其中一员)对于软件中的安全问题已经习以为常了。这也使得,对于公开讨论和披露的安全问题的重要性已经形成了共识。通过这些公开的讨论,也使得对于存在安全风险的Bug得到了更深入的认识。虽然这个行业对于硬件Bug还不太了解,但是通过公开讨论和披露这些相同的方式,也可以让硬件安全获益。

考虑到这一点,我们可以得出两点经验:

Bug的可以用性:回过头来,如果有更多的关于“Row Hammer”的披露,这个问题就会被更早的当做一个安全问题。看来生产商对于“Row Hammer”的了解已经有一段时间了,就像刚刚提到的LPDDR4中的“Row Hammer”攻击缓解的方案。也许是因为生产商并不认为这是一个具有威胁的安全问题。

评估计算机风险:期待公布更多的关于“Row Hammer”的技术细节,这将有助于评估一台计算机究竟存不存在这个问题。截止到这篇文章结束,还是很难断言一台计算机不受“Row Hammer”影响。测试可以说明一台计算机存在漏洞,但不能证明完全不存在漏洞。

我们接下来具体阐明这两点

Bug的可以用性

生产商并不会认为这是一个具有威胁的安全问题,假设这个溢出很难实现。我们所看到的关于“Row Hammer”的材料,没有一篇(除了Yoongu Kim等人的论文)探讨其安全威胁。

然而,许多问题看上去很难实现溢出,但实际被证明可以被利用。这些问题最初可能被认为仅仅是一个无关紧要的问题,结果最终变成了一个安全问题。

举个极端的栗子,最近Project Zero的Blog上描述的一个很难溢出的问题(地址:http://googleprojectzero.blogspot.com/2014/08/the-poisoned-nul-byte-2014-edition.html)这里展示了通过一字节偏移的覆盖实现了溢出以一个正常用户获得了root权限

对于大多数安全研究人员,尤其是那些练习写验证性溢出程序的人员,大家都知道bit翻转是可以被拿来利用的。例如一篇2003年的论文就像我们展示了如何利用随机bit翻转来实现JAVA虚拟机的逃逸。(详见“利用内存错误攻击虚拟机”,作者Sudhakar GovindavajhalaAndrew W. Appel.,地址:

https://www.cs.princeton.edu/~appel/papers/memerr.pdf)

而且,就像我们文章中所说的,“Row Hammer”引发的bit翻转是比随机bit翻转更加好利用,因为“Row Hammer”引发的bit翻转是可重复尝试的。

评估计算机风险

我们鼓励生产商公布设备的信息,这样安全研究人员和公众可以用以评估他们的计算机是否存在“Row Hammer”问题

接下来信息对于我们的评估将会是有帮助的:

对于每一种DRAM设备:

这个DRAM设备在物理层面上容易被“Row Hammer”引发bit翻转吗?

这个DRAM设备包含了那些“Row Hammer”的缓解方法?它包含TRR或者MAC吗?这些缓解方法是否需要CPU内存控制器的支持?

对于每一款CPU:

这款CPU的内存控制器中包含那些缓解方法?这些方法需要DRAM设备支持吗?

是否有关于在计算机初始化时如何配置CPU内存控制器的公开文档?

当初始化完成后,还是否有可能读写内存控制器的配置内容,用来验证是否开启了缓解方法?

内存控制器是如何将物理地址与DRAM中的存储单元、行、Bank对应起来的?这对于发觉究竟是哪几种内存访问方式可以引起“Row Hammering”是有很大帮助的

对于每一种BIOS:

究竟哪一种缓解机制被BIOS在CPU内存控制器中开启了?例如,BIOS开启了双倍的刷新频率或者使用了TRR?这些配置都可见吗?

截止到发布这篇文章,我们都不能找到一点关于以上内容的公开信息。

如果以上的信息大部分都可以获得,那么评估一台计算机将会非常简单。这也使得我们可以更容易的在测试没有产生bit翻转时,判断这台计算机是否存在这个问题。当一台机器经过测试没有发现bit翻转时,我们可以解释说是因为DRAM包含了缓解措施,或者因为DRAM物理层面上不易受到影响(究其原因,是生产商使用了旧的生产工艺)或者因为BIOS初始化了两倍的内存刷新频率。如此解释,会让我们在测试没有结果的时候有更多的自信判断这台计算机并不受这个问题影响,而不是因为我们反复的测试中存在一些不足的地方。

我们希望研究人员在接下来的时间里,会对评估“Row Hammer”缓解方案感兴趣。例如,让DRAM设备记录内存行“激活”的次数(就像MAC方案中建议的一样)或者像PARA使用概率的方法。这些缓解方案的效果在双侧“Hammering”和单侧 “Hammering”下一致吗?DRAM设备和内存控制器独立的缓解方案是否会互相影响。

结论

我们展示了两种通过“Row Hammering”的溢出案例。历史不断向我们证明,一个看似不可利用的错误,最终变成了严重的安全问题,而本文中的“Row Hammer”就印证了这一点。许多的安全软件还停留在除非对地址进行操作,否则内存不会被篡改的思想里。

在过去的十年里,公开讨论软件的瑕疵和对应的利用使得计算机行业对于安全的理解有了巨大的发展。也使得可靠的软件生产商在他们的产品出现问题时及时通知用户进行升级。虽然相比于软件问题,计算机行业还不太习惯于硬件问题,我们应该鼓励硬件生产商采取相同的态度,来彻底的分析这些看似不可利用的错误所带来的影响,提供详尽的说明、缓解方案以及固件或者BIOS的升级。通过讨论可以使得硬件更加安全,而让广大的用户从中受益。

友情出演

Matthew Dempsky提出通过对PTE进行bit翻转来实现“Row Hammer”攻击

Thomas Dullien帮助测试了大量受影响的计算机,提出了双侧“Hammering”的思路,作了BIOS升级实验,并帮助具体的完善了PTEbit翻转溢出。




本文由 安全客 翻译,转载请注明“转自安全客”,并附上链接。
原文链接:http://googleprojectzero.blogspot.com/2015/03/exploiting-dram-rowhammer-bug-to-gain.html







版权所有© 2018 Index of Computer System and Security 保留所有权利.