张超:漏洞挖掘的艺术

摘要:模糊测试是近年来最流行的漏洞挖掘方法。研究人员也提出了众多的改进方案,极大提高了自动化漏洞挖掘的效率。本文中将介绍模糊测试面临的挑战,当前最前沿的研究进展,以及演讲人团队提出的解决方案。

张超

张超    清华大学副教授

今天的题目是“漏洞挖掘”。我本科和博士是在北大毕业,博士后毕业在伯克利工作三年,2016年底回到清华,我研究的方向是软件系统安全的方向,做了很多攻防相关事情,包括CGC做了自动化攻防,参加过微软的防御竞赛blueHat获得了特别评委奖,随着这个方案演化之后,变成了刚才宋凯讲到的CFG那个防范和实验部署,还有Defcon也参加过,当时蓝莲花的成员,获得2016年第二名的成绩。

我们蓝莲花队首先是清华的学生发起的,2013年第一次打入Defcon CGC半决赛,这是大陆第一次。2016年拿到第二名,是目前国内排到最优成绩的。右边列了过去五年Defcon的名次,第一名绝大部分都是PPP,是美国CNU大学带队;2015年第一名是韩国战队,因为当年出了一个很神奇的小伙子,很厉害,大家可以去了解一下。

CGC是我们做的最有意思的系统,也是目前正在研究推进的事情,做的是自动化攻防,刚才大家听到凯讲到,真的要找到漏洞,利用漏洞这么一长串的事情,非常复杂。即使你很有经验,做这个事情也要花很长的时间,这个比赛是三天的时间,题目相对要简单很多,一般大家花半天或一天的时间才能解出一道题,非常困难。真实的软件难度更大。CGC是美国国防部DARPA发起的一个项目,两年的时间花了5000万美元做这个事情,最终设计自动化攻防系统,有点像AlphaGo一样,它的任务不是下围棋,而是做黑客的事情,攻击防御的事情。当时我带领队伍参加这个比赛,资格赛的时候我们是行域(音)第一名,决赛时是防攻击一等奖(音)。我的研究是与CDC主题非常相关的。

今天我们的主题是漏洞挖掘,一个简单的故事是WannaCry,大家都知道。

WannaCry背后是因为美国NASA的合作承包商被攻击了,它的网络军火库被偷出来了,其中包括攻击武器,WannaCry就把这个攻击武器做了包装,写了一个勒索软件。这个泄漏的网络军火库里有攻击工具,这个攻击工具是因为有漏洞,大家知道SMB的漏洞,攻击工具可以利用这个漏洞发起攻击。微软在真正WannaCry爆发之前,3月份已经发布补丁,WannaCry是5月份爆发的,如果大家打过微软的补丁,WannaCry就没有事。

从科普角度看一下漏洞的模式,为什么漏洞很重要。从系统角度来看,用户的数据或计算机理比较重要的是数据,还有比较重要的事情是计算机上的控制权,在上面有运行代码,可以用在系统里。大家可以想想,攻击者在外面怎么攻击你的系统。我认为主要是两个攻击链,一是软件,你这个系统怎么着都得需要软件与外界进行交互;二是人,这两方面都很容易被突破,软件方面可能存在漏洞,人这边可能存在社交工程,比如钓鱼网站、欺诈,它以心理学相关的东西,欺骗人去下载一个恶意程序来安装的方式。通过这两种渠道之后,它最后进入到你的系统,一般形式是运行恶意代码,大家推说过病毒、蠕虫这些东西。我们这次通过软件漏洞进入系统方式,关注的是软件漏洞。软件漏洞,具体我们关注很常见一类的内存漏洞,包括缓冲区,除了Use-after-free等等漏洞,刚才宋凯也介绍了一个漏洞就是这个类型。这些漏洞是大家听过很多安全故事的根源。像苹果iOS越狱,Android的root,甚至包括伊朗核设施、震网病毒、心脏滴血Heart dripping等等,背后其实都是有着漏洞的。这些网络漏洞危害那么大,攻击当然也想挖洞,必须有漏洞能力攻击。防御方也是在考虑怎么挖漏洞,把漏洞挖出来,我可以把漏洞修掉,让攻击者没办法冲击。

怎么去挖漏洞?主要方式是两大类,第一是带上手机,人看源码或逆向工程,很多黑客很擅长做这个事儿,逆向做安全程序或审这个源代码,前段时间,360报的EOS的虚拟机漏洞,其实是人工审计中发现的。自动化方面,学术界提出了很多方法,包括程序分析里的静态分析和动态分析,污点分析,符号执行,我想重点说的最主要的是Fuzzing测试技术。当然,非公开数据说有80%以上可能都是用Fuzz技术来发现的,我重点介绍一下Fuzz怎么做漏洞挖掘。

Fuzz的基本想法很简单,就是给程序做测试,给程序进行大量输入,让程序运行,运行过程中程序出现了问题,比如程序崩溃了,那就是有漏洞。更聪明一点,在运行过程中监控这个程序,把监控的结果反馈给前面,前面再负责新的输入,这是基本的流程,非常简单的流程,和程序测试很像。这样的逻辑它都能实现,但我们简单实现一个东西效果很差,最关键的是我们怎么样有效生成这个输入,很快找到输入的触发漏洞,如果完全没有办法,随机的话,就比买彩票还难,因为输入空间太大了。所以,研究热点的时候我们怎么生成这个输入。

主要分类有两种,第一种是基于生成的,它的想法是,我们知道这个输入会长什么样,知道它的格式,知道它的word文档,是个word格式,我们生成的时候基于这个格式生成就好了。它要求我们比较知道输入的格式和规范,这不是所有情况下都有,有的并不知道它的输入长成这样。第二种是更通用的基于变异的,我们不需要教它语法,你给我的输入,我在输入上随便变异一下,像自然界中的变异,输入新的再测试就好了。基于生成有很多工作可以做,PEACH这是个开元的工具,它可以自己来定义,你告诉它输入什么样的格式,它会有文件指定这个格式。工具自动基于这个格式帮你做输入生成。除了数据格式之外,PEACH还提供程序内部处理输入,可以想象是很难的,要给程序做状态建模,相当于把程序写一遍,本身就是很复杂的事情。这个东西还是挺有效的,但工程量非常大,我也得告诉它输入规范,数据的规范和程序内部的状态,可能有不少工业界的人在用这个东西。基于变异,给我一个数据,随便从原来的输入这儿随便找一些自己进行编译,就得到新的样本。这是变异的第三个特点,三个样本。

这两个方案的对比,基于变异这种,它很容易设置,不需要知道这个输入应该采用什么格式,它的缺陷是,因为它不知道格式,格式进而是错的,错误的格式输入扔进去之后,程序给他拒绝了,导致代码测试的时候测试覆盖率比较低。还会遇到特殊的像校验格检查,MagicNubmer检查等等,如果你这个不对,程序也不帮他走,他测试的时候,后面代码测不到,会有这样的情况。反过来,基于生成类的话,它的特点是相反的。

在实践中,有很多种方案,除了这两种分类,还分黑盒、白盒、灰盒的,所谓白盒一般是指源码的;黑盒是什么都没有,只是搭个黑盒来测;介于两者之间的灰盒,意思是你可以在这个程序执行过程中获取一定程序的信息,灰盒应该说现在很常见,大家用的很多,我们重点介绍这一类。

实践中,如果人工去做Grammar based,要输入文档,可以做这个事情。通常我们没有这种,一般会采用基于编译的方法更好,它的扩展性更好。但它的局限在于coverage,它的覆盖率比较低,因为它没有格式信息,所以导致覆盖率比较低。为什么大家会关心覆盖率呢?漏洞,代码如果没覆盖的话,一定存在漏洞,肯定没法触发。在一定程度上,如果覆盖率不够的话,找到漏洞就更少,大家尽量提高自己的覆盖率,不同Fuzz都会尝试做覆盖率的提升。

怎么做覆盖率提升呢?有一类方法是基于覆盖率导向的Fuzz,代码是AFL。AFL是个开源的工具,是Google开发人员提供的。他的想法还比较聪明,类似跟杂交水稻一样进化的想法,杂交水稻目标是要找好的水稻种子,有比较高的产量。现在怎么做呢?他们会不断地培育新的种子,一轮一轮地培育,有好有坏,会把好的种子留下来,好的种子再进行下一轮种子杂交,会生成下一批种子,再选出好的种子进行杂交,这样的方式不断迭代,进化的想法,一代会比一代好,最终挑选出比较好的种子。在这里,AFL用了类似的想法,他找了一些种子触发漏洞或提高代码覆盖率,这是它的目标。它的做法也是一样的,其实中间的大循环也是一轮一轮的测试,它会把好的种子留下来,进入下一轮测试,会把这个好的种子进行编译,然后再测试,把好的留下来,这样一轮轮下来,最后达到比较好的效果。

什么是它的好种子?定义的标准是,如果这个种子对覆盖率的贡献,早期的代码别人没走过的代码,你的种子就是好的,就留下来了。就这么一个想法,让这个东西不断走下去,自然而然地最终达到测试的效果,它的覆盖率会比较好。AFL这个方案是基于编译的,可扩展性比较好,不需要太多的先验知识,它的测试速度非常快,基本和原始程序执行没有太多差别,原来程序能测多快它就能测多快。而且它可以支持并行化测试。另外一个特点,它比较敏感,与其他工具结合起来,可以捕获很多类型的漏洞,而不是简单地依赖Crash崩溃,有些漏洞触发时并不会崩溃,如果不会捕获这种漏洞你会漏掉这个漏洞。这几个特点导致AFL效果非常好,大家用的非常多,学术界也对它进行了很多扩展。

对它感兴趣的,首先会想我怎么选它初始种子?初始种子挺重要的,因为初始种子选得好,Fuzz测试会非常快,能达到比较好的出事状态,底下会走出很多代码。而且初始种子可以在不同的被测试程序之间进行共享,测一个PDF软件有一批种子,这批种子可以在下一个PDF软件里重用,效果非常好。怎么去找这种初始种子呢?我们程序里会自带benchmark,benchmark通常用于测功能的,它会有大量训练代码会辅到,所以,benchmark是比较好的输入live。没有benchmark的时候,我们会从网络上爬的样本里筛选,学术界里也有一些研究,2017年南洋理工的李奥(音)他们做的一篇文章,去年微软做的用RNN学习的想法,这两个工作核心的想法,是从大量已知样本里学出一种模式,比较符合有效输入格式,基于这个模式再生产新的种子。

对AFL第二块感兴趣的在于它的选种,刚才这个循环里,它每轮迭代其实是说,它会把上一轮留下来好的种子选一部分出来再进行变异杂交操作。怎么操作?上一轮留下来的可能不是一个种子,而是一百个种子,这一百个种子到底先选谁出来变异,这块学问研究非常多。先选为什么重要?如果选得好的话,展开100个种子,如果第一轮选第一个,第二轮选第二个,第一百轮选第一百个。选得特别好的话,第一轮你就把这个漏洞给触发,选得不好的话,等到第100个人才会触发这个漏洞,差别非常大。所以,选种子顺序是非常关键的。学术界在这块做了很多研究,包括2016年的CCS,这里列的都是顶级会议地,就是安全圈或者软件圈里的顶级漏洞。2016年CCS漏洞的想法是,怎么选这个漏洞,他会考虑这个种子被选出来过多少次,因为每个人会选出一个种子,他会评估100个种子哪个种子被选出多少次,有的种子选择了1万次,有的只选择了1次,这时候他会优先选被选的少的种子,背后的原理是,要给每个种子均等的机会,你选出来1万次的那个种子已经被充分测试过了,没有什么剩余价值了。

AFLgo 2017年CCS方案,这是一个比较特殊的方案,它不是针对覆盖率的,是针对另外一个时间,是定向化的。我们程序员写代码每次会提交commit,我们可能关心提到的这个commit里会不会有问题,他会说我用Fuzz测试新提出来的代码,按目标定向测试对象,他的目标是像原来Fuzz一样最终是要探索指定的代码行的东西。他的想法是,也是改种子选择策略,选种子的时候会考虑,这个种子离目标有多远,近的话如何选择,这样可以迭代,比较快地找到这些输入,触发目标的路径。

选完种子之后下一步进行变异,到测试地来测试。怎么编译,给你一个输入,你对这些输入进行改动,改动成什么内容?现在研究也包括Vuzzer的,Vuzzer这个工作是NDSS发表的,它其实核心解决两个问题,对什么地方进行编译,以及用什么值,他用数据模分析,分析这个程序输入怎么影响这个程序的运行。对哪些字节变异,他会考虑输入如果影响到某一个判断语句,输入的这几个字节就是他需要变异的地方。变异采用什么值呢?就是magic number,因为你经常会检查,IF某些字节等于magic number,这个magic number就是它要变异的值。最近,学者有提出来QEI(音)、RNN、GAN强化学习的方法来辅助指导Fuzz怎么进行编译,大家感兴趣可以去查这个paper。编译完之后要进行测试,核心问题是怎么让它测得更快。CCS有个工作室是做并行化测试,AFL本身是有并行化模式,但它的并行化模式效率比较低,达不到线性速率,CPU数量加上去之后没有效果,所以,CCS把这个并行化基本让它做线性,很好地提高了。在测试过程中,还有很关键的问题,怎么跟踪测试中出现的安全漏洞。

这里经典的工具是AddressSanitizer,这是很经典的工具,是Google提供的,能捕获缓冲区溢出和Use-after-free运行漏洞,非常经典。学术界在去年阿迪森(音译)的时候提出对AddressSanitizer感兴趣的工作AMAZ(音),除了捕获安全问题,还有更多代码覆盖率的问题,代码覆盖率是它的属性,要用覆盖率指导Fuzz,根据这个覆盖率跟踪判断这个种子是好的还是不好的,应不应该留下来。刚才已经简单回复了绝大多数基于Coverage based Fuzz学术界改进,获得更好效率的方案。这些方案考虑得很全面了了,还有可以改进的地方。我们注意到,他们说的是Coverage Guider Fuzz,这些方案里很少有几个方案真的很关心Coverage。

我们做了一个工作,就是Fuzz的CollAFL。

我们有两个观察,测试过程中,它会跟踪Coverage,它会和Coverage有碰撞。这不是我们第一次关注到,AFL作者知道碰撞,也写到自己文档里,但他选了折中的办法放在那儿。碰撞是怎么回事呢?要简单说一下细节,AFL要用到一个64KB bitmap来保存Coverage的信息。怎么保存的呢?他关心的是边的Coverage,这个程序的边到底怎么走过,边是有两个块连接构成,它怎么保存呢?它对每个基本块附了一个key,上面是prev,下面是cur,然后他算这个边,他给这个边算了哈希出来,这个哈希就代表这条边,更新bitmap的技术细节。这样的做法,原理很简单。大家看这个哈希算法很简单,会进行碰撞。两个不同的边算出来的哈希是一样的,碰撞有什么问题呢?最大的问题,它而影响这个Fuzzer的判断,这个Fuzzer会根据bitmap来判断当前这个种子是不是号种子,判断这个种子是不是走了新的边,如果碰撞了,它是看不出来这是新的边。如果新的边出现了,它的哈希值与前哈希值是一样的,那么Fuzzer认为这个边是测过的边,认为这个种子没用,其实扔掉了,但它实际是好的种子。

第二,它甚至可能帮你找到漏洞里了,因为找到漏洞,崩溃了,Fuzzor和AFL会做一个检测,会检查这是不是重复的崩溃,这个种子走的是和原来一模一样的东西,不是一模一样就认为是重复的,要扔掉了。同样的,碰撞以后导致这样的情况,就可以导致你漏掉漏洞。还有比较严重的是,bitmap碰撞以后导致它提供Coverage信息不准确,其他依赖Coverage信息做决策的,就会做出错误的决策,这就包括前面讲的怎么选种的问题,有策略,选种子的时候是基于Coverage做的判断,Coverage不准的话会导致他做出错误的判断。

这个问题是非常严重的,比大家想象的严重。我们做的测量,测了二十多个开元软件,他们碰撞像Libtorrent是75%的边会碰撞,整体效果影响会非常大的;nm边数小于64kb,碰撞率是36%;vim边数是大于64kb,碰撞更严重,超过60%(61.04%)。这个碰撞的问题不仅仅是AFL中存在,AFL会有更多边的概念,这算做得比较好的,其实有的Fuzz只是做基本块的覆盖率。大家注意,边的覆盖率会推导出基本块覆盖率,但基本块覆盖率推导不出来边的覆盖率。基本块的覆盖,很多工具是这么做的,像lib Fuzzer,cloud里带着这个,honggfuzz是Google后来提供的一个开源的Fuzz,他们都用的基本块覆盖率,里面的碰撞问题更严重。其实边覆盖率还不够,最好的情况应该考虑做路径覆盖率。因为边的顺序对漏洞还有影响,最理想的情况下是做漏洞覆盖率,但在代码中,工具没法实现的时候,我们做路径做到两条不同路径,它的内部表示还不一样,这个事情太大了,这个路径太长了,这个怎么存储?这中间太多了,每一次记录runtime的开销特别大,没有好的办法做这个事情,微软选择Edge也是非常好的选择,也许将来还会有提升。

关于Coverage第二个环节,现在这些策略里对Coverage没有考虑太多,其中一个是选种子,选种子也是基于它的测试速度,是不是离目标最近的策略选种子,但所有提到的策略里没有一个是直接和Coverage相关的,也没有哪个策略说我优选对Coverage有贡献的策略。Coverage会有碰撞,Coverage并没有被很好地应用Seed selection里去。

基于这两个观测,我们提出了新的方案——CollAFL方案,我们做了两嗯个改进,一是消除Coverage跟踪碰撞问题,二是选种的时候把Coverage作为优先策略来应用。

具体做法。

1、消除碰撞。

AFL用到64kb bitmap跟踪边的覆盖率。它的跟踪方式大概是这样的哈希算法。怎么消除碰撞呢?一个很简单的方式,把64kb bitmap增大,把哈希表变大一些,碰撞概率自然就会降低,这是很显然的事情,我们也试了一下,把bitmap大小变大,碰撞率自动降低了。但把bitmap加大之后,AFL测试速度也跟着马上往下降。所以,这不是个最优方案。

我们提出一个方案,不降低它的测试速度。怎么做呢?是按照替换哈希算法,哈希算法原来很简单,就是current key,当前基本块的key与上一个基本块的key做个异或的操作的,这里很简单,他用了1的常量,我们把它做了泛化,把当前的key做了x bit,前一个基本块key做了一个y,另外再加一个z,这样分三个参数泛化,原来是固定的。这样变成每条边就是x、y、z,变成我们寻找一个答案,每条边路来复制一个x、y、z来消除碰撞。我们碰到一个边搜一个x、y、z,让以前的哈希值不碰撞就行了。我不断地沿着这条边搜索下去,前面是一条边,显而易见搜索到后面的时候,前面已经搜索的,到了后面就非常难以找到合适的x、y、z与以前的哈希值不碰撞,非常难找,刚开始没有碰撞,到后来边就很难找。

怎么解决这个问题呢?我们不用对所有边那么不用算,有些直接赋个哈希值或者固定值就可以了。怎么做呢?有两种情形,第一种情形,这个基本块只有一个前驱,它直接就复制,这样就直接给条边附一个常数,不要运行时算这个哈希值,只要这个常数和别的哈希值不碰撞就完了,他就随便选,只要是没有人用这个哈希值就可以。第二种情形,还是我原来的策略,我搜索x、y、z,我怎么都搜索不出来x、y、z,怎么办呢?做法就是要用时间换空间的想法,我们直接给这条边也赋一个哈希值,这个哈希值存到哈希表里了,我们运行的时候就搜索哈希表。比如这边有条边,有个基本块,有两个前驱,我们搜不出来合适的x、y、z怎么办?我们就给这两个边静态赋一个哈希值,但这个哈希值不能将静态写死,只能通过runtime去查。我们把哈希值放到哈希表里,它的key就是前一个基本块的key和底下key两个组合起来做到key。之所以不能写死,因为有很多个禁区(音188:35),没法写死。对这两个问号都不用进行计算,要么直接静态赋行,要么运行查一下哈希表。总的来说,这三种模式,第一种是我们通常情况下去边搜索x、y、z,第二种是我实在搜不动了,它有多全驱,但我搜不到了,找不到x、y、z了,这时候就用哈希表,把它事先在静态中把它放到哈希表里,Hash demo里,runtime的时候去查这个哈希表就可以了;第三是single-precedent单驱,我直接给它赋个常数,这个常量我没用过就好。这个顺序必须严格按照这个顺序来,我们要解决碰撞问题。

实验室数据,这是基本把碰撞率消除为零,我们会对某些bitmap大小还是会扩大一些,因为边的数bitmap size超过64K,如果不把这个bitmap加大到64k怎么消除,这样的情况下,我们会把bitmap顺其自然地扩大,不是任意扩大。这三类当前区域最简单,给它赋予静态的哈希值,不需要运算,原来A表示对所有变量进行运算,现在要对当前变量进行运算。这个比例非常高,单前驱的基本块比例非常高,在程序中大部分的基本块都是单前驱的,这是好事儿,对这一情况都不用做运行式计算,它的碰撞和operate没有。最麻烦的是查哈希表的内容,我们严格控制哈希表的大小,如果哈希表大的话,runtime查询哈希表会非常慢,测试的时候会受到严重的影响。这里哈希表最多126个,查起来还是非常快,不受什么影响。它的速度比AFL快一些,相当于优化了,比原来的算法快一点,并且可以消除碰撞。

2、改进种子选择策略。

优先选择对Coverage有贡献的种子。我们提出几个策略,第一个策略,考虑每个种子会走一条路径,一条路径实际有不同分支的,有些分支是被其他种子测过,有的分支没有。我们会统计这个种子多样分支被测过,有多少分支没有被测过,可能有两个种子。第一个种子有一个分支没测过,第二个种子有100个分支没测过,我们选择第二个,因为在第二个进行变异的时候要有非常大的概率,种子有没有被触发、测试过的分支,第一个种子只有一个分支没有被测过,你的变异想触发这个测试种子的概率要低一些。第二个种子有100个分子,你都要对它变异,更大的概率是触发没有走过的分支,会更快提升覆盖率,这是它背后的想法。

第二个是改进,刚才分支技术这儿只记1,这儿分支后面会跟着一些子路径,也要考虑子路径的数目,计数不再是1,而是把后面的分支根据路径数量加进来。

第三个策略,会考虑到内存访问,我们会统计这个种子所走的路径,基本块访问的数量,会优先排序那些访问数量多的。为什么会这么排序呢?因为我们关注的是内存破坏漏洞,如果你的内存访问操作多,会更大概率地触发内存破坏漏洞的想法,所以,会优先排序。

这样三个策略都有一些改进,看一下实验效果。

第一,是Coverage这边的,代码覆盖率到底提升多少,三个策略,这里分别表示br、desc、memory三个策略,把这个策略加上去之后,路径覆盖率提升20%;如果不加策略,消除碰撞里的效率只提升9.9%,加上br策略它能提升到20%,这是br最好的策略。最后两个策略是对比Fuzz的种子选择策略,我们的方案可以应用在他们上面,所以比他们还是有提升的。

第二,考察挖漏洞的能力,第一个评估是它能找多少crash,这个数量我对比了好几组,包括原始AFL,消除碰撞之后的CollAFL,还加上br策略之后的CollAFL,还有另外几个策略,包括Fuzz还有平均值,100%是7个Fuzz的平均值。平均下来还是br这个策略效果最好,应该有320%的提升。

最后看bug,我们有157个bug在24个开源软件里,其中23个被别人报的,但没有公开,开发者知道。所以,有134个别人没有报过,其中95个我们拿到CVE,没有全部分析完,分析了一部分,其中9个可以阻挡任意代码执行,效果是非常好的。我们这张表里AFL找到51个,br策略找到141个,就是这157个中有141个是br策略找到的。

基本上我的报告就这么多。

结论是,Fuzz是现在比较流行的方法,AFL是代码整合率(音196:10)学术界很多Fuzz是基于这个来做的,如果大家感兴趣,非常建议从AFL开始,因为想法获得实现非常容易。在工业界,他们不是直接把AFL拿过来用,也会进行改进。更多的改进是基于对特定对象的知识,比如Fuzz浏览器,对浏览器也有经验,知道什么叫可触发的漏洞,做一些指导,这个其实很有效。学术界对这个东西没有办法泛化,所以学术界这边没有太多的研究。我们提供了一个CollAFL方案,在AFL上做了更多的改进,消除了它的碰撞,改进了它的种子选择策略,更快地提出代码覆盖率,找到更多的漏洞。

谢谢大家!

主持人潘柱廷:谢谢张超的演讲,张超讲的比较偏学术。今天四位讲者内容各有特色。下面大家还有什么问题可以提问。

Q:张超老师您好,久仰你的大名。我有个问题,AFL我了解的不是特别多,我之前对符号执行那套东西有点了解,2015年开始有个文章开始叫driner(音)把符号执行和AFL做了一个结合,后来这方面的东西我关注的比较少,但一直有个疑惑,想听听您对这个事情的判断,纯做AFL更有前途还是做driner(音)这套更有前途?

宋凯:Driner(音)这个想法是他们UCSB参加CGC方案里一个创新点,这不光是给CGC做补充,我们系统也是类似的方案。非常简单的想法,Fuzz到一定瓶颈的时候,你调节一下就好了,然后再做,用这样简单的方法。那个效果没有想象中那么好,如果你自己实现这个工具,最主要局限在符号执行或者背后的应用场景,UCSB目前那个文件还是个变量(171:35),它对真实程序路径下的约束很多执行不了,这是最讨厌的,目前没有特别好的办法。有些东西有些比较有意思的进展,有工作会把这个符号执行的工作转成Fuzz的工作,有人说Fuzz??(172:05听不清),现在有人说有些场景求不出来的时候扔回来,扔给??(172:10)。总的来说,应用场景是另外一个commit社区在做这个事情,非常困难。??(172:20)很早就有,一九七几年就开始有这个东西,中间一直沉寂,零几年又开始热闹起来,因为零几年计算机开始非常流行。但目前它还是非常有限的,理论上它是很完美的东西,实践中还用不起来,学术界为什么一直不放弃Fuzz呢?因为在很多应用场景下互相没有替代方案,目前在漏洞挖掘利用,CGC是有漏洞利用的,宋凯介绍的是人机来做利用。如果让机器来做这个利用怎么办呢?目前一定要依赖Fuzz,Fuzz在一些应用场景上还是必须的,所以大家一直在探索和改进,如果想有更好效果和收获的话,还是想去改进Fuzz最有效,如果想解决学术上的难题还是需要探索。

上一篇:宋凯(exp-sky):Chakra引擎的非JIT漏洞与利用

下一篇:ABBA GARBA (广博):Security and Privacy of Blockchain Technologies