几个智能合约漏洞分析

  1. 1、CVE-2018-11810
  2. 2、CVE-2018-11809
  3. 3、CVE-2018-11687
  4. 4、CVE-2018-11811

1、CVE-2018-11810

超额定向分配相关合约源码

漏洞点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function allocate(address _address, uint256 _amount, uint8 _type) public onlyOwner returns (bool success) {
// one allocations by address
require(allocations[_address] == 0);
if (_type == 0) { // advisor
// check allocated amount
require(advisorsAllocatedAmount + _amount <= ADVISORS_AMOUNT);
// increase allocated amount
advisorsAllocatedAmount += _amount;
// mark address as advisor
advisors[_address] = true;
} else if (_type == 1) { // founder
// check allocated amount
require(foundersAllocatedAmount + _amount <= FOUNDERS_AMOUNT);
// increase allocated amount
foundersAllocatedAmount += _amount;
// mark address as founder
founders[_address] = true;
} else {
// check allocated amount
require(holdersAllocatedAmount + _amount <= HOLDERS_AMOUNT + RESERVE_AMOUNT);
// increase allocated amount
holdersAllocatedAmount += _amount;
}
  • 该合约对不同身份按照份额进行代币分配,分配规则:
1
2
3
4
5
6
7
8
9
10
11
12
// 5% for advisors
uint256 constant ADVISORS_AMOUNT = 5 * onePercent;
// 15% for founders
uint256 constant FOUNDERS_AMOUNT = 15 * onePercent;
// 60% sold in pre-sale
uint256 constant HOLDERS_AMOUNT = 60 * onePercent;
// 20% reserve
uint256 constant RESERVE_AMOUNT = 20 * onePercent;
// ADVISORS_AMOUNT + FOUNDERS_AMOUNT + HOLDERS_AMOUNT +RESERVE_AMOUNT
uint256 constant INITIAL_AMOUNT = 100 * onePercent;
// 20% for holder bonus
uint256 constant BONUS_AMOUNT = 20 * onePercent;
  • 分别对应上述漏洞点中的三个require,主要的发生位置即为转账数额。allocate中_amount是可控的,同时为uint256,那么向上溢出可以使得和为0,满足require条件,但下面的加钱操作会使得数额超出限制。
  • 以5%的为例,使用两个账户测试,首先计算最大的数额

最大顾问数额

  • 可以看到当超出这个范围时就会失败
    失败
    成功
  • 将传入的金额为2^256 - 最大规定数额,那么溢出后为0,满足条件
    传入金额
    溢出1
    溢出2

2、CVE-2018-11809

超额铸币相关合约源码

  • 漏洞点
1
2
3
4
5
6
7
8
9
function mint(address _holder, uint256 _value) external icoOnly {
require(_holder != address(0));
require(_value != 0);
require(totalSupply + _value <= tokenLimit);

balances[_holder] += _value;
totalSupply += _value;
Transfer(0x0, _holder, _value);
}
  • 当_value为2^256-totalSupply,那么此时requie被绕过,用户金额超出上限。

  • 设置账户与金额上限

  • 给A账户转账5000

  • 利用整型溢出给B账户转大额数值

  • 备注:直接复制代码无法部署,会出现传参数量不匹配问题,测试过程可以作为函数使用(即PKT函数,设置账户与上限金额)

3、CVE-2018-11687

下溢增持相关合约源码

  • 漏洞点
1
2
3
4
5
6
7
function distributeBTR(address[] addresses) onlyOwner {
for (uint i = 0; i < addresses.length; i++) {
balances[owner] -= 2000 * 10**8;
balances[addresses[i]] += 2000 * 10**8;
Transfer(owner, addresses[i], 2000 * 10**8);
}
}
  • 通过BitcoinRed函数中balances (owner)限制上限,执行多次balances(addresses)的加操作后,可以整型上溢出,同时因为没有判断Owner的账户是否有足够的余额,所以导致了减法的整型下溢出.

4、CVE-2018-11811

高卖低收相关合约源码

  • 漏洞点
1
2
3
4
5
6
 function sell(uint256 amount) {
require(this.balance >= amount * sellPrice);
_transfer(msg.sender, this, amount);
msg.sender.transfer(amount * sellPrice);
}
}
  • 漏洞描述:sellPrice被修改为精心构造的大数后,可导致amount * sellPrice的结果大于整数变量(uint256)最大值,发生整数溢出,从而变为一个极小值甚至归零
1
2
3
4
5
6
7
8
9
10
function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {
sellPrice = newSellPrice;
buyPrice = newBuyPrice;
}

/// @notice Buy tokens from contract by sending ether
function buy() payable {
uint amount = msg.value / buyPrice; // calculates the amount
_transfer(this, msg.sender, amount); // makes the transfers
}
  • 根据以上两个函数setPrices与buy修改sellPrice的值,造成溢出.

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1259742453@qq.com

💰

×

Help us with donation