智能合约整数溢出漏洞详解 |猿创征文

StevenX5 StevenX5 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要 + 加入社区

漏洞原理

以太坊虚拟机 (EVM) 为整数指定固定大小的数据类型。这意味着一个整数变量,只能表示一定范围的数字。例如uint8 只能存储 [0,255] 范围内的数字。尝试将 256 存储到 uint8 将导致 0。如果不小心,用户输入未被检查,并且执行的计算结果超出了存储它们的数据类型的范围,那么 Solidity 中的变量可能会被利用而导致漏洞。

整数溢出漏洞有上溢和下溢两种情形。

上溢

整数上溢是指数字的增量超过其能存储的最大值。如对于 uint256 类型的变量,Solidity 可以处理多达 256 个比特位的数值 (最大值是 2256  - 1),所以如果在最大数上增加 1 会导致 0。如下所示:

	0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ 	0x000000000000000000000000000000000001
------------------------------------------
= 	0x000000000000000000000000000000000000

下溢

同样,在相反的情况下,当数字是无符号的时,递减将会下溢该数字,从而得到可能的最大值。如下所示:

    0x000000000000000000000000000000000000
- 	0x000000000000000000000000000000000001
------------------------------------------
= 	0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

安全隐患

当执行一个操作需要一个固定大小的变量来存储变量的数据类型范围之外的数字时,就会发生上溢或下溢。

例如,从一个存储值 为 0 的 uint8 (8 位无符号整数) 变量中减去 1 时,将得到数字 255,这是一个下溢。我们指定了一个低于 uint8 范围的数字,结果是给出了一个 uint8 可以存储的最大数字。同样的,从一个存储值 为 255 的 uint8 变量中增加 1 时,将得到数字 0,这是一个上溢。我们指定了一个高于 uint8 范围的数字,结果是给出了一个 uint8 可以存储的最小数字。虽然这两种情况都很危险,但在现实应用场景中下溢情况更有可能发生,也更具危害性。

让我们来看下面这个合约例子:

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

// contract to test uint8 integer underflows and overflows
contract OverFlowUnderFlow {
    uint8 public a = 0;
    uint8 public b = 2**8-1;

    // a will end up at 2**8-1
    function underflow() public {
        a -= 1;
    }

    // b will end up at 0
    function overflow() public {
        b += 1;
    }
}

我们利用 remix 工具来编译和部署这个合约,然后看看发生了什么。部署好合约后,a 的默认值是 0,b 的默认值是 255。当我们执行 overflow 函数后,b 的值变成了 0,执行 underflow 函数后,a 的值变成了 255。如下图所示:

这个结果正如我们预料的那样。当执行 overflow 函数时发生了整数上溢,当执行 underflow 函数时发生了整数下溢。这个演示是在 Solidity 0.4.18 编译器版本上进行的。实际上,如果不指定编译器版本,Remix 将使用最新的 Solidity 编译器(也就是 0.8.7 版本)来编译合约。那么当我们执行 overflow 和 underflow 时编译器会报错且不会出现溢出的结果,也就是说,目前新的 Solidity 编译器版本已更新了这个漏洞。

预防措施

我们建议使用 OpenZeppelin 的 SafeMath 库来解决整数溢出问题。OppenZepplin 在构建和审计安全库方面做得很好,特别是他们的安全数学库是一个用来避免溢出漏洞的参考或库,且已称为一个标准。

下面是 SafeMath 合约安全库的源码:

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

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) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    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;
  }
}

下面是经我们修复后的合约例子:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import "./SafeMath.sol";

// contract to test uint8 integer underflows and overflows
// fixed by using SafeMath
contract OverFlowUnderFlowFixed {
    using SafeMath for uint;
    uint public a = 0;
    uint public b = 2**256-1;

    // will throw
    function underflow() public {
        a = a.sub(1);
    }

    // will throw
    function overflow() public {
        b = b.add(1);
    }
}

同样的,我们还是利用 remix 工具来编译和部署这个合约,然后看看会发生什么。实际上,经过安全修复后的合约,当我们执行 overflow 函数和 underflow 函数时,Solidity 编译器会抛出错误但不会改变 a 和 b 的值。

注:以太坊智能合约开发中,对于整数溢出漏洞,编译器在编译时是发现不了的,所以我们在编写合约时更应该谨慎处理。

...全文

相关推荐

ERC20智能合约整数溢出系列漏洞披露

【ERC20智能合约整数溢出系列漏洞披露】揭示了智能合约在区块链安全领域面临的严峻挑战。

weixin_38543749

基于代币智能合约整数溢出漏洞的建模与验证

针对代币智能合约的安全问题,提岀一种基于代币智能合约整数溢岀漏洞的形式化建模与验证方法。分析现有Thedao和BEC等漏洞攻击事件,定义代币智能合约的安全属性,通过引入全局变量和数值比较等约束条件对代

weixin_38614391

区块链智能合约安全漏洞测试

但是,该合约存在一个致命的安全漏洞:整型溢出漏洞。在某些情况下,整数加法运算可能会导致整数回绕,即整数超出其最大值后归零。攻击者可以利用这一漏洞提前解除锁定时间,从而在冻结期内非法提取资金。

BKZz

基于字节码关键路径的智能合约漏洞检测.docx

表 1 可重入漏洞关键指令| 关键指令 | 说明 || --- | --- || CALL | 调用其他合约中的方法,可发送以太币 || JUMP | 逻辑运算指令负责逻辑运算 |根据上述关键指令,可重入漏洞的检测规则具体定义为

罗伯特之技术屋

智能合约安全最佳实践:防止常见漏洞和攻击.md

智能合约的安全最佳实践,旨在帮助开发者防止常见的漏洞和攻击。主要涵盖了重入攻击、整数溢出和下溢、授权漏洞、时间依赖性、随机数生成、拒绝服务攻击、恶意合约、函数可见性和交易顺序依赖性等九大安全问题。通过

勤劳兔码农
评论 1
收藏 已收藏
分享
返回顶部