区块链安全—经典溢出漏洞cve分析
字数 1098 2025-08-22 12:22:15

区块链安全:经典溢出漏洞CVE-2018-11811分析与教学

一、漏洞概述

CVE-2018-11811是一个典型的智能合约整数溢出漏洞,由清华-360企业安全联合研究中心的张超教授团队于2018年6月12日披露。该漏洞影响了以太坊上288个智能合约,安比(SECBIT)实验室检测发现共有866个合约存在类似问题。

二、漏洞合约分析

1. 合约结构

该合约是一个代币合约,主要功能包括:

  • 允许用户用以太币(ETH)兑换代币
  • 允许用户出售代币换取以太币
  • 合约所有者可以设置买卖价格
  • 账户冻结功能
  • 代币铸造和销毁功能

合约继承关系:

INTToken → owned + token

2. 关键函数

价格设置函数

function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {
    sellPrice = newSellPrice;
    buyPrice = newBuyPrice;
}

购买代币函数

function buy() payable {
    uint amount = msg.value / buyPrice;
    _transfer(this, msg.sender, amount);
}

出售代币函数

function sell(uint256 amount) {
    require(this.balance >= amount * sellPrice);
    _transfer(msg.sender, this, amount);
    msg.sender.transfer(amount * sellPrice);
}

三、漏洞原理

1. 整数溢出机制

漏洞存在于sell()函数的amount * sellPrice计算中。当合约所有者恶意设置极高的sellPrice时,乘法运算可能导致uint256整数溢出。

例如:

  • 设置sellPrice = 2^255
  • 用户出售2个代币:2 * 2^255 = 2^256
  • 由于uint256最大值为2^256-1,计算结果溢出为0
  • 最终用户发送了2个代币给合约,但获得0 ETH

2. 攻击场景

  1. 合约所有者设置:

    • buyPrice = 1 ether (用户花1 ETH买1个代币)
    • sellPrice = 2^255 (极高的卖出价格)
  2. 用户购买:

    • 花费1 ETH → 获得1个代币
  3. 用户出售:

    • 出售2个代币 → 应得2 * 2^255 = 2^256 ETH
    • 实际获得0 ETH (整数溢出)
    • 净损失:2个代币(价值2 ETH)

四、漏洞利用分析

1. 恶意价格设置

合约所有者可以通过以下方式设置恶意价格:

// 设置购买价格为1 ETH/代币,卖出价格为2^255
setPrices(2**255, 1 ether);

2. 溢出计算

当用户尝试出售代币时:

amount * sellPrice = 2 * 2^255 = 2^256  0 (mod 2^256)

3. 资金损失

由于溢出结果为0:

msg.sender.transfer(0); // 用户获得0 ETH
_transfer(msg.sender, this, amount); // 但代币已转移给合约

五、安全建议

1. 使用SafeMath库

import "./SafeMath.sol";

function sell(uint256 amount) {
    uint256 ethAmount = SafeMath.mul(amount, sellPrice);
    require(this.balance >= ethAmount);
    _transfer(msg.sender, this, amount);
    msg.sender.transfer(ethAmount);
}

2. 合理的价格限制

设置买卖价格的合理范围:

function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {
    require(newSellPrice < 2**128 && newBuyPrice < 2**128);
    sellPrice = newSellPrice;
    buyPrice = newBuyPrice;
}

3. 权限控制增强

限制价格变动频率和幅度:

uint256 public lastPriceChange;
uint256 public maxPriceChangePercent = 10; // 10%

function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {
    require(now >= lastPriceChange + 1 days);
    require(newSellPrice <= sellPrice * (100 + maxPriceChangePercent) / 100);
    require(newSellPrice >= sellPrice * (100 - maxPriceChangePercent) / 100);
    // 同样检查buyPrice
    sellPrice = newSellPrice;
    buyPrice = newBuyPrice;
    lastPriceChange = now;
}

六、漏洞复现步骤

  1. 部署合约
  2. 设置恶意价格:
    setPrices(2**255, 1 ether)
    
  3. 用户账户:
    • 调用buy()花费1 ETH购买1个代币
    • 调用sell(2)出售2个代币
  4. 观察结果:
    • 用户失去2个代币
    • 用户获得0 ETH
    • 合约获得2个代币

七、总结

CVE-2018-11811展示了智能合约中整数溢出漏洞的实际危害,特别是当合约所有者可以控制关键参数时。开发人员应当:

  1. 始终使用SafeMath进行算术运算
  2. 对关键参数设置合理限制
  3. 考虑权限控制的适当粒度
  4. 进行全面的安全审计

通过理解这类漏洞的原理和利用方式,开发者可以更好地保护智能合约免受类似攻击。

区块链安全:经典溢出漏洞CVE-2018-11811分析与教学 一、漏洞概述 CVE-2018-11811是一个典型的智能合约整数溢出漏洞,由清华-360企业安全联合研究中心的张超教授团队于2018年6月12日披露。该漏洞影响了以太坊上288个智能合约,安比(SECBIT)实验室检测发现共有866个合约存在类似问题。 二、漏洞合约分析 1. 合约结构 该合约是一个代币合约,主要功能包括: 允许用户用以太币(ETH)兑换代币 允许用户出售代币换取以太币 合约所有者可以设置买卖价格 账户冻结功能 代币铸造和销毁功能 合约继承关系: 2. 关键函数 价格设置函数 购买代币函数 出售代币函数 三、漏洞原理 1. 整数溢出机制 漏洞存在于 sell() 函数的 amount * sellPrice 计算中。当合约所有者恶意设置极高的 sellPrice 时,乘法运算可能导致uint256整数溢出。 例如: 设置 sellPrice = 2^255 用户出售2个代币: 2 * 2^255 = 2^256 由于uint256最大值为 2^256-1 ,计算结果溢出为0 最终用户发送了2个代币给合约,但获得0 ETH 2. 攻击场景 合约所有者设置: buyPrice = 1 ether (用户花1 ETH买1个代币) sellPrice = 2^255 (极高的卖出价格) 用户购买: 花费1 ETH → 获得1个代币 用户出售: 出售2个代币 → 应得 2 * 2^255 = 2^256 ETH 实际获得0 ETH (整数溢出) 净损失:2个代币(价值2 ETH) 四、漏洞利用分析 1. 恶意价格设置 合约所有者可以通过以下方式设置恶意价格: 2. 溢出计算 当用户尝试出售代币时: 3. 资金损失 由于溢出结果为0: 五、安全建议 1. 使用SafeMath库 2. 合理的价格限制 设置买卖价格的合理范围: 3. 权限控制增强 限制价格变动频率和幅度: 六、漏洞复现步骤 部署合约 设置恶意价格: 用户账户: 调用 buy() 花费1 ETH购买1个代币 调用 sell(2) 出售2个代币 观察结果: 用户失去2个代币 用户获得0 ETH 合约获得2个代币 七、总结 CVE-2018-11811展示了智能合约中整数溢出漏洞的实际危害,特别是当合约所有者可以控制关键参数时。开发人员应当: 始终使用SafeMath进行算术运算 对关键参数设置合理限制 考虑权限控制的适当粒度 进行全面的安全审计 通过理解这类漏洞的原理和利用方式,开发者可以更好地保护智能合约免受类似攻击。