RSS Feed
更好更安全的互联网

波场 DeFi 项目 Myrose 无法提现 USDT 技术分析

2020-11-03

作者:昏鸦,Al1ex@知道创宇404区块链安全研究团队
时间:2020年9月16日

事件起因

2020年9月14日晚20:00点,未经安全审计的波场最新Defi项目Myrose.finance登陆Tokenpocket钱包,首批支持JST、USDT、SUN、DACC挖矿,并将逐步开通ZEUS、PEARL、CRT等的挖矿,整个挖矿周期将共计产出8400枚ROSE,预计将分发给至少3000名矿工,ROSE定位于波场DeFi领域的基础资产,不断为持有者创造经济价值。

项目上线之后引来了众多的用户(高达5700多人)参与挖矿,好景不长,在20:09左右有用户在Telegram"Rose中文社区群"中发文表示USDT无法提现:

Telegram

截止发文为止,无法提现的USDT数量高达6,997,184.377651 USDT(约700万USDT),随后官方下线USDT挖矿项目。

https://tronscan.io/#/contract/TM9797VRM66LyKXq2TbxP1sNmuQWBrsnYw/token-balances
total_value

分析复现

我们直接通过模拟合约在remix上测试。

USDT模拟测试合约代码如下,USDT_Ethereum和USDT_Tron分别模拟两个不同平台的USDT代币合约,分别代表transfer函数有显式return true和无显式return true

Myrose模拟测试合约代码如下:

Remix部署USDT_EthereumUSDT_TronTest三个合约。

调用USDT_Ethereum和USDT_Tron的mint函数给Test合约地址增添一些代币。

然后调用Test合约的withdraw函数提现测试。

success-and-false

可以看到USDT_Ethereum提现成功,USDT_Tron提现失败。

失败的回滚信息中,正是safeTransfer函数中对最后返回值的校验。

Missing Return Value Bug

上文的合约模拟实验揭示了以太坊与波场两个不同平台下USDT代币合约中transfer函数关于返回值处理差异性带来的安全风险,而关于"missing return value bug"这一个问题,早在2018年就有研究人员在Medium上公开讨论过,只不过是针对以太坊的,这里对以太坊中的"missing return value bug"问题做一个简单的介绍:

ERC20标准是以太坊平台上最常见的Token标准,ERC20被定义为一个接口,该接口指定在符合ERC20的智能合同中必须实现哪些功能和事件。目前,主要的接口如下所示:

在ERC20的开发过程中,有研究人员对于ERC20合约中的transfer函数的正确返回值进行了讨论,主要分为两个阵营:一方认为,如果transfer函数允许在调用合约中处理Failed error,那么应该在被调用合约中返回false值,另一方声称,在无法确保安全的情况下,ERC20应该revert交易,关于这个问题在当时被认为都是符合ERC20标准的,并未达成一致。

事实证明,很大比例的ERC20 Token在传递函数的返回值方面表现出了另一种特殊的方式,有些智能合约的Transfer函数不返回任何东西,对应的函数接口大致如下:

那么符合ERC20标准的接口的合约试图与不符合ERC20的合约进行交互,会发生什么呢?下面我们通过一个合约示例来做解释说明:

在solidity中,函数选择器是从它的函数名和输入参数的类型中派生出来的:

函数的返回值不是函数选择器的一部分,因此,没有返回值的函数transfer()和函数transfer()返回(bool)具有相同的函数选择器,但它们仍然不同,由于缺少返回值,编译器不会接受transfer()函数作为令牌接口的实现,所以Goodtoken是Token接口的实现,而Badtoken不是。

当我们通过合约去外部调用BadToken时,Bad token会处理该transfer调用,并且不返回布尔返回值,之后调用合约会在内存中查找返回值,但是由于被调用的合约中的Transfer函数没有写返回值,所以它会将在这个内存位置找到的任何内容作为外部调用的返回值。

完全巧合的是,因为调用方期望返回值的内存槽与存储调用的函数选择器的内存槽重叠,这被EVM解释为返回值“真”。因此,完全是运气使然,EVM的表现就像程序员们希望它的表现一样。

自从去年10月拜占庭硬叉以来,EVM有了一个新的操作码,叫做returndatasize,这个操作码存储(顾名思义)外部调用返回数据的大小,这是一个非常有用的操作码,因为它允许在函数调用中返回动态大小的数组。

这个操作码在solidity 0.4.22更新中被采用,现在,代码在外部调用后检查返回值的大小,并在返回数据比预期的短的情况下revert事务,这比从某个内存插槽中读取数据安全得多,但是这种新的行为对于我们的BadToken来说是一个巨大的问题。

如上所述,最大的风险是用solc ≥ 0.4.22编译的智能合约(预期为ERC0接口)将无法与我们的Badtokens交互,这可能意味着发送到这样的合约的Token将永远停留在那里,即使该合约具有转移ERC 20 Token的功能。

类似问题的合约:

有两种方法可以修复这个错误:

第一种:受影响的Token合约开放团队需要修改他们的合约,这可以通过重新部署Token合约或者更新合约来完成(如果有合约更新逻辑设计)。

第二种:重新包装Bad Transfer函数,对于这种包装有不同的建议,例如:

另一方面,正在编写ERC 20合约的开发人员需要意识到这个错误,这样他们就可以预料到BadToken的意外行为并处理它们,这可以通过预期BadER 20接口并在调用后检查返回数据来确定我们调用的是Godtoken还是BadToken来实现:

事件总结

造成本次事件的主要原因还是在于波场USDT的transfer函数未使用TIP20规范的写法导致函数在执行时未返回对应的值,最终返回默认的false,从而导致在使用safeTransfer调用USDT的transfer时永远都只返回false,导致用户无法提现。

所以,在波场部署有关USDT的合约,需要注意额外针对USDT合约进行适配,上线前务必做好充足的审计与测试,尽可能减少意外事件的发生


智能合约审计服务

针对目前主流的以太坊应用,知道创宇提供专业权威的智能合约审计服务,规避因合约安全问题导致的财产损失,为各类以太坊应用安全保驾护航。

知道创宇404智能合约安全审计团队: https://www.scanv.com/lca/index.html
联系电话:(086) 136 8133 5016(沈经理,工作日:10:00-18:00)欢迎扫码咨询:

区块链行业安全解决方案

黑客通过DDoS攻击、CC攻击、系统漏洞、代码漏洞、业务流程漏洞、API-Key漏洞等进行攻击和入侵,给区块链项目的管理运营团队及用户造成巨大的经济损失。知道创宇十余年安全经验,凭借多重防护+云端大数据技术,为区块链应用提供专属安全解决方案。欢迎扫码咨询:

参考链接

[1] Missing-Return-Value-Bug
https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca


Paper

本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1337/

作者:江 | Categories:安全科普技术分享 | Tags: