Move语言安全性分析及合约审计要点之回退攻击
2022-12-2 16:50:25 Author: www.aqniu.com(查看原文) 阅读量:11 收藏

SharkTeam在之前的“十大智能合约安全威胁”系列课程中,根据历史发生的智能合约安全事件,总结分析了在智能合约领域中出现较多、危害最大的前10大漏洞。这些漏洞之前通常出现在Solidity智能合约中,那么对于Move智能合约来说,会不会存在相同的危害呢?

SharkTeam【Move语言安全性分析及合约审计要点】系列课程将带您逐步深入,内容包括权限漏洞、重入漏洞、逻辑校验漏洞、函数恶意初始化、回退攻击、操纵预言机、合约升级漏洞、三明治攻击、重放攻击、提案攻击。本章内容【回退攻击】。

回退是区块链上的一种机制,无论是简单的转账交易,还是处理一些更复杂的逻辑合约调用,一旦交易失败,区块链就会恢复到交易前的状态。

回退攻击指根据操作结果来决定交易是否执行,如果操作结果没有达到攻击者的预期,攻击者会让交易回退。

在Solidity中,之所以会出现回退攻击,是因为Solidity提供了require、assert、revert等函数用于条件的判断,攻击者可以在合约中利用这些函数来判断执行调用函数的结果是否是自己预期得到的(对自身有利),若是,则继续执行交易;否则回退,即中止交易执行,恢复区块链状态。

从以上原因中可以看出,攻击者发起回退攻击需要满足3个条件:

1. 随机性。攻击者发起交易,访问合约中的函数,执行结果应该具有随机性。若是每次调用的结果都是一样的,或者对攻击者的影响都是一样的,则没有发起攻击的必要。因为发起回退攻击,也只会造成更大的损失(额外的Gas费用),而没有更多的收益。

2. 有利可图。在所有的随机结果中,不同的结果对攻击者有不同的用途,存在某个结果是对攻击者最有利的。若是所有结果对攻击者都是不利的,攻击者发起回退攻击只会造成更大的损失(额外的Gas费用),这必然不会是攻击者想要的。

3. 合约访问合约。攻击者需要自定义攻击合约的逻辑,在攻击合约中调用目标合约中的函数,然后根据结果判断是继续执行还是回退。若是EOA账户调动目标合约中的函数,则无法在交易执行中对结果进行判定,只能在交易完成后才能访问结果,此时交易已经完成,区块链状态已经更新,则不能再回退。

满足以上3个条件,即为攻击者发起回退攻击创造了可能性。了解了回退攻击产生的根本原因和条件,更方便在合约开发过程中防御回退攻击。在Solidity智能合约中,最常用的防御手段就是限制合约访问合约,即与随机性相关的合约函数使用modifier限制调用者地址,只允许EOA账户调用,不允许合约调用。下面是modifier的两种实现方式:

在各种类型的生态项目中,GameFi项目更容易遭受到回退攻击,因为GameFi项目中有较多的场景应用了随机性来增加用户体验,比如CryptoZoan和CryptoZoons这两个GameFi项目遭受过回退攻击。

CryptoZoan是币安智能链 (BSC)上面以NFT游戏的玩法和体验为重点的GameFi项目,旨在创建一个与区块链和游戏相结合的新金融系统,使用户在进行游戏的同时赚取收益。该游戏通过加入随机性的机制来增强用户体验,用户可以将游戏中的“蛋”进行孵化得到ZOAN,并且在孵化时随机分配一个稀有度等级,ZOAN终生依附于这个稀有度等级。稀有度等级总共有6个,1级最低,6级最高,并且等级越高,价值越高。

攻击者利用随机性与回退的结合,使得攻击者的孵化请求得到想要的结果(等级为6),破坏游戏的公平性,使得攻击者获得最高收益。

攻击流程如下:

(1)将待孵化的蛋NFT批准授权给攻击合约;

(2)调用攻击合约触发evolveEgg(uint256)函数;

(3)检查稀有度,如果等级不符合预期(等级为6)则进行回退;(可能会消耗Gas费用,需要去权衡选择是否继续。)

(4)取出等级为6的高等级宠物。

攻击合约代码如下:

CryptoZoons的任务是与怪兽战斗。玩家首先选择要在战斗中使用的生物,并通过在 MarketPlace 购买这些物品来为它们装备武器。玩家将支付一点 BNB gas 价格与选定的敌人进行战斗,同时获胜的一方会获得一定数量的代币。

正是由于合约中回退机制,使得攻击者在战斗结束后可通过余额判断是否获胜。取得胜利时,则发送交易正常执行;失败时进行回滚。

攻击流程如下:

(1)将宠物NFT批准授权给攻击合约;

(2)调用合约中的函数触发战斗;

(3)检查代币是否增加(战斗是否胜利);

(4)若战斗失败,交易回退;若战斗胜利,发送并执行交易。

攻击合约代码如下:

上面分析了回退攻击的3个必要条件:随机性、有利可图、合约访问合约。其中,随机性和有利可图属于业务层面的要求,合约访问合约则是代码层面的要求。对比Move合约和生态,Move生态中同样有NFT和GameFi等生态,同样会用到随机性。另外,Move合约中的函数一般都是可以由合约(模块和脚本程序)来调用的。因此,Move合约中同样可能存在回退攻击的条件。

针对Move生态中的回退攻击,我们提出以下两种思路:

(1)不允许合约(模块和脚本)调用,类似于Solidity中只允许EOA账户调用。在move中,entry 修饰符旨在允许像脚本一样安全直接地调用模块函数。这允许模块编写者指定哪些函数可以成为开始执行的入口。若是entry修饰私有函数,则该函数不能被模块和脚本调用,只能作为开始执行的入口,即只能通过命令或者SDK等方式调用,在调用后获得返回的结果时交易执行完成,不可以再回退。

(2)添加时间锁定。在提交交易后,结果不能够立即读取,需要等待一定时间,即添加时间锁定,比如采用交易缓冲队列,交易提交后需要等待一定时间(比如一个区块时间)后才能够执行。也可以考虑一下交易的执行结果不允许在交易执行后立即查询,而是需要等待时间锁定。这样做,可以保证在调用函数的交易中不能对结果进行判定,也就不再构成回退攻击的条件。


文章来源: https://www.aqniu.com/vendor/91842.html
如有侵权请联系:admin#unsafe.sh