零时科技丨CTF技能宝典之智能合约#整数溢出漏洞
字数 1708 2025-08-22 12:22:54

智能合约整数溢出漏洞分析与利用

1. 整数溢出漏洞概述

整数溢出是智能合约中常见的安全漏洞之一,主要发生在算术运算结果超出变量类型所能表示的范围时。在Solidity中,整数类型(uint/int)都有固定的位数(如uint256为256位),当运算结果超出这个范围时会发生溢出。

溢出类型

  • 上溢(Overflow): 当数值超过类型最大值时,会"回绕"到最小值
  • 下溢(Underflow): 当数值小于类型最小值时,会"回绕"到最大值

2. 漏洞合约分析

以2018年WCTF比赛中的BelluminarBank合约为例,该合约存在整数溢出和变量覆盖漏洞。

合约关键结构

pragma solidity ^0.4.23;

contract BelluminarBank {
    struct Investment {
        uint256 amount;
        uint256 deposit_term;
        address owner;
    }
    
    Investment[] balances;
    uint256 head;
    address private owner;
    bytes16 private secret;
    
    // ... 其他函数 ...
}

关键漏洞点

  1. 整数溢出漏洞:
require(deposit_term >= balances[balances.length - 1].deposit_term + 1 years);

balances[balances.length - 1].deposit_term + 1 years计算结果超过uint256最大值时,会发生上溢归零。

  1. 变量覆盖漏洞:
Investment storage investment = balances[account];
investment.amount = msg.value;
investment.deposit_term = deposit_term;
investment.owner = msg.sender;

未初始化的storage指针会从storage[0]开始覆盖全局变量。

3. 漏洞利用步骤

攻击目标

获取合约所有权并清空合约余额。

详细攻击流程

  1. 初始状态分析

    • 合约部署时存入31337 wei
    • 初始owner为合约创建者
    • secret为部署时设置的私密值
  2. 第一次invest调用

    • 参数:
      • account: 1
      • deposit_term: 2^256 - 31536000 (1年秒数)
      • value: 1 wei
    • 效果:
      • 通过整数溢出绕过存款期限检查
      • 变量覆盖:
        • balances.length被覆盖为2
        • head被覆盖为大数值
        • owner被覆盖为攻击者地址
  3. 第二次invest调用

    • 参数:
      • account: 2
      • deposit_term: 0
      • value: 2 wei
    • 效果:
      • 将head重置为0
      • 进一步调整balances和amount值
  4. 平衡合约余额

    • 由于变量覆盖导致账目不一致
    • 通过自毁合约向目标合约转账2 wei
  5. 调用confiscate

    • 参数:
      • account: 2
      • secret: 从storage读取的值
    • 效果:
      • 满足所有条件检查
      • 转移合约全部余额

4. 关键知识点

1. Solidity存储布局

  • 状态变量按声明顺序存储在storage中
  • 复杂类型(struct/array)的局部storage变量会覆盖全局变量

2. 时间单位处理

  • 1 years = 31536000秒
  • 时间计算同样受整数溢出影响

3. 变量覆盖机制

Investment storage investment = balances[account];

未初始化的storage指针会从storage[0]开始覆盖:

  • investment.amount → storage[0] (balances.length)
  • investment.deposit_term → storage[1] (head)
  • investment.owner → storage[2] (owner)

4. 整数溢出计算

// 当x + 1 years >= 2^256时,结果为0
uint256 x = 2^256 - 31536000;
require(deposit_term >= x + 1 years); // 恒成立,因为x + 1 years = 0

5. 防御措施

  1. 使用SafeMath库

    using SafeMath for uint256;
    a = b.add(c); // 会自动检查溢出
    
  2. 正确初始化storage指针

    Investment storage investment = balances[balances.length];
    balances.push(Investment(msg.value, deposit_term, msg.sender));
    
  3. 合理设计时间检查逻辑

    • 避免直接进行大数值时间运算
    • 使用区块时间戳进行比较
  4. 最小权限原则

    • 关键函数添加权限检查
    • 避免owner可以被任意修改

6. 工具与资源

  1. 测试工具

    • Remix IDE: http://remix.ethereum.org/
    • MetaMask: https://metamask.io/
    • MyEtherWallet: https://www.myetherwallet.com/
  2. 学习资源

    • Solidity文档: https://docs.soliditylang.org/
    • CTF题库: https://github.com/beched/ctf
    • 安全实践: https://consensys.github.io/smart-contract-best-practices/

7. 总结

整数溢出漏洞常与其他漏洞(如变量覆盖)结合出现,在CTF比赛中是常见题型。理解Solidity的存储布局和算术运算特性是发现和利用这类漏洞的关键。开发者应使用SafeMath等防护措施,审计时应特别注意涉及大数值计算的代码路径。

智能合约整数溢出漏洞分析与利用 1. 整数溢出漏洞概述 整数溢出是智能合约中常见的安全漏洞之一,主要发生在算术运算结果超出变量类型所能表示的范围时。在Solidity中,整数类型(uint/int)都有固定的位数(如uint256为256位),当运算结果超出这个范围时会发生溢出。 溢出类型 上溢(Overflow) : 当数值超过类型最大值时,会"回绕"到最小值 下溢(Underflow) : 当数值小于类型最小值时,会"回绕"到最大值 2. 漏洞合约分析 以2018年WCTF比赛中的BelluminarBank合约为例,该合约存在整数溢出和变量覆盖漏洞。 合约关键结构 关键漏洞点 整数溢出漏洞 : 当 balances[balances.length - 1].deposit_term + 1 years 计算结果超过uint256最大值时,会发生上溢归零。 变量覆盖漏洞 : 未初始化的storage指针会从storage[ 0 ]开始覆盖全局变量。 3. 漏洞利用步骤 攻击目标 获取合约所有权并清空合约余额。 详细攻击流程 初始状态分析 合约部署时存入31337 wei 初始owner为合约创建者 secret为部署时设置的私密值 第一次invest调用 参数: account: 1 deposit_ term: 2^256 - 31536000 (1年秒数) value: 1 wei 效果: 通过整数溢出绕过存款期限检查 变量覆盖: balances.length被覆盖为2 head被覆盖为大数值 owner被覆盖为攻击者地址 第二次invest调用 参数: account: 2 deposit_ term: 0 value: 2 wei 效果: 将head重置为0 进一步调整balances和amount值 平衡合约余额 由于变量覆盖导致账目不一致 通过自毁合约向目标合约转账2 wei 调用confiscate 参数: account: 2 secret: 从storage读取的值 效果: 满足所有条件检查 转移合约全部余额 4. 关键知识点 1. Solidity存储布局 状态变量按声明顺序存储在storage中 复杂类型(struct/array)的局部storage变量会覆盖全局变量 2. 时间单位处理 1 years = 31536000秒 时间计算同样受整数溢出影响 3. 变量覆盖机制 未初始化的storage指针会从storage[ 0 ]开始覆盖: investment.amount → storage[ 0 ] (balances.length) investment.deposit_ term → storage[ 1 ] (head) investment.owner → storage[ 2 ] (owner) 4. 整数溢出计算 5. 防御措施 使用SafeMath库 正确初始化storage指针 合理设计时间检查逻辑 避免直接进行大数值时间运算 使用区块时间戳进行比较 最小权限原则 关键函数添加权限检查 避免owner可以被任意修改 6. 工具与资源 测试工具 Remix IDE: http://remix.ethereum.org/ MetaMask: https://metamask.io/ MyEtherWallet: https://www.myetherwallet.com/ 学习资源 Solidity文档: https://docs.soliditylang.org/ CTF题库: https://github.com/beched/ctf 安全实践: https://consensys.github.io/smart-contract-best-practices/ 7. 总结 整数溢出漏洞常与其他漏洞(如变量覆盖)结合出现,在CTF比赛中是常见题型。理解Solidity的存储布局和算术运算特性是发现和利用这类漏洞的关键。开发者应使用SafeMath等防护措施,审计时应特别注意涉及大数值计算的代码路径。