智能合约审计系列————1、整型溢出
字数 1704 2025-08-22 12:22:30

智能合约审计:整型溢出漏洞详解

1. 智能合约基础概念

1.1 合约与智能合约

合约是双方当事人之间的"合意",是一种以发生、变更、担保或消灭某种法律关系为目的的协议。

智能合约由Nick Szabo在1993年提出,定义为:

  • 一套数字形式定义的承诺
  • 包括合约参与方可以执行这些承诺的协议

智能合约特点

  • 数字形式:写入计算机可执行代码
  • 自动执行:当预设条件满足时自动执行
  • 不可篡改:一旦部署到区块链上便无法修改

1.2 Solidity基础架构

智能合约使用Solidity编写,基本架构如下:

pragma solidity ^版本号;

contract 合约名称 {
    // 状态变量
    address public owner;
    uint256 public balance;
    
    // 构造函数
    constructor() public {
        owner = msg.sender;
    }
    
    // 函数
    function 函数名(参数) public 修饰器 returns (返回值) {
        // 函数体
    }
    
    // 修饰器
    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }
}

2. Solidity数据类型

2.1 基本数据类型

  1. 布尔型(bool)

    • 取值:true/false
    • 运算符:! && || == !=
  2. 整型

    • 有符号:int/int8到int256
    • 无符号:uint/uint8到uint256
    • 默认:int256/uint256
  3. 地址(address)

    • 20字节,160位
    • 可转换为uint160
  4. 数组

    • 定长字节数组:bytes1到bytes32
    • 动态字节数组:bytes, string
  5. 字符串(string)

    • UTF-8编码的动态尺寸字符串
    • 无结束符
  6. 映射(mapping)

    • 键值对存储结构
    • 语法:mapping(_keyType => _valueType)

2.2 修饰器(Modifiers)

用于改变函数行为,常用于权限检查:

modifier onlyOwner() {
    require(msg.sender == owner);
    _;
}

function close() public onlyOwner {
    selfdestruct(owner);
}

2.3 函数结构

function 函数名(参数列表) 可见性 修饰器 returns (返回值类型) {
    // 函数体
}

3. 审计工具介绍

3.1 Etherscan

  • 以太坊区块链浏览器
  • 通过合约地址查看源码
  • 功能:
    • 合约代码验证
    • 交易记录查询
    • 合约交互界面

3.2 Remix IDE

在线Solidity开发环境:

  • 代码编辑
  • 编译
  • 部署
  • 调试

3.3 Sublime编辑器

  • 支持Solidity语法高亮
  • 便于代码审计

4. 整型溢出漏洞详解

4.1 溢出原理

当算术运算结果超出数据类型表示范围时:

  • 上溢:超过最大值 → 归零或变为极小值
  • 下溢:低于最小值 → 变为极大值

以太坊虚拟机(EVM)为整数指定固定大小类型,如uint8范围[0,255],存储256会变为0。

4.2 乘法溢出案例

CVE-2018-10299漏洞代码

function batchTransfer(address[] _receivers, uint256 _value) public {
    uint cnt = _receivers.length;
    uint256 amount = cnt * _value;  // 未检查乘法溢出
    require(cnt > 0 && cnt <= 20);
    require(_value > 0 && balances[msg.sender] >= amount);
    
    balances[msg.sender] -= amount;
    for (uint i = 0; i < cnt; i++) {
        balances[_receivers[i]] += _value;
    }
    emit Transfer(msg.sender, _receivers, amount);
}

攻击方式

  • 传入_value = 2^255
  • amount = 2 * 2^255 = 2^256 → 溢出为0
  • 绕过余额检查,实现代币增发

4.3 减法下溢案例

function distribute(address[] addresses, uint256 _value) public onlyOwner {
    for (uint i = 0; i < addresses.length; i++) {
        balances[owner] -= _value;  // 未检查下溢
        balances[addresses[i]] += _value;
    }
}

攻击方式

  • 转出总额 > owner余额
  • balances[owner]下溢变为极大值

4.4 加法上溢案例

GEMCHAIN漏洞代码

function mintToken(address target, uint256 mintedAmount) public onlyOwner {
    balances[target] += mintedAmount;  // 未检查加法溢出
    totalSupply += mintedAmount;
    emit Transfer(0, owner, mintedAmount);
    emit Transfer(owner, target, mintedAmount);
}

攻击方式

  • 连续铸币使余额超过uint256最大值
  • 余额变为极小值

5. 溢出漏洞防范措施

5.1 使用SafeMath库

OpenZeppelin提供的SafeMath库:

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

5.2 正确使用示例

import "./SafeMath.sol";

contract SafeContract {
    using SafeMath for uint256;
    
    mapping(address => uint256) balances;
    
    function safeTransfer(address to, uint256 value) public {
        balances[msg.sender] = balances[msg.sender].sub(value);
        balances[to] = balances[to].add(value);
    }
}

5.3 其他防护措施

  1. 输入验证:检查用户输入是否在合理范围内
  2. 使用较新Solidity版本(>=0.8.0内置溢出检查)
  3. 严格测试边界条件
  4. 限制循环次数和计算规模

6. 审计要点总结

  1. 检查所有算术运算:特别是涉及用户可控输入的运算
  2. 验证SafeMath使用:确认所有+-*/运算都使用SafeMath
  3. 检查边界条件:特别是最大值、最小值附近的行为
  4. 审查铸币函数:确认总量控制和溢出防护
  5. 测试极端情况:使用极大/极小值进行测试

7. 参考资料

  1. OpenZeppelin SafeMath: https://github.com/OpenZeppelin/openzeppelin-solidity
  2. 漏洞合约示例:
    • https://github.com/sec-bit/awesome-buggy-erc20-tokens
    • https://github.com/peckshield/vuln_disclosure
    • https://github.com/BlockChainsSecurity/EtherTokens
  3. 以太坊浏览器: https://etherscan.io
  4. Remix IDE: https://remix.ethereum.org
智能合约审计:整型溢出漏洞详解 1. 智能合约基础概念 1.1 合约与智能合约 合约 是双方当事人之间的"合意",是一种以发生、变更、担保或消灭某种法律关系为目的的协议。 智能合约 由Nick Szabo在1993年提出,定义为: 一套数字形式定义的承诺 包括合约参与方可以执行这些承诺的协议 智能合约特点 : 数字形式:写入计算机可执行代码 自动执行:当预设条件满足时自动执行 不可篡改:一旦部署到区块链上便无法修改 1.2 Solidity基础架构 智能合约使用Solidity编写,基本架构如下: 2. Solidity数据类型 2.1 基本数据类型 布尔型(bool) 取值:true/false 运算符:! && || == != 整型 有符号:int/int8到int256 无符号:uint/uint8到uint256 默认:int256/uint256 地址(address) 20字节,160位 可转换为uint160 数组 定长字节数组:bytes1到bytes32 动态字节数组:bytes, string 字符串(string) UTF-8编码的动态尺寸字符串 无结束符 映射(mapping) 键值对存储结构 语法:mapping(_ keyType => _ valueType) 2.2 修饰器(Modifiers) 用于改变函数行为,常用于权限检查: 2.3 函数结构 3. 审计工具介绍 3.1 Etherscan 以太坊区块链浏览器 通过合约地址查看源码 功能: 合约代码验证 交易记录查询 合约交互界面 3.2 Remix IDE 在线Solidity开发环境: 代码编辑 编译 部署 调试 3.3 Sublime编辑器 支持Solidity语法高亮 便于代码审计 4. 整型溢出漏洞详解 4.1 溢出原理 当算术运算结果超出数据类型表示范围时: 上溢:超过最大值 → 归零或变为极小值 下溢:低于最小值 → 变为极大值 以太坊虚拟机(EVM)为整数指定固定大小类型,如uint8范围[ 0,255 ],存储256会变为0。 4.2 乘法溢出案例 CVE-2018-10299漏洞代码 : 攻击方式 : 传入_ value = 2^255 amount = 2 * 2^255 = 2^256 → 溢出为0 绕过余额检查,实现代币增发 4.3 减法下溢案例 攻击方式 : 转出总额 > owner余额 balances[ owner ]下溢变为极大值 4.4 加法上溢案例 GEMCHAIN漏洞代码 : 攻击方式 : 连续铸币使余额超过uint256最大值 余额变为极小值 5. 溢出漏洞防范措施 5.1 使用SafeMath库 OpenZeppelin提供的SafeMath库: 5.2 正确使用示例 5.3 其他防护措施 输入验证:检查用户输入是否在合理范围内 使用较新Solidity版本(>=0.8.0内置溢出检查) 严格测试边界条件 限制循环次数和计算规模 6. 审计要点总结 检查所有算术运算 :特别是涉及用户可控输入的运算 验证SafeMath使用 :确认所有+-* /运算都使用SafeMath 检查边界条件 :特别是最大值、最小值附近的行为 审查铸币函数 :确认总量控制和溢出防护 测试极端情况 :使用极大/极小值进行测试 7. 参考资料 OpenZeppelin SafeMath: https://github.com/OpenZeppelin/openzeppelin-solidity 漏洞合约示例: https://github.com/sec-bit/awesome-buggy-erc20-tokens https://github.com/peckshield/vuln_ disclosure https://github.com/BlockChainsSecurity/EtherTokens 以太坊浏览器: https://etherscan.io Remix IDE: https://remix.ethereum.org