CVE-2018-12067及类似漏洞分析与相关思考
字数 1466 2025-08-22 12:22:36
智能合约安全漏洞分析与防范:以CVE-2018-12067为例
一、漏洞背景
本文分析的漏洞类型主要存在于以太坊智能合约中,特别是那些具有代币发行功能的合约。这类漏洞不仅涉及代码层面的安全问题,还包括金融设计上的缺陷。代表性案例包括PolyAI和Substratum等项目合约中的漏洞。
二、漏洞类型分析
1. 可超额铸币漏洞
漏洞描述:
合约中存在无限制的铸币函数,允许合约所有者(owner)无限制地增加任何地址的代币余额。
典型代码:
function mintToken(address target, uint256 mintedAmount) onlyOwner {
balanceOf[target] += mintedAmount;
totalSupply += mintedAmount;
Transfer(0, this, mintedAmount);
Transfer(this, target, mintedAmount);
}
风险分析:
- 恶意owner可以任意增发代币,导致通货膨胀
- 破坏代币经济模型,影响市场价值
- 中心化控制违背区块链去中心化原则
2. 乘法溢出漏洞
2.1 卖出函数中的溢出
漏洞代码:
function sell(uint256 amount) {
if (balanceOf[msg.sender] < amount) throw;
balanceOf[this] += amount;
balanceOf[msg.sender] -= amount;
if (!msg.sender.send(amount * sellPrice)) {
throw;
} else {
Transfer(msg.sender, this, amount);
}
}
问题分析:
amount * sellPrice未做溢出检查- 当乘积超过uint256最大值(2²⁵⁶-1)时会发生溢出
- 导致用户应得的以太币金额计算错误
2.2 购买函数中的溢出
漏洞代码:
function buy() payable {
uint amount = msg.value / buyPrice;
if (balanceOf[this] < amount) throw;
balanceOf[msg.sender] += amount;
balanceOf[this] -= amount;
Transfer(this, msg.sender, amount);
}
问题分析:
- 虽然除法操作不会溢出,但相关合约可能存在乘法溢出
- 其他类似合约中
amount = msg.value * buyPrice存在溢出风险
3. 价格设置机制缺陷
漏洞代码:
function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {
sellPrice = newSellPrice;
buyPrice = newBuyPrice;
}
风险分析:
-
中心化风险:
- 价格完全由owner控制
- 恶意owner可操纵价格获利
-
套利风险:
- 当合约价格与市场价格不一致时,存在套利机会
- 例如:
- 合约卖出价 > 市场买入价:从市场购买,向合约卖出
- 合约买入价 < 市场卖出价:从合约购买,向市场卖出
三、漏洞复现与验证
乘法溢出攻击模拟
-
环境准备:
- 部署测试合约
- 设置初始余额:100,000代币
-
攻击步骤:
- 设置极端sellPrice值:57896044618658097711785492504343953926634992332820282019728792003956564819969
- 用户调用sell()卖出2个代币
- 计算应得以太币:2 * sellPrice
- 实际结果:由于溢出,仅得到2 wei
-
数学原理:
- uint256最大值:115792089237316195423570985008687907853269984665640564039457584007913129639935
- 设置sellPrice接近最大值的一半
- 2 * sellPrice > uint256最大值 → 结果溢出为极小值
四、安全建议与修复方案
1. 铸币功能改进
修复方案:
// 添加最大供应量限制
uint256 public constant MAX_SUPPLY = 100000000 * (10 ** 18);
function mintToken(address target, uint256 mintedAmount) onlyOwner {
require(totalSupply + mintedAmount <= MAX_SUPPLY);
balanceOf[target] += mintedAmount;
totalSupply += mintedAmount;
emit Transfer(address(0), target, mintedAmount);
}
2. 算术运算安全
安全乘法实现:
function safeMul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
应用示例:
function sell(uint256 amount) {
// ...其他检查...
uint256 etherAmount = safeMul(amount, sellPrice);
require(msg.sender.send(etherAmount));
// ...
}
3. 价格机制改进
去中心化方案:
- 使用预言机(Oracle)获取市场价格
- 实现自动化做市商(AMM)机制
- 或完全移除合约内买卖功能,仅保留转账功能
五、相关资源
六、总结
本文分析的智能合约漏洞展示了区块链开发中需要特别注意的两类问题:
- 技术安全:算术溢出、权限控制等代码层面的漏洞
- 经济安全:代币机制设计中的金融风险
开发者应当:
- 使用SafeMath等安全库进行算术运算
- 避免过度中心化的控制功能
- 全面考虑合约的经济模型设计
- 进行严格的安全审计和测试
遵循"代码即法律"的原则,智能合约应当具备完备的安全性和合理的金融设计。