Securify之旅2之审计相关知识前导

现在的审计方法有人工的攻防审计以及自动化的审计。在海量的智能合约中,当然是要降低人工审计的部分,并增加更多的部分通过自动化审计来进行。

当前主流的自动化审计有三大类:

  1. 特征代码匹配。
  2. 基于形式化验证。
  3. 基于符号执行和符号抽象。

特征代码匹配

大家从名字上来看应该就能猜到,其实它就是对恶意代码进行一些提取抽象,正如像我们之前对常规软件系统做的代码静态检测。我们会将恶意代码抽样成一种语义匹配,然后再去寻找与它匹配的静态源代码。这里所讲的静态,正是因为代码并不需要被运行。

这种审计的方法的优点是显而易见的,比如说速度很快,因为它就是对原码进行一个字符串的匹配。第二是它能够迅速的响应新的漏洞,因为这种审计方法大部分是以插件形式开发,比如出现了一个新的漏洞,我们就可以快速提交一些新的匹配模式。

它的缺点就是需要代码开源。听起来似乎与智能合约很吻合,因为区块链是推荐开源的。但事实上,有人做过统计,目前智能合约的代码的开源率仅仅只占48.62%,其余的只是暴露它的一个OPCODE。如果让安全人员去分析这些OPCODE,去逆向OPCODE,将是巨大的挑战,这肯定将会花了大力气,所能cover的范围也极为有限。

它的另一个缺点是漏报率高。因为智能合约的静态审计和传统的静态代码并不完全一致:传统的静态审计方法,比如说APP检测,会调用成熟库里面的,确定稳定的一些函数,进而对它进行审计;但智能合约里面它的一些函数、它一些特征等等,相较传统的代码库存在更大的变化性,所以说相较传统的代码,采取此方法的漏报率还会更高。

基于形式化验证

该方法是当下比较火的。

形式化验证来审计智能合约安全,最早是在16年,由Hirai提供的,当时拿Isabelle高阶逻辑交互定理证明器,然后交EVM的一些OPCODE ,通过它的一个lem language转化成了一个形式化的model,然后通过形式化model的验证来去判断它代码中的逻辑是否存在问题。

但是lem language这种转换方式比较低效,因此两位科学家把这种形式化方法进行了进一步的改正,分别得到了F-framework和K-framework,它们会将EVM的OPCODE转化为一个formal model。其中F-framework就是NASA他们经常在航空航天领域当中做一些形式化漏洞验证的框架,而K-framework则是更注重语意整合的框架。

基于符号执行、符号抽象

这个是我们今天重点要讲的,也是现在智能合约自动化审计最常用的方法。

我们先想个问题:在分析一个智能合约的时候,最合适的分析对象是什么?没错,正是我们前面谈到的,应该是EVM里OPCODE。所以输入自动化引擎的最好就是EVM OPCODE。所有基于符号的审计的自动化引擎,都选择了分析对象,就是这些OPCODE。

在这种基于符号执行和符号抽象化的自动化审计框架里面,其实它有些共有的特性,就是它在OPCODE或者在输到这个引擎之后,都会转化成一个CFG(Control flow graph,控制流程图)。CFG就是说他把合约代码里面的逻辑包装成每个块,然后有逻辑有分叉的时候,比如说有IF等等这种判断的时候,就把它分叉。

像下图中的assertion这个合约,我们首先是将input与256进行一个比较,那么在出现一个If的判断之后,我们需要对这个CFG进行一个分叉。
在这里插入图片描述

CFG Builder主要是对OPCODE这种智能合约代码,把它形成一个十分庞大完善的一个CFG,然后让程序员更好的去了解它里面执行的一些逻辑。而在CFG生成了之后,进行验证的方法会有两种模式:

  1. 基于符号执行的验证,这边比较有代表性的,可能大家都比较熟知的像Mythril、Oyente、Maian。
  2. 基于符号抽象的验证,典型的代表就是我们今天的主角:Securify。
    在这里插入图片描述

Oyente符号执行验证

Oyente的处理流程是在CFG builder构建CFG之后,首先会调用EXPLORER进行处理,EXPLORER的意思就是说我会把代码当中的每一个执行路径都去验证一遍,确认这些路径上是否存在异外。如下图:
在这里插入图片描述

该例子要做的验证就是:是否有一个X,使得X不仅满足C1、C2、C3三个条件,并且Z=X+2,那么这时候我们可以判断他的状态是no还是yes,然后以此来验证整个逻辑的一个流程。

接着会调用code analysis,这一部分其实是这个Oyente最为核心的一个部分,就是它将刚刚输出的EXPLORSER

这种路径把它转化,提取其中只包含Ether转换的一些路径,进行一些有针对性的漏洞验证。他目前主要提供包括

TOD、Timestamp dependence、Mishandled exceptions这三种验证。最后系统为了保障误报率和漏报率,还采用了微软的Z3 Bit-Vector Solver 这个开源的验证器,对整体架构进行了封装。
在这里插入图片描述

到这里我们应该了解到,在CFG转EXPLORER验证的时候,我们需要对CFG中的每条执行路径,不断循环进行这种验证。这是特别耗时,关键是还不一定成功(碰到递归等,很容易就会导致内存爆炸)。

比如说像parity的那个钱包代码,它的Oyente覆盖率仅仅达到20%,剩下80%的代码,是没有办法去跟踪的。所以代码逻辑覆盖率就是Oyente目前存在一个巨大的问题。

Securify符号抽象分析

针对上述Oyente它们的问题,Securify就提供了另外一种方法,它认为现在合约代码其实是特别容易解耦合的。在合约代码里面,就有transfer等等一些比较固定解耦合的一些结构和模块;我们并不是需要对整个合约的逻辑进行校验,只要对合约解耦合的各个模块进行校验分析就可以。明显,如果Securify这个思路可行,将大大提高智能合约审计的自动化程度。

下图也就是Securify做智能合约验证的整体流程:
在这里插入图片描述

它把contract bytecode转化成一种其自定义的一种语义语言,然后将转化后自定义的语义语言,输入一个验证模块;这个验证模块就特别像“特征代码匹配”节里说的那种模式匹配:就是先把一些漏洞转化成一种其验证语言的模式匹配的框架,然后去验证它这个语意在此是否能够匹配其中某种漏洞模型,最终会生成一个安全报告。

Securify具体是如何从bytecode分析出语义的呢?

Securify分析这种合约代码,是从两个维度,第一个是逻辑,第二个是数据:

  1. 在逻辑方向上,它定义了两种逻辑:
  • MayFollow:意思是说L2是有一条路径是跟在L1后面的;
  • MustFollow:是说L2每一条路径都跟在L1后面。
  1. 在数据方面,它分了3种情形:
  • MayDepOn:就是说有两个因素,一个叫Y、一个叫T,T变Y可能变也可能不变;
  • Eq:就是说Y是由T来决定的;
  • DetBy:就是说Y和T是一一对应的,只要T变Y就肯定要变了。
    在这里插入图片描述

验证模块就是通过逻辑和数据这两个维度进行验证。在Securify中,智能合约漏洞的验证性语言,也就依据上述分析方法形成,并以插件化的形式补充进Securify审计系统;其他的安全开发者可以不断去丰富这个漏洞的验证语言。

通过考察Securify的自动化程度,漏报率、误报率来评估,该自动审计工具还是占优的。

另外据统计,当前几种主要的基于符号的审计方法的执行时间是:像Mythril,平均在60秒,Oyente大概在30秒,而Securify大概在20秒。

猜你喜欢

转载自blog.csdn.net/DongAoTony/article/details/124238988