“前有狼後有虎”,去中心化的區塊鏈治理的安全思路和考慮

撰文:CertiK

去中心化區塊鏈網絡的主要核心之一治理,指的是「用戶就去中心化協議的管理達成共識,或達成多數同意」。基於區塊鏈的治理系統的獨特功能為其帶來了諸多優勢,但也伴隨着眾多安全風險

本文將主要為大家講解關於區塊鏈治理系統的一些常見安全問題,但在這之前,我們需要先了解一下它的具體功能。

區塊鏈治理系統是一個基於規則的決策過程。它允許社區提出建議、討論和實施更改及改進。在區塊鏈世界中,有兩種主要的治理類型:層面治理和 dApp 層面的治理。

鏈層面治理

鏈層面治理旨在管理和實施對區塊鏈本身的更改。在這種類型的治理中,進行更改的規則會嵌入在區塊鏈協議中。開發人員通過代碼更新提出更改,由每個節點投票決定是接受還是拒絕。

dApp 層面治理

應用程序層面(或是去中心化應用程序 dApp 層面)治理類似於鏈層面治理,但範圍僅限於dApp 類的項目,處理時間通常要短得多。

“前有狼後有虎”,去中心化的區塊鏈治理的安全思路和考慮

下方是一個 dApp 治理項目的簡述。

在查看這一簡述前,我們先了解一下主要術語

abstain:棄權,是一種計入法定人數但不計入閾值的投票類型。在大多數協議中並不常見。

Deposit:存款,是一種旨在避免惡意用戶破壞治理的機制。提議者(以及對提案感興趣的社區用戶)需要在存款期間向提案存入一定數量的 token。雖然某些提案可能需要檢查用戶的 token 餘額,但這也驗證了用戶的意圖——如果提案失敗,用戶的 token 將面臨無法取回的風險。一旦提案籌集到確定數量的 token,提案就可以進入投票階段。

Proposal:提案,是一個治理系統組件,旨在對系統進行更改並由用戶投票。用戶通過提交提案、存款和投票來與提案進行交互。每個用戶都可以提交提案。提案可以是參數更改、代碼升級更改、分發算法更改、新功能請求等。

Proposer:提議者,是提交提案的用戶。提案人可以但非必要提供全額存款資金。

Quorum:法定人數,是在投票期結束時需要投票的 token 總數的百分比。

Tally:記錄,是計算提案結果的過程。確定提案是否通過的等式是:Pass = Quorum && Threshold (&& Veto)。例如,對於法定人數=40% 且閾值=66.7% 的協議,提案的「通過」要求至少有 40% 的治理 token 持有者參與提案,並且他們中至少⅔的人投了贊成票。

Threshold:閾值,是提案通過則需要「for/yes」投票的參與 token 所佔的百分比。

Veto:否決,是一種投票類型,當否決票的百分比超過特定閾值時,會導致提案被拒絕。可以看作是更強烈的「against/no」。在大多數協議中並不常見。在某些協議中,提案的「否決」結果可能會導致一些懲罰。

Vote:投票,是治理參與者(token 持有者)與提案互動的方式。每個參與者都可以在投票期間對提案進行投票。投票可以是「for/yes」和「against/no」,但是一些協議也有「abstain」和「no-with-veto」這樣的選項。

“前有狼後有虎”,去中心化的區塊鏈治理的安全思路和考慮

來源:Lucid

首先,任何持有治理 token 的用戶都可以提交一個提案,該提案需要一個持續兩天的審查期。在兩天的時間內,創建者可以無代價取消提案。之後,該提案將進入為期三天的投票期。在投票期間,治理 token 持有用戶可以根據其投票權對活躍提案投「for/yes」或「against/no」票。持有的治理 token 數量決定投票權及其投票的總權重。投票期結束后,治理系統將開始統計投票結果。系統將根據預先配置的法定人數和閾值得出「拒絕」或「通過」的結果。如果提案被拒絕,它將被取消,如果通過,則在 timelock 後由系統執行。timelock 有助於留出時間來通知用戶即將發生的更改。

上圖底部是一個帶有存款步驟和「否決」投票選項的版本。這是一些鏈採用的稍微複雜的解決方案。存款期有點像審查期的延長版。每個提案都有最小所需存款的要求,包括提案人在內的任何用戶都可以向提案存款。如果提案在兩周的存款期限內沒有收集到足夠的存款,它將被取消。投票周期類似於上圖中頂部位置的系統,但現在的投票期更長。這裡的區別在於投票選項。第一種機制只有「or/yes」和「against/no」兩個選項,現在增加了兩個選項,分別是「abstain」和「no-with-veto」。

選擇「abstain」即代表棄權,會被計入法定人數檢查,但不計入閾值和否決檢查。因此,在計票結束時,除了「拒絕」或「通過」以外,還會多出一個結果,稱為「rejected with veto」,意味着投給「no-with-veto」的有效票數超過了否決檢查。

如果這一提案的結果是「rejected with veto」,那麼將會進行一定的懲罰,例如押金將可能被直接銷毀,不予退還。

鏈上與鏈下治理

鏈上和鏈下治理的一個直觀區別是去中心化程度。鏈下治理通常取決於開發或管理組織的決策。誠然,在區塊鏈世界,或者說是在開源項目世界,鏈下治理也可以通過社區會議和公共代碼審查變得更加透明。

透明度不等於去中心化。在很多情況下,數量更多但話語權較小的社區用戶並沒能積極有效地參與治理。

但是對區塊鏈或應用層面項目的更改,並非由核心開發社區來評估利弊進行。相反,每個節點都可以對提議的更改進行投票,並可以探討它們的優缺點——它是去中心化的,依靠社區來達成共識。

鏈下治理系統需要驗證者之間花費時間和精力來達成共識;而由於基於規則的決策制定反饋循環,鏈上治理可以在相對較短的時間內就提議的變更達成共識。鏈下操作可能導致情況混亂,某些節點可以允許不同意且不運行提議的更改。算法投票機制相對較快,因為其實現的測試結果可以通過代碼更新看到。

基於規則的決策可以自動化並加快變化速度,但它不能減少衝突

例如,如果一群社區用戶堅持必須修改分配算法以增加其 token 的流動性和供應,這可能會造成通貨膨脹;而另一派堅持認為,流動性較低的貨幣帶來的金融代價是抵禦通貨膨脹危害的必要條件。

在這些情況下,為了推進這個項目,需要有一個人或一個團體站出來推翻規則從而做出決定。當然,這與區塊鏈的去中心化精神背道而馳。

儘管踏入鏈上治理仍然存在障礙,但與鏈下治理相比,鏈上治理的門檻通常較低。

針對幾乎所有應用層項目的鏈上治理,唯一的門檻就是成為治理 token 的持有者。一些項目的治理 token可以購買或交易,而另一些項目只能通過參與項目獲得。

大多數區塊鏈項目不要求用戶進行 KYC 認證,以便投票和參與治理。再加上社區池提供的一些投票獎勵,或者一些項目的獎勵分配,鏈上投票可以極大地激發用戶的參與和積極性。

鏈層面與 dApp 層面

對於鏈層面治理,token 持有者的投票有時用於決定誰操作運行網絡的驗證節點(例如 EOS、Cosmos 等中的權益委託證明(DPoS)),有時用於對協議參數(例如以太坊 gas 限制)進行投票,有時用於投票並直接批量實現協議升級(例如 Tezos)。在所有這些情況下,執行都是自動的——協議本身包含更改驗證器集或更新其自己的規則所需的所有邏輯,並根據投票結果自動執行。

dApp層面治理的理念源自鏈層面治理。同時,由於 dAppp 沒有區塊鏈那麼複雜,因此提案涵蓋了更多方面。

其中一些提案與鏈層面治理提案類似,如重新選舉管理委員會或更新參數。有些提案並非設計為自動觸發,比如:償還採用新發布功能的費用、與其他項目建立合作夥伴關係,甚至建立合資項目等。

常見安全問題

缺乏防禦閃電貸機制

部分項目的治理 token 可以被任何用戶通過閃電貸借出。因此如果在投票時沒有對持有時間進行限制,用戶可以隨時借出治理 token,創建或投票給惡意提案並執行提案。這一類型的典型案例是Beanstalk漏洞利用事件,稍後將深入探討。

提案缺少審查期

為了簡化流程,一些項目選擇跳過審查或存款期,這意味着無論提案是否合法,所有提案都將直接進入投票期。這將增加用戶對這些惡意提議投「拒絕」票的工作量,或者更會發生更糟糕的情況:惡意提案以某種方式通過並被執行。

配置錯誤

治理系統中的參數很敏感,需要謹慎設置。一些項目分配了不適當的值,這可能會導致攻擊。例如,如果提案通過的門檻太低,攻擊者就更容易控制提案的結果。如果惡意提案通過但是timelock/delay 時間太短,合法用戶將沒有足夠的時間做出反應。他們無法在提案執行前及時解決這一惡意提案。

治理系統的錯誤實現

不正確的系統設計和實現也會導致協議出現嚴重問題。與傳統 token 不同,治理 token 的核心功能是對提案進行投票。一些項目使用他們的項目 token 進行治理,這使得治理 token 可以像普通的 ERC 20 token 一樣自由交易。這將可能導致下列嚴重問題

  • 同一地址重複投票
  • 當投票權被取消時,投票不會被清除
  • 取消委託調用不會刪除委託的投票權

為了解決上述問題,一些項目要求用戶在投票時將 token 轉移到合約中,這將導致另一個常見問題:投票權不能重複用於不同的提案。在這種情況下,治理 token 在同一時期只能對一個提案進行投票。這裡的問題是,如果在投票期間有多個提案,一些提案很難達到閾值,導致一些合法的提案被拒絕。

最後但同樣重要的是,我們在某些系統中看到,投票提案在計票過程之後仍然可以更新或投票。這將擾亂系統的工作流程,並根據系統的實施情況產生不可預測的後果。例如,如果一項提案從未最終確定,則存款 token 將保留在合約中,何時應將其返還給存款人或銷毀,具體取決於提案的投票結果。

案例分析:Beanstalk Finance

Beanstalk 是一個「去中心化的基於信用的穩定幣協議」,於 2021 年上線。

Beanstalk 的主要目標是激勵獨立市場參與者以可持續的方式定期將1 Bean 的價格與美元掛鈎。它的治理機制由兩個不同的部分組成:BeanstalkDAO 和 Stalk 系統。

BeanstalkDAO 是協議的管理機構,對軟件升級的執行提出建議和投票。要加入,用戶必須存入任何列入白名單的資產。此外,還存在參與 Silo 以賺取被動收益的激勵。

Stalk 系統是 Silo 的經濟激勵。當列入白名單的資產存入 Silo 時,Beanstalk 會用 Stalk 和 Seed 獎勵存款人。Stalk 是允許用戶參與 DAO 投票和投提案的治理 token。

每一季,Seed產量為新Stalk的 1/10000。Stalk 持有者有權參與 Beanstalk 治理並獲得一部分 Bean 鑄幣。治理權和 Bean mints 的分配與每個 Stalk持有者的 Stalk 餘額相對於未償還的 Stalk 總量成正比。

準備階段

為了發起這個特殊的攻擊,攻擊者為他們的賬戶注資,將 token 交換為 BEAN 並將其存入 Silo 以獲得 Stalk,這使他們能夠創建提案並為提案投票。然後他們在兩個交易中創建了兩個提案,Beanstalk 改進提案 18(BIP-18)和 19(BIP-19)。

BIP-18 最初是空白的,BIP-19 則包含一份經過驗證的合約,提議向烏克蘭錢包地址捐贈 25 萬美元,並向提議者捐贈 1 萬美元。該提案用於將資產轉移給攻擊者,並需要 24 小時才能進行調用emergencyCommit()。

攻擊流程

1. 攻擊者通過閃電貸借取了 3.5 億枚 Dai、5 億枚 USDC、1.5 億枚 USDT、3200 萬枚 Bean 和 1160 萬枚 LUSD

2. 閃電貸資產轉換為 795,425,740 枚 BEAN3Crv-f 和 58,924,887 枚 BEANLUSD-f:

a. 10 億(約 3.5 億 Dai、5 億 USDC、1.5 億 USDT)作為流動性被添加到 Curve.fi 池中,獲得了 979,691,328 枚 DAI/USDC/USDT 3Crv token。

b. 將上述步驟中的 1500 萬 3Crv 替換為 15,251,318 LUSD,將剩餘 Crv兌換為95,425,740 BEAN3Crv-f。

c. 添加 32,100,950BEAB 和 26,894,383LUSD 作為流動性,並獲得 58,924,887 BEANLUSD-f 作為回報。

3. 攻擊者將從閃電貸中獲得的所有資產存入 Diamond 合約,並投票支持 BIP-18 提案。

4. 立即調用emergencyCommit()來執行 BIP-18 提案。

5. 在步驟 3 和步驟 4 之後,攻擊者能夠耗盡 36,084,584 枚BEAN、0.54 UNIV2(BEAN-WETH)、874,663,982 枚BEAN3Crv 和60,562,844 枚 BEANLUSD-f。

6. 攻擊者使用耗盡的資產(在步驟 5 中)償還閃電貸款並獲得剩餘的利潤:

a. 874,663,982 枚 BEAN3Crv 因 1,007,734,729枚3Crv 而從流動性中移除

b. 60,562,844枚BEANLUSD-f 從流動性中移除,換取 28,149,504枚LUSD

c. 返還 11,678,100枚LUSD 和 32,197,543枚BEAN 到相應的礦池

d. 16,471,404枚LUSD 兌換成 16,184,690枚3Crv

e. 銷毀所有 3Crv 以獲得 522,487,380枚USDC、365,758,059枚DAI 和 156,732,232枚USDT

f. 償還 350,315,000 枚 DAI、500,450,000 枚 USDC 和 150,135,000USDT 到相應的資金池

g. 0.54枚UNIV2(BEAN-WETH) 從流動性中移除,獲得 10,883枚WETH 和 32,511,085枚BEAN

h. 250,000枚USDC 被轉移到烏克蘭數字貨幣捐贈

i. 15,443,059枚DAI 兌換成 11,822枚WETH,37,228,637枚USDC 兌換成 2,124枚WETH

j. 最後,24,830枚WETH 被轉移給了攻擊者。

但是攻擊者如何使協議將 token 轉移給自己呢?要回答這個問題,我們需要深入研究一下emergencyCommit() 函數。

emergencyCommit()

通常情況下,一旦 BIP 被提出,它需要至少 7 天的投票時間才能在鏈上執行。

這被認為是一種偽時間鎖定機制,以允許適當的時間來驗證提案的安全性。然而,emergencyCommit()函數允許在等待 1 天而不是 7 天後立即在鏈上執行提案,emergencyCommit()的閾值為⅔。

當達到閾值時,該emergencyCommit()函數允許人們「執行指定的 BIP、創建與 BIP 相關的 diamond cut、暫停 BIP、並以未經證明的獎勵獎勵提議者」。

“前有狼後有虎”,去中心化的區塊鏈治理的安全思路和考慮

執行emergencyCommit()的提議者創建了一個diamond cut,並可以委託給一個地址,該地址將被_init()執行並執行其邏輯。這允許提議者執行他們想要的任何代碼。

“前有狼後有虎”,去中心化的區塊鏈治理的安全思路和考慮

提案通過後,攻擊者創建了另一個合約,其中包含將 Silo 存放的白名單資產轉移給自己的代碼。

由於 Diamond在合約上執行_init()(在上圖的cutBip()函數中),底層代碼通過_calldata執行其函數,攻擊者能夠取出價值大約 7600 萬美元的 token。

漏洞分析

有兩個問題為漏洞利用打開了大門。第一個是 Silo 系統中的 BEAN3Crv-f 和 BEANLUSD-f(用於投票)可以被閃電貸。

由於 Beanstalk 協議中缺少防禦閃電貸機制,攻擊者可以借用協議支持的大量 token,並對惡意提案進行投票。

第二個問題是emergencyCommit()函數過於強大。如上所述,當提案通過時,治理系統允許提案人為所欲為,而無需任何形式的驗證。該emergencyCommit()功能允許提案立即執行,導致沒有留下任何時間來檢查提案的有效性。

接下來的兩個事件並沒有直接利用治理系統中的漏洞,但治理系統在利用中仍起到了「關鍵」作用。

其他治理漏洞案例

Audius

Audius 治理合約利用 OpenZeppelin proxy upgradability pattern,並重寫 AudiusAdminUpgradabilityProxy 合約中的標準實現。

在其實現中,AudiusAdminUpgradebilityProxy 使用 slot 0 作為 proxyAdmin 的地址。Audius 協議的 proxyAdmin 設置為治理系統地址 0x4deca517d6817b6510798b7328f2314d3003abac。

這導致 proxyAdmin 地址中的最後兩個字節與 OpenZeppelin 的 Initializable 合約中的兩個布爾狀態變量發生衝突。也就是說,最後兩個字節和兩個布爾值「initialized」和「initializing」都存儲在 slot 0 中(第一個和第二個字節)。鑒於 proxyAdmin 地址的最後一個字節是 0xac,由於衝突,initialized 被賦予了 true。同樣,因為 proxyAdmin 地址的第二個字節是 0xab,所以 `initializing`也被賦予了 true。這導致了 initializer() 總是返回 true:

require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized");

攻擊者能夠調用已部署的 Audius 合約的初始化方法,這些合約實現了 Initializable 並更改了本應在初始化中僅設置一次的存儲狀態。攻擊者隨後提交惡意提案並從合約中竊取 1800 萬枚 AUDIO,當時價值 705 枚 ETH。

Fortress協議

Fortress 是一種具有鏈上治理系統的借貸協議。治理合約可以執行修改借貸相關配置的成功提案(即添加抵押品及其對應的抵押品因素)。但是,要成功執行提案,投票所需的最低 FTS 數量為400,000。

由於 FTS 代幣的價格較低,攻擊者在攻擊發生時只需要用約 11 枚 ETH 兌換超過 400,000 枚 FTS。攻擊者使用超過 400,000 個 FTS 創建惡意提案並將其成功執行。

另一個問題是鏈合約的「submit」功能存在允許任何人更新價格

攻擊者在這裡所做的是將這兩個問題聯繫在一起。他們先是借出大量的 ETH,購買 FTS 用於投票和抵押,然後提交了一份惡意提案,並對其進行了投票,該提案因門檻較低而改變了抵押因素。

隨後在預言機中更新了 FTS 的價格,並從合約中借入大量其他 token,獲利約 300 萬美元。

寫在最後

自被引入區塊鏈系統以來,治理系統發生了巨大的變化,但安全挑戰仍然存在。

作為高獲利的攻擊渠道,治理系統是攻擊者的主要目標之一,因此項目在開發過程中應格外注意其安全性。

CertiK 建議智能合約開發人員審查並採用成熟的開源治理框架,以「避免 reinventing the wheel」(指代避免重複創造一個已經存在的基本方法,要充分利用已有的經驗和成果,避免不必要的投入和浪費)。

本文鏈接:https://www.8btc.com/article/6799476

轉載請註明文章出處

(0)
上一篇 2023-03-25 01:49
下一篇 2023-03-25 01:50

相关推荐