Uniswap和Lendf.Me遭攻擊始末:DeFi樂高組合下的“多米諾”式崩塌

買賣虛擬貨幣

04月18日上午08:58開始,一 DeFi 平臺 Uniswap 被駭客利用重入漏洞實施了攻擊。PeckShield 安全團隊迅速定位到問題,發現駭客利用了 Uniswap 和 ERC777 標準的相容性問題缺陷實施了重入攻擊。

糟糕的是,僅僅在24小時後,於04月19日上午08:45,又一知名DeFi平臺Lendf.Me 也被駭客以類似的手段實施了攻擊。

駭客攻擊的原理是:攻擊者利用以太坊 ERC777 標準的 transferFrom() 回撥機制,在內部呼叫_callTokensToSend()回撥函式時劫持交易 ,並在真正更新餘額的 _move() 函式之前進行惡意攻擊。

在 Uniswap 的攻擊案例中,攻擊者利用此漏洞消耗盡 Uniswap ETH-imBTC 池約1,278個 ETH。而在 Lendf.Me 中,攻擊者則利用它來任意增加內部 imBTC 抵押金額,並透過從其他可用的 Lendf.Me 交易中借入10多種資產(總價值約 2,524萬美元)。

PeckShield 安全團隊認為這是自年初 bZx 遭攻擊之後,又兩起駭客利用 DeFi 系統性風控漏洞實施的攻擊。一個不容忽視的問題是,DeFi市場的風險可能不僅僅侷限於平臺本身,單個平臺的模式創新很可能在與其他平臺業務接軌時產生漏洞風險。

詳細漏洞攻擊細節,我們將在文章後面做詳細介紹。

Figure 1: ERC777 transferFrom()

ERC777 標準的業務組合相容性問題

我們首先介紹下 ERC777 標準,ERC777 出現的目的是對 ERC20 標準進行改進。其不但實現了功能擴充套件,還有 ERC20 標準一樣良好的相容性,願景是成為 ERC20標準的有效繼承者。

該標準擴充套件的功能之一是提供了“hook”機制,可以使普通地址或合約透過註冊一個tokensToSend() hook 函式來控制或拒絕傳送 Token。這原本是在 ERC20基礎上加強了對 Token 的風險控制介面,是一次有益的改進。不過由於 DeFi 專案的可組合特性,一個合約在不同產品之間相互呼叫時,其業務邏輯複雜度也會大大增加,這就給注入程式碼攻擊提供了可能性。

其中最關鍵的部分是,攻擊者可以透過註冊 from 的 tokensToSend()來實行回撥。我們從下面的程式碼片段可以看到,ERC777 標準中可以透過 getInterfaceImplementer()(1,054行)獲得攻擊者的 tokensToSend() 介面,並在第1,056行呼叫此函式。而此處正是駭客劫持交易實施攻擊的入口。

Figure 2: ERC777-Compatible tokensToSend() Hijacking

如2019年4月OpenZeppelin 釋出的帖子以及2019年7月釋出的漏洞利用演示中所述,攻擊者可以自己定義函式 tokensToSend(),並透過 setInterfaceImplementer() 來設定合約中的 hook 函式。

Figure 3: OpenZeppelin's Exploit Demo (Hook Setup)

之後攻擊者就可以像傳統 PC 上的 hook 函式一樣,在 tokensToSend()做任何事情。如下圖所示,攻擊者可以對同一筆交易進行多次交易。

Figure 4: OpenZeppelin's Exploit Demo (Hook Function)

Uniswap攻擊分析

Uniswap 被率先發現利用 ERC777 的相容性問題實施了攻擊。就如此惡意交易在 Bloxy 中的截圖所示(hash:0x9cb1d93d6859883361e8c2f9941f13d6156a1e8daa0ebe801b5d0b5a612723c1),函式內部進行了一次 tokenToEthSwapInput()呼叫。這意味著攻擊者可以先透過操縱交易匯率,然後再用另一筆 imBTC 以較低價格兌換更多的 ETH。

Figure 5: Uniswap Hack

Lendf.Me攻擊分析

在 Uniswap 遭攻擊約24小時後,又一 DeFi 平臺 Lendf.Me 也遭到了駭客攻擊。下面是其中一個攻擊交易的截圖。如圖所示,supply() 函式中呼叫真實轉賬函式 transferFrom()時,被 hook 的攻擊者合約裡嵌入了盜用 Lendf.Me 的 withdraw() 的提幣操作。

Figure 6: Lendf.Me Hack

在這個交易例子中,攻擊者第一次 supply() 時確實向 Lendf.Me 存放了289.99999999個 imBTC,而在第二個 supply() 中,攻擊者只存放0.00000001個 imBTC,但由於攻擊者註冊了 tokensToSend(),所以在執行 doTransferIn() -> IMBTC :: transferFrom()(第1,583行)時,呼叫了攻擊者函式 tokensToSend(),攻擊者函式透過呼叫 Lendf.Me 的 withdraw() 函式把290個 imBTC 直接全部提走。

需要注意的是,正常的業務邏輯應該是專案合約中的 Balance 會減去被攻擊者提走的290個 imBTC,然而當 supply()執行返回時,餘額並未被重置,仍然為290 imBTC(第1,599行)。攻擊者就是透過控制修改 Lendf.Me 中攻擊者的 imBTC 抵押金額,有了足夠大的 imBTC 抵押,攻擊就可以從各種流動交易對中借出所有可用的10多種資產(資產總值25,236,849.44美元)。

Figure 7: Lendf.Me Hack Details

資產流向

攻擊者 0x538359 共計從 Lendf.Me 獲利 25,236,849.44 美元,其中各個 Token 分佈如下:

如上圖,攻擊者在獲利之後,馬上將各個 Token 轉移至其關聯賬號 0xa9bf70 之中,之後攻擊者數十次 透過 1inch.exchange, ParaSwap 等平臺將其中比較搶手的 WETH, PAX, BUSD 等 Token 換成 ETH, DAI, BAT 代幣,另外將其中的 TUSD, USDT 代幣存入 Aave 借貸平臺。至此為止,攻擊者及其關聯賬號的餘額如上所示。

修復建議

PeckShield 安全團隊在此建議開發者,可以採用 “Checks-Effects-Interactions”方法來防止這類重入攻擊。舉個例子,Lendf.Me 的 supply() 裡如果是先更新 token 餘額,再呼叫 doTransferIn() 。這將會讓攻擊在 withdraw() 之後沒有重置餘額的可能性。

另一方面, ERC777 標準特性會不可避免地啟用 hook 機制,因此我們需要檢測並防止所有交易功能產生可以重入的風險。例如,如果 supply()和 withdraw()同時執行時加個互斥鎖,那麼攻擊者就無法在 supply()函式內部執行 withdraw()操作。

最後並不能被忽視的一點是,我們需要認真思考下 DeFi 業務組合可能存在的系統性風險問題,平臺方不僅要確保在產品上線前有過硬的程式碼審計和漏洞排查,還要在不同產品做業務組合時考慮因各自不同業務邏輯而潛在的系統性風控問題。

可能一個新創新,在原平臺一點問題都沒有,但組合接入另一個產品後就可能存在業務邏輯缺陷,進而成為駭客攻擊整個 DeFi 市場的入口。

PS:此次駭客對 Lendf.Me 的攻擊對 DeFi 社羣來說無疑是一場災難,在此建議廣大 DeFi 開發者務必注意業務存在的系統性風控風險,應儘可能和第三方安全公司合作排查一切潛在的安全風險。更多詳情請點選左下角“閱讀原文”檢視英文原版分析報告。

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;