【慢霧分析】DeFi平台Lendf.Me被黑細節分析及防禦建議

tsai
分享
【慢霧分析】DeFi平台Lendf.Me被黑細節分析及防禦建議

據慢霧區情報,以太坊DeFi 平台 Lendf.Me 遭受重入漏洞攻擊。慢霧安全團隊在收到情報後隨即對此次攻擊事件展開分析,並快速定位了問題所在。

據慢霧科技反洗錢(AML)系統初步統計分析,Lendf.Me 被攻擊累計的損失約24,696,616 美元,具體盜取的幣種及數額為:

WETH: 55159.02134,
WBTC: 9.01152,
CHAI: 77930.93433,
HBTC: 320.27714,
HUSD: 432162.90569,
BUSD: 480787.88767,
PAX: 587014.60367,
TUSD: 459794.38763,
USDC: 698916.40348,
USDT: 7180525.08156,
USDx: 510868.16067,
imBTC: 291.3471

之後攻擊者不斷通過1inch.exchange、ParaSwap、Tokenlon 等DEX 平台將盜取的幣兌換成ETH 及其他代幣。

以下是詳細分析過程。

攻擊細節

本次對Lendf.Me實施攻擊的攻擊者地址為0xa9bf70a420d364e923c74448d9d817d3f2a77822,攻擊者通過部署合約0x538359785a8d5ab1a741a0ba94f26a800759d91d對Lendf.Me進行攻擊。

通過在Etherscan 上查看攻擊者的其中一筆交易:https://etherscan.io/tx/0xae7d664bdfcc54220df4f18d339005c6faf6e62c9ca79c56387bc0389274363b

我們發現,攻擊者首先是存入了0.00021593 枚imBTC,但是卻從Lendf.Me 中成功提現了0.00043188 枚imBTC,提現的數量幾乎是存入數量的翻倍。那麼攻擊者是如何從短短的一筆交易中拿到翻倍的餘額的呢?這需要我們深入分析交易中的每一個動作,看看究竟發生了什麼。

通過把該筆交易放到bloxy.info 上查看,我們能知道完整的交易流程

通過分析交易流程,我們不難發現攻擊者對Lendf.Me 進行了兩次supply() 函數的調用,但是這兩次調用都是獨立的,並不是在前一筆supply() 函數中再次調用supply () 函數。

緊接著,在第二次supply() 函數的調用過程中,攻擊者在他自己的合約中對Lendf.Me 的withdraw() 函數發起調用,最終提現

在這裡,我們不難分析出,攻擊者的withdraw() 調用是發生在transferFrom 函數中,也就是在Lendf.Me 通過transferFrom 調用用戶的tokensToSend() 鉤子函數的時候調用的。很明顯,攻擊者通過supply() 函數重入了Lendf.Me 合約,造成了重入攻擊,那麼具體的攻擊細節是怎樣的呢?我們接下來跟進Lendf.Me 的合約代碼。

代碼分析

Lendf.Me 的supply() 函數在進行了一系列的處理後,會調用一個doTransferIn 函數,用於把用戶提供的幣存進合約,然後接下來會對market 變量的一些信息進行賦值。回顧剛才說的攻擊流程,攻擊者是在第二次supply() 函數中通過重入的方式調用了withdraw() 函數提現,也就是說在第二次的supply() 函數中,1590 行後的操作在withdraw() 之前並不會執行,在withdraw() 執行完之後,1590 行後的代碼才會繼續執行。這裡的操作導致了攻擊者可提現餘額變多。

我們深入分析下supply() 函數

根據上圖,可以看到,在supply()函數的末尾,會對market和用戶的餘額進行更新,在這之前,用戶的餘額會在函數的開頭預先獲取好並保存在localResults.userSupplyCurrent,如下:

通過賦值給localResults變量的方式,用戶的轉入信息會先暫時保存在這個變量內,然後此時攻擊者執行withdraw()函數,我們看下withdraw()函數的代碼:

這裡有兩個關鍵的地方:

1、在函數的開頭,合約首先獲取了storage的marketsupplyBalance變量。

2、在withdraw()函數的末尾,存在同樣的邏輯對market用戶的餘額信息( supplyBalance)進行了更新,更新值為扣除用戶的提現金額後的餘額。

按正常的提現邏輯而言,在withdraw()單獨執行的時候,用戶的餘額會被扣除並正常更新,但是由於攻擊者將withdraw()嵌入在supply()中,在withdraw()函數更新了用戶餘額(supplyBalance)後,接下來在supply()函數要執行的代碼,也就是1590行之後,用戶的餘額會再被更新一次,而用於更新的值會是先前supply()函數開頭的保存在localResults中的用戶原先的存款加上攻擊者第一次調用supply()函數存款的值。

在這樣的操作下,用戶的餘額雖然在提現後雖然已經扣除了,但是接下來的supply() 函數的邏輯會再次將用戶未扣除提現金額時的值覆蓋回去,導致攻擊者雖然執行了提現操作,但是餘額不但沒有扣除,反而導致餘額增加了。通過這樣的方式,攻擊者能以指數級別的數量提現,直至把Lendf.Me 提空。

防禦建議

針對本次攻擊事件慢霧安全團隊建議:

  1. 在關鍵的業務操作方法中加入鎖機制,如:OpenZeppelin 的ReentrancyGuard
  2. 開發合約的時候採用先更改本合約的變量,再進行外部調用的編寫風格
  3. 項目上線前請優秀的第三方安全團隊進行全面的安全審計,盡可能的發現潛在的安全問題
  4. 多個合約進行對接的時候也需要對多方合約進行代碼安全和業務安全的把關,全面考慮各種業務場景相結合下的安全問題
  5. 合約盡可能的設置暫停開關,在出現「黑天鵝」事件的時候能夠及時發現並止損
  6. 安全是動態的,各個項目方也需要及時捕獲可能與自身項目相關的威脅情報,及時排查潛在的安全風險

附:

OpenZeppelin ReentrancyGuard: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol

原文連結

衍伸閱讀


立即加入 Telegram 獲得最精準的區塊鏈新知、加密貨幣動態!