2023-01-16|閱讀時間 ‧ 約 9 分鐘

分散式應用漏洞分類-DASP TOP10

在過往大家所較為熟知的漏洞分類為OWASP (Open Web Application Security Project) Top10,對web 應用程序安全風險進行分類,並訂立了相關的安全檢核標準:OWASP ASVS (Application Security Verification Standard),將風險分級並於應用層面訂立詳細的驗證需求。
而在智慧合約發展不久後,於2018 年也有了類似的漏洞分類,即為DASP(Decentralized Application Security Project) TOP10,與之對應的安全檢查標準便是SCSVS(Smart Contracts Security Verification Standard),首次發表於OWASP Global AppSec Amsterdam 2019 會議,旨在為開發人員、安全審查人員及產品供應商等等標準化智慧合約的安全性,有助於避免大多數已知的安全問題及漏洞。
該列表於2020 年12 月5 日發表新版本,更新第十四個分類項目DeFi,並於OWASP 會議上進行發表。

(一) Reentrancy

合約在執行外部合約調用時被攻擊者劫持,重入遞迴呼叫合約內函數,著名的DAO 事件便是駭客利用此漏洞進行攻擊,最終導致以太坊的硬分叉。

(二) Arithmetic

通常分為整數上溢和整數下溢,以uint8 為例,只能存8 bit,意即0 到2⁸ -1 的數字(0–255),uint256能存0 到2²⁵⁶-1 的數字,以此類推。若試圖存256 至uint8 類型中,數字會變成0。下溢原理亦是。要防止整數溢出可以使用OpenZeppelin 所開發的SafeMath 合約對算術邏輯進行檢查,另外Solidity 在v0.8.0 後預設會進行算數檢查,將不必另外引入函式庫。

(三) Short Addresses

處理ERC20 代幣的交易時,若未在帳戶地址長度上執行輸入驗證,EVM 檢測到缺少字節時將會自動補零,會使攻擊者於交易時可以領走對方帳戶數十或是百倍的金額。若是在交易所進行交易,交易所需要對帳戶地址進行檢查,方能避免此類攻擊。

(四) Access Control

使用Solidity撰寫合約時可以使用private、public、external 和internal 對合約存取權限進行控管,而在使用和儲存變數可以使用memory、storage 和calldata。
• private 函數僅能在合約內部被調用。
• public 函數可以被任何帳號調用或呼叫,可以為外部合約或使用者、內部其他函數等。
• external 函數不能透過內部呼叫,僅能從外部調用。
• internal 一般用於合約繼承,父合約提供子合約進行呼叫或調用。
• memory 資料僅在函式執行期間存在,執行完畢後就被刪除。
• storage
storage 中的資料會寫入區塊鏈,只要合約存在就一直保留,修改狀態的話鏈上資料也會改變,這也是storage 使用成本高的原因。
• calldata 外部函數的引用必須使用calldata,也可用於其他變數的引用。只讀數據位置,可以確保資料不被修改,可以用來保存函數調用參數(之前僅能針對外部函數使用),Solidity 0.6.9 版本之後先前僅用於外部函數(external 修飾的函數)的 calldata 位置,現在可以在內部函數(internal 修飾的函數)使用。函數也可以返回使用calldata 宣告的陣列和結果,但是不能分配這些型別。
2017 年7 月19 日所發生的Parity Multisig Wallet 攻擊便是利用此漏洞,由於錢包合約並沒有使用權限控管,用public 使任何人皆可呼叫,攻擊者將其所有權改成自己,並將合約內金額全數轉給攻擊者地址。

(五) Bad Randomness

在以太坊鏈上所有交易都是公開可以被查詢的,若在撰寫合約使用隨機數時沒有考慮到此特性,此漏洞可能被惡意使用者用以圖利。 以DASP 所提供的例子進行說明:
Bad Randomess範例
其利用private seed 與iteration 數字和keccak256 hash 函數結合,用以確定呼叫者是否獲勝,seed 的值可以透過檢視與該合約相關的交易紀錄來取得。得到 seed 值後 iteration 值也可以此方式計算獲取,整個 uint(keccak256(seed + iteration))的值便是可以被預測的。惡意的攻擊者可藉此使自己不斷贏得獎勵。

(六) Transaction Ordering Dependence (TOD)

亦被稱為Front-Running,在以太坊區塊鏈中,礦工藉由驗證交易獲得獎勵,手續費較高的交易會優先被完成,因此礦工的選擇會影響交易的順序,在以太坊鏈上任何人都可以看到他人未被驗證的交易內容,惡意攻擊者可以藉此竊取他人交易內容或合約,以更高的費用複製其交易,使礦工會選擇交易高的一方,便會產生TOD 之漏洞。

(七) Time Manipulation

合約若依賴於block.timestamp 是有被攻擊利用的風險的,礦工在對交易進行驗證時可以掌握時間,若礦工對使用時間戳進行控制的合約持有股份或有利可圖,可能造成有心的礦工(攻擊者)藉由選擇特定時間驗證圖利自己。

(八) Denial of Services

導致DOS 的狀況很多,包含out of gas、含有kill()的合約、可能意外阻斷服務之呼叫等等皆算此類。
經典的舉例如「King Of Ether Throne」,「King Of Ether Throne」是一個能賺取以太幣以及可以留名的合約,使用者可以向合約投入金額換取成為國王的機會,若在14 天內都沒有被篡位就可以在專屬網站留下地址及帳戶名稱,若在14 天內被篡位,新任國王所投入的金額有部分金額會給遭篡位者作為補償。漏洞利用方式是以惡意合約作為篡位帳戶,在惡意合約的fallback() 內添加錯誤函數(如:revert()),即可阻斷合約,使後續其他使用者永遠都無法篡位成功。

(九) Unchecked Return Values For Low Level Calls

指在呼叫外部函數發生錯誤或是沒有對調用返回值進行檢查所產生的安全問題,DASP TOP 10 內所述有三種底層調用方式分別為: call()、delegatecall()、 callcode()。而在目前的Solidity 版本中,用法為call()、delegatecall()、 staticcall(),和三個發送ether 的函數:call{value: value}、send()、 transfer()。
• call() 多用於調用外部合約函數,會回傳一個bool 值來表示外部調用成功或是失敗。
• delegatecall()、 staticcall() 允許合約於現有合約之環境進行上下文調用其它使用者之合約的程式碼,藉由回傳的bool 值來表示調用成功或者失敗。
• call{value: value}() 若只是透過fallback() 發送以太幣時,可以使用此方法。
• send() 在發送款項時若失敗會回傳false,有gas 消耗限制,僅提供2300 gas,但交易失敗狀態不會回滾。
• transfer() 若發送失敗交易狀態會回滾,有gas 消耗限制,僅提供2300 gas,在用以發送交易時是較為安全的寫法。

(十) Unknown Unknowns

由於智慧合約尚在發展階段,許多項目在發布前進行安全審計時漏洞無法被完全揭露,現有的驗證工具或方法也有侷限性,未來可能有新型態攻擊發生。
作者Alice目前為分散式金融應用安全從業人員,將來也會持續在Vocus以及medium上分享相關的研究,如果喜歡我的文章歡迎追蹤我的帳號喔!
另外,我已經加入由趨勢科技防詐達人所成立的方格子專題-《區塊鏈生存守則》,在那裡我會跟其他優質的創作者一起帶大家深入瞭解區塊鏈,並隨時向大家更新區塊鏈資安事件
> 追蹤《區塊鏈生存守則》學習如何在區塊鏈的世界保護自己
> 關注防詐達人獲得其他最新詐騙情報
分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.