SWC智能合约漏洞库

在线工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器

SWC-107/重入漏洞

调用外部合约的主要风险之一是外部合约可以接管控制流程。在重入攻击(也称为递归调用攻击)中, 恶意合约会在函数的第一次调用完成之前回调发起调用的合约,这可能导致函数的不同调用以预期之外 的方式进行交互。

CWE漏洞分类

CWE-841:工作流程执行不当

整改方案

避免重入漏洞的最佳实践是:

  • 确保在执行外部调用之前已经更新了所有的内部状态,这一模式被成为:Checks-Effects-Interactions
  • 使用可重入锁,例如 OpenZeppelin的ReentrancyGuard

参考文献

合约示例

Modify_reentrancy.sol

pragma solidity ^0.5.0;

contract ModifierEntrancy {

  mapping (address => uint) public tokenBalance;
  string constant name = "Nu Token";
  Bank bank;

  constructor() public{
      bank = new Bank();
  }

  //If a contract has a zero balance and supports the token give them some token
  function airDrop() hasNoBalance supportsToken  public{
    tokenBalance[msg.sender] += 20;
  }

  //Checks that the contract responds the way we want
  modifier supportsToken() {
    require(keccak256(abi.encodePacked("Nu Token")) == bank.supportsToken());
    _;
  }

  //Checks that the caller has a zero balance
  modifier hasNoBalance {
      require(tokenBalance[msg.sender] == 0);
      _;
  }
}

contract Bank{

    function supportsToken() external returns(bytes32) {
        return keccak256(abi.encodePacked("Nu Token"));
    }

}

Modify_reentrancy.yaml

description: Reentrancy (state change after external call)
issues:
- id: SWC-107
  count: 1
  locations:
  - bytecode_offsets: {}
    line_numbers:
      modifier_reentrancy.sol: [14, 15]

Modify_reentrancy_fixed.sol

pragma solidity ^0.5.0;

contract ModifierEntrancy {
  mapping (address => uint) public tokenBalance;
  string constant name = "Nu Token";
  Bank bank;
  constructor() public{
      bank = new Bank();
  }

  //If a contract has a zero balance and supports the token give them some token
  function airDrop() supportsToken hasNoBalance  public{ // In the fixed version supportsToken comes before hasNoBalance
    tokenBalance[msg.sender] += 20;
  }

  //Checks that the contract responds the way we want
  modifier supportsToken() {
    require(keccak256(abi.encodePacked("Nu Token")) == bank.supportsToken());
    _;
  }
  //Checks that the caller has a zero balance
  modifier hasNoBalance {
      require(tokenBalance[msg.sender] == 0);
      _;
  }
}

contract Bank{

    function supportsToken() external returns(bytes32){
        return(keccak256(abi.encodePacked("Nu Token")));
    }
}

Modify_reentrancy_fixed.yaml

description: Reentrancy (state change after external call)
issues:
- id: SWC-107
  count: 0
  locations: []

simple_dao.sol

/*
 * @source: http://blockchain.unica.it/projects/ethereum-survey/attacks.html#simpledao
 * @author: Atzei N., Bartoletti M., Cimoli T
 * Modified by Josselin Feist
 */
pragma solidity 0.4.24;

contract SimpleDAO {
  mapping (address => uint) public credit;

  function donate(address to) payable public{
    credit[to] += msg.value;
  }

  function withdraw(uint amount) public{
    if (credit[msg.sender]>= amount) {
      require(msg.sender.call.value(amount)());
      credit[msg.sender]-=amount;
    }
  }  

  function queryCredit(address to) view public returns(uint){
    return credit[to];
  }
}

simple_dao.yaml

description: Reentrancy (state change after external call)
issues:
- id: SWC-107
  count: 1
  locations:
  - bytecode_offsets:
      '0xe85040f3e719fc3c0e490a0134d2e8daffadf2d2b7f011336f95505f8d9a92f8': [648, 655]
    line_numbers:
      simple_dao.sol: [17, 18]

simple_dao_fixed.sol

/*
 * @source: http://blockchain.unica.it/projects/ethereum-survey/attacks.html#simpledao
 * @author: Atzei N., Bartoletti M., Cimoli T
 * Modified by Bernhard Mueller, Josselin Feist
 */
pragma solidity 0.4.24;

contract SimpleDAO {
  mapping (address => uint) public credit;

  function donate(address to) payable public{
    credit[to] += msg.value;
  }

  function withdraw(uint amount) public {
    if (credit[msg.sender]>= amount) {
      credit[msg.sender]-=amount;
      require(msg.sender.call.value(amount)());
    }
  }  

  function queryCredit(address to) view public returns (uint){
    return credit[to];
  }
}

simple_dao_fixed.yaml

description: Reentrancy (state change after external call)
issues:
- id: SWC-107
  count: 0
  locations: []