您的智能合约中的“幻影”

本文为机器翻译
展示原文

Solidity 编码的智能合约是一个封装了包括确定的功能和逻辑的方法的类。调用智能合约中不存在的函数通常会导致交易被还原。然而,Solidity 有一个称为“后备”的功能,这意味着对合约的任何函数调用如果与匹配的函数名称不匹配,都会被后备捕获。虽然这提供了有用的目的,但它也带来了危险。让我们看看为什么在下一节中使用后备时要小心很重要。

“后退”的历史

在版本0.6.0发布之前,Solidity 有以下后备语法:

 function() public payable{}

上述方法处理任何向合约发送本机代币(ETH、 BNBETC)的传入“调用”。它还充当合约中未指定的函数调用的接收者。也许以太坊/Solidity 团队发现了一个问题,导致在0.6.0版本中引入了重大更改。这需要更改语法以及分离具有以下功能的两个函数:

  • receive() external payable :当调用数据为空时触发。其目的是处理发送到智能合约的本机代币的接收。

  • fallback() external payable :每当没有找到匹配的函数时就会触发。它可以替代旧的后备方案,并且如果无意接收原生代币,则可以将其设为免付费。

“后退”风险与案例研究

回退功能是代理模式中经常使用的强大功能。然而,在某些情况下,合约内部存在的回退可能会带来重大风险,可能导致用户直接经济损失。

为了说明这一点,考虑这样一种情况:合约 A 包含回退,而另一方的不相关合约 B 与合约 A 进行交互。当合约 B 调用合约 A 未知的函数时,会触发回退,交易不会恢复。这会创建一个场景,如果合约 B 使用不存在的函数调用 A,则调用者以某种方式“绕过”逻辑。

虽然这种情况的发生似乎必须满足多个条件,但此类攻击的现实例子已经导致了严重的影响。探索下面两个案例研究的具体细节,了解为什么回退可能很危险以及它对安全意味着什么。

Multiswap (anyswap) — 访问控制漏洞

Multiswap Router 合约(V6 之前)有一些称为“ permit ”的功能,它们在利用委托权限代表其他人桥接或交换代币方面发挥作用。例如:

 function anySwapOutUnderlyingWithPermit(address from,address token,address to,uint amount,uint deadline,uint8 v,bytes32 r,bytes32 s,uint toChainID) external {address _underlying = AnyswapV1ERC20(token).underlying();IERC20(_underlying).permit(from, address(this), amount, deadline, v, r, s);TransferHelper.safeTransferFrom(_underlying, from, token, amount);AnyswapV1ERC20(token).depositVault(amount, from);_anySwapOut(from, token, to, amount, toChainID);}

anySwapOutUnderlyingWithPermit函数调用底层代币的permit函数,将转账权限委托给合约。接下来,合约调用transferFrom来转移资金,桥接过程将资金转移到另一个区块链。

虽然上面的代码看起来很正常,但如果基础代币的合约包含回退,它就会呈现异常性质。总是有后备的代币的一个典型例子是包装原生代币(WETH、WBNB、WAVAXETC)。这是一个潜在的攻击场景:

  • 受害者 Alice已向路由器批准了 10 WETH。

  • 攻击者 Bob使用 10 WETH 和任意vrs值执行anySwapOutUnderlyingWithPermit函数。

  • 合约执行permit功能,目的是委托授权。然而,此时的代币是 WETH,它包含一个后备。没有逻辑来检查正在发生哪个授权,并且调用不会被恢复。结果,合约将 10 WETH 从 Alice 转移到 Bob

最终,Bob 成功从 Alice 那里窃取了 10 WETH,因为 Router 合约在调用另一个合约中的函数时缺乏强大的限制。

这次攻击造成了巨大的经济损失,总损失达 144 万美元。这是一笔巨款,对许多项目开发人员、程序员和安全审计人员来说都是一个重要的教训。

通过闪贷任意造成另一份合约的代币损失

该漏洞是由Code4rena的审计人员发现的。我将以简化的方式重现易受攻击的合约以及脚本,以演示它如何导致其他合约的财务损失。

 interface IFlashBorrower {function onFlashLoan(uint256, bytes) external;}contract VulnerableContract {IERC20 tokenX = 0x001234;function flashloan(IFlashBorrower receiver, uint256 amount, bytes calldata data) public payable {uint256 fee = amnount * 50 / 1_000;tokenX.mint(address(receiver), amount);receiver.onFlashLoan(shareAmount, data);tokenX.burn(address(receiver), amount + fee);emit Flashloaned(receiver, eusdAmount, burnShare);}}

flashloan函数的调用者可以完全控制receiver是谁。该函数内没有验证逻辑,它会继续mintburn tokenX ,同时计算接收者的费用。如果接收方是具有后备功能且无法恢复的合约,则合约内的tokenX将被烧毁,造成与费用等额的损失。攻击场景:

  • 受害者是通过GnosisSafeProxy部署的合约 A ,其中包含一个后备函数,该函数在调用不存在的函数时不会恢复。用户在合约中存储 100 tokenX

  • 攻击者调用flashloan函数,并将接收者设置为合约 A

  • 在此阶段,逻辑运行时不会遇到任何可能导致其恢复的约束。交易成功后,合约A被烧毁5个代币,这是攻击者闪电贷期间的费用。这是对用户使用该产品时的保护的重大侵犯。

结论

通过上面的两个案例研究,合约中的后备功能类似于一个隐藏的幽灵,可能会对合约的用户造成影响。用户损失的直接来源不是合约本身,而是使用该合约的第三方合约。但是,作为开发者,您必须始终承担所有场景下用户安全的责任。

对于包含后备功能的合约,始终检查逻辑并在数据中存在任何无效行为时立即恢复至关重要。

当使用第三方合约时,你永远无法预测其整个内部逻辑。始终验证返回值,并且绝不允许用户控制传递给它的关键数据。

Verichains团队不断更新他们已审核的项目和当前正在审核的项目中发现的最新漏洞,以及来自区块链安全社区的信息。

感谢您阅读 Verichains!免费订阅以接收新帖子并支持我的工作。

关于维瑞链

Verichains是一家领先的区块链安全公司,专门从事代码审计、密码分析、周边安全和事件调查。该公司由世界一流的安全研究人员于 2017 年创立,利用安全、密码学和核心区块链技术方面的丰富专业知识,帮助调查和修复了BNB Bridge 和Ronin Bridge 等最大的加密黑客攻击中的安全问题。如有任何疑问或疑问,请通过info@verichains.io联系我们

来源
免责声明:以上内容仅为作者观点,不代表Followin的任何立场,不构成与Followin相关的任何投资建议。
喜欢
收藏
评论