避坑指南:常见合约安全漏洞盘点

一、引言

智能合约[1]作为区块链核心构成要素之一,主要用来实现可编程交易和去中心化应用(DApp),凭借其灵活多变的特性,催生了丰富的区块链应用,极大的促进了区块链生态繁荣,为传统金融、医疗保险等领域带来了巨大变革。有别于比特币交易中使用的简单脚本语言,在功能更加完备的以太坊中[2],使用图灵完备的Solidity语言来编写智能合约,以太坊智能合约工作原理如图1所示。

图1 智能合约工作原理(以太坊)

相较于传统合约,智能合约不仅解决了信任问题,还承载着巨额数字资产交易。伴随着过去十年智能合约的爆发式增长,智能合约安全问题引发的各类安全事件层出不穷,据统计,目前因智能合约编码不当和安全漏洞造成的经济损失每年高达数十亿美元。因此,本文以以太坊智能合约为例,选取了一些常见合约安全漏洞,并结合过往发生的安全事件对其进行回顾分析,想以此来警醒各位读者,重视合约安全,避免漏洞“踩坑”。

二、整数溢出

2.1 原理概述

类似于“千年虫”BUG的产生一样,在以太坊虚拟机(EVM)中,整数通常使用固定大小的数据类型来声明,这就意味着一个整形变量的数字表示范围是有限的,因此,在不检查用户输入的情况下执行计算,很容易导致数字超出存储范围,发生整数上溢或下溢。例如在Solidity中,一个uint8类型的数据存储范围是0~255,若试图存储256,则实际存储值将变为0,原理如图2所示。故合约中的溢出漏洞往往会导致计算的实际结果和预期结果产生巨大差异,轻则影响合约的正常逻辑,丢失资金,重则造成项目代币增发,价值归零。

图2 整数溢出攻击原理

2.2 安全事件

通过精心构造的参数,攻击者便可完美绕过校验。2018年4月,一款名为BEC的代币遭受溢出攻击,在短时间内,攻击者利用乘法溢出,向外部账户转入了海量的合约代币并进行抛售,导致该代币价格迅速缩水归零,并且在攻击手法被披露的24小时内,还有多达30个合约遭受到类似攻击,攻击者利用溢出漏洞,成功做到了“无中生有”[3]。

2.3 漏洞合约

图3 整数溢出漏洞合约

如图3所示,上述合约主要实现了用户与合约间的交易转账功能。合约类似于银行(支持接收ETH),可提供存取款功能,函数deposit()用于调用者向合约账户存入ETH;函数withdraw()用于调用者提取自己在合约账户中的ETH;函数accountBalance()用于查看合约账户余额。由于红框中的代码编写不当,一旦遭遇攻击导致减法溢出,便会失去对用户的限制,当合约账户余额不为0时,攻击者可无限次调用withdraw()函数,窃取合约账户中的代币资产。

2.4 防护手段

在以太坊智能合约代码库中,OpenZeppelin提供了一套很好的SafeMath库,通过调用SafeMath库函数进行检查,能够有效避免溢出漏洞。除此之外,使用高版本的Solidity开发合约也可提前规避该漏洞,但仍需慎用unchecked关键字及变量类型的强制转换。

三、拒绝服务

3.1 原理概述

利用软件缺陷、协议漏洞,对服务施加资源压制,使得其降低或者失去可用性均称为拒绝服务(DoS),而造成DoS的攻击行为也被称作DoS攻击,攻击原理如图4所示。同计算机网络一样,智能合约也面临着DoS攻击的威胁,只不过遭受攻击的对象由服务器变为了合约,当合约中存在相应安全漏洞时,攻击者通过消耗计算资源或不返回预期处理结果,可在短时间内或某些状态下破坏合约自身逻辑,导致合约无法正常执行或者不能响应正常的服务请求,从而“死锁”。

图4 拒绝服务攻击原理

3.2 安全事件

KotET是一个区块链游戏的简称,游戏中设有一个King,玩家通过向合约发送ETH来参与King的竞选,而在竞选中失败的玩家,退出游戏后将被返还参与竞选的花销,然而在2016年2月,玩家们发现无论发送多少ETH,合约都不会产生响应,交易永远执行不成功。攻击者在竞选成功后,通过回调revert()函数使合约拒绝相应服务,最后以较低的开销赢得了King的竞选[4]。

DDoS作为DoS攻击的一个实现手段,可以控制“肉鸡”针对某个服务器发起大规模的流量攻击,攻击实现方式如图5所示。2018年8月,Fomo3D游戏的攻击者通过提前准备好的合约发送大量高额手续费交易来拥堵网络,最后成功拿到key,成为奖金获得者,巧妙的实现了一次低投资,高回报的DDoS攻击。

图5 DDoS攻击方式

3.3 漏洞合约

图6 拒绝服务漏洞合约

如图5所示,上述代码共包含两个合约,一个是游戏合约(KotET),用于模拟KotET游戏过程,另一个是攻击者合约(Attack),用以发起DoS攻击,函数bid()通过判断金额大小来决定King的归属;函数fallback()是回退函数。由于红框中的代码编写不当,Attack合约不支持接收ETH,故KotET合约无法执行退还金额操作,这将导致KotET合约被阻塞,新的竞选者无论出价多少都无法成功当选King,攻击者利用合约漏洞成功实现DoS攻击。

3.4 防护手段

引入时间判断机制,化被动为主动,对于调用外部函数的代码一定要考虑周全,防止外部合约回调操控。除此之外,还应限制部分关键函数调用,在防止自动化攻击的同时注意提高攻击方成本。

四、代码重入

4.1 原理概述

在以太坊智能合约中,由于合约之间可以相互调用,故在传递Gas冗余的情况下,都有可能存在重入漏洞。简单来说,一个被攻击者控制的外部恶意合约,通过发起一笔非预期的外部调用来打断目标合约的正常执行逻辑,绕过代码中的限制条件,一次次重新进入到目标合约的内部执行敏感操作,进而引发重入攻击,重入攻击本质上与递归调用的思想类似。

图7 代码重入攻击原理

4.2 安全事件

作为智能合约中的常见安全漏洞,重入漏洞引发了不少安全事件,例如对以太坊影响深远的The Dao事件[5]。The Dao是一个去中心化的自治风险投资基金,通过发布智能合约来募集资金并用投资以太坊上的应用,如果盈利,参与者就能获得回报。2016年6月,黑客利用重入漏洞在屏蔽个人余额的情况下,从募资合约中盗出360万以太币,直接迫使以太坊进行硬分叉。

近两年来,伴随着DeFi生态的火热,不少黑客灵活利用闪电贷等金融手段,放大漏洞危害,增加非法收益。2021年8月,以太坊上的DeFi协议Cream Finance 遭遇重入漏洞攻击,黑客通过闪电贷运作大量资金进行交易,致使项目方损失超过1800万美元[6]。

4.3 漏洞合约

图8 代码重入漏洞合约

如图7所示,上述代码共包含两个合约,一个是银行合约(Funds),用于募集资金,支持调用者存取ETH,另一个是攻击者合约(Attack),用以发起重入攻击,函数depositFunds()用于调用者向合约账户存入ETH;函数withdrawFunds()用于调用者提取属于自己的ETH;函数attackFunds()用于外部调用Funds合约中的函数并发起攻击。由于红框中的代码编写不当,攻击者利用call函数的gas传递机制,只要Attack合约拥有足够的gas且Funds合约中余额不为0,就可以在循环中重复的调用自己去窃取Funds合约代币,攻击者利用合约漏洞成功实现重入攻击。

4.4 防护手段

在编写合约代码时,需遵循Checks-Effects-Interactions(CEI)编码规范,即先检查输入是否符合条件,再修改合约状态,最后和用户进行交互。或是添加锁函数,通过判断关键变量值,也可有效限制函数之间的相互调用。

五、小结

在本篇文章中,我们通过攻击原理、安全事件、漏洞复现、防范措施这四个层面重点介绍了整数溢出、拒绝服务、代码重入三类常见合约安全漏洞,而除此之外,智能合约还存在短地址、关键参数依赖、未校验返回值等一系列其他安全漏洞,限于篇幅本文并未详细展开,感兴趣的读者可自行了解。通过分析不难看出,智能合约在业务逻辑实现的过程中非常容易出现各类安全问题,稍不注意就会造成巨大的经济损失。

随着数字经济的不断发展,智能合约正变得越来越复杂多样,在未来也必将承载更高的价值,但发展在左,安全在右,合约安全应该是也必须是区块链生态建设过程中的“压舱石”。

参考文献

  1. https://mp.weixin.qq.com/s/G5wUoavHzFHPiQT2vYdeOw
  2. Buterin V. A next-generation smart contract and decentralized application platform. 2014. https://ethereum.org/en/
  3. https://www.dandelioncloud.cn/article/details/1527155375002632193
  4. https://www.it-bound.com/archives/26576
  5. https://www.cnblogs.com/gzhlt/p/10218447.html
  6. https://blog.csdn.net/SierraW/article/details/120043230

版权声明
本站“技术博客”所有内容的版权持有者为绿盟科技集团股份有限公司(“绿盟科技”)。作为分享技术资讯的平台,绿盟科技期待与广大用户互动交流,并欢迎在标明出处(绿盟科技-技术博客)及网址的情形下,全文转发。
上述情形之外的任何使用形式,均需提前向绿盟科技(010-68438880-5462)申请版权授权。如擅自使用,绿盟科技保留追责权利。同时,如因擅自使用博客内容引发法律纠纷,由使用者自行承担全部法律责任,与绿盟科技无关。

Spread the word. Share this post!

Meet The Author