区块链整数溢出漏洞
字数 1638 2025-08-22 12:22:54

区块链智能合约整数溢出漏洞详解与防御

1. 整数溢出漏洞概述

整数溢出是智能合约开发中常见的安全漏洞,当算术运算结果超出变量类型所能表示的范围时,就会发生溢出。Solidity作为智能合约开发语言,其整型变量只能存储固定大小数值范围内的数,从uint8到uint256(int8到int256)。

1.1 溢出类型

  • 上溢(Overflow): 当数值超过类型最大值时,会回绕到0
  • 下溢(Underflow): 当数值低于类型最小值时,会回绕到最大值(2^n-1)

1.2 溢出形式分类

  1. 加法溢出
  2. 乘法溢出
  3. 减法溢出

2. 历史案例分析

2.1 BEC攻击事件(2018年4月22日)

黑客利用整数溢出漏洞,凭空取出57,896,044,618,658,100,000,000,000,000,000,000,000,000,000,000,000,000,000,000.792003956564819968个BEC代币并抛售,导致BEC价值归零。

2.2 SMT攻击事件(2018年4月25日)

黑客利用函数漏洞创造了65,133,050,195,990,400,000,000,000,000,000,000,000,000,000,000,000,000,000,000 + 50,659,039,041,325,800,000,000,000,000,000,000,000,000,000,000,000,000,000,000的SMT币。

2.3 FNT攻击事件(2018年12月27日)

以太坊智能合约Fountain(FNT)出现整数溢出漏洞,黑客创造了2 + 115792089237316195423570985008687907853269984665640564039457584007913129639935的SMT币。

3. 漏洞原理与演示

3.1 加法溢出示例

uint8 max = 255; // 2^8 -1
uint8 _overflow = max + 1; // 结果为0,发生加法上溢

3.2 乘法溢出示例

uint8 max = 255; // 2^8 -1
uint8 _overflow = max * 2; // 结果为254,发生乘法上溢

3.3 减法溢出示例

uint8 min = 0;
uint8 _underflow = min - 1; // 结果为255,发生减法下溢

4. 典型漏洞代码分析

4.1 SMT合约漏洞(加法溢出)

漏洞代码片段:

function transferProxy(address _from, address _to, uint256 _value, uint256 _feeSmt, uint8 _v, bytes32 _r, bytes32 _s) public transferAllowed(_from) returns (bool){
    if(balances[_from] < _feeSmt + _value) revert(); // 溢出点
    // ...其他代码...
}

攻击方式:

  • 构造极大的_value_feeSmt值,使两者相加后溢出为0
  • 绕过余额检查balances[_from] < _feeSmt + _value
  • 实现恶意转账

4.2 EBC合约漏洞(乘法溢出)

漏洞代码片段:

function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) {
    uint cnt = _receivers.length;
    uint256 amount = uint256(cnt) * _value; // 溢出点
    require(cnt > 0 && cnt <= 20);
    require(_value > 0 && balances[msg.sender] >= amount);
    // ...其他代码...
}

攻击方式:

  • 设置_value为极大值(如0x8000000000000000000000000000000000000000000000000000000000000000)
  • 当与接收者数量(cnt)相乘时,结果超出uint256范围,amount变为0
  • 绕过余额检查balances[msg.sender] >= amount

4.3 BTCR合约漏洞(减法溢出)

漏洞代码片段:

function distributeBTR(address[] addresses) onlyOwner {
    for(uint i = 0; i < addresses.length; i++) {
        balances[owner] -= 2000 * 10**8; // 潜在下溢点
        balances[addresses[i]] += 2000 * 10**8;
        Transfer(owner, addresses[i], 2000 * 10**8);
    }
}

漏洞特点:

  • 合约部署时balances[owner] = 21000000 * 10^8
  • 最多执行10500次Transfer()就会产生下溢
  • 没有检查owner账户余额是否足够

5. 防御措施

5.1 算术运算前后验证

  • 加法验证: 确保和大于加数和被加数
  • 乘法验证: 确保积大于乘数和被乘数
  • 减法验证: 确保差小于被减数

5.2 使用SafeMath库

OpenZeppelin提供的SafeMath库是防御整数溢出的最佳实践:

library SafeMath {
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        assert(c / a == b);
        return c;
    }
    
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a / b;
        return c;
    }
    
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);
        return a - b;
    }
    
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        assert(c >= a);
        return c;
    }
}

使用示例:

using SafeMath for uint256;

function safeAdd(uint256 a, uint256 b) public pure returns (uint256) {
    return a.add(b); // 使用SafeMath的加法
}

5.3 其他防御建议

  1. 对所有用户输入进行严格验证
  2. 使用最新版本的Solidity编译器,它内置了部分算术检查
  3. 进行充分的测试,包括边界值测试
  4. 考虑使用形式化验证工具验证合约安全性

6. 总结

整数溢出漏洞在智能合约开发中危害严重且常见,开发者必须:

  1. 充分理解Solidity整数类型的范围和限制
  2. 对所有算术运算进行安全检查
  3. 优先使用经过验证的安全库如SafeMath
  4. 进行全面的测试和审计

由于区块链的不可篡改性,合约部署后无法修复漏洞,因此必须在部署前消除所有潜在的整数溢出风险。

区块链智能合约整数溢出漏洞详解与防御 1. 整数溢出漏洞概述 整数溢出是智能合约开发中常见的安全漏洞,当算术运算结果超出变量类型所能表示的范围时,就会发生溢出。Solidity作为智能合约开发语言,其整型变量只能存储固定大小数值范围内的数,从uint8到uint256(int8到int256)。 1.1 溢出类型 上溢(Overflow) : 当数值超过类型最大值时,会回绕到0 下溢(Underflow) : 当数值低于类型最小值时,会回绕到最大值(2^n-1) 1.2 溢出形式分类 加法溢出 乘法溢出 减法溢出 2. 历史案例分析 2.1 BEC攻击事件(2018年4月22日) 黑客利用整数溢出漏洞,凭空取出57,896,044,618,658,100,000,000,000,000,000,000,000,000,000,000,000,000,000,000.792003956564819968个BEC代币并抛售,导致BEC价值归零。 2.2 SMT攻击事件(2018年4月25日) 黑客利用函数漏洞创造了65,133,050,195,990,400,000,000,000,000,000,000,000,000,000,000,000,000,000,000 + 50,659,039,041,325,800,000,000,000,000,000,000,000,000,000,000,000,000,000,000的SMT币。 2.3 FNT攻击事件(2018年12月27日) 以太坊智能合约Fountain(FNT)出现整数溢出漏洞,黑客创造了2 + 115792089237316195423570985008687907853269984665640564039457584007913129639935的SMT币。 3. 漏洞原理与演示 3.1 加法溢出示例 3.2 乘法溢出示例 3.3 减法溢出示例 4. 典型漏洞代码分析 4.1 SMT合约漏洞(加法溢出) 漏洞代码片段: 攻击方式: 构造极大的 _value 和 _feeSmt 值,使两者相加后溢出为0 绕过余额检查 balances[_from] < _feeSmt + _value 实现恶意转账 4.2 EBC合约漏洞(乘法溢出) 漏洞代码片段: 攻击方式: 设置 _value 为极大值(如0x8000000000000000000000000000000000000000000000000000000000000000) 当与接收者数量(cnt)相乘时,结果超出uint256范围,amount变为0 绕过余额检查 balances[msg.sender] >= amount 4.3 BTCR合约漏洞(减法溢出) 漏洞代码片段: 漏洞特点: 合约部署时 balances[owner] = 21000000 * 10^8 最多执行10500次Transfer()就会产生下溢 没有检查owner账户余额是否足够 5. 防御措施 5.1 算术运算前后验证 加法验证 : 确保和大于加数和被加数 乘法验证 : 确保积大于乘数和被乘数 减法验证 : 确保差小于被减数 5.2 使用SafeMath库 OpenZeppelin提供的SafeMath库是防御整数溢出的最佳实践: 使用示例: 5.3 其他防御建议 对所有用户输入进行严格验证 使用最新版本的Solidity编译器,它内置了部分算术检查 进行充分的测试,包括边界值测试 考虑使用形式化验证工具验证合约安全性 6. 总结 整数溢出漏洞在智能合约开发中危害严重且常见,开发者必须: 充分理解Solidity整数类型的范围和限制 对所有算术运算进行安全检查 优先使用经过验证的安全库如SafeMath 进行全面的测试和审计 由于区块链的不可篡改性,合约部署后无法修复漏洞,因此必须在部署前消除所有潜在的整数溢出风险。