2021 年08 月04 日,據慢霧區消息,跨鏈收益率平台Popsicle Finance 的Sorbetto Fragola 產品遭受黑客攻擊,慢霧安全團隊第一時間介入分析,並將結果分享如下。

攻擊背景

在本次攻擊中,攻擊者通過創建3 個攻擊合約來完成對Sorbetto Fragola 的攻擊,以下是本次攻擊涉及的具體地址:

攻擊者:

H1:0x3A9D90eD069021057d9d11E78F142F2C4267934A

H2:0xf9E3D08196F76f5078882d98941b71C0884BEa52

攻擊合約:

C1:0xdFb6faB7f4bc9512d5620e679E90D1C91C4EAdE6

C2:0x576cf5f8ba98e1643a2c93103881d8356c3550cf

C3:0xd282f740bb0ff5d9e0a861df024fcbd3c0bd0dc8

Sorbetto Fragola:

0xc4ff55a4329f84f9Bf0F5619998aB570481EBB48

攻擊對象

通過官方的介紹我們可以知道被攻擊的Sorbetto Fragola 產品主要是用於幫助用戶管理Uniswap V3 頭寸,以避免用戶在Uniswap V3 做市的頭寸超出所選定的價格範圍。用戶可以在Sorbetto Fragola 中存入提供流動性對應的兩種代幣,Sorbetto Fragola 會給到用戶Popsicle LP (PLP) 憑證,用戶使用此憑證可以獲取獎勵並取回抵押的流動性資金,同時此憑證也是可以隨意轉移給其他用戶的。

攻擊核心

此次攻擊的核心在於,Sorbetto Fragola 中通過用戶持有的PLP 憑證數量來參與計算用戶所能獲得的獎勵,但PLP 憑證是可以隨意轉移給其他用戶的,但其憑證轉移的過程中沒有進行獎勵結算轉移等操作。這就導致了只要持有PLP 憑證就可以立即獲取獎勵。最終造成同個PLP 憑證卻能在同個時間節點給多個持有者帶來收益。接下來我們對整個攻擊細節進行詳細分析。

攻擊細節

攻擊首先通過H1 地址創建了攻擊合約C1、C2 與C3,隨後攻擊者通過H2 地址調用了攻擊合約C1 開始進行具體的攻擊,交易為:

0xcd7dae143a4c0223349c16237ce4cd7696b1638d116a72755231ede872ab70fc。

通過分析此交易我們可以發現,其先從AAVE 中利用閃電貸借出了30,000,000 個USDT、13,000 個WETH、1,400 個WBTC、30,000,000 個USDC、3,000,000 個DAI、200,000 個UNI,為後續在Sorbetto Fragola 中提供流動性獲得PLP 憑證做準備。

隨後攻擊者調用Sorbetto Fragola 合約的deposit 函數存入提供流動性對應的兩種代幣(這里以攻擊者首次存入的WETH 與USDT 代幣為例),其會先通過checkDeviation 與updateVault 修飾器分別檢查價格與更新獎勵。價格檢查主要是針對價格是否出現大波動被操控等情況,這裡不做展開。而獎勵更新就與本次攻擊密切相關了,我們切入分析:

可以看到其調用了_updateFeesReward 函數進行具體的更新操作,我們跟進此函數:

從上圖我們可以很容易的發現其先通過positionLiquidity 函數獲取tickLower 與tickUpper 範圍內合約所持有的流動性數量。然後通過_earnFees 函數從Uniswap V3 Pool 中收取提供流動性獎勵。之後再通過_tokenPerShare 函數計算每個PLP 憑證所能分得的流動性獎勵。最後通過_fee0Earned 與_fee1Earned 函數來計算用戶所持有的PLP 憑證數量可以獲得多少獎勵,並使用

user.token0Rewards 與user.token1Rewards 變量進行記錄,如下圖所示:

但由於此時攻擊者剛進行充值操作,還未獲得PLP 憑證,因此其user.token0Rewards 與user.token1Rewards 變量最終記錄的自然是0。

看到這裡你可能已經意識到問題所在了,既然user.token0Rewards 與user.token1Rewards 變量記錄的獎勵是根據用戶持有的PLP 憑證進行計算的,且PLP 憑證是可以轉移的,那麼是否只要持有PLP憑證再去觸發此變量記錄獎勵就可以讓我們獲得獎勵。答案自然是肯定的。我們繼續看deposit 函數:

在獎勵更新之後通過liquidityForAmounts 函數計算出在目標價格區間內用戶提供資金所佔的流動性然後調用Uniswap V3 Pool mint 函數注入流動性。隨後通過_calcShare 計算出Sorbetto Fragola 所需要鑄造給用戶的PLP 憑證數量。

在攻擊者獲得PLP 憑著後也正如我們所想的那樣將PLP 憑證轉移給其他地址,並調用Sorbetto Fragola 合約collectFees 函數來進行獎勵記錄。

通過上圖的PLP 憑證鏈上轉移記錄我們可以看到,在攻擊合約C1 獲得PLP 憑證後,將其轉移給了攻擊合約C2,隨後調用了collectFees 函數。之後攻擊合約C2 再將PLP 憑證轉移給攻擊合約C3 再次調用了collectFees。最後攻擊合約C3 將PLP 憑證轉移回攻擊合約C1。我們切入collectFees 函數進行分析:

通過上圖我們可以很容易的看出此函數也有updateVault 修飾器,而經過上面的分析我們可以知道updateVault 修飾器用於獎勵更新,因此在攻擊合約C2 持有PLP 憑證的情況下調用collectFees 函數觸發updateVault 修飾器則會根據其持有的PLP 憑證數量來計算應分得的獎勵,並記入用戶的token0Rewards 與token1Rewards 變量。需要注意的是此時對於此類PLP 憑證持有者緩存的tokenPerSharePaid 變量是0,這直接導致了用戶可以獲得PLP 憑證持有獎勵。

我們從鏈上狀態的變化也可以看出:

隨後攻擊合約C2 也如法炮製即可獲得獎勵記錄。

最後PLP 憑證轉移回到攻擊合約C1,並調用了Sorbetto Fragola 合約的withdraw 函數燃燒掉PLP 憑證取回先前存入的WETH 與USDT 流動性。並且攻擊合約C2、C3 分別調用collectFees 函數傳入所要領取的獎勵數量以領取獎勵。這樣攻擊者在同個區塊中不僅拿回了存入的流動性還額外獲得多份流動性提供獎勵。

隨後攻擊者開始利用其他的代幣對如法炮製的薅取獎勵,如下圖所示:

攻擊流程

1、攻擊者創建多個攻擊合約,並從AAVE 中利用閃電貸借出大量的代幣;

2、攻擊者使用借來的代幣存入Sorbetto Fragola 合約中獲得PLP 憑證;

3、攻擊者利用Sorbetto Fragola 合約的獎勵結算缺陷問題將獲得的PLP 憑證在其創建的攻擊合約之間進行轉移並分別調用了Sorbetto Fragola 合約的collectFees 函數來為各個攻擊合約紀錄獎勵;

4、攻擊者燃燒PLP 憑證取回在Sorbetto Fragola 合約中存入的流動性資金,並通過各個攻擊合約調用Sorbetto Fragola 合約的collectFees 函數來獲取紀錄的獎勵;

5、不斷的循環上述操作攻擊各個流動性資金池薅取獎勵;

6、歸還閃電貸獲利走人。

MistTrack 分析過程

慢霧AML 團隊分析統計,本次攻擊損失了約4.98M USDT、2.56K WETH、96 WBTC、5.39M USDC、159.93K DAI、10.49K UNI,接近2100 萬美元。

資金流向分析

慢霧AML 旗下MistTrack 反洗錢追踪系統分析發現,攻擊者H1 地址首先從Tornado.Cash 提幣獲取初始資金隨後部署了三個攻擊合約:

攻擊獲利後通過Uniswap V3 將獲得的代幣兌換成ETH 再次轉入了Tornado.Cash:

目前攻擊者賬戶餘額僅為0.08 ETH,其餘資金均已通過Tornado.Cash 進行轉移。

總結

本次漏洞的核心在於由於獎勵更新記錄缺陷導致同個PLP 憑證能在同個時間節點給多個持有者都帶來收益。針對此類漏洞,慢霧安全團隊建議在進行憑證轉移前應處理好獎勵結算問題,記錄好轉移前後用戶的獎勵緩存,以避免再次出現此類問題。

參考攻擊交易:

https://etherscan.io/tx/0xcd7dae143a4c0223349c16237ce4cd7696b1638d116a72755231ede872ab70fc