作者:天宸@螞蟻安全實驗室
原文鏈接:https://mp.weixin.qq.com/s/ZxrBHgZ5a_IuU0nNySIlwA

南方科技大學教授張殷乾:

智能合約是運行在區塊鏈的具備圖靈完備行的分布式應用程序,在以太坊、EOS等區塊鏈上有廣泛的應用。然而,隨著智能合約的普及和應用,針對智能合約的攻擊事件屢見不鮮。為了幫助人們更好地理解這些漏洞的原理,螞蟻安全實驗室“智能合約安全系列 -- 舉一反三總結篇”文章總結了以太坊和EOS區塊鏈上智能合約的一些已知攻擊的原理。

  • 文章首先介紹了智能合約基本概念,以及智能合約運行機制。它從隔離機制、停機機制、以及跨合約調用三部分出發,闡明了智能合約本身的工作原理以及安全機制。其次,文章按照漏洞在各個平臺上的通用性高低程度,對于已經發生的若干種漏洞進行分類總結。漏洞類型分為五類:1.基礎漏洞類型 2.函數接口漏洞類型 3.平臺特性漏洞類型 4.充值場景漏洞類型 5.經典攻擊手法區塊鏈上再現。

  • 由于智能合約漏洞常引發大規模的經濟損失,智能合約的漏洞得到了人們的廣泛關注,不少相關機構都已經提出類似的漏洞總結文章。螞蟻安全實驗室這篇文章從三個新角度帶給人們一些啟發性:(1)以太坊和EOS兩條區塊鏈上漏洞的共性和差異,(2)從平臺適用性角度對這些漏洞的分類總結,(3)針對充值場景漏洞類型的幾種分類。

螞蟻安全實驗室還發表了其他關于智能合約漏洞的文章總結,其中對于每一種漏洞的介紹更為具體詳細。感謝螞蟻安全實驗室為區塊鏈平臺做出的努力和貢獻,也由衷希望區塊鏈在這些安全機構的幫助上能更加安穩、蓬勃發展。

本文是智能合約安全分析系列的最后一篇文章。在智能合約安全系列 -- 運行平臺科普篇智能合約安全系列——百萬合約之母以太坊的漏洞攻防術(上集)智能合約安全系列——百萬合約之母以太坊的漏洞攻防術(下集)智能合約安全系列——EOS菠菜應用篇之后,本文希望對智能合約安全分析系列做一個總結。

1 引言

智能合約安全分析系列已接近尾聲了。本系列前幾篇文章著重分析了以太坊和 EOS 的智能合約漏洞。分析這兩個平臺一方面是因為這兩個平臺的漏洞數量多,損失重,另一方面是因為這兩個平臺是很多聯盟鏈的借鑒對象,比如摩根大通開發的 Quorum 聯盟鏈就是從以太坊演變而來,比如多個區塊鏈平臺都支持的回滾特性也是受這兩個平臺的影響。

分析這兩個平臺的合約漏洞對分析其他平臺的合約漏洞有借鑒意義。本文的主要目的是總結這些漏洞類型,舉一反三地看其他平臺的智能合約安全。

2 平臺安全機制總結

智能合約的運行離不開平臺支持。平臺本身也提供了一些安全機制,為智能合約的運行提供了有限的安全性。

2.1 隔離機制

圖靈完備的智能合約意味著可以編寫并執行任意的邏輯,包括惡意代碼。如果智能合約能直接在區塊鏈節點的宿主系統上運行,惡意代碼可以破壞宿主系統的自身數據。因此智能合約必須放在一個隔離的沙盒環境中運行。對于這個問題,每個智能合約的合約平臺都提供了虛擬機。

· 以太坊有 EVM

EVM 是內存隔離的。在每次消息調用開始,EVM 都要執行清除內存操作。EVM 虛擬機能夠保證不同的合約之間,內存是隔離的。

· EOS 有 EOS-VM

EOSVM 是內存安全的。EOSVM 設定合約運行環境為32位機器,但是EOSVM運行環境需為64位。也正是通過這個機制,可以高效地控制內存使用。首先,EOSVM使用mmap方法為合約映射一塊略大于4G大小的虛擬地址,作為合約可訪問的數據邊界。當合約內訪問某個地址的數據時,實際上是訪問基于該虛擬地址的偏移。因為合約的運行環境設定是32位,所以不存在越界訪問的問題。

2.2 停機機制

智能合約的執行是需要消耗資源的,在區塊鏈世界里,資源非常珍貴,不能任由智能合約無限執行,必須要讓合約在一定的條件下停下來,也就是要解決停機問題。停機問題(halting problem)是邏輯數學中可計算性理論的一個問題。通俗地說,停機問題就是判斷任意一個程序是否能在有限的時間之內結束運行的問題。

· 比特幣

比特幣提供的比特幣腳本執行機制只能算作智能合約模型,因為比特幣腳本的指令有限,且非圖靈完備。也得益于這些限制,尚未發現利用比特幣腳本實現的攻擊案例。因為比特幣腳本是非圖靈完備的,且沒有循環或者復雜流控制功能,不能創造無限循環或其它類型的邏輯炸彈,所以比特幣腳本是可停止的。

· 以太坊

以太坊提供了圖靈完備的智能合約執行機制,提供的 Solidity 語言和 EVM 能夠滿足開發者開發出復雜的業務邏輯。相應的,就會面臨停機問題。以太坊的應對方式是計價器方式,引入了 gas 機制,在以太坊中,每一個操作都需要消耗一定量的gas,如果gas消耗完了,程序就可以停止下來。以太坊在發起每筆交易時,都會預設一定量的gas limit,如果在執行過程中,gas被消耗完,合約就會停止執行。

· EOS

EOS 和以太坊一樣,也提供了圖靈完備的合約執行機制,但是 EOS 解決停機問題的方式跟以太坊不同。EOS 采用了計時器方式,EOS 利用控制執行時間來解決停機問題,即用戶須要預先抵押 EOS 換取 CPU 資源(以時間為單位,如300ms),在合約執行前在關鍵位置注入 checktime(),執行時不斷檢查時間,若已超出時間上限,則停止執行。

· 聯盟鏈

聯盟鏈有很多,如 fabric,quorum,mychain。聯盟鏈的停機問題更多的是靠約束參與者本身達成的。如 Fabric 使用 docker 虛擬機,可支持多種編程語言,但是 Fabric 沒有計價器也沒有計時器,更多的是依賴審核聯盟成員的身份來約束成員不作惡。Quorum 和 Mychain 都參考了以太坊的實現,盡管保留 gas 本身,但是刪除了以太坊中 gas 的定價,即 gasPrice = 0,轉賬時沒有礦工費。gas 也就不能作為停機的依據。這兩個鏈也是默認聯盟成員自身不作惡。

2.3 跨合約調用控制

跨合約調用必須是確定性的靜態調用——在運行前即知曉被調用合約的地址,且調用結果是確定性的。需要注意兩個方面:

2.3.1 上下文的切換

上下文切換常發生在跨合約調用中:合約A調用合約B時,上下文應是合約A還是變更為合約B。典型例子,在Solidity中,msg.sender和storage是上下文相關的,語言提供了call, delegateCall 來適應不同的上下文切換的需求。

在EOS中,跨合約調用的上下文永遠是被調用合約,由于調用action需要顯式指定調用者賬戶(類似solidity中的msg.sender),且storage與上下文分離,因此沒有以太坊那樣的問題,使用起來更加簡單。

2.3.2 權限控制

權限控制是跨合約調用中不可避免的問題,它關系到用戶的數據安全。我們來看下面這個例子:

Bob 調用合約 A 的 hi 方法,hi 中包含一個跨合約調用,形如 B.hello(),調用了合約 B 的 hello 方法。

那么問題來了:Bob 只是希望調用合約 A 的方法,而合約 A 是否有權利以 Bob 的賬戶調用合約 B?

EVM實際并沒有考慮權限的問題。開發者在編寫合約時可自行選擇 call, delegateCall 中任意一種方式調用其他合約。這么做似乎并沒有太大的影響,因為以太坊合約部署后任何人不能修改,也無法升級,只要用戶確認了代碼是符合要求的,那調用的后果就應由用戶自行負責。然而,合約開發者們還是擔心資產安全問題,主流的資產標準(如ERC20)都提供了授權的接口,即只有被授權的合約才能進行轉移用戶的相應資產,以此實現權限的控制。

而在EOS中,由于合約代碼可以升級,情況則大不一樣:假如合約A的運營方在某次合約升級中(或被黑客攻擊)悄悄把hi方法中對合約B的合約調用改為transfer,把Bob的 xxx Token轉賬給自己。Bob可能并不能及時知曉代碼更新,則很有可能在后續調用中觸發轉賬操作,丟失資產。為了解決這一情況,EOS提供了兩種方法:

· Bob創建新的權限,并授予合約的eosio.code權限,并指定合約A的hi和合約B的hello,如此Bob賬戶只能用于調用A.hi與B.hello。

· 新增了require_receipt的通知方法,它使用合約A賬戶而非Bob賬戶調用合約B,并修改上下文變量以指明來源方。

以上問題是平臺為智能合約提供的最基礎的安全機制。這些安全機制為智能合約的執行提供了最基本的保障,然而,事實證明,這些安全機制仍然不足以保障智能合約的安全,和現實世界中涌現出的大量的智能合約漏洞。

3 合約漏洞類型總結

真實世界的智能合約反反復復被攻擊,合約漏洞層出不窮,攻擊方式多種多樣,由攻擊導致的損失已超百億美元。這些漏洞的背后是否有跡可循呢?如此巨大的代價換來的經驗是否可以服務于其他鏈平臺的合約安全?本小節試圖討論一下這個問題。我們按照漏洞在各平臺的通用性的高低把漏洞類型分為 5 個類型,分開討論。

3.1 基礎類型漏洞類型

基礎類型漏洞最為通用,每個平臺都會涉及。

3.1.1 整數溢出/Integer Overflow

整數溢出發生的原因是因為寄存器能表示的數值位數有限,當存儲的數值大于能表示的最大范圍后,數值發生溢出,或稱為反轉。最大值溢出會變成最小值,最小值溢出會變成最大值。

C++ 語言經常會發生整數溢出問題。看一個具體的案例:

if (p->size() < x*y) {
            return COORDICATE_IS_ILLEGAL;
 }

左右滑動查看完整代碼

if (p->size() < x * y) 語句中 x * y 可以溢出,溢出后為一個很小的數,可以繞過 if 語句的檢測,進入到后面的邏輯。這種情況在任何平臺都可能發生,是平臺通用性最高的一類。

3.1.2 隨機數可預測/Predictable Random

隨機數的使用場景非常廣泛,如彩票,游戲,簽名算法。雖然隨機數很重要,但是在區塊鏈中實現一個基本的隨機數并不是一件想象中那樣簡單的事情。在傳統互聯網中,隨機數是密碼學與隱私安全的基礎。傳統的偽隨機數生成算法或多或少與單臺機器的物理狀態或運算狀態相關,這在區塊鏈上是行不通的。對于不熟悉區塊鏈的人而言,這可能有些難以理解:畢竟大多數編程語言都有生成隨機數的功能。區塊鏈是一個分布式的系統,它要求各個節點的運算結果是可驗證、可共識的,這就使得在區塊鏈上進行隨機數生成有了天然的限制。

為了保證每個節點的運算結果是可驗證,可共識的,平臺通常使用鏈上的公開信息作為隨機源。每個平臺都有一些特有的屬性,如以太坊有 block.number,block.timesteamp;EOS 有 ref_block_num,ref_block_prefix。這些屬性是公開可得的,但是也可以被操控或者預測。如果使用這些屬性作為隨機數的種子,那么隨機性會被破壞。以太坊和 EOS 上有非常多被攻擊的真實案例。

其他平臺的合約里如果使用了可預測的隨機種子,那么合約的安全性也會受到威脅。如波場TVM提供了以下特殊函數來獲得鏈上公開信息:

· block.number (uint): 當前區塊號

· block.timestamp (uint): 自 unix epoch 起始當前區塊以秒計的時間戳

· block.coinbase (address):當前區塊的出塊SR地址

由于這些區塊基礎信息具有一定的隨機性,很多合約開發者使用以上的三種特殊函數來進行隨機數的生成。其中就包括著名的Fomo3D,seed的計算依賴于區塊數據,比如timestamp, difficulty, coinbase, gasLimit, number等字段,一旦這筆交易被打包進區塊,這些值就已經確定了。因此,攻擊者可以構造如下的合約,在合約內提前對結果進行測算,當結果符合預期時再進行對Fomo3D目標合約的調用,成功破解了Fomo3D。

3.2 函數接口漏洞類型

函數接口相較于基礎類型復雜性有所提升。其他平臺上也會有函數調用類問題。

3.2.1 外部調用注入/External Call Injection

外部調用在各種語言和平臺都極為常見。外部傳入的參數可控,攻擊者就可以通過控制參數改變合約的執行邏輯。

· 以太坊

以太坊里有 2 個特殊的外部調用傳參的入口:

· call:普通調用,執行上下文是外部合約的上下文,會更改調用者為實際調用者。

· delegatecall :代理調用,執行上下文是本地合約上下文,傳入的參數會影響本地的數值。

利用這 2 個接口改變調用者或上下文的特性,攻擊者傳入精心設計的參數可以控制合約的執行邏輯,可以繞過訪問控制,修改敏感的狀態數據,如賬戶余額等。具體案例可查看百萬合約之母以太坊的漏洞攻防術(上集) call 注入漏洞和 delegatecall 漏洞小節。

· EOS

EOS體系是以通訊為基本的,Action 就是EOS上通訊的載體。EOSIO 支持兩種基本通信模型:

· 內聯(inline)通信,如在當前交易中處理 Action。

· 延遲(defer)通信,如觸發一筆將來的交易。

Inline 通信使用原始交易相同的 scope 和權限作為執行上下文,并保證與當前 action 一起執行。Deferred 跟 inline 通信相比,執行上下文是相同的,不同的是會延遲執行。

跟以太坊 call 調用不同,EOS 體系不改變調用者或者上下文。是否不改變調用者和上下文就免受外部調用注入的影響呢?事實并非如此。

2020 年 10 月 8 日就發生了一起通過精心設計傳入的參數進行外部調用注入的攻擊。imToken 發推表示,用戶報告稱 31 萬枚 DAI 被盜,這與 DeFi Saver Exchange 漏洞有關。攻擊者通過調用 DeFi Saver 的 swapTokenToToken 函數傳入 _exchangeAddress,_hide,_dest 為 DAI 合約地址,選擇 _exchangeType 為 4,并傳入自定的 _callData。通過構造這些參數,成功的控制了合約的執行邏輯,盜取了31萬 DAI。

所以,不管是否利用call/delegatecall這類特殊接口的特性,只要合約存在外部調用的接口,都可能受到外部調用注入的影響。

3.2.2 未檢查返回值/Unchecked Return Value

未檢查返回值在任何平臺都可能出現。具體案例可查看百萬合約之母以太坊的漏洞攻防術(下集)未檢查返回值小節 。

· gasless send 問題:未檢查 send 和 call 的返回值,導致雙方賬目不一致。

· exception disorder 問題:未檢查 call 調用的返回值,導致異常不能向上傳遞,發生邏輯錯誤。

EOS 尚未發現由未檢查返回值引起的安全問題,但是 EOS 也會受此問題的影響。

任何合約不檢查返回值,都導致非常嚴重的后果,如以下代碼:

  for (int i = 0; i < static_cast<int>(admin_addresses.size()); ++i) {
    bool exists = CheckAccount(admin_addresses[i]);
    (void)exists;
  }
  CheckAccount(admin_core_contract_id);

左右滑動查看完整代碼

CheckAccount() 檢查了帳號有效性,但是未對返回值做處理,導致無論帳號是否有效都可以進入到后續的邏輯。這種問題在任何平臺都可能出現,要全力避免。

3.2.3 未校驗參數合法性/Illegal Parameter

跟外部調用注入不同之處在于,這一類別內外部接口的參數都需要校驗。參數的合法性包括:參數個數,參數大小,參數結構,參數有效期等等。如果接口沒有校驗參數合法性,則會存在較大安全風險。

短地址漏洞 (short address) 成因之一是因為函數中沒有校驗傳入的參數的 size 是否正確。攻擊者調用其他合約的時候,特意選取以 00 結尾的地址,傳入地址參數的時候省略最后的 00,EVM 在解析數量參數時候對參數錯誤的補 0,導致超額轉出代幣。如果校驗了傳入參數的合法性,則此問題可以避免。此漏洞發現后已很快被修復。

3.2.4 權限控制問題/Access Control

權限控制問題是安全設計類問題,每個平臺都需要安全設計。若缺少安全設計,則合約會更容易暴露在攻擊者面前。

3.2.4.1 合約對用戶無權限控制

敏感函數完全沒有權限控制。敏感函數可以是轉賬類函數,修改全局變量類函數,查詢敏感信息類函數。敏感函數無訪問控制的問題平臺無關,任何合約運行平臺都可以存在。

如 2020 年 7 月 1 日,VETH 合約遭遇黑客攻擊。此次攻擊主要利用 Vether 合約中 changeExcluded 函數的可見性為 external 且未有權限限制,用戶可以直接進行外部調用為攻擊創造了必要的條件,最終盜走巨額的 VETH。

3.2.4.2 合約對用戶權限控制不當

這類問題比起完全無權限控制問題,提升了攻擊門檻,但是處境并無差別,因為依然可以被攻破。屬于設計上有安全設計,但是實際實現上沒有達到預期。

· 以太坊一般使用 msg.sender 驗證身份,如果錯誤地使用了 tx.origin 驗證身份,就可以被繞過。具體案例可以查看百萬合約之母以太坊的漏洞攻防術(下集)權限控制漏洞小節。

· EOS 的入口函數 apply 里通常要驗證發送者的身份,如果錯誤地使用了 if (code == receiver ) 判斷,認證可以被繞過。具體案例可查看EOS菠菜應用篇合約對用戶權限控制不當 — apply 函數小節。

權限控制不當的表現方式多種多樣,如2020 年 8 月 5 日,Opyn 合約遭遇黑客攻擊。原因在于 vaultToExerciseFrom 的校驗存在缺陷。此檢查未校驗 vaultToExerciseFrom 是否是調用者自己,而只是簡單地檢查是否創建了 vault,導致攻擊者可以任意傳入已創建 vault 的地址來通過檢查。

3.2.5.3 合約濫用用戶權限

濫用權限是指合約申請了用戶的授權,然后合約自主更新成惡意版本,拿著用戶的授權做惡意操作。如果合約升級沒有任何管控,合約創建者可以自主升級,用戶無感知。這就存在合約創建者可能升級為惡意合約的問題,是一種安全隱患。

EOS 有eosio.code 權限的問題,eosio.code 權限是 dawn4.0 后新增的內部特殊權限,用來加強 inline action 的安全性。inline action 簡單來說就是action 調用另外一個 action,具體來說就是一個智能合約調用另外一個智能合約。

inline action 需要向用戶申請 eosio.code 權限。用戶只有授權 eosio.code 權限給合約之后,合約才可以以用戶身份調用另一個合約。任何申請用戶 active 權限的場景。由于合約可以升級,即使授權版本的合約經過審計,也無法保證后續升級合約不作惡。

DeFi 中也存在濫用權限的問題。DeFi 合約可能會為了“能更方便地操縱你的資產”的目的,向你申請授權,那這個授權調用又是個什么樣子呢?看一個具體的示例:

https://etherscan.io/tx/0x419d17e216cda75dd9635a752e9aedb8f43ed4bfe31a6f75ed8923779c73eb6e

這筆交易表示【0x3693】 這個地址授權給【Uniswap V2: Router 2】合約無限動用自己全部 USDT 的權力。這就帶來一個巨大的隱憂,在合約 owner 作惡,或者合約存在漏洞的情況下,用戶【0x3693】可能失去全部的 USDT。

因為濫用授權,即便用戶沒有或者只向合約轉入了很少的資產,如果合約有授權轉賬相關的漏洞,則所有授權過的用戶錢包內的資產都將面臨風險。即便是沒有漏洞,合約開發者也具備更新代碼后拿走授權用戶錢包內全部資產的權力。所以,用戶測要小心授權,避免授予無限權限,定期回收不需要的權限,項目測要最小申請用戶權限,避免申請無限權限。

3.3 平臺特性漏洞類型

特性比函數調用更為復雜。一些特性會引起安全問題。支持此特性的平臺需留意。

3.3.1 利于重入(Re-entrancy)的特性

fallback 特性利于重入漏洞,重入漏洞最先在以太坊平臺上被發現。具體案例可查看百萬合約之母以太坊的漏洞攻防術(上集)重入漏洞小節。雖然只要有外部調用就存在重入的可能,但是正常情況下,1、調用外部函數的時候會進行代碼審計,2、外部函數不會提前預見到調用者的函數名。所以僅利用外部調用進行重入攻擊是有難度的。但是以太坊平臺還支持 fallback 特性,在兩種情況下會調用到 fallback 函數:

1.未找到函數名,默認會調用 fallback。

2.轉賬操作默認會調用 fallback。

利用 fallback 特性可以大大降低重入的難度。

除了 fallback,目前還發現一種特性也利于重入——合約升級。審計版本是正常合約,但是后來悄悄升級成惡意合約,實施重入。如果其他平臺支持合約無感升級,那么重入的風險會非常大。

3.3.2 提前交易(Front-running)特性

提前交易是指攻擊者發現有利可圖的時候就通過一些手段讓自己的交易優先執行。關于提前交易的具體案例可以參考百萬合約之母以太坊的漏洞攻防術(上集)提前交易漏洞小節。

交易順序通常由 3 種方式決定:

手續費

手續費高的優先執行,手續費低的延后執行。以太坊的交易手續費可以決定交易被打包的順序。所以攻擊者發現有利可圖的時候就通過增加手續費的方式讓自己的交易優先執行。這種方式的代價就是額外付出手續費,技術層面不需要。

先進先出

先接收到的交易優先執行。典型的例子是 EOS。這種情況下,普通攻擊者很難通過經濟手段讓自己先執行,除非通過技術手段攻破出塊節點,操控交易順序。但這個難度是相當高的。

共識節點排序

現在越來越多的公鏈引入了 PBFT 共識協議或者由 PBFT 衍生的同類協議。使用這種共識協議時,交易順序通常由主節點決定,如果主節點存有私心,選擇了有益于自身利益的順序,也會產生提前交易問題,且主節點的偏袒不會被發現。普通攻擊者無法通過經濟手段操縱順序,通過技術手段,或者社交工程學手段可以達成目的,但是這種手段目前沒有發現真實案例。

總結來看,如果交易順序可以被人為操控,那么會受提前交易漏洞的影響。

3.3.3 延遲交易(Delayed-transaction)特性

EOS 支持延遲交易的特性,通過設置 delay_sec 讓交易在指定的時間觸發執行。如果 delay_sec = 0,由于EOS執行交易采用FIFO策略,這些延遲交易肯定在其他交易之前執行。大量 delay_sec = 0 的延遲交易可以發起 DoS 攻擊。具體案例可以參考EOS菠菜應用篇DoS漏洞/交易延遲漏洞小節。

目前,我們僅了解到 EOS 支持延遲交易,但是可以推斷的是支持此特性的平臺都會受此漏洞影響。

3.3.4 回滾(Rollback)特性

回滾是一種特性,當函數執行失敗的時候回滾到初始狀態,一般區塊鏈平臺都會支持這個特性。

在以太坊平臺有以下方式可以觸發回滾:

· require();

· assert();

· revert();

在 EOS 平臺有 eosio_assert() 可以觸發回滾。

攻擊者可以使用這些方式在不符合自己利益的時候把交易回滾,就可以達到一直盈利的目的。比如,彩票合約中,不中獎就回滾。以太坊平臺和EOS平臺回滾特性的具體案例可以參考百萬合約之母以太坊的漏洞攻防術(上集)EOS菠菜應用篇的回滾漏洞小節。

支持回滾特性的平臺都會受回滾攻擊的影響。例如波場的多個 Dapp 都遭受過回滾攻擊:SPOKpark、DappRoulette、Divitron、DiceGame、TRONtopia_ultimate_dice、Wheel Of Fortune DApp,等等。

3.4 充值場景漏洞類型

一個場景可以用到多個特性。充值場景多發生在向交易所或者游戲項目方充值的場景。目前已經發現了 3 類漏洞:假充值,假通知(fake transfer notice),假代幣(fake token)。這些漏洞都是利用交易所/項目方校驗邏輯存在漏洞, 0 成本獲得充值。

3.4.1 假充值漏洞

假充值漏洞是指易所給用戶充值的余額和交易所自己實際收到的余額不符,通常情況下是實際收到的金額少于給用戶充值的金額,導致交易所損失。

這類漏洞的主要成因是交易所沒有正確的校驗充值結果。

· 以太坊的假充值的原因是錯誤的認為交易回執中 status = true 就是充值成功,實際上 status = true 是指沒有拋出異常,即使充值執行失敗函數 return false,交易回執中的 status 也會是 true。僅判斷 status 是否為 true 是不正確的。具體案例可以查看百萬合約之母以太坊的漏洞攻防術(上集)假充值漏洞小節。

· EOS 的假充值也是類似的問題。項目方只是對交易是否存在作出了判斷。但是交易可能執行失敗,交易狀態變成 hard_fail。hard_fail 的交易也可以在鏈上出現記錄。所以,把交易是否存在作為充值成功的依據是不正確的。具體案例可以查看EOS菠菜應用篇的假充值漏洞小節。

如果交易所僅僅通過校驗中間結果,而不去校驗實際收到的金額,就會出現假充值問題。

舉一反三來看,USDT 假充值漏洞,XRP 假充值漏洞,門羅幣假充值也是類似的原因。門羅幣交易所沒有檢測真實錢包收賬余額,而是僅僅通過 show_transfers 來確認用戶充值金額,show_transfers 指令并沒有跳過重復的交易,每筆重復交易的轉賬金額也會被計算在內,并最終輸出出來,便會出現假充值漏洞,導致交易所給用戶充值的余額和交易所自己實際收到的余額不符,攻擊者假充值成功后可以進行消費或提款。

所以,涉及到充值場景時,交易所/項目方要仔細辯證校驗邏輯是否合理。

3.4.2 假通知漏洞

假通知漏洞可以用 EOS 平臺上發生的攻擊案例解釋,具體見EOS菠菜應用篇的假transfer通知小節。EOS 上可以用 require_receipt(someone) 向任何一人發送轉賬通知。那么攻擊者在自己控制的帳號之間轉賬,但是把轉賬通知發送給項目方。項目方沒有校驗接收方是否是自己,默認為攻擊者做了充值操作。

目前以太坊上還沒有發現假通知漏洞,但是不代表這種漏洞就不存在。交易所如果沒有校驗交易回執中的 to 字段是否是自己,也會被攻擊者攻擊。

在項目方一側要全面的校驗當前交易回執是否跟自己有關。

3.4.3 假代幣漏洞

顧名思義,假代幣就是拿假錢當真錢花。EOS 平臺已經出現了真實的攻擊案例,具體見EOS菠菜應用篇假EOS代幣小節,以太坊平臺目前還沒有發現。假代幣發生的原因是交易所/項目方沒有驗證幣的真偽,使得攻擊者可以用假幣換真幣。

假代幣的問題在其他平臺也存在。波場 DApp tronbank 于2019年4月11日凌晨1點曾遭受假幣攻擊。該次假幣攻擊事件主要原因在于合約沒有嚴格驗證代幣的唯一標識符代幣 ID,錯誤地將攻擊者自己發行的無價值代幣識別為價值85萬元的BTT代幣,從而造成了損失。

如果平臺發行了代幣,那么需要告知交易所/項目方,進行真偽代幣的校驗。

3.5 經典攻擊手法的再現

一些經典的攻擊手法,如重放攻擊,DoS,跟平臺特性結合之后,可以引起新的安全問題。

3.5.1 重放/Replay

經典重放攻擊的基本原理就是把以前竊聽到的數據原封不動地重新發送給接收方。很多時候,網絡上傳輸的數據是加密過的,此時竊聽者無法得到數據的準確意義。但如果他知道這些數據的作用,就可以在不知道數據內容的情況下通過再次發送這些數據達到愚弄接收端的目的。

重放攻擊在幣圈被熱談,是以太坊硬分叉的時候。我們知道以太坊硬分叉出現了ETH和ETC兩條鏈,兩條鏈上的交易數據結構是完全一樣的,因此一筆交易在ETH上是有效的, 那它在ETC上同樣會被接受,反之亦然。

因為沒能提前識別重放攻擊的威脅,以太坊分叉時幾乎所有交易所也都沒意識到這個問題,更沒有提前做ETH和ETC分離, 這時候只要有人從交易所提取ETH幣,就有可能得到同等數量的ETC幣。許多人利用這個漏洞,不斷在交易所充幣和提幣(ETH), 從而獲取額外的ETC。

分叉鏈都面臨相似的問題。BCH硬分叉成 BCH 和 BSV 兩條鏈時,也面臨相似的問題。在BSV鏈上交易時,由于相同的地址、算法和交易格式,拿到BCH鏈上去重新廣播,就有可能會被BCH鏈承認有效,從而進行相同的交易操作。

除了鏈層面,合約層面也會受重放攻擊的影響。如攻擊者在以太坊合約上重放用戶的簽名信息,具體案例可查看以太坊(下集)重放漏洞小節,在 EOS 合約上重放中獎消息,具體案例可查看重放漏洞 — 重放中獎消息小節。重放攻擊是一種攻擊思想,任何平臺任何環節都可能被影響。

3.5.2 拒絕服務/DoS

經典攻擊手法里的拒絕服務攻擊(英語:denial-of-service attack,簡稱DoS攻擊)是一種網絡攻擊手法,其目的在于使目標電腦的網絡或系統資源耗盡,使服務暫時中斷或停止,導致其正常用戶無法訪問。

DoS 攻擊思路用于以太坊可以有多種形式,攻擊以太坊的多種特性都可以讓以太坊無法提供服務。

· king of ether 代表的 DoS 漏洞類型。這種 DoS 漏洞類型是:依賴外部調用的進展,如果外部調用執行失敗,后續的操作也就無法執行,導致拒絕服務。

· GovernMental 騙局代表的 DoS 漏洞類型。這種 DoS 漏洞類型是:依賴外部可以操作的數據,如數組或映射,如果外部操作改變了數據,修改后的數據使得后續的操作因超時或者 out of gas 無法執行,導致拒絕服務。

· freezing ether 代表的 DoS 漏洞類型。這種 DoS 的漏洞類型是:依賴外部的合約庫。如果外部合約的庫被刪除,那么所有依賴庫的合約服務都無法使用。

EOS 的 DoS 攻擊是利用延遲交易特性和執行交易的先進先出特性。攻擊者可以在正常交易里嵌入大量 delay_sec=0 的惡意延遲交易,由于EOS執行交易采用FIFO策略,這些延遲交易在其他交易之前執行。只要這些惡意延遲交易足夠多,正常交易會被一直阻塞,無法提供正常服務。

針對這幾個特性,分析一下其他平臺是否會受影響。

· king of ether 類:要看平臺是怎么處理合約調用的,合約 A 調合約 B,如果 B 執行失敗,會不會影響 A 的執行。如果影響,那么就跟以太坊一樣存在 DoS 攻擊。如果不影響 A 的執行,那么就不存在 DoS 攻擊。

· GovernMental 類:如果平臺有停機機制,如 gas,會受影響。如果平臺可以無限執行指令,那么不會受影響。

· Freezing ether 類:要看平臺是否支持合約地址可指定。如果合約地址向以太坊一樣不可指定,那么合約一旦被刪除將無法恢復,會受影響。如果合約地址可指定,那么即使被刪除,也可以恢復,不受影響。

· 延遲交易類:支持延遲交易的平臺會受影響,反之,不受影響。

DoS 是一種攻擊思路,平臺盡可能防范,但無法完全避免。

4 小結

本文按照由簡單到復雜的順序排列漏洞類型。越簡單基礎的類型,平臺通用性就越強,如整數溢出,權限控制不當,在任何平臺都有可能出現。對于平臺特性類,平臺支持某個特性,就會受相應特性的影響,進行安全設計時,需要考量平臺特性帶來的安全風險。一個場景涉及多個特性,場景中比較特殊的是充值場景,有涉及到充值場景的項目方需提高警惕。最后,經典的攻擊手法重放攻擊、DoS 攻擊可能被應用到任何一個環節,出其不意地引發各式各樣的安全問題。

本文是智能合約漏洞系列總結篇,主要目的是回顧已經發生的漏洞,總結漏洞根因,并預測其他平臺是否會受影響。前車之鑒,后事之師。

參考文獻

https://bbs.pediy.com/thread-250801-1.htm

https://bcsec.org/index/eventsearch/name/attack_type/value/回滾攻擊/page/1/tag/1

https://www.8btc.com/books/834/blockchain-security/_book/09.html

https://xz.aliyun.com/t/3316

https://www.chainnews.com/articles/558348165334.htm?spm=ata.21736010.0.0.32931a73wOg8Mk

https://www.chainnews.com/articles/180110076539.htm?spm=ata.21736010.0.0.32931a73wOg8Mk


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1646/