這是自年初 bZx 遭攻擊之後,又兩起駭客利用 DeFi 系統性風控漏洞實施攻擊。
4 月18日上午 8:58 開始, 一 DeFi 平台 Uniswap 被駭客利用重入漏洞實施了攻擊。PeckShield 安全團隊迅速定位到問題,發現駭客利用了Uniswap 和 ERC777 標準的兼容性問題缺陷實施了重入攻擊。
糟糕的是,僅僅在 24 小時後,於 4 月19日上午 8:45,又一知名 DeFi 平台 Lendf.Me也被駭客以類似的手段實施了攻擊。
駭客攻擊的原理是:攻擊者利用以太坊 ERC777 標準的transferFrom() 回調機制,在內部調用 _callTokensToSend() 回調函數時劫持交易,並在真正更新餘額的_move() 函數之前進行惡意攻擊。
延伸閱讀:Lendf.me 神轉折!駭客將「7.5億贓款」全數歸還,疑因經驗不足 IP 洩漏身份遭掌握
在 Uniswap 的攻擊案例中,攻擊者利用此漏洞消耗盡 Uniswap ETH-imBTC 池約 1,278 個ETH。而在 Lendf.Me 中,攻擊者則利用它來任意增加內部 imBTC 抵押金額,並通過從其他可用的Lendf.Me 交易中借入10多種資產(總價值約2, 5 24萬美元)。
PeckShield 認為這是自年初 bZx 遭攻擊之後,又兩起駭客利用 DeFi 系統性風控漏洞實施的攻擊。一個不容忽視的問題是,DeFi 市場的風險可能不僅僅局限於平台本身,單個平台的模式創新很可能在與其他平台業務接軌時產生漏洞風險。
延伸閱讀:探討|回顧幣圈驚魂 24 小時,交易所、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() 調用。
這意味著攻擊者可以先通過操縱交易匯率,然後再用另一筆i mBTC 以較低價格兌換更多的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 開發者務必注意業務存在的系統性風控風險,應盡可能和第三方安全公司合作排查一切潛在的安全風險。
更多詳情請閱讀英文原版分析報告。
?相關報導?
波場進軍 DeFi!孫宇晨宣布推出穩定幣借貸平台 JUST,欲實現「真正的公平正義」
揭秘借貸協議中的「清算人」:如何在 DeFi 賺取豐厚利潤?
Defi 新手入門|一文看懂 Uniswap,什麼是以太坊上的「代幣交換協議」
讓動區 Telegram 新聞頻道再次強大!!立即加入獲得第一手區塊鏈、加密貨幣新聞報導。
LINE 與 Messenger 不定期為大家服務