DeFiVulnLabs靶场全系列详解(二十六)交易失败时不回滚

admin 2025年4月10日17:08:06评论7 views字数 3178阅读10分35秒阅读模式
01
前言
此内容仅作为展示Solidity常见错误的概念证明。它严格用于教育目的,不应被解释为鼓励或认可任何形式的非法活动或实际的黑客攻击企图。所提供的信息仅供参考和学习,基于此内容采取的任何行动均由个人全权负责。使用这些信息应遵守适用的法律、法规和道德标准。
DeFiVulnLabs一共有47个漏洞实验,包括各种经典的合约漏洞和一些少见的可能造成安全问题的不安全代码,本系列将逐一解析每个漏洞,包括官方的解释和自己的理解。
02
交易失败时不回滚

漏洞解析:

    如果是某个合约采用了ZRX代币作为交易的代币,例如某个交易所合约实现借贷转账ZRX代币,那么使用ZRX代币的transfer则会返回false或者是true。(ZRX代币没有严格按照ERC20规范)

    这个时候就需要交易所合约自己判断以决定后续的动作(例如更新余额),可能会有疏漏或者考虑不周的点。

    因此如果使用旧版ERC20规范的代币就需要在合约里进行特殊处理,但是如果遵循了ERC20规范的代币,在遇到transfer fail的时候,则会自动回滚,而不是返回false或者true让处理。

项目地址:
https://github.com/SunWeb3Sec/DeFiVulnLabs/blob/main/src/test/Returnfalse.sol

// SPDX-License-Identifier: MITpragma solidity ^0.8.18;import "forge-std/Test.sol";import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";import "@openzeppelin/contracts/token/ERC20/IERC20.sol";/*Name: No Revert on FailureDescription:Some tokens do not revert on failure, but instead return false (e.g. ZRX).ZRX transfer return false:    function transfer(address _to, uint _value) returns (bool) {        //Default assumes totalSupply can't be over max (2^256 - 1).        if (balances[msg.sender] >= _value && balances[_to] + _value >= balances[_to]) {            balances[msg.sender] -= _value;            balances[_to] += _value;            Transfer(msg.sender, _to, _value);            return true;        } else { return false; }    }Mitigation:Use OpenZeppelin’s SafeERC20 library and change transfer to safeTransfer.*/contract ContractTest is Test {    using SafeERC20 for IERC20;    IERC20 constant zrx = IERC20(0xE41d2489571d322189246DaFA5ebDe1F4699F498);    function setUp() public {        vm.createSelectFork("mainnet"16138254);    }    function testTransfer() public {        vm.startPrank(0xef0DCc839c1490cEbC7209BAa11f46cfe83805ab);        zrx.transfer(address(this), 123); //return false, do not revert        vm.stopPrank();    }    function testSafeTransferFail() public {        vm.startPrank(0xef0DCc839c1490cEbC7209BAa11f46cfe83805ab);        // https://github.com/foundry-rs/foundry/issues/5367 can't vm.expectRevert        // vm.expectRevert("SafeERC20: ERC20 operation did not succeed");        zrx.safeTransfer(address(this), 123); //revert        vm.stopPrank();    }    receive() external payable {}}

可以看到zrx代币里只实现了transfer方法,但是引入了SafeERC20这个库,所有遵循ERC20标准的代币都可以使用 SafeERC20 库。

SafeERC20 库的设计目的是为了增强和安全化对ERC20代币的操作,特别是处理转账操作

functiontransfer(address _to, uint _valuereturns (bool{        //Default assumes totalSupply can't be over max (2^256 - 1).        if(balances[msg.sender] >= _value && balances[_to] + _value >= balances[_to]) {            balances[msg.sender] -= _value;            balances[_to] += _value;            Transfer(msg.sender, _to, _value);            return true;        } else { return false; }    }  //返回了false

利用_callOptionalReturn来对交易失败时进行回滚

  function safeTransfer(IERC20 token, address to, uint256 value) internal {        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));    }

可以看到一个返回了revert 一个返回了False

DeFiVulnLabs靶场全系列详解(二十六)交易失败时不回滚
如下所示可能为某个交易所的合约代码。
// 危险版本(使用transfer)function withdraw(address user, uint amountpublic {    zrx.transfer(user, amount); // 如果失败返回false但继续执行    balances[user] -= amount; // 即使转账失败也会扣余额!}// 安全版本(使用safeTransfer)function safeWithdraw(address user, uint amountpublic {    zrx.safeTransfer(user, amount); // 失败则完全回滚    balances[user] -= amount; // 只有成功时才执行}
03
总结
建议所有的合约交易的时候都采用OpenZeppelin的SafeERC20封装,尤其是一些不确定的代币。
04
感谢关注
个人语雀账号:https://www.yuque.com/iceqaq

原文始发于微信公众号(Ice ThirdSpace):DeFiVulnLabs靶场全系列详解(二十六)交易失败时不回滚

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年4月10日17:08:06
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   DeFiVulnLabs靶场全系列详解(二十六)交易失败时不回滚http://cn-sec.com/archives/3938578.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息