亚洲日本免费-啊轻点灬太粗太长了三男一女-麻豆av电影在线观看-日韩一级片毛片|www.grbbt.com

以太坊合約審計(jì) CheckList 之“以太坊智能合約編碼設(shè)計(jì)問題”影響分析報(bào)告

一、簡介

在知道創(chuàng)宇404區(qū)塊鏈安全研究團(tuán)隊(duì)整理輸出的《知道創(chuàng)宇以太坊合約審計(jì)CheckList》中,把“地址初始化問題”、“判斷函數(shù)問題”、“余額判斷問題”、“轉(zhuǎn)賬函數(shù)問題”、“代碼外部調(diào)用設(shè)計(jì)問題”、“錯(cuò)誤處理”、“弱隨機(jī)數(shù)問題”等問題統(tǒng)一歸類為“以太坊智能合約編碼設(shè)計(jì)問題”。

“昊天塔(HaoTian)”是知道創(chuàng)宇404區(qū)塊鏈安全研究團(tuán)隊(duì)獨(dú)立開發(fā)的用于監(jiān)控、掃描、分析、審計(jì)區(qū)塊鏈智能合約安全自動(dòng)化平臺(tái)。我們利用該平臺(tái)針對上述提到的《知道創(chuàng)宇以太坊合約審計(jì)CheckList》中“以太坊智能合約編碼設(shè)計(jì)”類問題在全網(wǎng)公開的智能合約代碼做了掃描分析。詳見下文:

二、漏洞詳情

以太坊智能合約是以太坊概念中非常重要的一個(gè)概念,以太坊實(shí)現(xiàn)了基于solidity語言的以太坊虛擬機(jī)(Ethereum Virtual Machine),它允許用戶在鏈上部署智能合約代碼,通過智能合約可以完成人們想要的合約。

這次我們提到的編碼設(shè)計(jì)問題就和EVM底層的設(shè)計(jì)有很大的關(guān)系,由于EVM的特性,智能合約有很多與其他語言不同的特性,當(dāng)開發(fā)者沒有注意到這些問題時(shí),就容易出現(xiàn)潛在的問題。

1、地址初始化問題

在EVM中,所有與地址有關(guān)的初始化時(shí),都會(huì)賦予初值0。

如果一個(gè)address變量與0相等時(shí),說明該變量可能未初始化或出現(xiàn)了未知的錯(cuò)誤。

如果開發(fā)者在代碼中初始化了某個(gè)address變量,但未賦予初值,或用戶在發(fā)起某種操作時(shí),誤操作未賦予address變量,但在下面的代碼中需要對這個(gè)變量做處理,就可能導(dǎo)致不必要的安全風(fēng)險(xiǎn)。

2、判斷函數(shù)問題

在智能合約中,有個(gè)很重要的校驗(yàn)概念。下面這種問題的出現(xiàn)主要是合約代幣的內(nèi)部交易。

但如果在涉及到關(guān)鍵判斷(如余額判斷)等影響到交易結(jié)果時(shí),當(dāng)交易發(fā)生錯(cuò)誤,我們需要對已經(jīng)執(zhí)行的交易結(jié)果進(jìn)行回滾,而EVM不會(huì)檢查交易函數(shù)的返回結(jié)果。如果我們使用return false,EVM是無法獲取到這個(gè)錯(cuò)誤的,則會(huì)導(dǎo)致在之前的文章中提到的假充值問題

在智能合約中,我們需要拋出這個(gè)錯(cuò)誤,這樣EVM才能獲取到錯(cuò)誤觸發(fā)底層的revert指令回滾交易。

而在solidity扮演這一角色的,正是require函數(shù)。而有趣的是,在solidity中,還有一個(gè)函數(shù)叫做assert,和require不同的是,它底層對應(yīng)的是空指令,EVM執(zhí)行到這里時(shí)就會(huì)報(bào)錯(cuò)退出,不會(huì)觸發(fā)回滾。

轉(zhuǎn)化到直觀的交易來看,如果我們使用assert函數(shù)校驗(yàn)時(shí),assert會(huì)消耗掉所有剩余的gas。而require會(huì)觸發(fā)回滾操作。

assert在校驗(yàn)方面展現(xiàn)了強(qiáng)一致性,除了對固定變量的檢查以外,require更適合這種情況下的使用。

3、余額判斷問題

在智能合約中,經(jīng)常會(huì)出現(xiàn)對用戶余額的判斷,尤其是賬戶初建時(shí),許多合約都會(huì)對以合約創(chuàng)建時(shí)余額為0來判斷合約的初建狀態(tài),這是一種錯(cuò)誤的行為。

在智能合約中,永遠(yuǎn)無法阻止別人向你的強(qiáng)制轉(zhuǎn)賬,即使fallback函數(shù)throw也不可以。攻擊者可以創(chuàng)建帶有余額的新合約,然后調(diào)用selfdestruct(victimAddress)銷毀,這樣余額就會(huì)強(qiáng)制轉(zhuǎn)移給目標(biāo),在這個(gè)過程中,不會(huì)調(diào)用目標(biāo)合約的代碼,所以無法從代碼層面阻止。

值得注意的是,在打包的過程中,攻擊者可以通過條件競爭來在合約創(chuàng)建前轉(zhuǎn)賬,這樣在合約創(chuàng)建時(shí)余額就為0了。

4、轉(zhuǎn)賬函數(shù)問題

在智能合約中,涉及到轉(zhuǎn)賬的操作最常見不過了。而在solidity中,提供了兩個(gè)函數(shù)用于轉(zhuǎn)賬tranfer/send。

當(dāng)tranfer/send函數(shù)的目標(biāo)是合約時(shí),會(huì)調(diào)用合約內(nèi)的fallback函數(shù)。但當(dāng)fallback函數(shù)執(zhí)行錯(cuò)誤時(shí),transfer函數(shù)會(huì)拋出錯(cuò)誤并回滾,而send則會(huì)返回false。如果在使用send函數(shù)交易時(shí),沒有及時(shí)做判斷,則可能出現(xiàn)轉(zhuǎn)賬失敗卻余額減少的情況。

function withdraw(uint256 _amount) public {
    require(balances[msg.sender] >= _amount);
    balances[msg.sender] -= _amount;
    etherLeft -= _amount;
    msg.sender.send(_amount);  
}

上面給出的代碼中使用 send() 函數(shù)進(jìn)行轉(zhuǎn)賬,因?yàn)檫@里沒有驗(yàn)證 send() 返回值,如果msg.sender 為合約賬戶 fallback() 調(diào)用失敗,則 send() 返回false,最終導(dǎo)致賬戶余額減少了,錢卻沒有拿到。

5、代碼外部調(diào)用設(shè)計(jì)問題

在智能合約的設(shè)計(jì)思路中,有一個(gè)很重要的概念為外部調(diào)用。或是調(diào)用外部合約,又或是調(diào)用其它賬戶。這在智能合約的設(shè)計(jì)中是個(gè)很常見的思路,最常見的便是轉(zhuǎn)賬操作,就是典型的外部調(diào)用。

但外部調(diào)用本身就是一個(gè)容易發(fā)生錯(cuò)誤的操作,誰也不能肯定在和外部合約/用戶交互時(shí)能確保順利,舉一個(gè)合約代幣比較常見的例子

contract auction {
    address highestBidder;
    uint highestBid;
    function bid() payable {
        if (msg.value < highestBid) throw;
        if (highestBidder != 0) {
            if (!highestBidder.send(highestBid)) { // 可能會(huì)發(fā)生錯(cuò)誤
                throw;
            }
        }
       highestBidder = msg.sender;
       highestBid = msg.value;
    }
}

上述代碼當(dāng)轉(zhuǎn)賬發(fā)生錯(cuò)誤時(shí)可能會(huì)導(dǎo)致進(jìn)一步其他的錯(cuò)誤,如果碰到循環(huán)調(diào)用bid函數(shù)時(shí),更可能導(dǎo)致循環(huán)到中途發(fā)生錯(cuò)誤,在之前提到的ddos優(yōu)化問題中,這也是一個(gè)很典型的例子。

而這就是一個(gè)典型的push操作,指合約主動(dòng)和外部進(jìn)行交互,這種情況容易出現(xiàn)問題是難以定位難以彌補(bǔ),導(dǎo)致潛在的問題。

6、錯(cuò)誤處理

智能合約中,有一些涉及到address底層操作的方法

address.call()
address.callcode()
address.delegatecall()
address.send()

他們都有一個(gè)典型的特點(diǎn),就是遇到錯(cuò)誤并不會(huì)拋出錯(cuò)誤,而是會(huì)返回錯(cuò)誤并繼續(xù)執(zhí)行。

且作為EVM設(shè)計(jì)的一部分,下面這些函數(shù)如果調(diào)用的合約不存在,將會(huì)返回True。如果合約開發(fā)者沒有注意到這個(gè)問題,那么就有可能出現(xiàn)問題。

call、delegatecall、callcode、staticcall

http://rickgray.me/2018/05/26/ethereum-smart-contracts-vulnerabilities-review-part2/#4-Unchecked-Return-Values-For-Low-Level-Calls

7、弱隨機(jī)數(shù)問題

智能合約是借助EVM運(yùn)行,跑在區(qū)塊鏈上的合約代碼。其最大的特點(diǎn)就是公開和不可篡改性。而如何在合約上生成隨機(jī)數(shù)就成了一個(gè)大問題。

Fomo3D合約在空投獎(jiǎng)勵(lì)的隨機(jī)數(shù)生成中就引入了block信息作為隨機(jī)數(shù)種子生成的參數(shù),導(dǎo)致隨機(jī)數(shù)種子只受到合約地址影響,無法做到完全隨機(jī)。

function airdrop()
    private 
    view 
    returns(bool)
{
    uint256 seed = uint256(keccak256(abi.encodePacked(
        (block.timestamp).add
        (block.difficulty).add
        ((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (now)).add
        (block.gaslimit).add
        ((uint256(keccak256(abi.encodePacked(msg.sender)))) / (now)).add
        (block.number)
    )));
    if((seed - ((seed / 1000) * 1000)) < airDropTracker_)
        return(true);
    else
        return(false);
}

上述這段代碼直接導(dǎo)致了Fomo3d薅羊毛事件的誕生。真實(shí)世界損失巨大,超過數(shù)千eth。

8萬筆交易「封死」以太坊網(wǎng)絡(luò),只為搶奪Fomo3D大獎(jiǎng)??Last Winner

三、漏洞影響范圍

使用Haotian平臺(tái)智能合約審計(jì)功能可以準(zhǔn)確掃描到該類型問題。

基于Haotian平臺(tái)智能合約掃描功能規(guī)則,我們對全網(wǎng)的公開的共42538個(gè)合約代碼進(jìn)行了掃描,其中35107個(gè)合約存在地址初始化問題,4262個(gè)合約存在判斷函數(shù)問題,173個(gè)合約存在余額判斷問題,930個(gè)合約存在轉(zhuǎn)賬函數(shù)問題, 349個(gè)合約存在弱隨機(jī)數(shù)問題,2300個(gè)合約調(diào)用了block.timestamp,過半合約涉及到這類安全風(fēng)險(xiǎn)。

1、地址初始化問題

截止2018年9月21日,我們發(fā)現(xiàn)了35107個(gè)存在地址初始化問題的合約代碼,存在潛在的安全隱患。

2、判斷函數(shù)問題

截止2018年9月21日,我們發(fā)現(xiàn)了4262個(gè)存在判斷函數(shù)問題的合約代碼,存在潛在的安全隱患。

3、余額判斷問題

截止2018年9月21日,我們發(fā)現(xiàn)了173個(gè)存在余額判斷問題的合約代碼,其中165個(gè)仍處于交易狀態(tài),其中交易量最高的10個(gè)合約情況如下:

4、轉(zhuǎn)賬函數(shù)問題

截止2018年9月21日,我們發(fā)現(xiàn)了930個(gè)存在轉(zhuǎn)賬函數(shù)問題的合約代碼,其中873個(gè)仍處于交易狀態(tài),其中交易量最高的10個(gè)合約情況如下:

5、弱隨機(jī)數(shù)問題

截止2018年9月21日,我們發(fā)現(xiàn)了349個(gè)存在弱隨機(jī)數(shù)問題的合約代碼,其中272個(gè)仍處于交易狀態(tài),其中交易量最高的10個(gè)合約情況如下:

截止2018年9月21日,我們發(fā)現(xiàn)了2300個(gè)存在調(diào)用了block.timestamp的合約代碼,其中2123個(gè)仍處于交易狀態(tài),其中交易量最高的10個(gè)合約情況如下:

四、修復(fù)方式

1、地址初始化問題

涉及到地址的函數(shù)中,建議加入require(_to!=address(0))驗(yàn)證,有效避免用戶誤操作或未知錯(cuò)誤導(dǎo)致的不必要的損失

2、判斷函數(shù)問題

對于正常的判斷來說,優(yōu)先使用require來判斷結(jié)果。

而對于固定變量的檢查,使用assert函數(shù)可以避免一些未知的問題,因?yàn)樗麜?huì)強(qiáng)制終止合約并使其無效化,在一些固定條件下,assert更適用

3、余額判斷問題

不要在合約任何地方假設(shè)合約的余額,尤其是不要通過創(chuàng)建時(shí)合約為0來判斷合約初建狀態(tài),攻擊者可以使用多種方式強(qiáng)制轉(zhuǎn)賬。

4、轉(zhuǎn)賬函數(shù)問題

在完成交易時(shí),默認(rèn)推薦使用transfer函數(shù)而不是send完成交易。

5、代碼外部調(diào)用設(shè)計(jì)問題

對于外部合約優(yōu)先使用pull而不是push。如上述的轉(zhuǎn)賬函數(shù),可以通過賦予提取權(quán)限來將主動(dòng)行為轉(zhuǎn)換為被動(dòng)行為

contract auction {
    address highestBidder;
    uint highestBid;
    mapping(address => uint) refunds;
    function bid() payable external {
        if (msg.value < highestBid) throw;
        if (highestBidder != 0) {
            refunds[highestBidder] += highestBid; // 記錄在refunds中
        }
        highestBidder = msg.sender;
        highestBid = msg.value;
    }
    function withdrawRefund() external {
        uint refund = refunds[msg.sender];
        refunds[msg.sender] = 0;
        if (!msg.sender.send(refund)) {
            refunds[msg.sender] = refund; // 如果轉(zhuǎn)賬錯(cuò)誤還可以挽回
        }
    }
}

通過構(gòu)建withdraw來使用戶來執(zhí)行合約將余額取出。

6、錯(cuò)誤處理

合約中涉及到call等在address底層操作的方法時(shí),做好合理的錯(cuò)誤處理

if(!someAddress.send(55)) {
    // Some failure code
}

包括目標(biāo)合約不存在時(shí),也同樣需要考慮。

7、弱隨機(jī)數(shù)問題

智能合約上隨機(jī)數(shù)生成方式需要更多考量

在合約中關(guān)于這樣的應(yīng)用時(shí),考慮更合適的生成方式和合理的利用順序非常重要。

這里提供一個(gè)比較合理的隨機(jī)數(shù)生成方式hash-commit-reveal,即玩家提交行動(dòng)計(jì)劃,然后行動(dòng)計(jì)劃hash后提交給后端,后端生成相應(yīng)的hash值,然后生成對應(yīng)的隨機(jī)數(shù)reveal,返回對應(yīng)隨機(jī)數(shù)commit。這樣,服務(wù)端拿不到行動(dòng)計(jì)劃,客戶端也拿不到隨機(jī)數(shù)。

有一個(gè)很棒的實(shí)現(xiàn)代碼是dice2win的隨機(jī)數(shù)生成代碼。

當(dāng)然hash-commit在一些簡單場景下也是不錯(cuò)的實(shí)現(xiàn)方式。即玩家提交行動(dòng)計(jì)劃的hash,然后生成隨機(jī)數(shù),然后提交行動(dòng)計(jì)劃。

五、一些思考

在探索智能合約最佳實(shí)踐的過程中,逐漸發(fā)現(xiàn),在智能合約中有很多只有智能合約才會(huì)出現(xiàn)的問題,這些問題大多都是因?yàn)镋VM的特殊性而導(dǎo)致的特殊特性,但開發(fā)者并沒有對這些特性有所了解,導(dǎo)致很多的潛在安全問題誕生。

我把這一類問題歸結(jié)為編碼設(shè)計(jì)問題,開發(fā)者可以在編碼設(shè)計(jì)階段注意這些問題,可以避免大多數(shù)潛在安全問題。

智能合約審計(jì)服務(wù)

針對目前主流的以太坊應(yīng)用,知道創(chuàng)宇提供專業(yè)權(quán)威的智能合約審計(jì)服務(wù),規(guī)避因合約安全問題導(dǎo)致的財(cái)產(chǎn)損失,為各類以太坊應(yīng)用安全保駕護(hù)航。

知道創(chuàng)宇404智能合約安全審計(jì)團(tuán)隊(duì):?https://www.scanv.com/lca/index.html
聯(lián)系電話:(086) 136 8133 5016(沈經(jīng)理,工作日:10:00-18:00)

區(qū)塊鏈行業(yè)安全解決方案

黑客通過DDoS攻擊、CC攻擊、系統(tǒng)漏洞、代碼漏洞、業(yè)務(wù)流程漏洞、API-Key漏洞等進(jìn)行攻擊和入侵,給區(qū)塊鏈項(xiàng)目的管理運(yùn)營團(tuán)隊(duì)及用戶造成巨大的經(jīng)濟(jì)損失。知道創(chuàng)宇十余年安全經(jīng)驗(yàn),憑借多重防護(hù)+云端大數(shù)據(jù)技術(shù),為區(qū)塊鏈應(yīng)用提供專屬安全解決方案。

原文鏈接:https://paper.seebug.org/707/

上一篇:企業(yè)安全戰(zhàn)略TOP3:目標(biāo)、流程與培訓(xùn)

下一篇:幫助眾多惡意軟件逃避檢測:針對一款Delphi加殼器的分析