首页 > 世链号 > 【grccoin交易所靠谱吗】 ERC223及ERC827实现代码欠缺安全考虑----Token中的CUSTOM_CAL
区边社  

【grccoin交易所靠谱吗】 ERC223及ERC827实现代码欠缺安全考虑----Token中的CUSTOM_CAL

摘要:如果 Token 转账目标对象是 ERC223 合约,则尝试调用其 tokenFallback() 函数,如果目标对象不存在 tokenFallback() 函数,则让交易 fail 掉。tokenFallback() 在这里充当的作用就是类似以太转账里的默认 fallback 函数。

ERC223 提案实现与接口定义不一致

进一步调查我们发现,ERC223 提案的文字接口描述中并没有提到 _custom_fallback 这一参数的引入和使用。

以下是该提案规定的接口:

ERC223及ERC827实现代码欠缺安全考虑----Token中的CUSTOM_CALL漏洞深入分析(下)

可以看到两个 transfer() 接口定义中均没有出现 _custom_fallback 参数。

如果 Token 转账目标对象是 ERC223 合约,则尝试调用其 tokenFallback() 函数,如果目标对象不存在 tokenFallback() 函数,则让交易 fail 掉。tokenFallback() 在这里充当的作用就是类似以太转账里的默认 fallback 函数。

显然,ERC223 提案的初衷十分清晰,就是约定一个 tokenFallback() 接口作为 Token 合约标准,用于处理转入的 Token。ERC223 提案主分支的代码实现也没有 _custom_fallback 的问题。而作者推荐的 Recommended 分支里的代码却增加了一种引入 _custom_fallback 的 transfer() 实现,但是没有进行任何风险提示。

ERC223 代码实现的其他问题

事实上,ERC223 Recommended 分支代码实现还存在其他问题。

call() 在处理 bytes 变量时会引发 evm 层面的 bug,导致数据不一致 [6]。

ERC223及ERC827实现代码欠缺安全考虑----Token中的CUSTOM_CALL漏洞深入分析(下)

event 处理 indexed 的 bytes 变量,在特殊情况下也会引发报错 [7]。

ERC223及ERC827实现代码欠缺安全考虑----Token中的CUSTOM_CALL漏洞深入分析(下)

由此可以推断 ERC223 的 Recommended 分支代码是不成熟的,我们不推荐使用。

EVM 参数传递机制

下面我们解释一下 EVM 中函数调用与参数传递的机制,以便于对这个安全隐患的理解。以如下合约为例

ERC223及ERC827实现代码欠缺安全考虑----Token中的CUSTOM_CALL漏洞深入分析(下)

首先了解一下EVM参数传递机制:在调用函数时,如果目标函数有参数,正常情况下我们需要根据ABI指定的参数类型来构造输入。例如 transfer(address to, uint256 value) 在调用 transfer() 时,以太坊使用函数签名的哈希值前4字节作为 function selector,计算 sha3(transfer(address,uint256)) 得到 0xA9059CBB,再拼接上to地址,256位补全为

ERC223及ERC827实现代码欠缺安全考虑----Token中的CUSTOM_CALL漏洞深入分析(下)

,紧随其后拼接上value,同样256位补全为

ERC223及ERC827实现代码欠缺安全考虑----Token中的CUSTOM_CALL漏洞深入分析(下)

最后得到完整的calldata

ERC223及ERC827实现代码欠缺安全考虑----Token中的CUSTOM_CALL漏洞深入分析(下)

将这段 calldata 附加在交易中发送到目标智能合约地址即可实现函数调用。当以太坊节点收到交易时,将 calldata 与智能合约字节码一同加载到 EVM 中,字节码在编译时生成,也意味着对参数的处理在编译时也已经固定下来了。我们查阅以太坊黄皮书可以看到:

ERC223及ERC827实现代码欠缺安全考虑----Token中的CUSTOM_CALL漏洞深入分析(下)

现在我们来看一下实际编译出的字节码如何分离 transfer、address、value这三个参数,观察如下字节码片段:

ERC223及ERC827实现代码欠缺安全考虑----Token中的CUSTOM_CALL漏洞深入分析(下)

我们可以看到在字节码中,出于动态数组的考虑,只会判断 calldata 是否小于某个最小长度,但是不会检查参数是否过长。编译器会生成一系列 CALLDATALOAD 配合数学运算来分离出函数需要的参数。首先计算调用的目标函数:

CALLDATALOAD 指令将交易中的 calldata(0xa9059cbb0000000000000000000000003f5ce5fbfe3e9af3971dd833d26ba9b5c936f0be000000000000000000000000000000000000000000000000000000e8d4a51000)加载到栈中,然后使用除法运算,将数据前256位除以 0x 100000000000000000000000000000000000000000000000000000000, 得到0xA9059CBB,以此类推,每个参数都会用类似的方法分离出来。但是当参数过多的时候,字节码、EVM都不会处理,可以直接忽略,所以这个特性主要来源于编译器。黑客利用这一特性可以很容易地针对 CUSTOM_CALL 构造攻击参数。

ERC827 的有安全隐患代码实现

类似的 ERC827 Token 提案也存在相同的问题 [8]。下面的代码来自于 openzeppelin-solidity 的 ERC827 问题代码实现:

ERC223及ERC827实现代码欠缺安全考虑----Token中的CUSTOM_CALL漏洞深入分析(下)

该代码在 transferAndCall() 中转账功能完成后,会调用_to地址上的任意函数,并且参数由调用者任意指定。由于该函数检查了 _to != address(this),因此代码不会产生 与 ds-auth 库结合后绕开权限检查的安全漏洞(后果二),但是可能会引入前文所提到的 后果一与后果三,即可以任意支配问题合约所拥有或管理的 Token(即以 this 合约为跳板攻击其它合约)。

此外,还有不少 ERC20 Token 加入了类似的 call() 自定义数据的实现。这种允许自定义 call() 任意地址上任意函数的设计,十分危险。在特殊情况下,甚至允许攻击者盗走合约中的各种 Token,以及绕过合约本身的权限控制。

ERC20, ERC721 中关于“接收通知调用”正确的代码实现

正确的代码实现中,对于“接收通知调用”的处理应该将被通知函数的签名(signature)写死为固定值,避免由攻击者来任意指定的任何可能性。下面举两个例子说明正确的通知调用的写法:

  1. 声明Receiver函数,并通过声明的函数进行接收通知调用

例如在以太坊官网(ethereum.org)维护的 ERC20 代码中关于通知调用的代码片段:

ERC223及ERC827实现代码欠缺安全考虑----Token中的CUSTOM_CALL漏洞深入分析(下)

调用通知采用了正常的函数调用方式。

  1. 通过 Receiver 函数的签名常量进行接收通知调用

下面一段正确实现代码来自于 Consensys 维护的 Token-Factory 项目

ERC223及ERC827实现代码欠缺安全考虑----Token中的CUSTOM_CALL漏洞深入分析(下)

下面是正确实现“接收通知调用”的代码实现库

  • https://github.com/svenstucki/ERC677

  • https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721BasicToken.sol#L349

  • https://github.com/ConsenSys/Token-Factory/blob/master/contracts/HumanStandardToken.sol

  • https://github.com/ethereum/ethereum-org/blob/b46095815f52cf328ecf7676b2b38284d48fba58/solidity/token-advanced.sol#L138

总结与反思

  • ERC223 标准的实现与接口定义脱节,实现仓库存在两个分支接口不一致,使用权威代码时不能放松警惕

  • ERC827 代码同样存在隐患

  • 用 low-level call 一定要小心

  • 需要深刻理解 EVM 中关于合约函数调用的实现机制

Reference

  • [1] ATN抵御合约攻击的报告

  • [2] 以太坊智能合约call注入攻击

  • [3] ERC-223 Token Standard Proposal Draft

  • [4] ATN.sol transferFrom()

  • [5] ERC223_Token.sol transfer() function

  • [6] ERC223-token-standard Issue 50

  • [7] ERC223-token-standard Issue 51

  • [8] ERC827Token.sol

  • [9] New evilReflex Bug Identified in Multiple ERC20 Smart Contracts (CVE-2018-12702, CVE-2018-12703)

  • [10] HADAX Suspends 18T and GVE Deposits and Withdrawals

SECBIT(安比)实验室是谁?

安比(SECBIT)实验室专注于区块链与智能合约安全问题,全方位监控智能合约安全漏洞、提供专业合约安全审计服务,在智能合约安全技术上开展全方位深入研究,致力于参与共建共识、可信、有序的区块链经济体。

安比(SECBIT)实验室创始人郭宇,中国科学技术大学博士、耶鲁大学访问学者、曾任中科大副教授,后担任知名金融科技公司副总裁。专注于形式化证明与系统软件研究领域十余年,具有丰富的金融安全产品研发经验,是国内早期关注并研究比特币区块链技术的科研人员之一。研究专长:区块链技术、形式化验证、程序语言理论、操作系统内核。

 
来源: SECBIT
免责声明
世链财经作为开放的信息发布平台,所有资讯仅代表作者个人观点,与世链财经无关。如文章、图片、音频或视频出现侵权、违规及其他不当言论,请提供相关材料,发送到:2785592653@qq.com。
风险提示:本站所提供的资讯不代表任何投资暗示。投资有风险,入市须谨慎。
世链粉丝群:提供最新热点新闻,空投糖果、红包等福利,微信:juu3644。