Move语言安全性分析及合约审计要点之逻辑校验漏洞

区块链
当下Move仍处于发展阶段,Move生态离成熟尚一定距离,开发者较少,开发者经验欠缺,真正能够熟练开发Move合约的不多,因此更容易出现业务层面的一些漏洞。这需要Move合约在设计和开发过程中对Move语言特性以及业务都要熟悉,才可能少出现业务漏洞。

1、逻辑校验漏洞

智能合约开发的业务相关逻辑设计复杂,涉及的经济学计算和参数较多,不同项目和协议之间可组合性极其丰富,很难预测,非常容易出现安全漏洞。

在Solidity智能合约中,我们总结了4种类型的逻辑校验漏洞:

(1)未校验返回值

(2)未校验相关计算数据公式

(3)未校验函数参数

(4)未规范使用require校验

同样地,我们将从这4个方面分析Move合约中是否存在这些逻辑检验漏洞以及其可能性和危害。

1.1 未校验返回值

不检查消息调用的返回值,即使被调用的函数返回一个异常值,执行逻辑仍然会继续进行,只是该函数的调用并没有实现正确的逻辑,这会导致整个交易得不到正确的结果,甚至会威胁到数字资产的安全性。

比如,Solidity合约中的call函数,functionCallWithValue函数如下:

1668760850_637745120f7094a78ea22.png!small?1668760851680

代码中调用了call函数,如果call函数执行发生意外,比如转账失败,则返回值success为false。如果没有验证该返回值,即使success为false,交易仍然会正常执行。只是交易中的这笔转账没有成功。这里通过require对success进行了验证,如果是false,交易就会回滚(revert)。

call函数是Solidity动态函数调用的一个关键函数,是Solidity语言层面的一个容易因为返回值而产生漏洞的典型代表。除了call函数之外,在业务层面,Solidity合约也经常使用返回值来判断函数是否执行成功,比如ERC20合约中的函数:

1668760856_6377451882c342833e857.png!small?1668760858784

对于这类函数,在实际应用的时候一般需要对返回值进行校验,否则会产生漏洞,甚至会威胁到数字资产的安全性。

此外,根据实际的业务逻辑,函数会返回一些业务需要的数据,这些数据也需要根据业务进行验证,进一步保证函数调用没有发生意外,包括但不限于返回值的类型、长度、范围等。比如上面的functionCallWithValue函数中,调动了verifyCallResultFromTarget函数对返回值进行校验。其不仅对返回值success进行了检查,还对retrundata的长度进行了校验和处理。

1668760862_6377451e7a77296f647a5.png!small?1668760863743

在Move合约中,从语言层面来讲,由于其静态调用的特性,不存在类似于Solidity中的call函数需要校验返回值的情况,即使有需要校验函数是否执行正确,一般会在spec模块使用规范语言在Move Prover中进行校验,校验失败则交易会中止。

从业务层面来讲,Move合约中的spec模块同样可以校验函数对全局数据的修改。此外,还可以在合约中编写单元测试函数对函数直接进行单元测试,来保证函数执行的正确性。因此,一般不会将表示函数执行是否成功的布尔变量作为返回值。因此,Move函数的返回值多是实际的业务数据,是否需要校验,则需要根据实际业务需求来确定,比如需要根据返回值的不同,进入不同的函数逻辑分支,则需要对返回值进行判定和检验,比如DEX中的流动性函数:

1668760868_63774524461e95ead750c.png!small?1668760869911

X与Y的排序不同,需要访问的balance也是不同的,还需要校验order!=0。

总的来说,Move语言静态调用特性、spec模块以及单元测试等极大地提高了函数的安全性,这一点Solidity要好很多。但也不排除函数会因为没有校验返回值而产生漏洞的情况。因此,开发人员更需要对业务和实现逻辑熟悉,开发的时候需要谨慎而行。

1.2 未校验相关计算数据

相关业务在合约实现过程中,考虑到情况不够全面没有正确校验相应的业务经济学公式和计算数据,导致合约对于特殊的计算数据容错性差。比如:

(1)XCarnival安全事件

事件发生在2022年6月24日,NFT借贷协议XCarnival遭受到黑客攻击,损失大约380万美元。

根本原因是controller合约borrowAllowed函数调用的orderAllowed函数对数据结构order的校验不完整,仅仅是校验了订单存在、地址正确并且没有被清算,并没有校验订单中的NFT是否被提取,即使订单中的NFT已经被提取了,order的校验仍然可以通过。

1668760874_6377452ab0a27d13ff8a8.png!small?1668760876362

(2)Fortress Loans安全事件

事件发生在2022年5月9日,Fortress Loans遭到黑客攻击,损失了1048.1 ETH以及40万DAI。

根本原因是submit函数虽然校验了signer的数量,但却没有对signer本身和计算的数据power进行校验。

1668760880_637745306e9837d052c0f.png!small?1668760881843

这使得攻击者可以调用submit函数修改状态变量fcds,最终修改了价格预言机中的价格。

1668760886_637745364dd086d32b1bc.png!small?1668760887012

最终,攻击者利用该漏洞窃取了1048.1 ETH以及40万DAI。

类似的安全事件还有不少,它们都是因为在函数内部缺少对经济模型建立的数据结构或者计算的数据缺少校验引起的漏洞。这类漏洞是由于项目设计与开发并没有考虑到全部的情况造成的,其严重等级不一,严重的甚至会给项目带来极大的经济损失,就像上面的安全事件。

在Move合约实现各类项目时,同样难以保证不会出现这类问题,尤其是新型项目。希望发生在Solidity智能合约中的这些安全事件能够给Move开发者一些警示,在开发过程中,尽可能地避免安全漏洞。

1.3 未校验函数参数

函数接收参数时,它不会自动地验证输入的数据属性是否具有安全性和正确性。因此,函数在实现的时候需要根据业务需要对参数进行校验,若缺少校验后者校验不符合业务需求,则会产生漏洞,甚至会威胁到数字资产的安全性。

以Superfluid.Finance安全事件为例。事件发生在2022年2月8日,以太坊上的DeFi协议Superfluid遭遇黑客攻击,损失超1300万美元。

根本原因在于,Superfluid合约存在严重的逻辑漏洞,callAgreement函数缺少对参数的校验,使得攻击者将合约构造的ctx数据替换为自定义ctx数据,这给攻击者发起攻击提供了机会。

1668760893_6377453de069fd5846013.png!small?1668760894753

在Move合约开发中更加需要对参数进行校验。在Move中,函数的参数不仅仅是业务需求的数据,还包括了权限需要的数据,比如signer。Move没有类似Solidity中的msg.sender这种全局变量,Move中对权限的鉴定是通过参数实现的。比如下面的函数:

1668760899_63774543c460c91999772.png!small?1668760900965

该函数中的account参数是代币铸造的发起账户,它必须铸币的权限,即MintCapStore,类似于Solidity中的msg.sender必须是owner。如果缺失了这部分校验,该代币就是任何账户都可以铸造的了。

此外,Move生态中的项目类型跟Solidity生态相同,只是实现的语言不同。因此,Solidity合约中存在的业务逻辑上的漏洞在Move合约中有很大的可能性依然存在。因此,Move开发者在开发项目时要注意这些在Solidity合约中已经出现过的漏洞。

1.4 未规范使用require

Solidity中的require旨在验证函数的外部输入,包括调用者输入的参数、函数的返回值、函数执行前后状态变化等。如果不能规范使用require,合约可能会产生漏洞,甚至威胁到数字资产的安全性,比如XDXSwap安全事件。

事件发生在2021年7月2日,火币生态链(Heco)上DeFi项目XDXSwap受到闪电贷攻击,损失约400万美金。

1668760922_6377455ab31053aabe16e.png!small?1668760923882

根本原因就是闪电贷的功能实现合约,存在借出不还的严重漏洞,造成巨额损失,是项目方fork Uniswap合约代码并修改时引入的严重漏洞,即缺少K值校验的require语句。最根本的原因还是业务的不熟悉,导致实现存在漏洞。

在Move合约中, assert语句和spec模块完成require类似的功能。同样,很多Solidity生态的项目,包括DEX、借贷、农场等类型的项目在未来都将出现在Move的生态中。Move与Solidity原理以及机制是不同的,但项目的业务时相同的。鉴于Solidity生态项目踩坑无数,安全事件层出不穷,Move虽然安全性高,但是在实现各类项目时仍然要谨慎小心,尽量避免出现同类型的漏洞,希望同一个坑不要再踩一次了。

2、总结

当下Move仍处于发展阶段,Move生态离成熟尚一定距离,开发者较少,开发者经验欠缺,真正能够熟练开发Move合约的不多,因此更容易出现业务层面的一些漏洞。这需要Move合约在设计和开发过程中对Move语言特性以及业务都要熟悉,才可能少出现业务漏洞。

另外,Solidity已经实现了大量的业务类型,比如去中心化交易所、去中心化借贷、收益聚合、杠杆借贷、杠杆挖矿、闪电贷、跨链交易等。这些典型的业务场景需要在Move生态足逐一实现,而且需要结合Move与Solidity的差异进行重新设计实现方案。在这个过程中,就比较容易出现一下漏洞,就像Solidity早期经历了很多次攻击和大量资产的损失才逐步走向成熟。Move虽然是一个安全性较高的语言,但谁也无法保证没有漏洞,我们希望可以借鉴Solidity的发展过程,让Move生态的发展少走一些弯路,少一些损失,更快更稳地走向成熟。

责任编辑:武晓燕 来源: FreeBuf.COM
相关推荐

2011-03-25 09:46:16

Informix数据库安全性安全审计

2009-06-26 13:35:50

安全审计信息安全吉大正元

2012-12-26 10:53:26

2015-03-31 16:45:22

2018-10-19 11:06:41

2009-11-23 09:07:14

2011-03-23 12:58:57

2018-10-18 14:07:01

2011-07-22 13:52:46

2019-03-17 15:53:53

嵌入式安全安全漏洞黑客

2023-01-28 10:35:40

2009-08-20 08:43:54

2015-06-15 10:48:25

2009-10-15 10:28:42

2022-07-18 11:13:07

容器安全Docker

2015-11-05 14:40:48

2010-07-08 15:02:24

2009-11-30 09:41:38

2009-02-12 09:55:28

2022-10-13 06:46:05

Dapr访问控制策略
点赞
收藏

51CTO技术栈公众号