浅析智能合约的攻与防

智能合约的概念其实出现的非常早,在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这样的自然语言分析技术来保证项目安全。



搜索

招商

免费投递稿件

如果您对稿件有任何疑惑或希望发表新闻稿,请发邮件至 UUCJNEWS@gmail.com