譯文僅供參考,具體內(nèi)容表達(dá)以及含義原文為準(zhǔn)
EOSIO區(qū)塊鏈?zhǔn)蔷哂写硇缘臋?quán)益證明(DPoS)區(qū)塊鏈平臺(tái)之一,最近發(fā)展迅速。同時(shí),在野還發(fā)現(xiàn)并觀察到針對(duì)熱門EOSIO DApp及其智能合約的許多漏洞和攻擊,造成了嚴(yán)重的經(jīng)濟(jì)損失。大多數(shù)EOSIO智能合約不是開(kāi)源的,它們通常會(huì)編譯為WebAssembly(Wasm)字節(jié)碼,因此很難分析和檢測(cè)可能存在的漏洞。在本文中提出了EOSAFE,這是第一個(gè)可用于自動(dòng)檢測(cè)EOSIO智能合約中字節(jié)碼級(jí)別漏洞的靜態(tài)分析框架工具。框架包括一個(gè)用于Wasm的實(shí)用符號(hào)執(zhí)行引擎,一個(gè)用于EOSIO智能合約的定制庫(kù)模擬器,以及四個(gè)啟發(fā)式掃描器,用于識(shí)別EOSIO智能合約中四個(gè)最流行的漏洞的存在。實(shí)驗(yàn)結(jié)果表明,EOSAFE在檢測(cè)漏洞方面取得了較優(yōu)結(jié)果,F(xiàn)1-measure為98%。截至2019年11月15日,已將EOSAFE應(yīng)用于生態(tài)系統(tǒng)中所有有效的53,666份智能合約。結(jié)果表明,超過(guò)25%的智能合約易受攻擊。進(jìn)一步分析了對(duì)這些易受攻擊的智能合約的可能的利用嘗試,并確定了48種在野攻擊(其中25種已由DApp開(kāi)發(fā)人員確認(rèn)),造成的財(cái)務(wù)損失至少為170萬(wàn)美元。
隨著加密貨幣(例如比特幣)的繁榮發(fā)展,區(qū)塊鏈技術(shù)變得越來(lái)越有吸引力,并在許多領(lǐng)域被采用。由于工作證明共識(shí)的帶來(lái)的吞吐量有限(例如TPS),因此不能使用傳統(tǒng)的區(qū)塊鏈平臺(tái)(例如比特幣和以太坊)來(lái)支持高性能應(yīng)用程序。研究人員提出了不同的共識(shí)協(xié)議,例如權(quán)益證明(PoS)和委托權(quán)益證明(DPoS)以解決性能問(wèn)題。
作為最具代表性的DPoS平臺(tái)之一,EOSIO已成為最活躍的全球社區(qū)之一。 EOSIO采用了基于DPoS共識(shí)協(xié)議的多線程機(jī)制,能夠?qū)崿F(xiàn)數(shù)百萬(wàn)的TPS。 EOSIO的性能優(yōu)勢(shì)使其在去中心化應(yīng)用程序(DApps)開(kāi)發(fā)人員中很受歡迎。 EOSIO在其于2018年6月推出的三個(gè)月內(nèi),在DApp交易中成功超過(guò)了以太坊,并在接下來(lái)的幾個(gè)月中將其主導(dǎo)地位進(jìn)一步提高了數(shù)十倍,EOSIO的交易量平均是以太坊的100倍以上。截至2019年,EOSIO的鏈上交易總價(jià)值已超過(guò)60億美元。
智能合約是一種計(jì)算機(jī)協(xié)議,允許用戶以便捷安全的方式進(jìn)行數(shù)字協(xié)商。與傳統(tǒng)合約法相比,智能合約的交易成本大大降低,并且共識(shí)協(xié)議確保了其執(zhí)行的正確性。 EOSIO智能合約可以用C ++編寫,然后將其編譯為WebAssembly(又名Wasm)并在EOS虛擬機(jī)(EOS VM)中執(zhí)行。 Wasm是一個(gè)Web標(biāo)準(zhǔn),為基于堆棧的VM指定二進(jìn)制指令格式。它可以在現(xiàn)代Web瀏覽器和其他環(huán)境中運(yùn)行。
但是,要保證執(zhí)行智能合約的安全性并不容易,特別是EOSIO。 EOSIO智能合約中發(fā)現(xiàn)了許多漏洞,而在野發(fā)現(xiàn)了嚴(yán)重的攻擊,這造成了巨大的經(jīng)濟(jì)損失。例如,在2018年秋天,由于虛假EOS(fake EOS)和虛假收據(jù)(fake receipt)漏洞,一個(gè)DApp EOSBet在短短一個(gè)月中遭受了兩次攻擊,分別造成40,000和65,000 EOS損失。因此,有必要識(shí)別智能合約的安全性問(wèn)題,以防止此類攻擊。
不幸的是,EOSIO上的大多數(shù)智能合約都不是開(kāi)源的,并且很少有分析工具來(lái)分析Wasm字節(jié)碼,這使得自動(dòng)檢測(cè)EOSIO智能合約的漏洞更加困難。盡管已經(jīng)有很多工具可以分析以太坊智能合約,但是它們都不能應(yīng)用于EOSIO智能合約,因?yàn)檫@兩個(gè)生態(tài)系統(tǒng)完全不同,從虛擬機(jī),字節(jié)碼結(jié)構(gòu)到漏洞的類型。
具體來(lái)說(shuō),分析EOSIO智能合約存在一些挑戰(zhàn)。首先,就數(shù)量和種類而言,EOS VM比以太坊VM更復(fù)雜。例如,EOS VM支持浮點(diǎn)操作,類型轉(zhuǎn)換和br_table之類的高級(jí)跳轉(zhuǎn)指令。其次,與以太坊字節(jié)碼相比,Wasm字節(jié)碼本身由于函數(shù)中的多層嵌套結(jié)構(gòu)而使分析更加復(fù)雜,從而導(dǎo)致基本塊之間的跳轉(zhuǎn)關(guān)系復(fù)雜。第三,到目前為止發(fā)現(xiàn)的大多數(shù)EOSIO漏洞比以前發(fā)現(xiàn)的簡(jiǎn)單漏洞(例如整數(shù)溢出)更為復(fù)雜。因此,它通常需要更多的語(yǔ)義信息,例如平臺(tái)特定的數(shù)據(jù)結(jié)構(gòu)的字段作為索引,以對(duì)其進(jìn)行建模和分析。例如要檢測(cè)到虛假EOS,需要檢查apply函數(shù)中參數(shù)code的特定值。
本研究已經(jīng)實(shí)現(xiàn)了EOSAFE,這是第一個(gè)用于檢測(cè)EOSIO智能合約漏洞的系統(tǒng)靜態(tài)分析框架。具體來(lái)說(shuō),首先為Wasm字節(jié)碼實(shí)現(xiàn)一個(gè)符號(hào)執(zhí)行引擎,然后通過(guò)應(yīng)用啟發(fā)式引導(dǎo)剪枝方法來(lái)緩解路徑爆炸問(wèn)題。其次,為了分析EOSIO智能合約并模擬其外部交互環(huán)境,實(shí)現(xiàn)了一個(gè)模擬器來(lái)模擬關(guān)鍵EOSIO庫(kù)特征的行為,這些特征對(duì)于檢測(cè)漏洞至關(guān)重要。第三,提出了一個(gè)通用的漏洞檢測(cè)框架,該框架允許安全分析人員輕松地將自己的漏洞掃描器實(shí)現(xiàn)為插件。在這項(xiàng)工作中,實(shí)現(xiàn)了四個(gè)掃描器,旨在檢測(cè)四個(gè)重要的漏洞,包括虛假EOS,虛假收據(jù),回滾(rollback)和缺失權(quán)限檢查(missing permission check)。
為了評(píng)估EOSAFE的有效性,首先手動(dòng)設(shè)計(jì)了一個(gè)基準(zhǔn)套件,其中包括52個(gè)智能合約,由從公開(kāi)驗(yàn)證的攻擊中收集的易受攻擊的智能合約及其相應(yīng)的修補(bǔ)補(bǔ)丁組成,實(shí)驗(yàn)結(jié)果表明EOSAFE在識(shí)別現(xiàn)有漏洞方面取得了出色的性能。為了衡量EOSIO生態(tài)系統(tǒng)中漏洞的存在,進(jìn)一步將EOSAFE應(yīng)用于生態(tài)系統(tǒng)中的所有智能合約(總計(jì)53,666)。實(shí)驗(yàn)結(jié)果表明,安全漏洞在EOSIO生態(tài)系統(tǒng)中十分普遍:超過(guò)25%的智能合約(包括歷史版本)易受攻擊,并且其中很大一部分沒(méi)有及時(shí)修補(bǔ)。為了進(jìn)一步衡量漏洞的影響,收集了交易記錄(總計(jì)超過(guò)25億筆交易),并精心設(shè)計(jì)了一套保守的啟發(fā)式策略,以識(shí)別針對(duì)這些脆弱智能合約的攻擊。已經(jīng)識(shí)別出48起攻擊,以及183起缺少權(quán)限檢查的行為。截至撰寫本文時(shí),DApp開(kāi)發(fā)者已確認(rèn)25起攻擊,已造成超過(guò)170萬(wàn)美元的經(jīng)濟(jì)損失。
作為第一個(gè)工業(yè)級(jí)規(guī)模的分布式操作系統(tǒng),EOSIO平臺(tái)可以實(shí)現(xiàn)高性能,即數(shù)百萬(wàn)個(gè)TPS,以有效執(zhí)行復(fù)雜的DApp。它如此高效地執(zhí)行的事實(shí)很大程度上歸功于它使用的共識(shí)算法,即DPoS。與傳統(tǒng)的PoW(比特幣和以太坊采用)相比,它不會(huì)在不必要的挖掘過(guò)程中花費(fèi)大量的計(jì)算資源。接下來(lái),介紹一些關(guān)鍵概念以促進(jìn)對(duì)這項(xiàng)工作的理解。
EOSIO中的帳戶是識(shí)別實(shí)體的基本單位,它可以觸發(fā)與EOSIO中其他帳戶的交易。此外,為了確保帳戶安全并防止身份欺詐,EOSIO實(shí)施了基于權(quán)限的高級(jí)訪問(wèn)控制系統(tǒng)。具體而言,該帳戶可以將公共/專用密鑰分配給特定的操作,并且特定的密鑰對(duì)將只能執(zhí)行相應(yīng)的操作。默認(rèn)情況下,EOSIO帳戶附加到兩個(gè)公用密鑰:ownerkey(用于指定帳戶的所有權(quán))和active key(用于授予對(duì)帳戶活動(dòng)的訪問(wèn)權(quán)限)。這兩個(gè)密鑰授權(quán)兩個(gè)本機(jī)命名權(quán)限:owner和active權(quán)限,以管理帳戶。除了本機(jī)權(quán)限,EOSIO還允許自定義命名權(quán)限以進(jìn)行高級(jí)帳戶管理。
與以太坊不同,EOSIO智能合約不被視為單獨(dú)的實(shí)體。智能合約只是帳戶中存儲(chǔ)的一小段代碼,這可以輕松解釋為什么EOSIO中的智能合約是可更新的,而不是所有者無(wú)法自由更改和銷毀的東西,因此,當(dāng)一個(gè)帳戶被另一個(gè)人調(diào)用時(shí),它所駐留的智能合約將負(fù)責(zé)處理收到的調(diào)用。這樣,合約中最關(guān)鍵的組件就是dispatcher,它可以將請(qǐng)求調(diào)度到相應(yīng)的函數(shù)。由EOSIO官方定義,智能合約中的調(diào)度程序被命名為apply,如下所示。
事務(wù)是要由節(jié)點(diǎn)驗(yàn)證的基本單位,它被打包在塊中。如下圖所示,一個(gè)事務(wù)由一個(gè)或多個(gè)action組成。動(dòng)作是觸發(fā)函數(shù)的基本單位。例如,上面第1行的操作指定了目標(biāo)函數(shù)名稱。一個(gè)動(dòng)作負(fù)責(zé)攜帶調(diào)用者的權(quán)限。
一個(gè)動(dòng)作可以通過(guò)兩種方式在同一上下文中觸發(fā)其他動(dòng)作:inlined和deferred。具體來(lái)說(shuō),內(nèi)聯(lián)動(dòng)作可以看作是繼承其父級(jí)上下文(包括所攜帶的權(quán)限)的普通動(dòng)作。至于延遲動(dòng)作,引入該動(dòng)作的原因是每個(gè)事務(wù)的執(zhí)行時(shí)間上限為30毫秒,并且所有不必要的動(dòng)作都可以分為延遲動(dòng)作以執(zhí)行。因此,如上圖所示,在不同的事務(wù)中執(zhí)行了延遲的操作。
除了交易和動(dòng)作外,還有另一種排他性機(jī)制,即notifification。如上圖所示,EOS是帳戶eosio.token發(fā)行的正式token。它維護(hù)一個(gè)表格以記錄持有人及其余額。因此,要將EOS轉(zhuǎn)移到DApp,用戶必須在eosio.token中請(qǐng)求transfer函數(shù)。對(duì)于上圖中的步驟1,指示實(shí)際調(diào)用其代碼的代碼是eosio.token;代表動(dòng)作或通知的接收者的接收者也是eosio.token。更新余額表后,eosio.token將通知付款人和收款人(參閱步驟2和3)。請(qǐng)注意,步驟3中的代碼仍然是eosio.token,因?yàn)橥ㄖ静皇且粋€(gè)動(dòng)作,而接收者是DApp。最后,通知也將由調(diào)度程序處理,就像使用相同的動(dòng)作調(diào)用一樣姓名。
EOSIO智能合約用C ++編寫,然后編譯為WebAssembly(Wasm)字節(jié)碼,該字節(jié)碼將在EOS VM中執(zhí)行。Wasm是基于堆棧的虛擬機(jī)的二進(jìn)制指令格式。盡管它被設(shè)計(jì)為支持高性能Web應(yīng)用程序的開(kāi)放標(biāo)準(zhǔn),但它也可以用于支持其他環(huán)境,例如區(qū)塊鏈。由于其高效性和可移植性,除了EOSIO之外,其他流行的區(qū)塊鏈(例如,以太坊2.0)也將支持Wasm。
EOSIO Wasm二進(jìn)制文件稱為模塊。 在模塊內(nèi)部,存在許多部分。 具體而言,在Function”部分中確定函數(shù)的順序,該順序與Code部分中函數(shù)(在低級(jí)指令中)的實(shí)現(xiàn)順序相對(duì)應(yīng)。 出現(xiàn)在Element部分的所有函數(shù)索引都可以視為當(dāng)前模塊的條目。 此外,字符串文字常用于初始化“內(nèi)存”部分并存儲(chǔ)在Data部分中。
像以太坊VM一樣,EOS VM支持Stack,Local和Global,它們通過(guò)多個(gè)指令(例如local_set,global_get)從虛擬堆棧中推送和彈出。 同樣,EOS VM具有一個(gè)稱為Memory的區(qū)域,這是一個(gè)隨機(jī)可訪問(wèn)的線性字節(jié)數(shù)組,只能通過(guò)使用特定指令(例如load和store)進(jìn)行訪問(wèn)。
在合約執(zhí)行的生命周期內(nèi),可以隨時(shí)進(jìn)行攻擊。因此首先游戲以DApp為例,介紹智能合約執(zhí)行的一般生命周期,如下圖所示。首先,玩家在eosio.token中調(diào)用轉(zhuǎn)移以參與游戲。然后,當(dāng)DApp收到通知時(shí),它將分派要通過(guò)分派器進(jìn)行transfer的請(qǐng)求。在那之后,transfer將調(diào)用reveal以計(jì)算一個(gè)隨機(jī)數(shù),以確定玩家是否在本回合中中了頭獎(jiǎng)。如果是,DApp將觸發(fā)eosio.token中的transfer,以將獎(jiǎng)品返還給玩家。但是,攻擊者可以在每個(gè)步驟中利用這些漏洞來(lái)獲取利潤(rùn)。例如,在第3步和第4步中,攻擊者可能無(wú)法嚴(yán)格驗(yàn)證輸入?yún)?shù)的值。最重要的是,整個(gè)游戲過(guò)程都有可能被惡意回滾。在本節(jié)中討論與合約執(zhí)行生命周期有關(guān)的四種常見(jiàn)漏洞。
任何人都可以創(chuàng)建和發(fā)行稱為EOS的token,因?yàn)閠oken名稱和符號(hào)在EOSIO中不需要符合唯一性。因此,在上圖中的步驟3對(duì)code進(jìn)行的不正確驗(yàn)證可能會(huì)導(dǎo)致漏洞。
漏洞描述:由于eosio.token的源代碼是完全公開(kāi)的,因此任何人都可以復(fù)制其源代碼并發(fā)行具有相同名稱,符號(hào)和代碼的token。虛假EOS與官方的EOS唯一的區(qū)別在于,它們的發(fā)行人不同。因此,如果攻擊者通過(guò)復(fù)制的合約的transfer函數(shù)將虛假EOS轉(zhuǎn)移到游戲DApp,則項(xiàng)目方收到的通知代碼將不會(huì)是beeosio.token。此外,如果DApp碰巧不檢查code的值,那么將繞過(guò)調(diào)度程序中的驗(yàn)證。為了緩解上述問(wèn)題,一些開(kāi)發(fā)人員縮小了接受code的范圍,如前文的第6行所示“ code == self”用于處理來(lái)自其他帳戶的直接調(diào)用,而“ code == N(eosio.token )”僅接受來(lái)自官方帳戶的通知。但是,由于短路評(píng)估,如果攻擊者直接在DApp中調(diào)用transfer,則驗(yàn)證也將是無(wú)效的,因?yàn)閮蓚€(gè)實(shí)體的余額都沒(méi)有變化。
由于這兩種情況僅與虛假EOS token有關(guān),因此在本文中,將兩者都稱為虛假EOS漏洞。
如果DApp開(kāi)發(fā)人員對(duì)code進(jìn)行了全面檢查,則通知將由調(diào)度程序轉(zhuǎn)發(fā)到transfer,如上圖中的步驟4所示。但是,如果開(kāi)發(fā)人員在此步驟中未執(zhí)行驗(yàn)證,則DApp可以被攻擊。
漏洞描述:通知可以轉(zhuǎn)發(fā),并且code不會(huì)更改。因此,DApp可能會(huì)被同時(shí)扮演發(fā)起者和共犯雙重角色(帳戶)的攻擊者欺騙。具體來(lái)說(shuō),啟動(dòng)器通過(guò)eosio.token調(diào)用對(duì)同伙(由to表示,transfer函數(shù)的參數(shù))的常規(guī)轉(zhuǎn)移。當(dāng)eosio.token通知共犯時(shí),它將立即將通知轉(zhuǎn)發(fā)給DApp,而無(wú)需進(jìn)行任何修改。這樣,code就不會(huì)更改,這是官方發(fā)行者:eosio.token。因此,調(diào)度器將不會(huì)發(fā)現(xiàn)任何異常情況。但是,如果不檢查transfer中的參數(shù)to,則DApp將被欺騙,因?yàn)閠oken的轉(zhuǎn)移已在攻擊者控制的兩個(gè)帳戶之間完成。這會(huì)給DApp開(kāi)發(fā)人員造成直接的財(cái)務(wù)損失。由于通知是由require_recipient觸發(fā)的,因此將此漏洞稱為虛假收據(jù)。
在前圖中,transfer和reveal是關(guān)鍵函數(shù)。在transfer中,DApp處理隨玩家轉(zhuǎn)帳而收到的壓注;在reveal中,開(kāi)發(fā)人員經(jīng)常使用各種鏈上狀態(tài)值作為種子(例如current_time,該值表示執(zhí)行操作的時(shí)間戳)來(lái)生成偽隨機(jī)數(shù),并最終通過(guò)將生成的數(shù)字與玩家的輸入進(jìn)行比較來(lái)獲得結(jié)果。請(qǐng)注意,通常,回滾情況只能在游戲DApp中找到。假設(shè)reveal函數(shù)始終存在,并且對(duì)于每個(gè)游戲DApp而言都可以從入口點(diǎn)(即apply函數(shù))到達(dá)。
漏洞描述:即使開(kāi)發(fā)人員仔細(xì)檢查了輸入的每個(gè)參數(shù),并在采取任何敏感措施之前檢查了調(diào)用者的權(quán)限,與前圖中的模型匹配的游戲仍然可能受到攻擊。具體而言,所有動(dòng)作都是內(nèi)聯(lián)調(diào)用的,即位于單個(gè)事務(wù)中。因此,當(dāng)玩家在步驟8之后收到通知時(shí),他可以立即調(diào)用eosio.token的另一個(gè)內(nèi)聯(lián)動(dòng)作來(lái)檢查其余額。如果他的平衡減少,則意味著他沒(méi)有贏得本輪比賽。他可以使用斷言語(yǔ)句來(lái)強(qiáng)制當(dāng)前操作失敗。動(dòng)作失敗可能導(dǎo)致整個(gè)交易恢復(fù)。這樣,玩家可以繼續(xù)嘗試,直到他中獎(jiǎng)為止。將此惡意回滾稱為回滾漏洞。
在執(zhí)行任何敏感操作之前,開(kāi)發(fā)人員應(yīng)檢查動(dòng)作是否攜帶了相應(yīng)的權(quán)限。例如,在前圖中的步驟5之前,DApp應(yīng)檢查調(diào)用者是否可以代表實(shí)際付款人參加游戲。
漏洞描述:權(quán)限檢查由EOSIO中的require_auth(acct)強(qiáng)制執(zhí)行,用于檢查調(diào)用者是否已被acct授權(quán)來(lái)觸發(fā)相應(yīng)的函數(shù)。請(qǐng)注意,內(nèi)聯(lián)操作繼承了其父級(jí)的上下文,包括權(quán)限(請(qǐng)參見(jiàn)第2.1節(jié))。因此,如果攜帶不足權(quán)限的攻擊者調(diào)用了一個(gè)函數(shù),該函數(shù)通過(guò)內(nèi)聯(lián)動(dòng)作并且沒(méi)有權(quán)限檢查就執(zhí)行敏感操作,則可能會(huì)發(fā)生意外行為。將所有沒(méi)有權(quán)限檢查的函數(shù)視為缺少權(quán)限檢查漏洞。
在EOSIO中,此問(wèn)題主要是由于兩種情況造成的:執(zhí)行條件跳轉(zhuǎn)指令(例如br_if)或調(diào)用函數(shù)調(diào)用。具體而言,與僅生成兩個(gè)新分支的普通條件跳轉(zhuǎn)指令不同,EOSIO中的br_table將其元素為目標(biāo)指針的數(shù)組作為參數(shù)。結(jié)果,單個(gè)br_table可以導(dǎo)致n個(gè)新分支,其中n是數(shù)組的長(zhǎng)度。除了這些條件跳轉(zhuǎn)指令外,函數(shù)調(diào)用還強(qiáng)加了許多新分支來(lái)表示已發(fā)送所有可能的被調(diào)用者。顯然,如果存在深度調(diào)用堆棧,則分支的數(shù)量將成倍增加。不幸的是,在EOSIO合約中,多個(gè)深度調(diào)用堆棧的串聯(lián)是很常見(jiàn)的。因此,實(shí)際需要緩解此問(wèn)題,否則符號(hào)執(zhí)行解決方案將不適用。
為此,采用啟發(fā)式指導(dǎo)的剪枝方法(heuristic-guided pruning approach)來(lái)解決挑戰(zhàn)。一方面,依靠幾種常規(guī)的修剪策略來(lái)緩解分支和深層函數(shù)調(diào)用帶來(lái)的問(wèn)題。例如,操作觀察結(jié)果表明,根據(jù)場(chǎng)景確定的特定深度閾值下的路徑丟棄不會(huì)影響(幾乎)所有情況下結(jié)果的精度。具體來(lái)說(shuō)公開(kāi):1)一個(gè)名為call depth的選項(xiàng),它限制了調(diào)用堆棧的深度; 2)名為timeout的選項(xiàng),供用戶限制符號(hào)執(zhí)行的過(guò)程。
但是,一般緩解策略的有效性在實(shí)踐中是有限的。幸運(yùn)的是,執(zhí)行漏洞檢測(cè)時(shí),EOSIO中的此問(wèn)題可以得到進(jìn)一步(部分)解決,因?yàn)橹恍枰⒁庖资芄舻拇a片段的某些特定函數(shù)/結(jié)構(gòu)即可。例如,在檢測(cè)到虛假EOS和虛假收據(jù)漏洞時(shí),僅考慮apply和transfer函數(shù)。
Wasm的存儲(chǔ)區(qū)可以看作是未解釋字節(jié)的向量,這意味著用戶可以通過(guò)load和store以不同的值類型來(lái)解釋這些原始位。模擬內(nèi)存的傳統(tǒng)方法是使用線性數(shù)組,但是由于模擬了EOSIO智能合約的稀疏內(nèi)存布局,因此非常耗費(fèi)內(nèi)存。因此決定使用key-value映射來(lái)模擬內(nèi)存,其中鍵是用于指定地址范圍的元組,而值是要存儲(chǔ)的數(shù)據(jù):(lower-bound,upper-bound) → data。
但是,此策略可能導(dǎo)致內(nèi)存重疊(參見(jiàn)下圖)。如果使用映射而不進(jìn)行優(yōu)化,則可以直接存儲(chǔ)鍵(A + 2,A + 3),(A + 3,A + 4)和(A + 2,A + 4),而不會(huì)發(fā)生沖突。結(jié)果,如果使用鍵(A,A + 4)檢索數(shù)據(jù),則存在兩種滿足條件的情況(下圖中的情況1和2),這可能導(dǎo)致檢索錯(cuò)誤的數(shù)據(jù)。此外,在情況3中,如果要更新(A + 1,A + 3)中的數(shù)據(jù),則必須遍歷鍵空間以確定是否只有一個(gè)實(shí)體包含提供的地址范圍,必須保證確保數(shù)據(jù)一致性。在情況4中,必須串聯(lián)相鄰的存儲(chǔ)數(shù)據(jù)塊,以確定如何將數(shù)據(jù)加載到存儲(chǔ)區(qū)中。簡(jiǎn)而言之,所有這些問(wèn)題都是由于內(nèi)存重疊和映射策略不正確造成的。
本文提出了一種內(nèi)存合并方法,通過(guò)合并分配的內(nèi)存來(lái)解決此問(wèn)題。如前所述,Wasm提供了20多個(gè)與內(nèi)存訪問(wèn)相關(guān)的指令。將首先為遇到的所有與存儲(chǔ)相關(guān)的指令創(chuàng)建鍵-值映射,其中值是按位存儲(chǔ)的數(shù)據(jù)。之后,可以根據(jù)所提出的內(nèi)存合并算法處理兩個(gè)鍵的范圍相鄰或重疊的情況,該算法將更新相應(yīng)的數(shù)據(jù)塊以保證執(zhí)行的準(zhǔn)確性。簡(jiǎn)而言之,盡力確保任意兩個(gè)任意鍵之間的間隔至少為一位。通過(guò)這樣做可以成功克服上圖中提出的挑戰(zhàn)。
為了促進(jìn)智能合約的開(kāi)發(fā),EOSIO允許將外部函數(shù)作為庫(kù)導(dǎo)入,這意味著這些導(dǎo)入函數(shù)的主體將不會(huì)編譯為Wasm字節(jié)碼。 EOSIO官方為DApp開(kāi)發(fā)人員提供了大量諸如系統(tǒng)庫(kù)之類的函數(shù)。它們已在許多(如果不是大多數(shù))智能合約中得到廣泛使用。結(jié)果,由于缺少那些導(dǎo)入的函數(shù)調(diào)用的主體,因此分析將被錯(cuò)誤地終止。
為了解決依賴關(guān)系,提出了一種按需且語(yǔ)義感知的方法來(lái)模擬導(dǎo)入的函數(shù)。 僅關(guān)注其功能和副作用與本文的分析有關(guān)的功能。 必須正確模擬這些函數(shù),以保證最終結(jié)果的正確性。 模擬的強(qiáng)度和覆蓋范圍取決于執(zhí)行分析的需要。 對(duì)于某些函數(shù),必須涵蓋參數(shù),返回值和副作用。 例如,與內(nèi)存有關(guān)的函數(shù)memmov,在其中必須考慮其對(duì)符號(hào)內(nèi)存的所有副作用。 對(duì)于其他一些可能只需要考慮可能的副作用。 例如,對(duì)于那些沒(méi)有返回值且對(duì)漏洞檢測(cè)沒(méi)有影響的與表相關(guān)的函數(shù),例如db_store_i64,可以平衡堆棧而無(wú)需模擬其行為。
下圖描繪了EOSAFE的總體架構(gòu),該架構(gòu)以EOSIO智能合約的Wasm字節(jié)碼作為輸入,并最終確定該字節(jié)碼是否易受攻擊。具體來(lái)說(shuō),EOSAFE基于Octopus(用于Wasm模塊的安全分析框架)來(lái)啟動(dòng)預(yù)處理。每個(gè)智能合約將被發(fā)送到Octopus,以使用反匯編的Wasm指令構(gòu)建其相應(yīng)的控制流圖(CFG)。
EOSAFE主要由三個(gè)模塊組成,即Wasm符號(hào)執(zhí)行引擎(簡(jiǎn)稱Engine),EOSIO 庫(kù)模擬器(簡(jiǎn)稱Emulator)和漏洞掃描程序(Scanner)。如上圖所示,將預(yù)處理后的輸入(CFG)輸入到Scanner,以使用Engine和Emulator通過(guò)兩步過(guò)程(定位可疑函數(shù)和檢測(cè)漏洞)執(zhí)行漏洞檢測(cè)。具體來(lái)說(shuō),Engine會(huì)相應(yīng)地執(zhí)行符號(hào)執(zhí)行以及路徑約束,Scanner將使用路徑約束來(lái)執(zhí)行漏洞檢測(cè)。此外,當(dāng)Engine遇到對(duì)導(dǎo)入函數(shù)的調(diào)用時(shí),Engine會(huì)請(qǐng)求Emulator實(shí)現(xiàn)建模的行為。
該引擎被設(shè)計(jì)為通用框架,可在基于堆棧的EOS VM上模擬智能合約的執(zhí)行。它接受CFG和反匯編的Wasm指令作為輸入,并象征性地在基本塊內(nèi)執(zhí)行指令,以獲取所有可行的路徑。在此過(guò)程中,會(huì)相應(yīng)地生成路徑約束。具體來(lái)說(shuō),該模塊必須維護(hù)兩個(gè)關(guān)鍵組件:路徑樹(shù)和狀態(tài)。對(duì)于路徑樹(shù),不僅記錄由符號(hào)執(zhí)行產(chǎn)生的約束,而且記錄沿路徑導(dǎo)入的函數(shù)的所有參數(shù)和返回值,這有助于分析漏洞檢測(cè)。關(guān)于狀態(tài),維護(hù)一些必要的狀態(tài)相關(guān)信息,包括局部/全局變量,線性存儲(chǔ)器,堆棧以及后續(xù)指令及其相應(yīng)的程序計(jì)數(shù)器。
本研究提供了兩個(gè)選項(xiàng),包括call depth和time-out,供用戶通過(guò)犧牲準(zhǔn)確性來(lái)緩解此問(wèn)題。一方面,選項(xiàng)call depth用于限制調(diào)用堆棧的深度,以防止分析陷入處理復(fù)雜分支或深度函數(shù)調(diào)用的麻煩。眾所周知,單個(gè)函數(shù)可能具有與該函數(shù)內(nèi)可行路徑相對(duì)應(yīng)的幾組約束,這可能導(dǎo)致路徑數(shù)量呈指數(shù)增長(zhǎng)。因此,限制了調(diào)用堆棧的深度以提高覆蓋范圍。另一方面,遇到一些非常耗時(shí)的情況時(shí)可能仍然會(huì)遇到麻煩。為了保證整個(gè)系統(tǒng)的進(jìn)度,引擎提供了另一個(gè)名為time-out的選項(xiàng),以控制路徑級(jí)分析的最大執(zhí)行時(shí)間。當(dāng)然,超時(shí)結(jié)果將被記錄以供進(jìn)一步調(diào)查。請(qǐng)注意,路徑爆炸問(wèn)題將在漏洞掃描器中進(jìn)一步解決,因?yàn)橹恍枰⒁庖资芄舻拇a片段的某些特定函數(shù)即可。
本文實(shí)現(xiàn)了一個(gè)符號(hào)存儲(chǔ)器來(lái)表示W(wǎng)asm的存儲(chǔ)器,并且還提出了一種存儲(chǔ)器合并算法來(lái)模擬存儲(chǔ)指令。該算法將符號(hào)存儲(chǔ)器,地址,字節(jié)數(shù)據(jù)長(zhǎng)度和數(shù)據(jù)作為輸入,最后返回合并的符號(hào)存儲(chǔ)器,而沒(méi)有重疊/相鄰的鍵作為輸出。具體來(lái)說(shuō),給定要存儲(chǔ)的新鍵,將檢查現(xiàn)有密鑰的地址范圍是否與新密鑰的地址范圍重疊。如果是這樣,將直接執(zhí)行插入操作;否則,它將相應(yīng)地更新重疊的部分并連接不重疊的部分。此外,按鍵以起始位置的升序排列。如果兩個(gè)相鄰的鍵不重疊,它們將合并在一起以形成一個(gè)新的鍵值對(duì)。例如,現(xiàn)有的鍵值對(duì)是:symbolic memory := {(0,2) → a0|a1,(3,4) → a3}。當(dāng)(2,4)→a2 | a’3到達(dá)時(shí),它將更新重疊的部分并在必要時(shí)將不重疊的部分連接起來(lái):symbolic memory := {(0,2) → a‘|a1,(2,4) → a2|a’3}。之后,它將合并相鄰的鍵:symbolic memory := {(0,4) → a0|a1|a2|a‘3}。簡(jiǎn)而言之,該算法通過(guò)強(qiáng)制所有有效地址在鍵空間中僅出現(xiàn)一次來(lái)保證數(shù)據(jù)的一致性。
使用按需和語(yǔ)義感知的方法來(lái)解決EOSIO庫(kù)依賴關(guān)系。已經(jīng)手動(dòng)分析了排名前100位的流行DApp的智能合約和現(xiàn)有已知的易受攻擊的智能合約,以從Function部分提取所有導(dǎo)入的函數(shù)。然后,根據(jù)其主要函數(shù)(如下表所示)將所有導(dǎo)入的函數(shù)分為五類進(jìn)行模擬。最后,可以從模擬的導(dǎo)入函數(shù)中檢索副作用。
區(qū)塊鏈狀態(tài)函數(shù):這些函數(shù)返回與區(qū)塊鏈系統(tǒng)相關(guān)的常量,這些常量通常由智能合約用作種子以生成偽隨機(jī)數(shù)。由于它們不會(huì)帶來(lái)任何副作用,因此只是通過(guò)直接返回一個(gè)代表區(qū)塊鏈狀態(tài)的符號(hào)值來(lái)模擬它們。
與內(nèi)存相關(guān)的函數(shù):顧名思義,此類函數(shù)與已實(shí)現(xiàn)的符號(hào)內(nèi)存有關(guān)。因此,將這些行為作為其初始進(jìn)行模擬,并在插入新數(shù)據(jù)時(shí)應(yīng)用內(nèi)存合并算法。由于約束解決,為未定義的行為(例如memcpy函數(shù)的負(fù)長(zhǎng)度)拋出了異常。
控制流相關(guān)函數(shù):這些函數(shù)是可以根據(jù)其返回結(jié)果更改或終止智能合約的控制流的函數(shù)。因此如有必要,將分叉兩條路徑。例如,如果eosio_assert函數(shù)的謂詞是符號(hào)值而不是特定的布爾值,則將生成兩條路徑。
與授權(quán)相關(guān)的函數(shù):由于權(quán)限系統(tǒng)僅與缺少權(quán)限檢查漏洞的檢測(cè)有關(guān),因此只需要檢查這些函數(shù)的存在,而無(wú)需考慮特定的權(quán)限。因此,只返回一個(gè)符號(hào)值來(lái)平衡堆棧。
與表相關(guān)的函數(shù):?EOSIO中有一個(gè)特殊的數(shù)據(jù)結(jié)構(gòu),可以持久存儲(chǔ)數(shù)據(jù)。與以太坊中的存儲(chǔ)概念類似,此類數(shù)據(jù)保存在稱為表的區(qū)塊鏈中。通過(guò)一些特定于平臺(tái)的指令,可以將Table視為支持CRUD操作(即,創(chuàng)建,檢索,更新和刪除)的數(shù)據(jù)庫(kù)。對(duì)于這些函數(shù)只需要關(guān)注內(nèi)存的副作用,而不是內(nèi)部操作。具體來(lái)說(shuō),使用用于更新內(nèi)存的返回值實(shí)現(xiàn)了它們,如下所示:
請(qǐng)注意,對(duì)于沒(méi)有任何返回值但修改表內(nèi)容的函數(shù)(例如db_update_i64),將其函數(shù)名稱和參數(shù)記錄在約束中。
為了檢測(cè)多個(gè)漏洞,Scanner被設(shè)計(jì)為執(zhí)行檢測(cè)的通用框架。它主要包括兩個(gè)步驟,即查找可疑函數(shù)和檢測(cè)漏洞。
只需要關(guān)注有價(jià)值的函數(shù),這些函數(shù)可以調(diào)用具有更改鏈上狀態(tài)的外部函數(shù),包括send_inline,db_update_i64和db_store_i64。根據(jù)觀察,在大多數(shù)情況下,這些有價(jià)值的函數(shù)可以試探性地視為目標(biāo)函數(shù),從而可以顯著減少分析時(shí)間。結(jié)果,借助CFG和路徑樹(shù)(由約束和有價(jià)值的函數(shù)組成),可以高效、準(zhǔn)確地識(shí)別漏洞。具體來(lái)說(shuō),定義以下公式:
這里conX表示給定函數(shù)的約束,其中X是要分析的函數(shù)的名稱。僅當(dāng)conX滿足三個(gè)條件中的至少一個(gè)條件時(shí),X才是有價(jià)值的函數(shù)。
結(jié)果,檢測(cè)框架的兩個(gè)步驟可以進(jìn)一步轉(zhuǎn)移并簡(jiǎn)化為以有價(jià)值的函數(shù)為中心的過(guò)程:1)定位有價(jià)值的函數(shù); 2)驗(yàn)證其可發(fā)起攻擊的能力。請(qǐng)注意,該過(guò)程的第二步是可選的,因?yàn)樵谀承┣闆r下始終可以保證可達(dá)性?;诖丝蚣?,將介紹四個(gè)掃描器的詳細(xì)信息。
如前文所述,虛假EOS漏洞只能通過(guò)調(diào)用傳遞函數(shù)來(lái)觸發(fā),該傳遞函數(shù)成為可以導(dǎo)致財(cái)務(wù)損失的有價(jià)值的函數(shù),它滿足以下條件:
而且,攻擊者必須能夠從條目(即apply函數(shù))訪問(wèn)transfer函數(shù),這意味著在pply函數(shù)中沒(méi)有適當(dāng)?shù)腸ode驗(yàn)證。具體地說(shuō),掃描器遍歷通過(guò)象征性地執(zhí)行apply函數(shù)生成的所有可行路徑,以檢查當(dāng)前路徑的約束條件是否符合以下條件:
具體來(lái)說(shuō),它限制了只能分析與transfer函數(shù)關(guān)聯(lián)的路徑。為了加速分析,引擎將提前終止不相關(guān)的路徑(如果目的地不是transfer),以避免進(jìn)一步執(zhí)行。然后,掃描器將檢查code值。因此,滿足與code相關(guān)的任何條件都意味著存在不正確的驗(yàn)證。綜上所述,滿足以上條件的智能合約被認(rèn)為是易受攻擊的。
此漏洞是由于transfer函數(shù)內(nèi)部的驗(yàn)證不足所致。但是,相應(yīng)的send_inline函數(shù)非常深,這總是導(dǎo)致調(diào)用深度溢出來(lái)破壞引擎。因此,直接通過(guò)符號(hào)執(zhí)行從條目(即apply函數(shù))中定位有價(jià)值的函數(shù)(即transfer函數(shù))是不可行的。
為了解決該問(wèn)題,改為采用基于啟發(fā)式的方法。具體而言,掃描器首先識(shí)別apply函數(shù),然后枚舉所有相關(guān)的基本塊以驗(yàn)證其跳轉(zhuǎn)目標(biāo)的索引可能指向可疑的transfer函數(shù)。找到可疑的transfer函數(shù)后,掃描器將根據(jù)1到3的標(biāo)準(zhǔn)來(lái)確定有價(jià)值的transfer函數(shù)。請(qǐng)注意,對(duì)于給定的智能合約,應(yīng)確切地存在一個(gè)transfer函數(shù),這意味著transfer函數(shù)是可疑函數(shù)之一,或內(nèi)聯(lián)在apply函數(shù)中,如下所示:
對(duì)于以上兩種情況中的任何一種,將進(jìn)一步檢查以下保護(hù)的存在:
滿足以上條件的智能合約被視為容易受到偽虛假收據(jù)漏洞的攻擊。此外,該掃描器還采用盡早終止的方法來(lái)加速整個(gè)過(guò)程。具體來(lái)說(shuō),對(duì)于有價(jià)值的transfer,應(yīng)在更新有關(guān)鏈上狀態(tài)的更改之前驗(yàn)證保護(hù)。因此,在遇到三個(gè)標(biāo)準(zhǔn)中的任何一個(gè)而沒(méi)有沿途保護(hù)的情況下終止分析是合理的。
reveal函數(shù)通常會(huì)生成隨機(jī)數(shù)來(lái)確定頭獎(jiǎng)中獎(jiǎng)?wù)撸⑼ㄟ^(guò)內(nèi)聯(lián)動(dòng)作調(diào)用eosio.token中的傳遞函數(shù)以返還獎(jiǎng)品。因此,根據(jù)標(biāo)準(zhǔn)1,reveal函數(shù)成為有價(jià)值的函數(shù)。但是,在某些情況下,處理reveal函數(shù)時(shí)必須考慮計(jì)算負(fù)擔(dān),即send_inline函數(shù)的調(diào)用深度對(duì)于引擎來(lái)說(shuō)太深了。
幸運(yùn)的是,由于沒(méi)有必要考慮任何目標(biāo)游戲DApp的路徑中send_inline函數(shù)的可達(dá)性,因此能夠應(yīng)用兩種策略來(lái)加快定位reveal函數(shù)的過(guò)程。具體而言,第一種策略是按需遍歷可行的路徑。除了枚舉所有路徑外,僅檢查可用于解析目標(biāo)send_inline函數(shù)的數(shù)據(jù)/變量依賴關(guān)系的路徑。另一方面,第二種策略在提取有價(jià)值的函數(shù)后減小了引擎正在檢查的路徑集的大小,即刪除了基本路徑完全是其他路徑的子集的冗余路徑。因此,可以獲得最小的路徑集,以覆蓋盡可能多的基本塊。
最后,檢測(cè)邏輯與兩個(gè)屬性相關(guān)聯(lián)。首先,研究表明,reveal函數(shù)將使用rem指令沿構(gòu)造的路徑集中的路徑生成隨機(jī)數(shù)。其次,如果模運(yùn)算的操作數(shù)(部分)是由區(qū)塊鏈狀態(tài)函數(shù)生成的,則智能合約將受回滾漏洞的影響??傊?,檢測(cè)邏輯必須滿足:
這里operand2始終是與區(qū)塊鏈狀態(tài)無(wú)關(guān)的常量或變量。如果滿足上述條件,可以確認(rèn)該合約容易受到回滾漏洞的影響。請(qǐng)注意,將刪除EOSIO官方庫(kù)(例如eoslib)生成的所有rem指令,以減少誤報(bào)。
將重點(diǎn)放在那些在敏感操作之前是有價(jià)值的和缺乏權(quán)威驗(yàn)證的函數(shù)上。同樣,這些函數(shù)應(yīng)該可以通過(guò)apply函數(shù)實(shí)現(xiàn)。根據(jù)1到3的標(biāo)準(zhǔn)對(duì)所有有價(jià)值的函數(shù)進(jìn)行過(guò)濾后,將檢查約束條件是否符合以下條件:
具體而言,第一個(gè)條件首先要求該函數(shù)(由func標(biāo)識(shí))是攻擊者可以通過(guò)apply函數(shù)實(shí)現(xiàn)的。然后,第二個(gè)條件意味著可以直接觸發(fā)函數(shù)。最后,第三個(gè)條件檢查函數(shù)是否缺乏權(quán)限驗(yàn)證。如果滿足上述條件,則智能合約容易受到缺少權(quán)限檢查漏洞的影響。
實(shí)現(xiàn):利用Octopus構(gòu)建Wasm字節(jié)碼的CFG,并使用Z3定理證明(版本4.8.6)作為約束求解器。所有其他主要組件,包括Wasm符號(hào)執(zhí)行引擎,庫(kù)模擬器和漏洞掃描程序,均由自己設(shè)計(jì)和實(shí)現(xiàn)。該實(shí)現(xiàn)基于Python,其中包括超過(guò)5.5k行代碼。
實(shí)驗(yàn)設(shè)置:實(shí)驗(yàn)是在運(yùn)行Debian的服務(wù)器上執(zhí)行的,該服務(wù)器具有2.10GHz @ 64G RAM的四個(gè)Intel?Xeon?E5-2620 v4。Wasm引擎提供了兩個(gè)配置選項(xiàng)(即調(diào)用深度和超時(shí))來(lái)部分解決路徑爆炸問(wèn)題。在實(shí)驗(yàn)過(guò)程中,根據(jù)經(jīng)驗(yàn)將調(diào)用深度設(shè)置為2層,它足以識(shí)別大多數(shù)漏洞。關(guān)于檢測(cè)時(shí)間,由于以下兩個(gè)主要原因,根據(jù)經(jīng)驗(yàn)將上限設(shè)置為5分鐘。首先,在5分鐘內(nèi),可以對(duì)基準(zhǔn)中的所有智能合約進(jìn)行全面分析并檢測(cè)出有希望的結(jié)果。其次,當(dāng)試圖將EOSAFE應(yīng)用于所有EOSIO智能合約時(shí),必須在準(zhǔn)確性和可擴(kuò)展性之間進(jìn)行權(quán)衡。因此,每個(gè)合約的檢測(cè)時(shí)間最多設(shè)置為5分鐘。請(qǐng)注意,所有這些設(shè)置都可以在工具中輕松配置和自定義,以滿足不同的要求。
研究問(wèn)題:本文評(píng)估以下三個(gè)研究問(wèn)題(RQ)
RQ1:?EOSAFE在檢測(cè)EOSIO智能合約的漏洞方面的準(zhǔn)確性如何?
RQ2:這些漏洞在生態(tài)系統(tǒng)中是否普遍存在?
RQ3:攻擊者利用了多少智能合約,這些攻擊的影響是什么?
為了回答RQ1,在研究社區(qū)中沒(méi)有建立基準(zhǔn)的情況下,本文收集實(shí)際攻擊并手動(dòng)檢查受害智能合約以制定可靠的基準(zhǔn)。為了回答RQ2,收集了EOSIO上所有可用的智能合約及其歷史版本。然后,應(yīng)用EOSAFE來(lái)檢測(cè)安全漏洞的存在,并描述漏洞的演變。為了回答RQ3,進(jìn)一步收集與已標(biāo)記的易受攻擊合約相關(guān)的所有鏈上交易,然后提出啟發(fā)式方法以查明可能的攻擊。
基準(zhǔn):為了評(píng)估EOSAFE,首先努力制定一個(gè)基準(zhǔn),并將其提供給社區(qū)。不時(shí)報(bào)告EOSIO攻擊。因此訴諸于知名區(qū)塊鏈安全公司發(fā)布的安全報(bào)告,以收集所有相關(guān)的公開(kāi)驗(yàn)證的攻擊作為數(shù)據(jù)。已經(jīng)收集了38次攻擊,針對(duì)總共34個(gè)不同的易受攻擊智能合約。盡管這些攻擊已由相應(yīng)DApp的官方團(tuán)隊(duì)確認(rèn),但發(fā)現(xiàn)某些攻擊與智能合約本身無(wú)關(guān),但與其他外部因素有關(guān),例如服務(wù)器的問(wèn)題。因此,進(jìn)一步手動(dòng)檢查了所有涉及的智能合約。具體來(lái)說(shuō),發(fā)現(xiàn)10種虛假EOS攻擊中有3種與服務(wù)器問(wèn)題有關(guān)。對(duì)于回滾,21種攻擊中有11種是由于服務(wù)器的錯(cuò)誤顯示策略所致。此外,其中兩個(gè)是回滾的變體,它們與EOS MainNet上某些節(jié)點(diǎn)的配置有關(guān)。最后,將上述所有合約從基準(zhǔn)中排除,以確保所有攻擊均來(lái)自智能合約本身中的代碼。
基準(zhǔn)的分布顯示在上表中,還收集了相應(yīng)的修補(bǔ)智能合約(無(wú)漏洞)作為評(píng)估EOSAFE有效性的比較。此外,據(jù)報(bào)告,僅有兩個(gè)與缺少權(quán)限檢查漏洞有關(guān)的易受攻擊的智能合約,并且尚未對(duì)其進(jìn)行修補(bǔ)。因此,進(jìn)一步手動(dòng)創(chuàng)建了4對(duì)智能合約(有和沒(méi)有缺少權(quán)限檢查漏洞)以補(bǔ)充基準(zhǔn)。最終總共將52個(gè)智能合約標(biāo)記為基準(zhǔn)。
結(jié)果:在52份智能合約中,EOSAFE將26份標(biāo)記為易受攻擊,只有一個(gè)漏報(bào)性案例(屬于回滾),沒(méi)有誤報(bào)性,導(dǎo)致準(zhǔn)確率和召回率分別為100%和96.97%。上表顯示了詳細(xì)的結(jié)果。對(duì)于回滾的唯一錯(cuò)誤否定情況,即fair-dogegame / betdogewallt,根本原因是可疑的揭示數(shù)量過(guò)多,無(wú)法建立路徑,并且在給定的超時(shí)時(shí)間(此處為5分鐘)內(nèi)象征性地執(zhí)行了它們。手動(dòng)定位易受攻擊的函數(shù)(即func73)后,可以獲得正確的結(jié)果。因此,優(yōu)化策略引入了漏報(bào)性,這是準(zhǔn)確性和可伸縮性之間的折衷。例如,通過(guò)探索更多路徑并增加分析時(shí)間,很容易調(diào)整本文的方法以涵蓋該方法。盡管如此,由于大多數(shù)智能合約并不太復(fù)雜,因此在實(shí)驗(yàn)過(guò)程中很少見(jiàn)到這種例外情況。
數(shù)據(jù)集:考慮了從2018年6月9日(EOS MainNet的最開(kāi)始)到2019年11月15日的所有53,666份智能合約(包括歷史版本)。請(qǐng)注意,與以太坊智能合約一旦部署便無(wú)法修改的不同,EOSIO合約可以按照前文中的說(shuō)明更新并綁定相同的帳戶。因此使用EOSIO帳戶來(lái)標(biāo)記每個(gè)唯一的智能合約,即一個(gè)帳戶可能對(duì)應(yīng)于多個(gè)合約版本。結(jié)果有53,666個(gè)不同版本的合約,它們屬于5,574個(gè)EOSIO帳戶。由于回滾漏洞僅與游戲DApp有關(guān),因此可以在此處縮小候選列表。使用DAppTotal-一種可靠的多平臺(tái)DApp瀏覽器來(lái)標(biāo)記游戲DApp,并使用此類合約(17,394)進(jìn)行回滾漏洞檢測(cè)。對(duì)于其他三種漏洞,將掃描器應(yīng)用于所有53,666個(gè)合約(請(qǐng)參見(jiàn)下表)。
上表顯示了總體結(jié)果。令人驚訝的是,在53,666個(gè)智能合約中,有25%以上是易受攻擊的(請(qǐng)參閱第3列)。缺少權(quán)限檢查漏洞是最普遍的漏洞,影響了超過(guò)15%的智能合約。偽造的收據(jù)漏洞也很普遍(13%)。對(duì)于回滾漏洞,盡管僅分析了游戲DApp的17,000個(gè)智能合約,但其中有1000多個(gè)易受攻擊。偽造的EOS漏洞影響大約2.7%的智能合約。這表明EOSIO智能合約生態(tài)系統(tǒng)中普遍存在安全漏洞,這表明識(shí)別和防止此類漏洞的緊迫性。
存在漏洞的唯一智能合約:由于一個(gè)智能合約可能對(duì)應(yīng)多個(gè)版本,因此從唯一合約(帳戶)的角度進(jìn)一步描述漏洞的分布。如上表的第5列所示,對(duì)于5,574個(gè)唯一合約,大約有一半具有至少一個(gè)易受攻擊的版本。 10%的唯一智能合約占易受攻擊版本的61.24%,這表明大多數(shù)易受攻擊的版本是由一小部分智能合約導(dǎo)入的。此外,有1,793個(gè)唯一智能合約,它們的版本都容易受到攻擊(其中41%的版本至少具有兩個(gè)版本)。合同eossanguoone是一種流行的游戲DApp,具有最多易受攻擊的版本(356個(gè)版本)。通過(guò)手動(dòng)檢查,發(fā)現(xiàn)2019年9月4日之前發(fā)布的所有版本都遭受了虛假收據(jù)漏洞,然后該漏洞由開(kāi)發(fā)人員修補(bǔ)。自2019年8月以來(lái),已發(fā)現(xiàn)缺少權(quán)限檢查漏洞,這可能是由于未經(jīng)授權(quán)就導(dǎo)入了新函數(shù)所致。
當(dāng)分析了不同版本的漏洞的演變時(shí),因此有必要進(jìn)一步研究修復(fù)每個(gè)唯一智能合約的漏洞的時(shí)間,這些時(shí)間可用于衡量攻擊者利用這些漏洞的窗口期。
結(jié)果:如上表所示,截至本研究,對(duì)于具有漏洞版本的2759個(gè)唯一智能合約,其中超過(guò)75%的最新版本仍至少存在一個(gè)安全漏洞。 679個(gè)唯一的智能合約在其演變過(guò)程中修補(bǔ)了所有漏洞,平均窗口期為16.84天。
補(bǔ)丁率:進(jìn)一步分析漏洞的補(bǔ)丁率。回滾漏洞的補(bǔ)丁程序率最高(超過(guò)66%),平均窗口期約為4天。其及時(shí)響應(yīng)的原因可能是回滾漏洞僅存在于游戲DApp中,這些DApp通常在其帳戶中具有較高的余額。如果開(kāi)發(fā)人員不理會(huì)該漏洞,則財(cái)務(wù)損失可能是災(zāi)難性的。對(duì)于缺少的權(quán)限檢查,有349個(gè)智能合約對(duì)其所有缺少的檢查操作進(jìn)行了修補(bǔ)。請(qǐng)注意,在此處測(cè)量了操作級(jí)別的平均補(bǔ)丁時(shí)間,因?yàn)橐粋€(gè)易受攻擊的合約可能有多個(gè)缺少權(quán)限檢查操作??偣灿?47個(gè)補(bǔ)丁操作,其中大約500個(gè)補(bǔ)丁補(bǔ)丁在一天之內(nèi)被修復(fù),而總補(bǔ)丁時(shí)間為4.38天。這表明大多數(shù)丟失的權(quán)限檢查操作都會(huì)得到及時(shí)修補(bǔ),而少數(shù)合約則需要相對(duì)較長(zhǎng)的時(shí)間才能解決。相反,虛假EOS和虛假收據(jù)漏洞具有最低的補(bǔ)丁率(即大約20%),并且補(bǔ)丁時(shí)間相對(duì)較長(zhǎng)(即平均2到3周)。手動(dòng)檢查發(fā)現(xiàn),與虛假收據(jù)相關(guān)的智能合約中有一半是在24小時(shí)內(nèi)修補(bǔ)的,這進(jìn)一步表明一些不活躍的智能合約拖延了平均修補(bǔ)時(shí)間。大多數(shù)不活動(dòng)的智能合約(帳戶)沒(méi)有余額,交易很少,通常不是攻擊者的目標(biāo)。
探索攻擊者成功利用了多少個(gè)易受攻擊的智能合約并不是一件容易的事。直到最近,安全研究人員仍需要大量臨時(shí)工作(通常是手動(dòng)工作)來(lái)進(jìn)行驗(yàn)證。因此,在存在易受攻擊的智能合約的情況下,首先收集其所有相關(guān)的鏈上交易,然后設(shè)計(jì)一套啟發(fā)式方法來(lái)定位可疑攻擊,這將用于促進(jìn)進(jìn)一步的手動(dòng)驗(yàn)證以確定實(shí)際攻擊??傆?jì),已經(jīng)收集了超過(guò)25億筆交易記錄。
虛假EOS攻擊:此攻擊的最重要行為是通過(guò)使用偽造的EOS token從易受攻擊的智能合約中欺騙官方EOS token,可以通過(guò)存儲(chǔ)token發(fā)行者信息的交易記錄來(lái)識(shí)別這些偽造的EOS token。根據(jù)觀察,將首先過(guò)濾掉所有token符號(hào)為“ EOS”的token轉(zhuǎn)移交易。然后,將根據(jù)以下定義對(duì)這些交易進(jìn)行分組:
?發(fā)送偽造的EOS token的偽造交易;
?發(fā)送真實(shí)EOS token的真實(shí)發(fā)送交易;
?接收真實(shí)EOS token的真實(shí)接收交易。
結(jié)果,可以將潛在的攻擊定義為假冒發(fā)送交易之后是真實(shí)接收交易的序列。請(qǐng)注意,假冒發(fā)送交易A可以與真實(shí)接收交易B合并,前提是且僅當(dāng)它們出現(xiàn)在同一時(shí)期,而A發(fā)生在B之前。對(duì)于所有這些潛在交易,主要關(guān)注那些獲得了更多收益的交易。真正的EOS代幣所花費(fèi)的金額為此,進(jìn)一步檢查了攻擊者與易受攻擊的合約之間的投入產(chǎn)出比,以確定可疑的攻擊。最后,基于可疑攻擊,將在收到偽造的EOS令牌后驗(yàn)證易受攻擊的智能合約是否將恢復(fù)正常執(zhí)行(例如,為真實(shí)玩家開(kāi)獎(jiǎng))。如果是這樣,會(huì)將可疑交易標(biāo)記為偽造的EOS攻擊。
虛假收據(jù)攻擊:攻擊的主要特征是易受攻擊的智能合約被虛假通知誤導(dǎo)以接收token,而實(shí)際的token轉(zhuǎn)移發(fā)生在屬于同一攻擊者的兩個(gè)帳戶之間。為簡(jiǎn)單起見(jiàn),下面將使用from_account和to_account表示這兩個(gè)帳戶,其中to_account將偽造的收據(jù)發(fā)送給易受攻擊的合約,而from_account是最終的受益人。
因此,將首先查詢其token由eosio.token發(fā)行且token符號(hào)為“ EOS”的所有token轉(zhuǎn)移交易,以獲取所有真實(shí)的EOS token轉(zhuǎn)讓。然后,將篩選出既不是eosio.token也不是from_account或to_account的接收者的交易。這些交易將被視為帶有虛假通知的偽造收據(jù)。接下來(lái),如果from_account在從易受攻擊的合約獲利之前發(fā)送了虛假收據(jù),會(huì)將相應(yīng)的交易標(biāo)記為潛在交易。之后,通過(guò)消除無(wú)關(guān)的EOS支出交易(例如,出于攻擊者發(fā)起的測(cè)試目的),主要關(guān)注那些獲得了比其花費(fèi)更多的真實(shí)EOS代幣的人。如果投入產(chǎn)出比仍然很高,則將相應(yīng)的交易標(biāo)記為可疑。最后將手動(dòng)檢查可疑交易,在收到虛假收據(jù)后,易受攻擊的智能合約是否將恢復(fù)正常執(zhí)行。如果是這樣,會(huì)將此類交易標(biāo)記為偽造的收據(jù)攻擊。
回滾攻擊:此攻擊的事務(wù)由動(dòng)作的順序調(diào)用組成,可以用作識(shí)別攻擊的模式。具體來(lái)說(shuō),將首先篩選出至少包含四個(gè)動(dòng)作作為潛在交易的所有交易。接下來(lái),將選擇可滿足以下四個(gè)條件的可疑交易:(1)必須在同一合約中調(diào)用第一個(gè)和最后一個(gè)動(dòng)作,第一個(gè)動(dòng)作是發(fā)起攻擊的手段,最后一個(gè)動(dòng)作將決定是否發(fā)起攻擊。從易受攻擊的智能合約中獲得獎(jiǎng)勵(lì)后,必須進(jìn)行回滾。 (2)中間的兩個(gè)動(dòng)作必須是通過(guò)eosio.token進(jìn)行的token轉(zhuǎn)移,兩個(gè)動(dòng)作的發(fā)送者和接收者(必須是易受攻擊的智能合約)彼此相對(duì)。 (3)交易方中的至少一個(gè),即發(fā)送者或接收者,被標(biāo)記為游戲DApp。 (4)從易受攻擊的智能合約轉(zhuǎn)移的代幣數(shù)量超過(guò)其收到的數(shù)量。此外,值得注意的是,回滾的事務(wù)將不會(huì)記錄在鏈上。因此,必須手動(dòng)檢查玩家每單位時(shí)間的成功率,即如果該成功率比其他人高,會(huì)將可疑交易標(biāo)記為回滾攻擊。
缺少權(quán)限檢查攻擊:由于授權(quán)信息與調(diào)用的事務(wù)一起存在,因此可以檢查它是否屬于被調(diào)用方合約以識(shí)別此攻擊。更準(zhǔn)確地說(shuō),將首先篩選出所有目標(biāo)操作為易受攻擊操作的交易,以獲取可疑交易。然后,如果交易的權(quán)限不屬于該操作所屬的智能合約,會(huì)將其標(biāo)記為缺少權(quán)限檢查攻擊。
總體結(jié)果如上表所示??偣泊_定了48個(gè)攻擊,包括9個(gè)虛假EOS攻擊,27個(gè)虛假收據(jù)攻擊和12個(gè)回滾攻擊。此外,還確定了183個(gè)未執(zhí)行權(quán)限檢查的調(diào)用操作(屬于144個(gè)合約)。請(qǐng)注意,對(duì)于這些缺少權(quán)限檢查的操作,其中一些是有意設(shè)計(jì)的,而不是意外的實(shí)現(xiàn)。很難區(qū)分它們是否是攻擊,并且無(wú)法估計(jì)經(jīng)濟(jì)損失。因此將其視為濫用行為,而不是攻擊。
攻擊影響:識(shí)別出的48種攻擊導(dǎo)致EOS損失超過(guò)341K,按攻擊日期的收盤價(jià)計(jì)算,大約相當(dāng)于170萬(wàn)美元。請(qǐng)注意,已經(jīng)與一家領(lǐng)先的區(qū)塊鏈安全公司合作,向DApp開(kāi)發(fā)人員報(bào)告了這些攻擊,其中27起已得到確認(rèn),占總損失的99%以上。所有未確認(rèn)的可疑攻擊事件僅與少數(shù)EOS有關(guān),并且大多數(shù)不再活躍。上表列出了前5大已確認(rèn)的攻擊事件。
未被漏洞利用的合約:有趣的是,盡管成千上萬(wàn)個(gè)合約易受攻擊,但攻擊者僅成功利用了其中的幾個(gè)合約。手動(dòng)采樣了一些智能合約以進(jìn)行逆向工程并檢查其交易,發(fā)現(xiàn)主要原因有兩個(gè)。首先,流行的智能合約(具有高余額)是攻擊者的主要目標(biāo),但是這些易受攻擊的合約可以及時(shí)修補(bǔ),并且為攻擊者留出了很短的窗口期。根據(jù)交易發(fā)現(xiàn)攻擊者一直在嘗試?yán)昧餍械暮霞s,并且某些攻擊確實(shí)是成功的(請(qǐng)參見(jiàn)上表),而大多數(shù)攻擊都失敗了。第二,正如前文中提到的那樣,考慮到低利潤(rùn)和攻擊成本之間的折衷,大多數(shù)未打補(bǔ)丁的智能合約都是余額較低的非活動(dòng)智能合約,因此吸引了攻擊者較少的注意力。
首先,本文系統(tǒng)繼承了符號(hào)執(zhí)行的局限性,即路徑爆炸。盡管已經(jīng)實(shí)施了幾種優(yōu)化策略,但是EOSAFE仍然報(bào)告錯(cuò)誤否定情況。但是,這對(duì)于系統(tǒng)來(lái)說(shuō)不是一個(gè)大問(wèn)題。一方面,大多數(shù)智能合約不像其他軟件那樣復(fù)雜??梢栽诙虝r(shí)間內(nèi)全面分析大部分智能合約。另一方面,在搜索可以消除大多數(shù)不相關(guān)路徑的漏洞時(shí),提出了特定的優(yōu)化方法。盡管如此,可以利用先進(jìn)的符號(hào)執(zhí)行技術(shù)來(lái)緩解這一問(wèn)題。其次,依靠試探法和半自動(dòng)方法來(lái)驗(yàn)證攻擊。當(dāng)然,這可能無(wú)法擴(kuò)展,這意味著本文僅提供了較低級(jí)別的攻擊的檢測(cè)。但是,確定的大部分攻擊已由DApp團(tuán)隊(duì)確認(rèn),這表明本文方法相當(dāng)可靠。不過(guò),可以采用某些技術(shù)(例如動(dòng)態(tài)測(cè)試)來(lái)幫助本文工具自動(dòng)識(shí)別攻擊。在本文中主要貢獻(xiàn)是自動(dòng)檢測(cè)安全漏洞,而攻擊驗(yàn)證不是這項(xiàng)工作的主要重點(diǎn)。第三,可能存在一些當(dāng)前版本中未涵蓋的新漏洞,以及其他軟件系統(tǒng)中的常規(guī)漏洞,例如緩沖區(qū)溢出。在本文中僅關(guān)注EOSIO特定的漏洞,主要原因是缺乏其他安全漏洞的真實(shí)性。盡管如此,將本文系統(tǒng)擴(kuò)展為涵蓋其他漏洞很容易,因?yàn)榉?hào)執(zhí)行引擎和掃描程序框架是通用的。
本文是首個(gè)有關(guān)檢測(cè)EOSIO智能合約中的安全漏洞工作。在文中提出了EOSAFE,這是一個(gè)準(zhǔn)確且可擴(kuò)展的框架,該框架能夠檢測(cè)EOSIO特定的漏洞。實(shí)驗(yàn)結(jié)果表明,EOSAFE具有良好的性能。本研究的大規(guī)模評(píng)估研究進(jìn)一步揭示了生態(tài)系統(tǒng)中的嚴(yán)重安全問(wèn)題,即超過(guò)25%的智能合約易受攻擊,并且成功造成了許多著名攻擊事件。
來(lái)源:安全客