第一课【权限漏洞及重入攻击】。
SharkTeam在之前的“十大智能合约安全威胁”系列课程中,根据历史发生的智能合约安全事件,总结分析了在智能合约领域中出现较多、危害最大的前10大漏洞。这些漏洞之前通常出现在Solidity智能合约中,那么对于新兴的Move智能合约来说,会不会存在相同的危害呢? SharkTeam【Move语言安全性分析及合约审计要点】系列课程将和您一起讨论和深入。第一课【权限漏洞及重入攻击】。
权限漏洞是指应用在检查授权时存在纰漏,使得攻击者在获得低权限用户账户后,利用一些方式绕过权限检查,访问或者操作其他用户或者更高权限。 智能合约中的权限漏洞和关键逻辑有关,例如铸造代币、提取资金、更改所有权等。 在Solidity合约中,权限漏洞主要包含以下类型:
在Solidity中,函数的权限有4种,即:private、internal、external 以及 public。
Solidity函数使用关键字 modifier 来声明调用函数需要的一些权限要求。调用函数时,调用者需要满足modifier中指定的权限才能够调用该函数。若是缺少了modifier验证条件或者验证条件中存在错误或漏洞,这使得调用者绕过权限校验来调用函数,这会给合约和资产带来一定的威胁。 Move合约虽然没有modifier,但同样需要特定的权限验证,比如,Move函数使用acquires关键来声明已获取到了资源。此外,Move中的一些权限的验证则是写在了Move规范语言中。这些都可能给Move合约带来一定的风险。
Solidity合约中有上下文调用的概念,包括tx.origin 和 msg.sender。
在Solidity中,初始化函数没有限制调用者或者没有次数限制,容易被攻击者调用,从而对状态变量进行自定义。表面上攻击者只是利用了初始化函数的漏洞,修改了状态变量。其中隐含的实际是状态变量的修改权限漏洞,即状态变量可以被修改,而修改状态变量的函数可以被攻击者利用,然后窃取合约中的数字资产。 从这一角度上讲,Move比Solidity要安全,因为Move中的数字资产都是具有唯一性的资源类型,不能被随意地修改和丢失,更加不能被复制。另外,Move中的资源只能被创建它的模块修改,保存在用户账户下的资源只有用户有权限修改。
Solidity合约中,selfdestruct(address payable addr) 函数可以销毁当前合约,并且把当前合约的余额发送给指定地址addr。因此,selfdestruct调用时若没有权限限制,则任意账户都可以调用该函数销毁合约,造成合约剩余的Token的巨大损失,进一步则会引发合约拒绝服务攻击,从而引起及其严重的后果。 相比之下,Move合约中并不存在拥有自毁功能的函数,因此,Move中并不存在这种漏洞。 虽然,Move没有自毁函数,但是,Move中的资源却可以被销毁。Move中的每一种资源都代表着一种数字资产,每次资产的错误销毁都是很大的损失,资源的无故销毁是会给合约以及用户带来安全风险的。因此,要严格控制Move资源的销毁权限,断绝随意销毁资源的可能。
重入,从字面上看,指在函数调用过程中,重新调用了当前函数,即执行重新进入了当前函数。Solidity是一种动态的语言,并且在调用call函数后会执行未命名的回调函数 fallback,该函数可以是自定义的函数。这些特性为重入提供了条件。从这一角度来看,重入并不是漏洞。动态调用甚至是重入使得Solidity智能合约可以灵活地实现一些DeFi中的特殊业务,如闪电贷。 以 Uniswap V2 的闪电贷为例,其实现原理就是在swap函数中先转账,然后动态调用业务函数,最后还款(包括手续费),通过K值校验来检查还款金额,从而保证余额满足经济模型以及合约状态的一致性。
如果闪电贷的业务有代币的兑换需求,然后业务函数再次调用了swap函数,于是函数调用的过程中发生了重入。如果没有额外获利,应该不属于重入攻击,因为这只是满足了实际的业务需求。 实际情况是,很难界定一次重入是不是攻击,因为重入很容易破坏“调用外部函数和修改状态变量”的原子性操作。因此,swap函数使用modifier lock以防止重入。 从此来看,重入攻击发生的根本原因是在重入调用外部函数时破坏了“调用外部函数和修改状态变量”的原子性操作,比如调用了两次外部函数,却只修改一次状态变量。 也因此,针对重入漏洞,我们有一条建议就是采用“检查-生效-交互”模式,即先修改状态变量,然后在执行外部函数调用,这样可以保证每一次外部函数调用时都会修改状态变量。 但实际上,对于简单函数,可以这么做,比如函数只调用一次外部函数并且修改一次状态变量。若函数很复杂,其中包含多个外部函数的调用,并且与状态变量更新检查相关的业务同样很复杂,该这种方案就不那么有效了,开发人员就需要采用其他抵御重入攻击的方法,比如添加防重入锁,完全不允许函数重入。 如果从根本原因的角度考虑,我们可以把所有通过破坏”调用外部函数和修改状态变量“的原子性来获取额外收益的交易都视为重入攻击,那么,函数可重入只是为重入攻击提供的一种可能。接下来,我们考虑一下动态调用在重入攻击中有着什么样的作用呢? 什么是动态调用呢?它与静态调用有什么区别呢? Solidity合约中,外部函数的调用(call)是通过调用合约的地址以及调用函数的函数签名(methodId)来确定的,并且在执行的时候进入到函数的上下文中进行执行,在执行之前的合约编译阶段,并不会加载和编译外部合约的代码,此时的外部函数调用只有一个合约地址和函数签名,其调用逻辑是动态未知的,只有在执行的时候才会根据实际传递的参数动态地确定真正要执行的函数,即传递的参数不同,执行的函数不同。 相比一下,静态调用则是在编译过程中会对每一个函数进行加载编译,整个函数的执行方法和逻辑都是静态已知的。 对于动态执行的函数调用来说,只有在真正执行的时候,才能够真正确定其逻辑是否破坏了”调用外部函数和修改状态变量“的原子性。在此之前,是无法检查和确定的。 静态调用同样可能出现这种情况,但却是可以在编译以及编译之前检查出来的,其更根本的原因是合约业务逻辑上存在漏洞,这才导致了存在破坏”调用外部函数和修改状态变量“的原子性的问题。这种情况是非常容易被发现的。 另外,Solidity动态调用(call)外部函数后会执行回调函数fallback(),该回调函数可以自定义,这个重入攻击提供了必要的条件。 对比动态调用和静态调用,我们总结出以下结论: 动态调用是重入攻击的必要条件,合约只有动态执行的情况下,才有可能发生重入攻击。 在静态调用的合约中,不会发生重入攻击,但可能存在类似的业务实现漏洞,但不再是重入漏洞。 通过以上分析,我们重新梳理了重入攻击的概念,如下: 智能合约中的重入攻击是指攻击者利用外部函数动态调用的特性,通过自定义回调函数,破坏了”调用外部函数和修改状态变量“的原子性,从而获取额外收益攻击手段。 Move是一种静态调用的言语,而且不支持回调函数fallback(),因此Move合约中是不可能发生重入攻击的,但这不代表着高枕无忧。通过以上分析,Move虽然没有发起重入攻击的条件,但可能会存在原因类似的业务逻辑漏洞,尽管这种漏洞比较低级,并且很容易被发现,但仍然是可能存在的,尤其是对于初学者以及粗心大意的开发人员。Move资源的唯一性以及存储特性也在一定程度上可以避免一些因为业务漏洞引起的资产损失。 Move资源是唯一的。Move代币是一个代表资源的结构类型,其中保存着代币的数量。数量是值类型,指定数量的代币是资源,对于代币的发行则是以资源类型的代币为原子单位,不能随意地铸造、销毁,更不能复制。Move的代币转账并像Solidity中只是简单的数值上的加和减,Move代币最主要的是通过资源的铸造和销毁来实现转账。 Move的代币资源在铸造后是存储在用户个人账户中的,只有用户自己有权处置(转移等)这些代币资源。而在Solidity合约中,代币余额是一个值,存储在代币合约中的状态变量中,若合约有漏洞,这些代币可以被复制和转移。 由此可见,Move语言从多个层面上保障了用户资产的安全性。
当下Move仍处于发展阶段,Move生态离成熟尚一定距离,开发者较少,开发者经验欠缺,真正能够熟练开发Move合约的不多,因此更容易出现业务层面的一些漏洞。这需要Move合约在设计和开发过程中对Move语言特性以及业务都要熟悉,才可能少出现业务漏洞。 另外,Solidity已经实现了大量的业务类型,比如去中心化交易所、去中心化借贷、收益聚合、杠杆借贷、杠杆挖矿、闪电贷、跨链交易等。这些典型的业务场景需要在Move生态足逐一实现,而且需要结合Move与Solidity的差异进行重新设计实现方案。在这个过程中,就比较容易出现一下漏洞,就像Solidity早期经历了很多次攻击和大量资产的损失才逐步走向成熟。Move虽然是一个安全性较高的语言,但谁也无法保证没有漏洞,我们希望可以借鉴Solidity的发展过程,让Move生态的发展少走一些弯路,少一些损失,更快更稳地走向成熟。
SharkTeam的愿景是全面保护Web3世界的安全。团队由来自世界各地的经验丰富的安全专业人士和高级研究人员组成,精通区块链和智能合约的底层理论,提供包括智能合约审计、链上分析、应急响应等服务。已与区块链生态系统各个领域的关键参与者,如Polkadot、Moonbeam、polygon、OKC、Huobi Global、imToken、ChainIDE等建立长期合作关系。
Twitter:https://twitter.com/sharkteamorg
Discord:https://discord.gg/jGH9xXCjDZ
Telegram:https://t.me/sharkteamorg
更多区块链安全咨询与分析,点击下方链接查看
D查查|链上风险核查https://m.chainaegis.com
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!