首頁  >  文章  >  $100如何撬動$650萬? Sonne Finance攻擊分析

$100如何撬動$650萬? Sonne Finance攻擊分析

WBOY
WBOY原創
2024-06-08 16:17:02610瀏覽

Sonne Finance 攻擊分析:$100 如何撬動 $650 萬?這次攻擊事件的本質是 market (soToken) 被創建出來時,攻擊者進行了第一筆抵押鑄造的操作,以少量 underlying token 鑄造了很少的 soToken,導致 soToken 的“ totalSupply ”數值太小。攻擊者繼而利用了Solidity 合約精度損失這個漏洞,再搭配直接往soToken 合約發送underlying token(不會鑄造soToken,也就意味著“ totalSupply ”不變,“ totalCash ”變大),而不是抵押+ 鑄造的方式存入underlying token。這樣的操作使得合約中「 totalCash 」 變數變大,但是「 totalSupply 」 保持不變,從而導致 exchangeRate 變大。當最終攻擊者在贖回underlying token 時,需要銷毀的soToken 少於抵押時鑄造的soToken,攻擊者利用賺取的soToken 去其他的soToken(比如soWETH、soUSDC)中藉出underlying token WETH、USDC,最終獲利高達2000 萬美元。

0如何撬动0万?Sonne Finance攻击分析

2024 年 5 月 15 日,Sonne Finance 在 Optimism 鏈上遭受攻擊,損失高達 2 千萬美元。攻擊發生後,X 上 @tonyke_bot 用戶發推文表示,其用約 100 美元保護了 Sonne Finance 的代幣抵押池(也稱為 market,類似於 Compound 中的 cToken)中剩餘的約 650 萬美元。

(https://twitter.com/tonyke_bot/status/1790547461611860182)

0如何撬动0万?Sonne Finance攻击分析

Sonne Finance 專案方發現攻擊之後,迅速暫停了Optimism上的所有markets,並表示Base 上的markets 是安全的。

(https://twitter.com/SonneFinance/status/1790535383005966554)

0如何撬动0万?Sonne Finance攻击分析

#攻擊簡述

Sonne Finance 是Optimism 上的一個fork 了Compound V2 的去中心化借貸協議,供個人、機構和協議訪問金融服務。 Sonne Finance 協議將用戶的 token 資產聚合起來,形成了借貸流動性池,為用戶提供了一個類似銀行的借貸業務。與 Compound 一樣,協議參與者可以將其持有的 token 抵押到 Sonne Finance 的借貸流動性池中,同時獲得憑證 soToken(與 cToken 一樣)。而 soToken 是一種生息資產憑證,隨著區塊的推進會產生一定的收益,同時還會獲得 SONNE token 激勵。而參與者憑藉著手裡的 soToken 還能從 Sonne 借貸資產池中藉出其他 token,例如參與者可以抵押一定數量的 USDC 獲得 soUSDC 憑證,隨後藉貸出WETH用於經一步的流通。 Sonne Finance 協議中的抵押貸款借貸可以是多對多的資產關係,在抵押借貸的過程中,協議會自動計算參與者地址的健康度(Health Factor),當健康度低於1 時,該地址的抵押品將支持被清算,而清算者也能獲得一定的清算獎勵。

使用者存入的 underlying token 與鑄造的 soToken 的數量關係,主要與一個叫做 exchangeRate 的變數有關,這個變數粗略可以用來表示每個 soToken 價值多少 underlying token。 exchangeRate 的計算公式如下:

0如何撬动0万?Sonne Finance攻击分析

在上述公式中,totalCash 是指soToken 持有的underlying token 的數量,totalBorrows 是指某market 中被借出去的underlying token的數量,totalReserves 是指總儲備金數量(其中包含借款人支付的利息),totalSupply 是指鑄造的soToken 的數量。

在贖回時,使用者可以指定想要贖回的underlying token 的數量redeemAmount,來計算需要銷毀掉的soToken的數量redeemTokens,計算方式大概為“ redeemTokens = redeemAmount / exchangeRat ”,注意這裡大概是“ redeemTokens = redeemAmount / exchangeRat ”,注意這裡並沒有對精度損失做處理。

這次攻擊事件的本質是market (soToken) 被創建出來時,攻擊者進行了第一筆抵押鑄造的操作,以少量underlying token 鑄造了很少的soToken,導致soToken 的“ totalSupply ”數值太小。攻擊者繼而利用了Solidity 合約精度損失這個漏洞,再搭配直接往soToken 合約發送underlying token(不會鑄造soToken,也就意味著“ totalSupply ”不變,“ totalCash ”變大),而不是抵押+ 鑄造的方式存入underlying token。這樣的操作使得合約中「 totalCash 」 變數變大,但是「 totalSupply 」 保持不變,從而導致 exchangeRate 變大。當最終攻擊者在贖回underlying token 時,需要銷毀的soToken 少於抵押時鑄造的soToken,攻擊者利用賺取的soToken 去其他的soToken(比如soWETH、soUSDC)中藉出underlying token WETH、USDC,最終獲利高達2000 萬美元。

攻擊中涉及的關鍵地址

攻擊準備交易:

https://optimistic.etherscan.io/tx/0x45c0ccfd3ca1b4a937feebcb0f5a166c409c9e40307080835交易:

https://optimistic.etherscan.io/tx/0x9312ae377d7ebdf3c7c3a86f80514878deb5df51aad38b6191d55db53e42b7f0

#EO 01f35804317f5ed80bbb

0xae4a7cde7c99fb98b0d5fa414aa40f0300531f43

#攻擊者(合約)相關地址:

0xa78aefd483ce3919c0ad55c8a2e5c97cbac1caf8

0x02fa2625825917e9b1f8346a465de1 #0x9560e827af36c94d2ac33a39bce1fe78631088db

漏洞合約(soVELO,類似Compound 的cToken):

0xe3b81318b1b6776f0877c3770afddff97b9f5fe5

X 上@tonyke_bot 使用者救援交易:https##misers或#optitic. tx/0x816f9e289d8b9dee9a94086c200c0470c6456603c967f82ab559a5931fd181c2

#Sonne 新增了攻擊流程分析

##Pexor 提案的前一提案(https Finance 「 twitter.com/SonneFinance/status/1786871066075206044),並透過多簽錢包安排了五筆在兩天之後執行的交易(https://optimistic.etherscan.io/tx/0x18ebeb958b5057997652838812868126 377b7),這五筆交易是用來創造VELO market(soVELO 合約),並設定該market 的一些關鍵配置,例如設定利率模型,設定價格預言機,設定抵押因子等。 VELO market 創建之後,用戶可以存入 VELO 代幣,以鑄造 soVELO 代幣,soVELO 代幣又可以用來借貸其他 soToken。

攻擊準備

攻擊準備階段主要是攻擊者在提案兩天鎖定時間結束後,根據Sonne Finance 專案方提案中的信息,創建VELO market(soVELO 合約),設定關鍵的配置,並透過抵押VELO 代幣進soVELO 合約來鑄造soVELO 代幣,同時也將自己持有的VELO 代幣以直接發送給soVELO 合約的方式,來增大exchangeRate,為後續攻擊獲利做準備。

具體步驟如下:

攻擊者在兩天鎖定時間結束後,首先將提案中安排的前四筆交易的操作打包到一筆交易中(交易0x45c0cc),用來建立VELO market(soVELO 合約),並設定好關鍵的配置。 VELO market 初始化時,exchangeRate 被設定為「 200,000,000,000,000,000,000,000,000 」。

攻擊者呼叫soVELO 合約的「 mint 」函數來存入VELO 代幣,並鑄造soVELO 代幣,攻擊者指定「 mintAmount 」為「 400,000,001 」(VELO 代幣的數量)。從函數「 exchangeRateStoredInternal 」可以看出,由於此時 soVELO 代幣的「 _totalSuppl 」是 0,因此 exchangeRate 即為第 1 步驟設定的值。根據公式「 mintTokens = actualMintAmount / exchangeRate 」,此時計算出的應該鑄造的 soVELO 代幣的數量為 2。簡而言之,這一步驟攻擊者向 soVELO 合約存入數值為「 400,000,001 」 的 VELO 代幣,攻擊者獲得數值為 2 的 soVELO 代幣。

soVELO.mint:

  • #攻擊者以直接給soVELO 合約發送VELO 代幣的方式,給soVELO 合約發送了數值為「 2,552,964,259,704,265,837,526 」的VELO 代幣,此時soVELO 合約持有的VELO 代幣增多,但由於沒有新的soVELO 代幣的鑄造,因此totalSupply 保持不變,也就意味著此時根據公式計算出的exchangeRate 會變大。

  • 攻擊者將持有的 soVELO 代幣轉移多次,最終轉移給了另一個攻擊 EOA 0xae4a。

攻擊獲利

攻擊獲利階段主要是攻擊者執行提案的第五筆交易,並透過閃電貸借出VELO 代幣直接發送給soVELO 合約,以進一步增大exchangeRate。然後攻擊者利用自己手上的數值為 2 的 soVELO 代幣,去其他的 soToken(例如 soWETH,soUSDC 等)合約中藉出了 WETH、USDC 等 underlying token,這些部分成為了攻擊者獲利。緊接著攻擊者去soVELO 合約中贖回自己的underlying token,由於exchangeRate 變大,以及計算贖回需要銷毀的soVELO 代幣時的精度損失問題,最終使得攻擊者僅使用數值為1 的soVELO 代幣就贖回了先前存入的幾乎全部的VELO 代幣,可以理解為攻擊者利用多得的數值為1 的soVELO 代幣,透過從其他soToken 借貸賺取了WETH、USDC 等underlying token。攻擊者使用同樣的手法多次重複攻擊,最後獲利巨大。

具體步驟如下:

  • 攻擊者執行題案中的第五筆交易,設定提案中規定的借貸因子。

  • 攻擊者從 VolatileV2 AMM - USDC/VELO 池子中閃電貸出數值為「 35,469,150,965,253,049,864,450,449 」的 VELO 代幣,這會觸發攻擊者的 hook 函數。在 hook 函數中,攻擊者繼續執行攻擊操作。

  • 攻擊者將自己持有的 VELO 代幣發送給 soVELO 合約,以進一步增大 exchangeRate。目前 soVELO 合約中一共有數值為「 35,471,703,929,512,754,530,287,976 」的 VELO 代幣(攻擊者三次轉入的 VELO 代幣和)。

  • 攻擊者創建新的合約0xa16388a6210545b27f669d5189648c1722300b8b,在建構函式中,將持有的 2 個 soVELO 代幣轉給新建立的合約 0xa16363(xa163)。

  • 攻擊者 0xa163 以持有的 soVELO 代幣,從 soWETH 借出數值為「 265,842,857,910,985,546,929 」的 WETH。

  • 攻擊者0xa163 呼叫soVELO 的「 redeemUnderlying 」函數,指定贖回VELO 代幣的數值為「 35,471,603,929,512,754,530,287,VE976」(幾乎是所有進位攻擊者之前的抵押貸款合約或VE VELO 代幣數量),此時需要根據公式「 redeemTokens = redeemAmountIn / exchangeRate 」來計算贖回所需銷毀的soVELO 代幣的數量。

    從「 exchangeRateStoredInternal 」函數可以看出,由於此時_totalSupply 是2 不是0,因此需要計算exchangeRate 的值,透過公式「 exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply 」計算出,目前的exchangeRate 為「 17,735,851,964,756,377,265,143,988,000,000,000,000,000,000 」,這個值遠遠大於設置的初始exchangeRate 「 200,000,000,000,000,000,000,000,00 」。

    根據新的 exchangeRate 計算出的“ redeemTokens ”的值為“ 1.99 ”,由於 Solidity 向下取整的特性,“ redeemTokens ”的值最終為 1。也意味著攻擊者 0xa163 使用數值為 1 的 soVELO 代幣,贖回了先前存入的幾乎所有的 VELO 代幣。同時攻擊者 0xa163 也賺取了從 soWETH 中藉出的數值為「 265,842,857,910,985,546,929 」的 WETH。

    soVELO.redeemUnderlying:

    0如何撬动0万?Sonne Finance攻击分析

    #soVELO.exchangeRateStoredInternal:

    0如何撬动0万?Sonne Finance攻击分析

  • 攻擊者0xa163 將藉到的WETH 和贖回的VELO 代幣全部轉給了上層攻擊者,然後自毀。
  • 攻擊者呼叫soWETH 的「 liquidateBorrow 」函數,用來清算前面新建立的合約0xa163 借貸的部分資產,目的是拿回鎖定住的數值為1 的soVELO 代幣。目前攻擊者只持有數值 1 的 soVELO 代幣。
  • 攻擊者呼叫soVELO 的「 mint 」函數,再一次抵押鑄造soVELO 代幣,目的是湊夠數值為2 的soVELO 代幣,然後再次執行上述第3-8步,獲利其他的undeylying token。

攻擊者執行數次第 9 步的操作,還掉閃電貸,獲利離場。

#########$100 如何撬動$650 萬######攻擊發生後,X 上@tonyke_bot 用戶在交易0x0a284cd 中,透過抵押1144 個VELO 代幣到soVELO 合約中,鑄造了0.00000011 個soVELO。這樣操作之所以能夠阻止攻擊者進一步攻擊,是因為這筆交易改變了soVELO 中totalSupply 的大小和持有的VELO 代幣的數量totalCash,而totalSupply 增長對於計算exchangeRate 產生的影響大於totalCash 增長產生的影響,因此exchangeRate 變小,從而導致攻擊者進行攻擊時,無法再利用精確度損失賺取soVELO,導致攻擊無法再進行。 ###

0如何撬动0万?Sonne Finance攻击分析

資金追蹤

攻擊者攫取非法收益後不久便將資金進行了轉移,大部分資金轉移到了以下4 個地址當中,有的是為了換個地址繼續攻擊,有的是為了洗錢:

  • 0x4ab93fc50b82d4dc457db85888dfdae28d29b98d

攻擊者將198 WETH 轉入了該位址,然後攻擊該位址採用了該位址相同的手法,在下列交易中獲得非法收益:

0如何撬动0万?Sonne Finance攻击分析

攻擊結束後,該地址將上述非法所得轉給了0x5d0d99e9886581ff8fcb01f35804317f5ed80bbb。

  • 0x5d0d99e9886581ff8fcb01f35804317f5ed80bbb

攻擊者將 724277 USDC、2353 VELO 轉入了該地址,並將 724277 USDC、2353 VELO 轉入了該地址,並將換成了 Ether。隨後立即將部分資金轉入了Stargate 跨鏈橋,剩下大部分非法資金殘留在該地址中:

0如何撬动0万?Sonne Finance攻击分析

  • 0xbd18100a168321701955e348f03d0df4f517c13b

##攻擊者將33 WETH 轉入了該地址,並採用peel chain 的方式嘗試洗錢,洗錢鏈路如下:

0xbd18100a168321701955e348f03d0df4f517c1321701955e348f03d0df4f517c13bb; d4fb59cb6928->0xc521bde5e53f537ff208970152b75a003093c2b4- >0x9f09ec563222fe52712dc413d0b7b66cb5c7c795。

  • 0x4fac0651bcc837bf889f6a7d79c1908419fe1770

攻擊者將 563 WETH ,目前沒有進一步行為。

攻擊者這次洗錢的手段相對來說較為專業,手法呈現多元趨勢。因此對於我們 Web3 參與者來說,在安全方面要持續不斷地提高我們的反洗錢能力,透過 KYT、AML 等相關區塊鏈交易安全產品來提高 Defi 專案的安全性。

安全建議

  • 精度損失需重視。精度損失導致的安全問題層出不窮,尤其是在Defi專案中,精度損失往往導致嚴重的資金損失。建議專案方和安全審計人員仔細審查專案中存在精確度損失的程式碼,並做好測試,盡量規避漏洞。

  • 建議類似於 Compound 中 cToken 這種 market 的創建和首次抵押鑄造操作由特權使用者來執行,避免被攻擊者操作,從而操作匯率。

  • 當合約中存在關鍵變數依賴「 this.balance 」或「 token.balanceOf() 」的值時,需要慎重考慮該關鍵變數改變的條件,例如是否允許直接透過給合約轉原生幣或代幣的方式改變該變數的值,還是只能透過呼叫某特定函數才能改變該變數的值。

  • #

以上是$100如何撬動$650萬? Sonne Finance攻擊分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn