Intel李晓宁:漏洞攻击防御技术探讨

李晓宁:大家好,今天很荣幸在这里跟大家分享一些关于防御方面的经验。我想大家也有看到,今天的话题很多都是关于攻击,可以说在过去的几年或者十年中,攻击始终是主流,因为防御是一件非常困难的事情。

当你设计一个很复杂的系统的时候,你不可避免的会导致各种各样没有考虑全的或者说潜在的设计上的一些漏洞也好,原因也好,最终你会发现你设计了很复杂的系统,或者说很强的防御系统,最终会被攻击者在一些点上轻易的绕过,所以这是一个非常挑战的事情。

我来自于英特尔实验室,在过去的10年里主要专注于利用硬件芯片技术去设计整个系统针对Zero Day和APT进行防御,今天我主要介绍一些我们做过的或者说相关的一些硬件的功能以及相关的防御思路。

首先我们看一下今天在Windows OS里面最流行的一些防御手段,我并没有列出所有的防御手段,这里列出比较重要的。DEP就是执行防御,它解决了一个数据本身,作为开发者没有允许它作为执行的情况下,

在过去的很多年里没有DEP的时候,攻击者可以很轻松的跳转到控制的数据里面执行,这个问题就彻底杜绝了数据的存储进行执行的这样一个问题。其实这个从实现上来说是一个很的实现,但是从防御的角度是一个很重要的。

有了DEP之后,我们发现实际上很多时候攻击者还可以用很多其他的方法,比如说IOP进行这些攻击。怎么样让他们的攻击成本更高,更困难,这个本身在地址空间访问上就带来了另一个防御手段叫ASLR,这里我用蓝色标注的都是依赖于硬件的功能,

没有标注的都是软件,因为ASLR这个功能大家可能知道,这个就是软件上的一些防御,然后怎么样保证它每次加载的时候是随机化的,去增加这个攻击的难度。

在这个之后,我们又看到了很多,因为在相当长的一段时间里面,栈溢出是非常流行的,针对这些,软件厂商也提出了很多新的功能,比如说Cookie这样的,集成到软件系统里面去,然后对它进行防御,这种防御手段更多的是针对特定的漏洞类型以及攻击方式。

在这之后,我们在硬件层面上Windows集成了一个SMEP的功能,SMEP解决了一个当你在内核态不经允许,任意返回到用户态去执行的时候,这一条路径是一个非法路径。在没有SMEP的时候,这是一个非常经典的内核提权的方法,有了SMEP之后,这条路就不能用了。

当然攻击者发现了很多途径,比如怎么样套到内核态去执行,这是一些新的攻击法,但是这条路就不能用了。

当栈溢出已经不再是主流的时候,我们发现在相当长一段时间之内,尤其是过去几年,这种漏洞非常流行,有很多人发现了各种各样这样的漏洞。在这个利用过程当中,你怎么样控制这个内存把它Free掉,重新到你可以控制的地方,

然后很准确的控制这个内存当中的数据,这本身都是在你在成功的Explore过程当中都需要解决的问题。微软有提供了这样的功能,让你的Explore变得更加的困难,当然设计本身也有很多的缺陷或者是漏洞。

今天CFG已经成为了一个非常流行的,你在Windows上进行跳转这件事情,他提供了一些功能,保证不能在任何地方都跳转过去,试图增加攻击者的难度。

这张图我只是讲了今天在Windows下面最主流,最流行的一个攻击的方法和环境。实际上我们作为硬件厂商提供了很多底层的功能,都可以用来做一些防御,这里我列到一些我们非常经典的安全功能,是芯片级别提供的。

第一个是EDB,这个很简单,就是最典型的第一批实现的硬件基础,就是你想去防止这样一个Memory去执行,你必须要告诉硬件这个Memory是否可以去执行,在传统的架构里面是没有这个Bit去做这个事情的,

通过EDB的项目,增加这个Bit可以保证我们可以很清晰的去让这个Data和Memory不可执行,这是硬件上面提供的功能,软件去执行,最终提供相应的解决方案。

SMEP是我刚才解释过的,超级模式下的访问,关键解决的问 就是,当你在内核态的时候,当你有一个漏洞,比如说你这个EDX被攻击者控制,如果没有SMEP这样的Feature,可以直接把内核态指向用户的地址,你可以非常容易的做提权,加一段代码替换掉。

有了这个功能之后,这条路就不工作了,你必须要想别的办法在内核态增加攻击者的难度。

还有一条功能是SMAP,这个和SMEP非常一致,但是不太一样的是在于,SMEP在于你在内核态的时候执行用户态代码,SMAP是说我在内核态的时候,我怎么样保证对用户态数据的访问是受限的,并不是在任何地方都可以。

这个主要是在硬件里面提供相应的功能,有一些状态说当你在内核里面需要访问用户态数据的时候,比如说最经典的Case就是说,你做了很多的参数,你需要靠一些Driver,需要从用户态获得数据。

在这种时候,因为这个Driver是开发者写的,他可以通过这些补丁强制说我只有在这个地方才能访问这些数据,其他的地方的访问可能都是非法的。这样的话,极大的降低了攻击者利用任何一个地方都能进行访问,比如说Time to choose的漏洞,就可以用来做这方面的防御工作。

下面一个叫做MPX,这个功能我想很多朋友都知道,它主要是我们提供了一组数据,可以让你可能导致Fold的地方加特定的指令,这些指令在每次做这些Memory访问的时候,可以通过预先已经配置好的数据,当然很多数据是编译阶段就已经获得了,对这个Memory的访问进行控制。

比如说一个数组只有10倍,在没有这些指令的时候,你对这些数组进行访问的时候,可能有一个变量,比如说这个变量可能是EVX。在这种情况下,我要做一个读写,当我的EVX被我控制之后,它可以不是10,如果是0到9的话,可能最大的值并不是9,可能是10或者说100。

如果你用了一套这样的指令去加入进行数据访问的地方,CPU就会自动的根据内存里面已经准备好的数据去对它进行一个检查。当你说我要访问的时候,CPU会根据预先配置好的数据去检查,这个指征只能是0到9,你用100的时候,可能就不行。所以这个功能可以用来帮助大家预防一些漏洞,降低被利用的可能性。

后面一个叫SGX,我想很多朋友也知道,这是一个很大的功能。我们提供了SGX这样一个功能,实际上它是说,有很多时候防御是很困难的,可能到最后一步的时候,的确病毒已经在运行了,我们并不能完全的停止Explore这个过程,

允许你把重要的数据,比如说银行卡,比如说密码这样的数据放到TE里面做预算,当你离开了这个环境之后,这些数据在外面不可信的是不可访问的,他没有权限获得这些敏感数。我们SGX已经发布了,后面有两个Feature,

一个是最新的CPU很快就会有这样的功能,主要是解决了一个Memory访问的问题,后面有一张幻灯片会更详细的讲这个功能,讲怎么样利用这个功能我们去设计一些沙箱,去防止这种攻击。

最后一个就是CET,这是一个非常重要的Feature去解决问题。怎么样有一套解决问题的方案,实际上是非常挑战的,这个我们和微软一起合作,推出了这样一个功能。

在此之外,我想各位朋友也知道,很多时候是他山之石可以攻玉,我们设计了一个功能可能并不是针对安全的,但是你可以用它来做一些安全防御上的事情,也许效果还非常好。

比如说这里面第一个例子是LBR,我想如果大家关注微软的话,你会发现他们几年前得第一名的项目最核心的技术就是利用LBR去记住当前执行PaaS过程中的执行信息,然后再根据一些Policy,这是今天已经非常流行的一个Policy,这是一个功能。

实际上LBR这个功能在我们的CPU里面已经存在了很多年,很多时候可能大家没有想到这个功能实际上也能用来做防御。

第二个功能是BTS,LBR的限制是它是一组MSR,这些MSR在每一代CPU里面都是有限制的,比如说16个,32个,最多是这样。你怎么样做到我们能有更多的信息在里面,抓到更全的信息。

这个时候你可以利用一个叫BTS的功能,你可以有一段Memory。当你正确的配置完这样一个功能之后,CPU会帮助你把所有执行过程当中的路径,相关信息存到这个Memory里面,当然这个对性能是有影响的,如果你做终端的话并不可行。但是如果你做沙箱或者是后端的话其实也是一个很好的选择。

在此之外,我们还提供一些很简单的DB,在很多场合里面也可以用来做防御,也许也会做得很巧妙。比如说我们支持Single Step每一个你去做检查不可能,我们同时还支持BTF,当你在Single Step的情况下,你获得了一个机会,你可以很容易做检查。

今年我们发过一个很小的工具,就是基于这个原理,每次发生的时候我们去做一下检查,看看有没有做。作为工具可能不可行,但是作为后台工具是足够的。

PT这个工具提供了一个更强大的功能,是说我怎么样让用户可以定制,说什么样的数据我要记录,并且提供一个很好的性能,今天这个功能里面这个性能已经可以接受了,可以用来做很多的研究。

比如说前几天有思科的同行发布了他们的研究工作,他们抓到了相关的数据。因为你知道,在没有这样的功能之前,大家很多人都是用的是其他的技术,但是实际上离这个技术还是有很多的限制。如果能够很好的利用PT这样一个功能,会获得很理想的数据。

还有一个是PMU,最初我们设计的时候是为了做整个代码的功能,但是你发现这个功能并不局限于它,你完全可以用它来做更多的防御上的工作。后面我还有一个幻灯片会稍微更详细的讲一讲。

下面一个是VT,实际上VT是一个非常复杂的东西,整个英特尔的这套VT的架构,包括你怎么样选,这是一个相对比较复杂的。这里面会有很多不同的Using,如果你关心最前沿的OS的动态的话,你会发现微软实际上在Windows10里面做了一个功能,核心的就是用VT提供了各种安全上的加固。

后面我会有一个幻灯片,举一些例子讲我们做过的工作,在上面怎么样做安全上的防御。

下一个很简单是Memory Model,我想大家很多人都知道,在英特尔的CPU里面保持了相当长一段时间。但是你会发现,如果你设计的非常好的系统,微软还没有正式的发布的一个Feature,包括腾讯的朋友也有分析,TK他们都有分析,你会发现,他们实际上里面应该是碰到了一些技巧去做一些保护。

今天我们实际上面临一个很大的问题就是Code Rease,实际上可以有很多的方式,它最核心的问题是说,我能够Run一些我需要的代码,同时能够把很多代码片拼在一起。

在这种情况下,这是一个简单直接的方法,这些都可以把代码拼在一起,做一个攻击者需要的事情,这个有相当长的时间,是专注于ROP、JOP、COP的事情。如果你做了这些时候,可以调用的代码实际上是受限的,必须在合法范围内。

在这里我们简单的回顾一下CFG,其实思想非常简单,都检查是不是合法,是不是应该跳到这个地方。通常这个OS里面都会很好的配置好,每次当你要到一个地方的时候,系统里面配置好的检查函数会根据他自己的算法去利用你要到的那个地址进行一个运算,最后去检查这个地址是一个合法的地址可以跳转。

事实上CFG这个工作,从设计的角度非常简单的漂亮,但是总有一些问题,很多人都在做这方面的研究工作。在这里我简单列一个思路,CFG站在这个角度有很多问题需要解决。

当你提供了这样一个很简单的Feature的时候,你发现产品去配合它需要很长的路要走,有很多时候可能就是兼容性的问题,各种各样兼容性的问题必须要去解决,去保证正确的Enable,如果你去看最新的Edge的进程的话,里面还是有这样的问题在里面。

CFG你可以Call到系统准备好的检查函数,可能是没有做到位,或者是有Bug或者是实现上的问题,会有一个方法最后篡改了这些Setting。比如张云海几年前就发布了这样一个信息,一套很复杂的代码操作流程,让一个只读的Memory变成可读性的。

一旦你由只读变成了可读性之后,只要你有这样一个功能,你可以很轻易的把CFG检查的函数那个指征存在的位置,改成了一个非常简单的,你跳到任何地方都没有人去挑战你。

在此之后,你会发现很多其实本身CFG生成的代码有时候可能并没有Enable非常到位,比如TK曾经讲,当你没有做出很好的准备的时候,你跳到一个Code里的时候,在用户调用的时候可以进行控制,

你可能一样还可以跳到其他的地方,有很多这样的问题可能还需要解决。这里面可能会涉及到很多OS的环境,兼容性等很多问题在里面。

即便你解决了所有的这些问题,但是你还保留了很多合法的函数,这些函数本身串在一起,可能一样可以提供一个强大的功能允许你去做By Pass。站在这个角度,CFG还有很长的路,还有很多问题需要解决。这就是为什么我们会有CET这样的功能推出来。

首先在CET里面,CET其实包括了两个功能,包括Shadow Stack和Indirect Tracking。如果CET有了之后,CPU会看这个过程,检查是不是合法的地方。另外Indirect Tracking就是看你是不是可以跳到这个地方,告诉系统说这个地方可以做,那个不能做。

这是Shadow Stack,当你今天调用一个Cop的时候,CPU会调到一个站上。如果你Retent的地方并不契合,会给你一个信号,你可以抓住攻击。

Indirect Tracking就是说,当跳转指令发生的时候,我们会很好的去比对,跳转到的地方有没有这样一个Tack,如果没有这样一个Tack就是一个非法的。我们把Shadow Stack和Indirect Tracking放在一起,试图加强这个防御,让攻击成本更高。

即便有一天我们有了CET这样的功能,你会发现所有没有Tack,都会被防御掉,只要做得足够好,保证你生成的这些里面没有合法的这些Tack,我们还是可以防止住这些,可能编译器编译的时候并没有告诉你说这个地方是可以跳转的,

但是由于种种原因,最后在可执行数据里面还包含了这样一个Tack,这个Tack一样可以跳转做一些事情。但是如果你做得足够好的话,可能这样一些东西可以避免掉。

反过来看,即便这些功能都在那里,有很多时候这些合法的函数跳出来,我们依然很难去控制。比如说最简单的例子,很多年前在GS里面,因为他要有相同的代码,通过一些Bit去强制一段上下文能不能执行一些敏感的函数,或者不能执行敏感的函数。

但是如果你拥有了这个之后,你可以很轻易的去修改,还可以跳到这些函数里面去。但是这个跳转在这个当中是不是合法?实际上并不合法,这些问题依旧在那里,很难去解决。还有包括TK曾经讲过的跨维度的攻击,

其实核心思想就是在这样的引擎里面,当你用合法的方法去操作或者是控制这个内存里面的时候,你可能就生成一组对应到底层一系列的API Copl。这些问题依旧在那里。包括Loop Cop,反复做一些事情,做各种防御,这些还都是在那里。

这是我们几年前一起讨论的,我们认为应该是有授权的。你看这张图里面,API里面有一个Funtion1.1,又有2.1,这张图的脉络是非常清楚的。Function直接到1.1是没有问题的,到2.1的时候是一个非法路径,我们需要把这样的看起来是合法的API的调用区分出来,利用完整的信息去停止这些攻击。

在这里我简单的列了一下,就是当你去判断一个Branch Transfer的时候你应该看到什么?我想我们大家应该都知道,原端口、原地址、目标地址、目标端口,这是一个非常清晰的地图。

反过来我们再看这里非常的相似,当你调一个指令的时候,你原地址是放的什么样的指令,你的目标地址是什么,在什么样的模式下面。当你把所有信息放在一起的时候,你会发现你会拼出一张很大的图,发现这里面隐含的逻辑,帮助你很好的去得到这些转换。

一旦你有了这样的机制,你可以很好的防止这些,包括调用一些完整正确的函数,但是可能在上下文逻辑里面并不是真正的函数。

在这里我举了一个例子,Branch Transfer Access Control是一套思路,如何做才能被产品和思路接受,因为性能是一个很可靠的衡量目标,PMU就是很好的让你去做研究的。在英特尔的PMU里面有很多的事件,当每一个你管线的invent可能会发生一个PMI,在这个里面你就可以去Apply你的一些Policy。

这边这个图很简单的讲了一下这个思路,比如说一个PMI发生的时候,你有可能就掉到了你的这个里面,你可以去加一些可以做的防御手段或者说Policy。如果你觉得这个东西有点麻烦,或者说你需要更多的Context,你看到这个执行,当A要跳到B的时候,A触发一个Interrup,检查函数执行完了以后再到B。这个路径本身可以看到,实际上很花时间。

作为一个防御手段或者说防御技术来说,在这个上面对于Invent选取非常讲究,你会发现所有的都会触发,我可以做拦截分析。这个在CPU里面是一个非常重要的单元,帮助提升处理器的性能。在这一层上,现有的这些信息非常好。

如果你说只在这个地方触发的话,会发现你这个Invent急剧下降,在尽可能少的里面减少这些供给的Case,可以很好的防御。特别是你做APT或者是后端分析的时候。

前面我们梳理了一遍以前做过什么,以后会有什么样的功能,包括再进一步说我们应该怎么样思考这个防御工作。转过来,Arbitrary Memory Access是一个很重要的,今天你说AMA,可能很多人通过这样一些方法去进行By Pass。

我们如何防止这种Arbitrary Memory是一个很重要的问题。在这里我简单介绍一下我们的一个Memory Protection Keys的功能,我们每一个岛下面都对应着一个Memory的权限是不是可以访问,大家知道,每一个地址在PTE里面都会有相应的PTE的项。

其中我们在这个上面加的一些新的Bit,让它提供一些信息。举一个最简单的例子,今天你有一个代码,这个代码你可能去想说,我这个Bit已经有了,我想去修改掉,今天你是随便去做,没有任何防御。

但是如果你有这样一个功能,你会发现,每次当我需要对重要的数据读写的时候,我切换到一个正确的模式,这个时候这个重要的数据所在的Memory对应的那个访问的权限是可读可写的,或者说你需要的可读或者说可写,这个根据你的上下文去解决。

当你不需要的时候你把它切换回来,那个Domain是不可以访问的。当你再去读写那个Memory的时候,因为那个Memory已经是不可访问的了,你会直接导致一个异常,就不工作了。这是一个非常简单轻量级的功能,我们可以用它来做一些重要的代码的沙箱或者怎么样,可以很好的提供防御,这是一个很典型的例子。

在这里我稍微延展一下讲,一样还是Memory Domain的问题,你可以有很多不同的方案去解决。EPT是一个基本的概念,就是针对于普通的OS,根据EPT这个值,对本身进行各种Memory的权限设置。

传统的环境下面实际上我们是没有这样一个功能的,但是你在EVT下面,你会发现已经在那里了,我们提供三个,Read、Write、Executable,如果大家关注最新微软发布的一些功能,有一个功能应该是在Edge里面提供了这种解决方案,我想可能EPT是一个很好的去做这个工作的。

在这里着重介绍两个我们做过的工作,其中一个叫VMFUNC,这是一个新的架构,你可以想像,在OS、Hypervisor里面,你试图保护一个重要的数据的时候,我们还举一个例子,比如相关的一些Bit数据。

有了这样的数据,你怎么样很好的配置权限?这个可能相同的一个,最后是相同的,在这种情况下,如果你能很好的做一套Design,当重要数据访问的时候,你切换到该有的,当结束之后你切换回来,当发生的时候是读一些重要数据的时候,

那个时候Memory对你的权限已经不允许它被读写了,这个时候会触发一个EPT Violation,会进行安全检查,看看谁访问了什么数据,是不是一个合法的攻击。

但是这条路实际上花费是比较高的,当你对一个Memory反复的进行读写的时候,就会导致EPT Violation,如果这并不是一个攻击的话,实际上对性能还是有很大的影响。虽然我们有这样的功能,尽可能的去减少,基本上如果你设计的好,不可能导致是一个攻击的Case,可能很好的提高性能。

如果这样的Case发生的时候,我们也希望降低整个系统性能上面的影响。我们推出了另一个功能是20的相量,也就是说,当你在Hypervisor配置了这个功能的时候,如果你提前在这个相量表里面填入了正确的数据,这个就会结合,你可以更好的在当中进行安全防御。

我想这实际上是一个很重要的功能,这两个功能,我们观察了一段时间,这种底层的技术会需要很长的时间被使用或者是最后普及下去,这是一个很长的过程。现在应该是慢慢有人开始做这方面的研究,去提供保护。

我们看过所有已有的,或者将要发生的,以及将来可能会发生的一些防御手段。我们可以看到,实际上Mitigation这个方面,可能会进入更多的CFI、CET这种功能,这是一个方向,我想可能需要有这样一个方向,最后很好的解决很多漏洞攻击的问题。

在另一个角度,Memory Domain沙箱是另外一个方向。所以怎么样提供一个沙箱的Domain,这是尽可能降低Explore攻击的一个防御手段。

今天我主要是跟大家分享一些我们做过的技术,包括分享一些我对这个防御手段发展的看法。最后非常感谢大家的时间,谢谢!

上一篇:Nicholas Dean Stephens:Automating Exploitation – Shellphish Style

下一篇:同济大学朱西产:道路交通“零愿景”——汽车变革的动力