1.uint256溢出漏洞(以BEC為例)
BEC token的代碼可在etherscan中查看
出問題的代碼為batchTransfer方法:
function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) {
uint cnt = _receivers.length;
uint256 amount = uint256(cnt) * _value;
require(cnt > 0 && cnt <= 20);
require(_value > 0 && balances[msg.sender] >= amount);
balances[msg.sender] = balances[msg.sender].sub(amount);
for (uint i = 0; i < cnt; i++) {
balances[_receivers[i]] = balances[_receivers[i]].add(_value);
Transfer(msg.sender, _receivers[i], _value);
}
return true;
}
該方法的目的是批量從請求發(fā)送者的賬號里各轉(zhuǎn)移_value個ether至_receivers中,于是該方法的執(zhí)行需要如下前提條件
該方法的調(diào)用者的賬號中的余額 >_receivers.length * _value
batchTransfer 方法乍一看沒什么問題荔烧,但作者忘了一個重要的問題茵宪,uint256(32個字節(jié))雖然能表示很大的整形玫芦,但總歸是有限的莺琳,會溢出
如果調(diào)用者發(fā)現(xiàn)這個漏洞茂契,精巧的構(gòu)造batchTransfer的參數(shù)_receivers, _val 使得
_receivers.length * _val = amount 溢出饮亏,并且 amount < 調(diào)用賬號的余額
那么_receivers賬號中每個就將憑空產(chǎn)生_val的余額
2.權(quán)限檢測漏洞(以EDU為例)
edu token的代碼可在etherscan中查看
如果上面的代碼漏還稍微具有隱蔽性,那么EDU智能合約中的漏洞就low得令人發(fā)指糯而。
請看漏洞代碼:
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
/// same as above
require(_to != 0x0);
require(balances[_from] >= _value);
require(balances[_to] + _value > balances[_to]);
uint previousBalances = balances[_from] + balances[_to];
balances[_from] -= _value;
balances[_to] += _value;
allowed[_from][msg.sender] -= _value;
Transfer(_from, _to, _value);
assert(balances[_from] + balances[_to] == previousBalances);
return true;
}
如果不管智能合約的其他部分天通,單看這個方法,你會莫名其妙熄驼,因為該方法的目的是允許任何人從任意賬戶中轉(zhuǎn)移一定金額到任意目標賬號中像寒,請注意主謂賓:
- 任何人
- 任意賬號
- 任意目標賬號
你在EDU中的資產(chǎn)在這個方法面前是完全沒有任何安全性可言的。
其實該方法的本來的目的是授權(quán)給一定用戶瓜贾,允許他轉(zhuǎn)移自己的資產(chǎn)诺祸,授權(quán)的代碼是
function approve(address _spender, uint256 _value) public returns (bool success) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
授權(quán)是放在allowed中,但transferFrom卻忘記了對授權(quán)的檢測祭芦,導致你在EDU中的資產(chǎn)完全沒有設(shè)防筷笨,完整的transferFrom應該如下
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
/// same as above
require(_to != 0x0);
require(balances[_from] >= _value);
require(balances[_to] + _value > balances[_to]);
//少了最關(guān)鍵的這一行:
require(allowed[_from][msg.sender] >= _value);
uint previousBalances = balances[_from] + balances[_to];
balances[_from] -= _value;
balances[_to] += _value;
allowed[_from][msg.sender] -= _value;
Transfer(_from, _to, _value);
assert(balances[_from] + balances[_to] == previousBalances);
return true;
}
3. 以太坊代幣“假充值”漏洞
https://mp.weixin.qq.com/s/-neSbS38cVsnHgvbO2NFLA
以太坊代幣交易回執(zhí)中 status 字段是 0×1(true) 還是 0×0(false),取決于交易事務(wù)執(zhí)行過程中是否拋出了異常(比如使用了 require/assert/revert/throw 等機制)龟劲。當用戶調(diào)用代幣合約的 transfer 函數(shù)進行轉(zhuǎn)賬時胃夏,如果 transfer 函數(shù)正常運行未拋出異常,該交易的 status 即是 0×1(true)昌跌。
如果想了解智能合約更多的漏洞仰禀,請看
如何保護你的智能合約:6個Solidity漏洞以及如何避開它們一
如何保護你的智能合約:6個Solidity漏洞以及如何避開它們二