区块链安全—经典溢出漏洞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. 攻击场景
-
合约所有者设置:
buyPrice = 1 ether(用户花1 ETH买1个代币)sellPrice = 2^255(极高的卖出价格)
-
用户购买:
- 花费1 ETH → 获得1个代币
-
用户出售:
- 出售2个代币 → 应得
2 * 2^255 = 2^256ETH - 实际获得0 ETH (整数溢出)
- 净损失:2个代币(价值2 ETH)
- 出售2个代币 → 应得
四、漏洞利用分析
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;
}
六、漏洞复现步骤
- 部署合约
- 设置恶意价格:
setPrices(2**255, 1 ether) - 用户账户:
- 调用
buy()花费1 ETH购买1个代币 - 调用
sell(2)出售2个代币
- 调用
- 观察结果:
- 用户失去2个代币
- 用户获得0 ETH
- 合约获得2个代币
七、总结
CVE-2018-11811展示了智能合约中整数溢出漏洞的实际危害,特别是当合约所有者可以控制关键参数时。开发人员应当:
- 始终使用SafeMath进行算术运算
- 对关键参数设置合理限制
- 考虑权限控制的适当粒度
- 进行全面的安全审计
通过理解这类漏洞的原理和利用方式,开发者可以更好地保护智能合约免受类似攻击。