HashKey 曹一新:深入分析 DeFi 經濟攻擊的常見模式
本文發布於HashKey Research,原文標題:《DeFi 經濟攻擊的一般模式分析》,作者:曹一新
2020 年以來,以太坊 DeFi 生態中有十多起利用閃電貸的大規模攻擊事件陸續被媒體曝光(如表 1 所示),而這些事件已經呈現出明顯的模式化和重複性特徵。有別於技術漏洞導致的攻擊事件(編號 6、8、11),其它幾起事件呈現了對 DeFi 生態經濟系統漏洞的攻擊手法。從表面上看,其共性是主攻協議都與某些 AMM 協議關聯,而攻擊者通過操縱 AMM 資產池內的資產價格或者資產數量使關聯協議蒙受損失,我們不妨稱之為「經濟攻擊」。至今出現的經濟攻擊分為「哄抬套利」和「操縱預言機」兩種手法,本文歸納發動經濟攻擊的必要非充分條件及一般攻擊模式,從而推斷出攻擊者攻擊 DeFi 系統的「命門」所在,為抵禦此類安全風險提出若干警示。
表 1. 閃電貸攻擊事件
「哄抬套利」攻擊
「哄抬套利」攻擊的原理與 CeFi 常見的 Pump-and-Dump 市場操縱行為或者鏈上交易容易碰到的「front running」攻擊本質上並無差異,都是先想辦法借助他人的資本抬高自有資產的價格再高價賣出獲利。DeFi 生態中此類經濟攻擊事件之所以能夠成功,都與至少兩個核心模塊------攻擊目標和 AMM 有關,並且這兩個模塊通過條件一相互關聯。
條件一:攻擊目標與 AMM 之間存在資產轉移關係,並能由用戶自主觸發相關智能合約執行資產轉移。
這裡的攻擊目標可以是機槍池、借貸平台、槓桿交易平台等 DeFi 模塊。機槍池是運行著一定投資策略的智能合約,可以把它類比於一個基金,為用戶提供代理理財業務,用戶將自有資產存入機槍池以期獲得收益,例如 Yearn 、Harvest ;借貸平台為出借方和貸方提供服務,賺取利息差,貸方一般要先超額抵押一部分資產,例如 Compound 、 Aave ;槓桿交易平台允許投資者抵押一定資產作為保證金進行槓桿交易,例如 bZx 。AMM 通過一個定價函數實現自動做市商交易,用戶可兌換資產或作為流動性提供商(LP)參與流動性挖礦,在此不再贅述。
「哄抬套利」攻擊的一般步驟
條件一是 DeFi 系統存在被「哄抬套利」攻擊的必要非充分條件,實際攻擊過程中還要考慮到資金量、手續費、智能合約在執行交易前設置的檢查點等因素。攻擊者可通過建立優化模型找到最優參數,預測其「哄抬套利」收益來決定是否採取行動。這種攻擊手法的一般操作步驟如下(結合圖 1 所示):
圖 1. 哄抬套利攻擊的基礎模型(序號代表攻擊步驟,實線表示必要步驟,虛線代表或有步驟;攻擊目標的淨值計算環節和 AMM 的定價函數在設計上存在被黑客利用的風險)
假設 AMM 資產池裡的流動性資產為 X、Y,流動性代幣為 C。
第一步,準備。持有即將被哄抬的初始資產 Y 及用於觸發攻擊目標自動執行策略的初始資產 A。
第二步,哄抬。將資產 A 發送至攻擊目標的相關智能合約,獲得代幣 B (代表在機槍池、借貸平台、槓桿交易平台等攻擊平台中的頭寸,以下稱為「頭寸代幣」),並觸發智能合約向 AMM 資產池投入資產 X,獲得資產 Y 或流動性代幣 C,並抬高 AMM 資產池內資產 Y 的價格。
第三步,套利。攻擊者將步驟二中的資產 Y 投入 AMM 資產池,以抬高後的價格獲得資產 X 或流動性代幣 C。需要說明的是,第二、三步中的操作對應於 swap (X、Y 之間交換)或流動性挖礦(X 或 Y 與 C 之間交換)。對於三個及以上幣種的 AMM,這裡的 X 或 Y 可視為資產組合。
第四步,收尾。攻擊者根據代幣 B 的最新淨值及後續交易計劃決策是否贖回資產 D。
對於流動性充足的資產池,為了在 AMM 裡製造可觀的價格滑點,往往需要投入很大的資金量,故攻擊者一般會從閃電貸借出初始資產。若閃電貸可供借貸的資產類別不滿足要求,攻擊者會去某些 AMM 或借貸平台通過 swap、流動性挖礦、借貸等方式獲得;也不排除攻擊者直接去與攻擊目標關聯的 AMM 獲取。若攻擊者在第一步的準備過程中採用了閃電貸,那麼在第四步就還需在同一筆攻擊交易中歸還閃電貸。
攻擊者獲利分析
若攻擊者不贖回頭寸代幣 B,那麼當初投入的資產 A 就是成本上限,只有當套利所得大於這一成本才能獲利,這種情況目前只在提供槓桿資金的攻擊目標中成功過,攻擊者以較少的保證金成本 A 撬動攻擊目標的大量資金 X 為其在 AMM 裡抬高資產 Y 的價格。但前提是在執行交易前攻擊者要避開攻擊目標對其保證金淨值是否跌破清算線的檢查點,表 1 中編號為 1 的攻擊事件就是典型案例。
這裡有兩點值得注意:
這裡的關鍵是攻擊目標發行的份額代幣 B 為攻擊者的初始資產提供了隔離保護作用,攻擊者往往會先操縱 AMM 裡的價格使得其中資產 X 大幅貶值,犧牲攻擊目標的基金資產撬動 AMM 內的價格滑點往有利方向偏移,使攻擊者在保證自有資產不大幅貶值的情況下實現可觀的套利,表 1 中編號為 10 的攻擊事件就是典型案例。
虧損分析
小節 1.2 分析了在「哄抬套利」攻擊模式下攻擊者獲利的原理,本節進一步分析誰是虧損的「冤大頭」?
站在攻擊目標的視角,在整個攻擊過程中,其底層資產淨值的變化來源於:
- 攻擊者投入資產 A 獲得份額;
- 與 AMM 發生資產交換的差額,即公式(6)所示;
- 攻擊者贖回份額。
若攻擊者最終用頭寸代幣 B 贖回份額,則攻擊目標資產價值變化為:
若攻擊者沒有贖回初始資產,則相當於攻擊目標淨收入資產 A,公式(10)變為,
對於 AMM 而言,其恆定乘積定價方程保證兌換操作前後,其資產池內資產數量乘以資產價格的總價值保持恆定;而在注入流動性的情況下,新發行流動性代幣的每份額價值與原有流動代幣每份額代幣的價值一致。故每次攻擊者或機槍池與之交互時,都是按 AMM 內部價格等額交換的。即使攻擊者利用巨額資金使得 AMM 的價格偏離市場價格,AMM 的流動性提供者只會暫時遭到價格偏差帶來的無常損失,後續會有套利者將價格搬平,而套利者獲得的受益來源於金融業務模塊損失的一部分。
案例舉例
表 1 中編號為 1 和 10 的事件都符合上述「哄抬套利」攻擊的一般模式,且易於複刻。在 Yearn 機槍池閃電貸攻擊事件中,攻擊者按照前面 1.1 總結的做了四個步驟:
第一步,從 Aave 和 dYdX 閃電貸借出 ETH,抵押到 Compound 獲得大量 DAI 和 USDC。一部分 DAI 留用,將另一部分 DAI 和 USDC 抵押至 Curve 的 3Pool 做流動性挖礦,獲得流動性代幣 3CRV。用全部 3CRV 贖回 USDT,這樣就準備好了資產 Y (USDT)和資產 A (DAI)。
第二步,將 DAI 抵押至 Yearn 的 yDAI Vault,獲得 yDAI (即頭寸代幣 B)。這個合約會自動觸發將 DAI (資產 X)投入到 Curve 3Pool 的流動性挖礦投資策略,獲得 3CRV (代幣 C)。由於 3CRV 中 DAI 的數量變多,根據定價函數更新後 DAI 發生貶值,USDT 增值。
第三步,將步驟一準備好的 USDT 投入 Curve 3Pool,高價換出流動性代幣 3CRV (代幣 C)。這時候攻擊者持有 3CRV 數量大於步驟一中的初始數量,套利成功。
第四步,用步驟二中的 yDAI 贖回 DAI (資產 D)。雖然 yDAI 的淨值有所下降,但這部分虧損小於套利所得。攻擊者在一筆閃電貸交易中重複上述步驟 10 次,歸還閃電貸,最終累計得到大量 3CRV 和 USDT,編號為 1 的 bZx 攻擊事件中,攻擊者從閃電貸借出 ETH (資產 A),先抵押一部分至 Compound 借出 WBTC (資產 Y),再抵押一部分 ETH 至 bZx 觸發其 5 倍槓桿做空 ETH 交易,獲得代表槓桿頭寸的 sETHwBTC5x (頭寸代幣 B)。bZx 合約為其提供槓桿資金向 Uniswap 賣出大量 ETH (資產 X)獲得 WBTC (資產 Y),將 WBTC 價格抬升 3 倍。攻擊者賣出 WBTC (資產 Y),得 ETH (資產 X),一部分歸還閃電貸,另一部分用於贖回 Compound 裡的抵押物,而沒有贖回槓桿頭寸 sETHwBTC5x,因為此時早已觸發清算線,而攻擊者發現合約漏洞避開了檢查點。
編號為 3 的攻擊事件利用了 Balancer 支持的一種利用銷毀自身代幣的方式來替代收取手續費行為的「通縮型」代幣 STA,通過反復交易 STA 來使得其數量不斷減少,從而價格不斷抬升,屬於特定條件下的案例,不易複刻。
「操縱預言機」攻擊
「操縱語言機」攻擊可以認為是「哄抬套利」攻擊的一種對稱操作,其必要條件為:
條件二:攻擊目標依賴 AMM 提供的信息對其內部資產進行定價。
圖 2. 操縱預言機攻擊的基礎模型(序號代表攻擊步驟,實線表示必要步驟,虛線代表或有步驟;攻擊目標的淨值計算環節和 AMM 的定價函數在設計上存在被黑客利用的風險)
這種情況下攻擊者雖然無法利用攻擊目標內的資產去哄抬 AMM 內某資產的價格,但可以考察 AMM 模塊作為預言機能否被操縱,從而哄抬攻擊目標內的資產。
攻擊目標依賴 AMM 提供信息的主要目的有兩種:
- 對抵押物進行估值;
- 對頭寸代幣進行定價。
我們也可將其視為「淨值計算」,而攻擊者則專門尋找在淨值計算中與實際情況出現偏差的合約進行操縱。
表 1 中編號為 5 和 9 的事件中攻擊者利用了同一種預言機漏洞。Cheese Bank 和 Warp Finance 這兩個機槍池都允許用戶超額抵押 Uniswap 的流動性代幣 UNI-V2 來借出穩定幣,而抵押品 UNI-V2 的價值通過一個自行編寫的預言機合約來計算。該合約利用相應 Uniswap 流動性池的資產數量、資產價格及 UNI-V2 的發行量計算,但資產數量和資產價格是從兩個不關聯的渠道獲取------資產數量直接從 Uniswap 流動性池餘額獲取,而資產價格從 Uniswap 官方提供的一個時間加權平均預言機獲取。這使得攻擊者能夠通過改變 Uniswap 流動性的資產數量,在資產價格維持不變的情況下提高抵押品 UNI-V2 的名義價值從而借出更多的穩定幣。這種類型的攻擊主要是因為預言機合約設計不夠嚴謹導致的,但仍然重複發生兩次,足以引起 DeFi 項目的警惕。
表 1 中編號為 2 的事件中,攻擊者通過操縱 bZx 為抵押物 sUSD 估值的預言機(Uniswap 和 Kyber),抬高 sUSD 的價格,從而借出更多 ETH。
表 1 中編號為 3、7 的事件則通過操縱預言機報價,提高機槍池內份額代幣的淨值,從而兌換出更多資產,重複多次累計收益。
「操縱預言機」攻擊的一般步驟為:
第一步,準備。獲得用於操縱 AMM 預言機的資產 Y 及準備存入攻擊目標的資產 A。
第二步,抵押。將資產 A 抵押至攻擊目標,獲得代表抵押物的頭寸代幣 B,有些情況下,不發放頭寸代幣 B,只在智能合約內部記賬。
第三步,操縱。將資產 Y 投入 AMM 兌換資產 X,改變 AMM 流動性池內資產的比例從而改變報價,更新攻擊目標合約內資產 A 或頭寸代幣 B 的定價;
第四步,收尾。若為借貸業務,則通過抬高的抵押物估值借出更多資產並不再歸還;若為機槍池業務,則通過抬高價格後的頭寸代幣 B 贖回資產,獲得增值收益。
討論與啟示
本文總結了 DeFi 系統遭受經濟攻擊的一般模式和命名所在,發現「哄抬套利」和「操縱預言機」攻擊模式本質上都是對淨值計算環節的利用和操縱行為。故而在設計 DeFi 系統的時候,妥善處理這一環節至關重要。最根本的預防措施就是取消用戶自動觸發交易策略鏈式執行或更新淨值的權限,從根本上阻斷攻擊者完成一整套連貫的操縱行為。
例如針對「哄抬套利」的攻擊策略,具體的做法可能是通過一個智能機器人識別用戶的投資行為,按固定時間段批量計算淨值及分配資金至策略池。但這種方法打破了原有原子交易的優勢,可能會引發用戶體驗不佳、成本抬高、機器人發送的交易被控制等新問題。另一方面,目前出現的 DeFi 組合模型大部分還停留在簡單的 A->B 模式,而生態內已經出現了 C->A->B (例如 Alchemix)的多層嵌套關聯,這些關聯關係可能無法避免涉及到智能合約之間的自動觸發,仍然可能存在系統性的經濟漏洞。
針對 「操縱預言機」所描述的攻擊風險,目前一些機槍池設置了滑點限制,約束被報價資產的價格變動範圍。但即便如此,攻擊者還是能找到一些超過成本的套利空間並通過多次實施來累積套利總額(例如編號為 4 的 Harvest 攻擊事件)。
閃電貸在整個攻擊環節中屬於錦上添花的角色,可為攻擊者提供大量初始資金及試錯成本僅為交易 gas 費的攻擊機會。不過近期隨著 ETH 價格的增長,構建如此複雜的攻擊策略的智能合約所需花費的交易 gas 費已經非常昂貴,最近發生的 yearn 機槍池的單筆閃電貸攻擊交易就耗費了攻擊者 1.933 個 ETH (當時折合 3088 美元)。
綜上所述,這些經濟攻擊事件表明,AMM 的設計機制很容易被攻擊者利用來對關聯產品進行攻擊,並且具備特定的攻擊模式。通過破除攻擊模式依賴的必要條件可能會引發新的問題,還沒有一種萬全的策略完全消除此類風險。通過添加一定的約束條件來使得套利空間大大小於攻擊者的期望值,或許是一種值得探討的方法,這需要項目方對自己及關聯協議的經濟系統有全面且深入的研究。