作者:深圳零時科技
本文,我們將詳細介紹搶跑者是如何進行攻擊的。
HopeLend是一個去中心化的虛擬貨幣借貸平台,能夠在無需雙方單獨撮合的情況下,根據資金池狀態實現即時貸款。類似於Aave等DeFi項目,HopeLend的運行模式如下圖:
簡單來講,黑客攻擊流程主要分爲兩部分:
利用Hopelend的hEthWBTC交易池流動性不足(流動性爲0)擡高hEthWBTC的價值,然後通過borrow掏空所有代幣(HOPE,stHOPE,wstETH,WETH,USDT,USDC);
利用rayDiv精度丟失問題,掏空從Aave中flashloan的其中2000 WBTC給Hopelend中存入的2000 WBTC。(掏空黑客前期攻擊投入的所有WBTC)。
在具體分析攻擊事件之前,我們需要簡單了解一下HopeLend的相關內容。
Hopelend是去中心化借貸平台,用戶通過deposti存入underlyingAssets(標的資產),獲得對應的hToken;反之,通過withdraw取出underlyingAssets時,銷毀對應的hToken。
其中,underlyingAssets標的資產和hToken的兌換比例是通過liquidityIndex(流動性指數)來控制的,簡單來講liquidityIndex(流動性指數)就是hToken的價值。例如,當liquidityIndex爲2時,1個對應的hToken可以兌換2個對應的underlyingAssets(標的資產)。其中,liquidityIndex是通過收益進行計算的。計算方式如下:
對應的代碼如下:
?在此次攻擊中,簡單來說,黑客通過操縱liquidityIndex(流動性指數)來擡高hToken的價值,使得hToken的價值失真。最終使用很小單位的hToken來借貸大額的其他標的資產。從而掏空Hopelend其他池子的underlyingAssets(標的資產)。隨後,黑客通過利用rayDiv精度丟失問題,反復deposit和withdraw,最終掏空轉給池子的所有WBTC完成攻擊。
黑客通過deposit存入標的資產WBTC,獲得mint的hEthWBTC,然後通過重復的flashloan來操縱hEthWBTC的流動性指數liquidityIndex,使hEthWBTC的價格虛高,最後利用極小的hEthWBTC作爲抵押物,通過borrow掏空除了WBTC之外的所有標的資產。
首先,黑客從Aave中利用flashloan貸了2300 WBTC,向Hopelend中deposit了2000 WBTC。同時,WTBC對應的池子向黑客mint了2000 hEthWBTC作爲存款憑證。隨後,黑客通過Hopelend的flashloan貸了2000 WBTC,然後向Hopelend的池子中transfer轉入2000 WBTC,接着從Hopelend中withdraw了1999.99999999 WBTC,剩下0.00000001 WBTC(最小單位)。向Hopelend的池子中transfer和withdraw的操作只有在第一次flashloan中進行。
?這是因爲,黑客向Hopelend中deposit了2000 WBTC,Hopelend隨後mint了2000對應的hToken(hEthWBTC)作爲存款憑證。隨後,黑客通過Hopelend的flashloan貸了2000 WBTC,隨後向標的資產對應的池子內transfer了2000 WBTC後withdraw了1999.99999999 WBTC。因此,該池子未初始化,所以對應的liquidityIndex爲1,因此,池子銷毀了1999.99999999 hEthWBTC,剩余0.00000001 hEthWBTC。
我們看一下,Hopelend在flashloan中是如何更新liquidityIndex的
首先,IERC20(reserveCache.hTokenAddress).totalSupply() + reserve.accruedToTreasury 是hToken對應的總價值,premiumToLP爲本次flashloan的收益,也就是新增價值。因爲flashloan的貸款利率是0.09%,且池子獲得利潤的30%歸項目方,70%歸流動性提供方,所以每次黑·客通過flashloan借貸2000 WBTC後,給池子產生的利潤爲2000 * 0.09% * 70% = 1.26 WBTC。所以在上面的公式中,premiumToLP 爲 1.26 WBTC。
因爲reserve.accruedToTreasury 爲 0,所以簡單來講,flashloan後hToken的價值(liquidityIndex)=(池子新增的價值 / 池子hToken的總價值 + 1) * 池子當前hToken的價值。所以,黑客要擡高hToken的價值,就是讓池子hToken的總價值盡可能小,這就解釋了爲什么黑客在flashloan借貸了2000 WBTC後要把2000 WBTC transfer轉給池子。
因爲 withdraw 操作會銷毀(burn)hToken,但是當前如果不給池子轉账,那么池子沒有資產(最开始存的2000WBTC目前由於進行閃電貸中所以已經鎖定),黑客就無法通過withdraw來銷毀對應的hToken。
黑客爲了讓池子的hToken的總價值盡可能小,所以黑客withdraw了1999.99999999 WBTC,剩下0.00000001 WBTC(最小單位)。所以,池子也銷毀了1999.99999999 hEthWTBC而剩下了0.00000001 hEthWTBC(最小單位)。由於WBTC對應了hEthWTBC的池子未初始化,所以此時的liquidityIndex爲1,當前池子的總價值就是0.00000001 hEthWTBC(最小單位)。
經過第一次flashloan後,hToken的價值liquidityIndex被更新爲,(126000000 * 10^27 / 1 + 1)* 1*= 126000001000000000000000000000000000。此時,0.00000001 hEthWTBC價值爲1.26000001 WBTC。
第二次,黑客通過flashloan借貸2000 WBTC,因爲第一次借貸後,liquidityIndex爲126000001000000000000000000000000000,所以通過算法得到此時liquidityIndex爲252000000999999999999999999948221218。
?黑客通過重復執行flashloan,最終將hEthWTBC的liquidityIndex提升到7560000001000000000000000009655610336,也就0.00000001 hEthWTBC可以兌換75.60000001 WBTC。
下圖是每次flashloan後hEthWTBC的liquidityIndex的值
因爲,池子中仍有黑客的0.00000001 hEthWBTC(價值75.60000001 WBTC)且價值巨大。所以,黑客利池子中的抵押物(0.00000001 hEthWBTC),通過borrow借空了所有代幣(HOPE,stHOPE,WETH,USDT,USDC)。
黑客利用rayDiv精度丟失問題,重復deposit和withdraw操作,掏空前期攻擊投入的所有WBTC。
黑客首先存入了151.20000002 WBTC,隨後取出了113.40000000 WBTC。因爲,此時的liquidityIndex已經提升到7560000001000000000000000009655610336,所以黑客通過deposit存入151.20000002 WBTC後,池子同樣mint了0.00000002 hEthWBTC。黑客通過withdraw取出了113.40000000 WBTC,應該銷毀的hEthWBTC爲0.000000019999999998015872個。但是,由於solidity截斷導致只銷毀了0.00000001 hEthWBTC。
具體看一下銷毀(Burn)的代碼
其中,_burnScaled爲縮放需要銷毀的hToken的函數。
我們可以看到,需要銷毀的hToken數量 =(取出標的資產的數量 / hToken的流動性指數)。但是這裏爲了減少數學運算的gas消耗,此處除法使用的是rayDiv,代碼如下:
因爲,需要銷毀的hToken的數量的計算公式爲銷毀的hToken數量 = (取出資產的數量 * 10^27 + (hToken的流動性指數 / 2) ) / hToken的流動性指數。此時,需要取出的資產數量爲113.40000000 WBTC, 此時hEthWBTC的流動性指數爲7560000001000000000000000009655610336。通過python計算我們可以得到
需要銷毀的數量爲(1.9999999998015872 * 10^-8)個hEthWBTC。但是因爲此處爲evm opcode div進行的整數除法運算,所以,此處相當於做了一個地板除(floor division)舍去了小數位。因此,最終得到需要銷毀的數量爲(1 * 10^-8)個hEthWBTC也就是0.00000001 hEthWBTC,相當於只銷毀了75.6 WBTC價值的hEthWBTC。所以,至此黑客通過精度丟失漏洞獲利(113.4 - 75.6 = 37.8 WBTC)。
隨後,黑客通過繼續deposit存入75.60000001 WBTC獲得池子mint的0.00000001 hEthWBTC(因爲此時hEthWBTC的流動性指數爲7560000001000000000000000009655610336,相當於1個最小單位的hEthWBTC,也就是0.00000001 hEthWBTC價值是75.60000001 WBTC)。因此,池子又剩下0.00000002 hToken。接着,黑客通過withdraw取出了113.40000000 WBTC,由於solidity的截斷,導致只銷毀了0.00000001 hToken。
?也就是說,黑客通過deposit存入75.60000001 WBTC然後通過withdraw取出了113.40000000 WBTC,可以憑空得到37.8000000 WBTC,黑客通過持續重復此操作,最終掏空了之前投入的WBTC,從而歸還了Aave的貸款。至此,所有攻擊流程均已完成。
黑客首先利用標的資產對應的池子流動差的原因,反復操作標的資產對應的hToken的流動性指數,使其價值失真。隨後,通過極小的hToken做抵押借出其他所有的標的資產。接着,利用合約存在的除法精度丟失的漏洞,反復存取掏空黑客攻擊中投入的標的資產。至此,黑客完成了一次針對DeFi項目Hopelend的一次復雜的攻擊,掏空了HopeLend的所有資產。
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播信息之目的,不構成任何投資建議,如有侵權行為,請第一時間聯絡我們修改或刪除,多謝。