当前位置: 新闻资讯  区块链   区块链生态安全指南:智能合约的攻与防

区块链生态安全指南:智能合约的攻与防

发表于:2018-10-26 关注 
智能合约的概念出现的非常早,在1994年就有人提出,但是因为当时没有可信化的执行环境,智能合约并没有应用到实际的场景当中。在08年中本聪提出了比特币的概念之后,人们发现作为比特币底层的区块链技术天然的为智能合约提供了可信化的执行环境。

智能合约是部署在EVM上,最终部署在区块链的公链上的。可以这样说,比特币引领区块链技术,而以太坊复活了智能合约

其实智能合约的发展是非常稳定的,通过猎豹区块链安全中心在最近一个月的统计中可以看到,智能合约平均每天的增量在2200左右,增长还是非常稳定的。

智能合约现在的应用场景有很多,比如说去中心化的钱包、代币发行、众筹基金,还有现在非常火的FO3D、以太猫之类的区块链游戏,随着智能合约如火如荼的发展,我们也开始看到很多关于智能合约的攻击事件,以下是11年到18年智能合约安全事件统计。

其实智能合约安全事件在所有区块链安全事件的比例非常低,大概只有6%,但是损失统计却达到了12.4亿美元,说明智能合约虽然事件比较少,但造成的后果是非常严重的,因为智能合约对数字货币实时会交易造成非常大的影响,所以我们应该对智能合约的安全高度重视。

我们非常熟悉的The DAO事件,发生在16年的6月,造成了以太坊的硬分叉,接近1/3,近6000万美元的资产损失。

17年7月parity钱包的多重签名漏洞,造成了150万以太币的损失。

18年4月,众所周知的美链事件,使BEC 的10亿的资产在几天内消亡,类似的还有smartmash事件,在溢出和权限控制出现了问题,造成了1.4亿美元的重大财产损失。

伴随着智能合约出现的这些重大事件,让我们不禁思考,在solidity的代码层面到底出现了什么样的问题,又有哪些智能合约的漏洞类型。

我在这里简单的总结了智能合约TOP10的攻击类型:重入攻击、权限控制、整型溢出、未检查的call返回值、交易顺序依赖、时间戳依赖、条件竞争、短地址攻击、可预测的随机处理等。

今天我们就来简单聊一聊三个常见的漏洞类型:

 

整型溢出

大家都知道汽车的里程表,在里程碑表上的范围是从0到9999的数值,当里程数值达到极限的时候,再增加时就会重新归零,其实这个就是生活中的整型溢出。

而在EVM和智能合约的漏洞当中,EVM的数据位数就相当于我们里程表的1-999999,在EVM上的数据位数是0到255的取值,向上加1就会溢出,造成归零的情况,到了0之后,减1之后,就会产生下溢,然后变成极大值。

数字加法、数字乘法,会出现上溢的问题,减法会产生下溢的问题,这是我们写代码时要注意的。

在著名的美链事件中,大家可以看到第257行的代码,简单的一个amount类型,amount参数等于局部变量CNT的值,这样简单的一个操作,对CNT是进行了验证了的,但是对amount没有进行验证。

所以在实际的攻击过程中,攻击者通过传入了一个非常大value值,导致amount溢出,当这个参数可以使amount的值为零,然后绕过检测,虽然下面他还做了很强劲的检测但是因为amount达到零之后,它绕过了这个检测,所以这个结果就是,黑客获取了非常大value值的数字货币,但是他自己的钱包里却没有支付一分钱。

我们可以通过etherscan来回顾这些攻击事件,仔细分析一下攻击过程到底是怎么产生的。

 

还有类似的edu事件,也是因为整型溢出,当然它还有数据的权限控制的问题,这两个事件有共同的地方,也有不一样的地方。

下面我们就说一下权限问题,其实权限问题包含种类比较多,这里我只简单的介绍一下构造函数的失控的问题,构造函数其实是智能合约里一个非常重要,也非常特殊的函数,它是用来初始化这个智能合约的所有权的。

智能合约在0.4.2之前的版本中,要求合约名与构造函数名严格一致,如果他们不同,构造函数就可以被其他合约所调用,通过这种方式,恶意的攻击者就可以获取了我们当前智能合约的所有权,然后进行一些其他的操作。

在MorphToken这个合约上,因为两者的大小写不一致,导致了攻击事件的发生。

重入漏洞

接下来介绍一下重入漏洞,重入其实就是递归,就是对于一个函数的循环调用和对自身的循环调用。代码合约的withdraw函数其实是可以进行递归操作,存在的问题在于,事先没有进行先判断后转账的操作,所以可以给攻击者产生这样可以成功进行重入漏洞的一个条件。

在靠value的时候可以调用fallback函数,攻击者通过这样的合约,可以循环的调用withdraw,也就是提款操作。

经过这样一个复杂操作,循环之后,攻击者可以通过自己的合约,把整个公共的合约的所有的数字货币转到自己的钱包当中。著名The DAO事件,就是因为这个漏洞产生的,当时也损失了大约1/3,约1.15亿美元当时的市值的财产。

 

关于漏洞的防范

简单了解以上三类漏洞之后,大家会考虑,对于这些漏洞我们应该如何防范? 比如说刚才的这个整数溢出漏洞,我们可以通过对于参数的一个详细控制,或者说利用一些第三方的safemath库来保证数字货币的安全。

还有刚才第二个所说的权限控制,我们要注意编码规范,保证合约名与构造函数名相同。如果现在使用构造函数,我们建议使用constractor来进行一些复合函数的创建。

到最后的重入漏洞,要注意三点,也是刚才说的,金额转移变量之前,一定要先进行进行金额转移操作,而后进行一些相关的循环操作。

再比如刚才的那个call.value它是没有限制gas上限的,我们可以用这个transfer操作的2300的gas上限,来保证这个循环不会递归的发生。

最后我们还可以在代码中的互斥锁来完成这些功能。

 

智能合约的自动化审计

在我们统计的数据上,现在的智能合约已经达到20万之多。单纯的从第三方的人工角度审计来说,可能已经跟不上合约发展了,所以自动化审批现在也是大家比较关注的。

自动化审计大约分成三种类型,第一种是基于特征码代码的匹配,第二个就是基于形式化验证自动化检测,第三种就是基于符号执行、符合抽象的自动化审批。

智能合约的特征码匹配与传统的特征代码类似,都是我们对智能合约代码的检测和抽象,通过对检测模块的源码进行匹配。

但是智能合约还存在着一个问题,其实合约在公网上并不都是有明码的,据我们统计,大约只有40%左右是有明码的。所以对于特征码匹配这一块,我们可能要结合一些逆向来进行一些特征码的匹配,所以说具有一定的难度。

再介绍一下基于符号执行和包括抽象的自动化检测,目前这类检测工具比较多,比如比较知名的Mythril、Oyente、Maian,以及其他的符号执行的工具。其实智能合约的源码,是通过SOC的编译器编译成OPcode,也就EVM,类似于汇编执行的这种操作码,然后再通过CFG(控制流程图)的建立,通过这种建模的形式把它转化成图,让我们更能清晰地理解opcode源码逻辑,比如出现了判断的时候,我们能更清晰的分析出这些问题。

到最后我们可能就是符号抽象的分析,就是Securify,在智能合约中与其他源码有一个非常不一样的地方,就是智能合约的这个代码的耦合度是非常低的,我们原来的代码耦合度非常高,所以在智能合约的检测当中,我们可能就针对个别模块进行检测,将各个模块进行建模,然后匹配出他的一些恶意攻击方式。

这是与传统资自动化检测分析不一样的地方,Securify也是通过这种方式,完成自己符号抽象分析的这种检测。

 

区块链生态安全

最后我还想再问大家一个问题,从项目安全的角度,如果我们解决了代码问题,就真的能保证一个项目的安全了吗?

我觉得不是这样的,智能合约作为项目很重要的一个点,肯定是不能忽视,但是智能合约还会存在一些其他的问题。一个项目,它不仅仅包含智能合约,还有后面的技术团队、或者白皮书质量,以及社交网络的舆情,这些都可能对我们的这个项目安全产生一定的风险。

比如说技术团队中,我们自己统计过,有很多技术团队造假,这些个人简历其实写的并不真实,或者是白皮书相似度非常高,但是质量却非常低。

再到薅羊毛现象,一个项目的空投,一个地址,可以薅走很多的币。比如说在官方的地址下,输入一些利用这些官方的名字,假装发现一些空投,然后骗取正常用户的以太币的行为。

所以我们觉得,区块链安全是一个多维度的安全,光光从一个智能合约或者代码的角度,并不能保证整个项目的安全,我们应该更多的结合大数据技术、或者是人工智能技术,或者说npl这样的自然语言分析技术,去检测项目的安全性。