作者:LoRexxar'@知道創宇404區塊鏈安全研究團隊
時間:2018年8月10日
英文版:http://www.bjnorthway.com/670/
一、 簡介
在知道創宇404區塊鏈安全研究團隊整理輸出的《知道創宇以太坊合約審計CheckList》中,把“未觸發Transfer事件問題”、“未觸發Approval事件問題”、“假充值漏洞”、“構造函數書寫錯誤”等問題統一歸類為“以太坊智能合約規范問題”。
“昊天塔(HaoTian)”是知道創宇404區塊鏈安全研究團隊獨立開發的用于監控、掃描、分析、審計區塊鏈智能合約安全自動化平臺。我們利用該平臺針對上述提到的《知道創宇以太坊合約審計CheckList》中“以太坊智能合約規范”類問題在全網公開的智能合約代碼做了掃描分析。詳見下文:
二、漏洞詳情
ERC20是一種代幣標準,用于以太坊區塊鏈上的智能合約。ERC20定義了一種以太坊必須執行的通用規則,如果在以太坊發行的代幣符合ERC20的標準,那么交易所就可以進行集成,在它們的交易所實現代幣的買賣和交易。
ERC20中規定了transfer函數必須觸發Transfer事件,transfer函數必須返回bool值,在進行余額判斷時,應拋出錯誤而不是簡單的返回錯誤,approve函數必須觸發Approval事件。
1、未觸發Transfer事件
function transfer(address _to, uint256 _value) public returns (bool success) {
require(balanceOf[msg.sender] >= _value);
require(balanceOf[_to] + _value >= balanceOf[_to]);
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
return true;
}
上述代碼在發生交易時未觸發Transfer事件,在發生交易時,未產生event事件,不符合ERC20標準,不便于開發人員對合約交易情況進行監控。
2、未觸發Approval事件
function approve(address _spender, uint256 _value) public
returns (bool success) {
allowance[msg.sender][_spender] = _value;
return true;
}
上述代碼在發生交易時未觸發Approval事件,在發生交易時,未產生event事件,不符合ERC20標準,不便于開發人員對合約情況進行監控。
3、假充值漏洞
function transfer(address _to, uint256 _amount) returns (bool success) {
initialize(msg.sender);
if (balances[msg.sender] >= _amount
&& _amount > 0) {
initialize(_to);
if (balances[_to] + _amount > balances[_to]) {
balances[msg.sender] -= _amount;
balances[_to] += _amount;
Transfer(msg.sender, _to, _amount);
return true;
} else {
return false;
}
} else {
return false;
}
}
上述代碼在判斷余額時使用了if語句,ERC20標準規定,當余額不足時,合約應拋出錯誤使交易回滾,而不是簡單的返回false。
這種情況下,會導致即使沒有真正發生交易,但交易仍然成功,這種情況會影響交易平臺的判斷結果,可能導致假充值。
2018年7月9日,慢霧安全團隊發布了關于假充值的漏洞預警。
2018年7月9日,知道創宇404區塊鏈安全研究團隊跟進應急該漏洞,并對此漏洞發出了漏洞預警。
4、構造函數書寫錯誤漏洞
Solidity0.4.22版本以前,編譯器要求,構造函數名稱應該和合約名稱保持一致,如果構造函數名字和合約名字大小寫不一致,該函數仍然會被當成普通函數,可以被任意用戶調用。
Solidity0.4.22中引入了關于構造函數constructor使用不當的問題,constructor在使用中錯誤的加上了function定義,從而導致constructor可以被任意用戶調用,會導致可能的更嚴重的危害,如Owner權限被盜。
構造函數大小寫錯誤漏洞
contract own(){
function Own() {
owner = msg.sender;
}
}
上述代碼錯誤的將構造函數名大寫,導致構造函數名和合約名不一致。這種情況下,該函數被設置為一個普通的public函數,任意用戶都可以通過調用該函數來修改自己為合約owner。進一步導致其他嚴重的后果。
2018年6月22日,MorphToken合約代幣宣布更新新的智能合約,其中修復了關于大小寫錯誤導致的構造函數問題。
2018年6月22日,知道創宇404區塊鏈安全研究團隊跟進應急,并輸出了《以太坊智能合約構造函數編碼錯誤導致非法合約所有權轉移報告》。
構造函數編碼錯誤漏洞
function constructor() public {
owner = msg.sender;
}
上述代碼錯誤的使用function來作為constructor函數裝飾詞,這種情況下,該函數被設置為一個普通的public函數,任意用戶都可以通過調用該函數來修改自己為合約owner。進一步導致其他嚴重的后果。
2018年7月14日,鏈安科技在公眾號公布了關于constructor函數書寫錯誤的問題詳情。
2018年7月15日,知道創宇404區塊鏈安全研究團隊跟進應急,并輸出了《以太坊智能合約構造函數書寫錯誤導致非法合約所有權轉移報告》
三、漏洞影響范圍
使用Haotian平臺智能合約審計功能可以準確掃描到該類型問題。

基于Haotian平臺智能合約審計功能規則,我們對全網的公開的共39548 個合約代碼進行了掃描,其中共14978個合約涉及到這類問題。
1、 未觸發Transfer事件
截止2018年8月10日為止,我們發現了4604個存在未遵循ERC20標準未觸發Transfer事件的合約代碼,其中交易量最高的10個合約情況如下:

2、 未觸發Approval事件
截止2018年8月10日為止,我們發現了5231個存在未遵循ERC20標準未出發Approval事件的合約代碼,其中交易量最高的10個合約情況如下:

3、假充值漏洞
2018年7月9日,知道創宇404區塊鏈安全研究團隊在跟進應急假充值漏洞時,曾對全網公開合約代碼進行過一次掃描,當時發現約3141余個存在假充值問題的合約代碼,其中交易量最高的10個合約情況如下:

截止2018年8月10日為止,我們發現了5027個存在假充值問題的合約代碼,其中交易量最高的10個合約情況如下:

4、構造函數書寫問題
構造函數大小寫錯誤漏洞
2018年6月22日,知道創宇404區塊鏈安全研究團隊在跟進應急假充值漏洞時,全網中存在該問題的合約約為16個。
截止2018年8月10日為止,我們發現了90個存構造函數大小寫錯誤漏洞的合約代碼,其中交易量最高的10個合約情況如下:

構造函數編碼問題
截止2018年8月10日為止,我們發現了24個存在構造函數書寫問題的合約代碼,比2018年7月14日對該漏洞應急時只多了一個合約,其中交易量最高的10個合約情況如下:

四、修復方式
1)transfer函數中應觸發Tranfser事件
function transfer(address _to, uint256 _value) public returns (bool) {
require(_value <= balances[msg.sender]);
require(_to != address(0));
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
2)approve函數中應觸發Approval事件
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
3)transfer余額驗證時應使用require拋出錯誤
function transfer(address _to, uint256 _value) public returns (bool) {
require(_value <= balances[msg.sender]);
require(_to != address(0));
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
4)0.4.22版本之前,構造函數應和合約名稱一致
contract ownable {
function ownable() public {
owner = msg.sender;
}
5)0.4.22版本之后,構造函數不應用function修飾
constructor() public {
owner = msg.sender;
}
五、一些思考
上面這些問題算是我在回顧歷史漏洞中經常發現的一類問題,都屬于開發人員沒有遵守ERC20標準而導致的,雖然這些問題往往不會直接導致合約漏洞的產生,但卻因為這些沒有遵守標準的問題,在后期對于合約代幣的維護時,會出現很多問題。
如果沒有在transfer和approve時觸發相應的事件,開發人員就需要更復雜的方式監控合約的交易情況,一旦發生大規模盜幣時間,甚至沒有足夠的日志提供回滾。
如果轉賬時沒有拋出錯誤,就有可能導致假充值漏洞,如果平臺方在檢查交易結果時是通過交易狀態來判斷的,就會導致平臺利益被損害。
如果開發人員在構造函數時,沒有注意不同版本的編譯器標準,就可能導致合約所有權被輕易盜取,導致進一步更嚴重的盜幣等問題。
我們在對全網公開的合約代碼進行掃描和監控時容易發現,有很大一批開發人員并沒有注意到這些問題,甚至構造函數書寫錯誤這種低級錯誤,在漏洞預警之后仍然在發生,考慮到大部分合約代碼沒有公開,可能還有很多開發者在不遵守標準的情況下進行開發,還有很多潛在的問題需要去考慮。
這里我們建議所有的開發者重新審視自己的合約代碼,檢查是否遵守了ERC20合約標準,避免不必要的麻煩以及安全問題。
智能合約審計服務
針對目前主流的以太坊應用,知道創宇提供專業權威的智能合約審計服務,規避因合約安全問題導致的財產損失,為各類以太坊應用安全保駕護航。
知道創宇404智能合約安全審計團隊: https://www.scanv.com/lca/index.html
聯系電話:(086) 136 8133 5016(沈經理,工作日:10:00-18:00)
區塊鏈行業安全解決方案
黑客通過DDoS攻擊、CC攻擊、系統漏洞、代碼漏洞、業務流程漏洞、API-Key漏洞等進行攻擊和入侵,給區塊鏈項目的管理運營團隊及用戶造成巨大的經濟損失。知道創宇十余年安全經驗,憑借多重防護+云端大數據技術,為區塊鏈應用提供專屬安全解決方案。
六、REF
[1] ERC標準
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
[2] Morpheus官方公告
https://medium.com/@themorpheus/new-morpheus-network-token-smart-contract-91
b80dbc7655
[3] 構造函數書寫問題漏洞詳情
https://mp.weixin.qq.com/s/xPwhanev-cjHhc104Wmpug
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/663/
暫無評論