我們團隊在整理和復盤 三樹犬事件 時,發現通縮代幣(Deflation Token)或FoT 代幣(Fee-on-Transfer Tokens)是造成這次攻擊的罪魁禍首之一。
我們對通縮代幣可能造成的安全漏洞進行了進一步分析,發現UniswapV2 在對Router01 的升級修復版 路由器02 的實現中引入了漏洞,使得其中的代幣可以被任意用戶取出。我們初步統計發現,有幾個地址持續從中獲利,僅其中一個 地址 就從中獲利1000+ETH,價值超過1600 萬人民幣。
而且,該問題不僅局限於Uniswap,在所有採用類似UniswapV2 Router02 的代碼的平台都存在這個問題,其中包括以太坊上的SushiSwap,BSC 鏈上的PancakeSwap 等。為幫助相關項目方了解該問題,在聯繫了相關項目方後,我們對該缺陷進行公開。
問題揭露與利用方法
Uniswap 是DeFi 領域舉足輕重的去中心化交易所,對於每一對代幣,Uniswap 設置了對應的Pair (流動性池,下稱Pair 或池子)實現了自動做市機制。然而直接調用UniswapV2 的Pair 進行交互(如圖中的Choice 1)對普通用戶而言是有一定的難度的。因此UniswapV2 為用戶進行了一層封裝,即用戶可以通過UniswapV2 的Router 實現代幣的交換(Swap)及流動性的增減(Add/Remove Liquidity)操作,而不必操心Router 與Pair 具體如何實現交互(如圖中的Choice 2)。
(要點1) Router 在代替用戶與Pair 進行代幣交換(Swap)和增減流動性(Add/Remove Liquidity)的時候,要么會直接將錢在用戶和Pair 之間transfer,而不經過Router;或者Router 會用變量amount 記錄用戶和Pair 轉進來的代幣數量,再分別地轉給對應的Pair 或者用戶。也就是說,正常情況下,Router 在一筆交易執行之後,是不會留存有任何Token 的。 (要點2)問題出在Router02 新增的減少流動性的函數實現。 Router02 在實現函數removeLiquidityETHSupportingFeeOnTransferTokens() 的時候,並沒有記錄應當返還給用戶多少代幣,而是調用該種代幣的balanceOf(address(this))balanceOf(地址(這個))removeLiquidityETHWithPermit 操作的時候,就會由於轉手了Fei 代幣,而被發放獎勵。
獲利實現分析
下面我們以交易0x46a8a8eb2fcf75e0a4874d0049d833eaa6432d4b28cb558dc631806be431618b 為例,具體介紹獲利是怎麼實現的。
該用戶監測到該獲利機會,在隨後的幾個塊實現了該交易(部分執行截圖如下)。
從圖中的第2、3 個紅框可以看到,用戶調用該特殊的移除流動性的函數後,Pair 轉給Router02 的錢僅約為2.6e16 wei (不到1 美元),而Router02 轉給用戶的錢卻約有6.9e23 wei,即純獲利Fei 約69 萬個。而產生差距如此巨大的原因就在於Router02 中本來就有將近這麼多錢(見第1 個紅框)。 (圖中可以看到Fei 在transfer 的時候調用了對應的Incentive 函數,感興趣的朋友可以自行查看交易。圖源https://tx.blocksecteam.com/)
用戶在獲得這些大量的Fei Token 之後在同一個交易內直接通過Uniswap 將其轉成WETH (超過297 個)後轉給獲利地址0x4d1d758f0966c6e6de873958e62788300c13f60e。
後續
Fei 項目已經在2021 年7 月4 號移除了該交易對的Incentive 合約,即Fei 項目不會再向Router02 發放獎勵,交易0xfa6e50b964f57a7fd9451af694d18b851a30e58649d878d21b10c20f810723d1。
漏洞分析及建議
漏洞來源
Router02 是UniswapV2 中引入的第二版Router,為了解決Router01 無法處理FoT 代幣(Fee-on-Transfer Tokens)的問題(如圖,來源 Uniswap 官方文檔)。
FoT 代幣會在transfer 過程中收取手續費,導致調用transfer()、transferFrom() 時,接收方實際獲得代幣數量小於發送方發出的代幣數量,致使Router01 無法根據Pair 傳給Router 的數量原封不動地轉給用戶。所以Router02 實現了removeLiquidityETHSupportingFeeOnTransferTokens() 用於解決該問題,將該轉給用戶的,都轉給用戶。