SWC智能合约漏洞库

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

SWC-126/gas不足

gas不足攻击可以在一个接受数据并在另一个合约的子调用中使用该数据的合约上执行。 如果子调用失败,则将整个交易还原或继续执行。在中继器合约的情况下,执行交易的 用户(“转发者”)可以通过仅使用足够的gas来执行交易来有效地审查交易,但不足 以使子调用成功。

CWE漏洞分类

CWE-691:控制流管理不足

整改方案

有两种方法可以防止gas不足:

  • 仅允许受信任的用户中继交易。
  • 要求转发人提供足够的gas。

参考文献

示例合约

relayer.sol

/*
 * @source: https://consensys.github.io/smart-contract-best-practices/known_attacks/#insufficient-gas-griefing
 * @author: ConsenSys Diligence
 * Modified by Kaden Zipfel
 */

pragma solidity ^0.5.0;

contract Relayer {
    uint transactionId;

    struct Tx {
        bytes data;
        bool executed;
    }

    mapping (uint => Tx) transactions;

    function relay(Target target, bytes memory _data) public returns(bool) {
        // replay protection; do not call the same transaction twice
        require(transactions[transactionId].executed == false, 'same transaction twice');
        transactions[transactionId].data = _data;
        transactions[transactionId].executed = true;
        transactionId += 1;

        (bool success, ) = address(target).call(abi.encodeWithSignature("execute(bytes)", _data));
        return success;
    }
}

// Contract called by Relayer
contract Target {
    function execute(bytes memory _data) public {
        // Execute contract code
    }
}

relayer.yaml

description: Relayer contract without protection against insufficient gas griefing
issues:
- id: SWC-126
  count: 1
  locations: 
  - bytecode_offsets: {}
    line_numbers:
      relayer.sol: [27]

relayer_fixed.sol

/*
 * @source: https://consensys.github.io/smart-contract-best-practices/known_attacks/#insufficient-gas-griefing
 * @author: ConsenSys Diligence
 * Modified by Kaden Zipfel
 */

pragma solidity ^0.5.0;

contract Relayer {
    uint transactionId;

    struct Tx {
        bytes data;
        bool executed;
    }

    mapping (uint => Tx) transactions;

    function relay(Target target, bytes memory _data, uint _gasLimit) public {
        // replay protection; do not call the same transaction twice
        require(transactions[transactionId].executed == false, 'same transaction twice');
        transactions[transactionId].data = _data;
        transactions[transactionId].executed = true;
        transactionId += 1;

        address(target).call(abi.encodeWithSignature("execute(bytes)", _data, _gasLimit));
    }
}

// Contract called by Relayer
contract Target {
    function execute(bytes memory _data, uint _gasLimit) public {
        require(gasleft() >= _gasLimit, 'not enough gas');
        // Execute contract code
    }
}

relayer_fixed.yaml

description: Relayer contract with protection against insufficient gas griefing
issues:
- id: SWC-126
  count: 0
  locations: []