BlockSec DeFi攻擊分析系列之四表裡不一:Sanshu Inu的Memestake合約遭襲事件分析
BlockSec
2021-08-03 07:27
本文约5655字,阅读全文需要约23分钟
系統性分析DeFi 安全事件,剖析安全事件背後的根本原因

去中心化金融(DeFi) 作為區塊鏈生態當紅項目形態,其安全尤為重要。從去年至今,發生了幾十起安全事件。

往期回顧:

往期回顧:

(1)往期回顧:

(2)往期回顧:

(3)[BlockSec DeFi 攻擊分析系列之一] 我為自己代言:ChainSwap 攻擊事件分析

[BlockSec DeFi 攻擊分析系列之三] 偷天換日:深度剖析Akropolis 攻擊事件

0xffffffff. 前言

0xffffffff. 前言

  • 北京時間2021 年07 月21 日03:40,我們的攻擊檢測系統檢測到某個交易異常。通過對該交易進行擴展分析,我們發現這是一起利用通縮代幣(deflation token) KEANU 的機制對Sanshu Inu 部署的Memestake 合約的獎勵計算機制的漏洞進行攻擊的事件,攻擊者最後獲利ETH 約56個。下面詳細分析如下:

  • 閱讀建議:

如果您剛剛接觸DeFi (Ethereum),可以從頭看器,但是文章比較長,看不下去記得點個關注再走。

如果您對Akropolis 等DeFi 聚合器項目比較了解,可以直接從「0x2 攻擊分析」開始。

0x0. 背景介紹

今年以來爆火的狗狗幣(DOGE)、柴犬幣(SHIB)引發了廣泛的關注,同時帶火了其他相關的meme 幣,更引發了大量的項目方開發自己的meme 幣及圍繞meme 幣提供服務,其中Sanshu Inu 就是其中一員。 Sanshu Inu 不僅發行meme 幣SANSHU,還創建了合約Memestake 作為meme 幣的耕種池。用戶只要往Memestake 中質押meme 幣,就可以獲得代幣Mfund 作為獎勵。

另一方面,大量的meme 幣都是通縮代幣,即該種代幣的發行量會逐漸減少。其中部分meme 幣的通縮實現形式是在用戶每次進行交易轉賬(transfer)的時候扣取一定比例的幣用於銷毀和再分配,這將導致接收方實際收到的token 數量小於支出方實際支付的數量。本次涉及的通縮代幣KEANU 就是採用這種實現。

該攻擊的大致原理就是通過控制Memestake 進行KEANU 的多次轉入轉出減少其持有的KEANU 數量,從而利用其獎勵計算函數的漏洞致使Memestake 給攻擊者發送大量Mfund。

0x1. 代碼分析

為了便於理解,我們首先簡要地介紹一下和此次攻擊相關的兩個實體合約:KEANU 代幣的KeanuInu 合約和Memestake 合約。


KeanuInu 合約http://tx.blocksecteam.com:8080/正如前面所說,KeanuInu 在實現代幣KEANU 的轉賬時,會扣取一定比例的幣用於銷毀和再分配,其中用於銷毀的比例設置為定值——2%。如圖,在調用KeanuInu 的transfer() 及transferFrom() 函數的時候,函數調用中顯示的轉賬數量跟emit 的事件log 中記錄的數量並不一致。

其由於其實際代碼實現調用較為複雜,此處不再展示,感興趣的朋友可以根據後面附錄給出的合約地址在etherscan.io 自行查看合約實現。另外,上面兩張截圖來源於我們自行開發的交易解析工具,目前開放公測中。歡迎各位點擊

試用。我們的工具將函數調用與過程中產生事件log 結合展示的方式,對於分析通縮代幣等問題更有幫助。

Memestake 合約

下圖是MemeStake 的deposit 函數。函數首先調用updatePool 更新資金池狀態,然後將用戶的token 轉賬給自己。當傳入的_amount 大於0 時會在代碼的1295 行進行轉賬。

然而,由於KEANU token 的通縮特性,雖然調用safeTransferFrom 函數時傳入的金額是_amount,但是實際上轉入資金池的金額小於_amount。並且在代碼分析中我們注意到,transfer 的目的地是自己,也就是說對於MemeStake 來說,所有用戶的某個幣種(如KEANU token)的存款都屬於MemeStake。

在轉賬後的1296 行,MemeStake 會對用戶的存款進行登記,但這裡登記採用的仍然是_amount (而真實的轉賬量小於_amount),因此用戶真正的存款量比登記的user.amount 更小。

最後在1299 行,可以看出user.rewardDebt 參數也是根據(比真實值要大的) user.amount 來計算的。

下圖是MemeStake 的withdraw 函數。該函數首先會檢查user.amount 是否還有足夠的餘額,但由於user.amount 本身比真實值大,因此這裡的檢查是不准確的。接下來,同樣會調用updatePool 函數更新資金池狀態。

在1321 行,withdraw 函數會先扣除在user.amount 中登記的餘額,然後調用transfer 函數把token 轉回用戶。和deposit 函數一樣,這裡的邏輯同樣存在問題,由於每次轉賬都會造成通縮,因此轉給用戶的數量會小於實際的轉賬量。

pool.accMfundPerShare += mFundReward / token.balanceOf(MemeStake)

最後來看MemeStake 的updatePool 函數。首先從1255 行可以看出,每次調用會記錄上一次更新的blockNumber,如果此次調用的區塊和上次更新時相同,則會直接返回,也就是說updatePool 對每個區塊只會更新一次資金池狀態。

rewardMfund = user.amont * pool.accMfundPerShare / 1e18 - user.rewardDebt。

接下來在1259 行,會獲取MemeStake 自身在token 合約中的餘額(上文提到,每次用戶deposit 都會將token 轉給MemeStake)。最後在1275 行,會利用這個餘額作為分母,計算該資金池每一次deposit 和withdraw 的獎勵(也就是pool.accMfundPerShare 參數)。計算方式如下:

user.rewardDebt = user.amount * pool.accMfundPerShare / 1e18

回到withdraw,我們來看存取款獎勵代幣Mfund 是怎樣轉賬的。首先在上圖withdraw 函數的第1325 行,計算用戶是否有pending 的Mfund token 沒有發放,計算公式為:

  • 而rewardDebt 是這樣計算的(圖中第1325 行):

    • 因此,從代碼中我們不難構造出一種可能的攻擊:

    • 首先,在一個交易內,通過反複調用deposit 和withdraw 函數,榨乾MemeStake 的資金池。這個操作利用了三個代碼問題:

    • 首先,user.amount 的記賬比真實值多,因此每次withdraw 都可以成功。

  • 第二,MemeStake 中所有用戶的資金都在一個池子中,因此每一筆轉賬實際上Burn 掉的是池子中其他用戶存入的KEANU token。

    • 第三,由於updatePool 在同一個塊中不會進行狀態更新,因此不會影響pool.accMfundPerShare 參數,也不會產生Mfund token 的reward。

    • 0x2. 攻擊分析

0x2. 攻擊分析

0x2. 攻擊分析

0x2. 攻擊分析

  • 第2 步(操縱),攻擊者先從uniswapV2 中flash loan 大量的KEANU 代幣,然後通過合約二往Memestake 中多次deposit 和withdraw 大量KEANU,導致Memestake 被迫大量交易KEANU。由於KEANU 是一種通縮代幣,每次交易會燒掉2% 的交易額,導致用戶真正存入Memestake 的量比登記的user.amount 更小,取出時又是按照user.amount 轉給用戶(詳見代碼分析),導致Memestake 池子中KEANU 的代幣持有量不斷減少,最終為1e-07。如下圖所示,涉及交易為Mfund,交易截圖未完全,請自行點擊鏈接查看。0xa945第3 步(獲利),攻擊者首先通過合約二調用了Memestake.updatePool() 函數,修改了KEANU 所在池子的accMfundPerShare,由於該值依賴於池子所持有的KEANU 的代幣量,而這在第二步中被操縱了(具體公式見下方代碼分析)。這使得合約二在接下來withdraw 的時候可以獲得遠超正常值的

  • (約61M)這種token 作為獎勵。第3 步發生於交易Tornado.Cash中,同時攻擊者開始將部分獲得的MFund 換成WETH 等代幣。

第4 步(收尾),攻擊者將獲得的MFund、KEANU 等代幣換成ETH,並通過0x0333轉移走,至此攻擊結束,攻擊者從中獲利ETH 55.9484578158357 個(攻擊者的EOA 地址及部署的攻擊合約還殘留有部分SANSHU 和KEANU 代幣未計入),約10 萬美元。

下圖為攻擊地址

的交易截圖,交易截圖未完全,請點擊地址鏈接查看詳情。

攻擊相關0x00ed有趣的是,攻擊的第2、3 步都與flashbots 交易有關。

其中第2 步涉及的交易0xa945由於採用了UniswapV2 flashloan,且交易前後相當於用約38ETH 去購買了KEANU,由此產生了很大的套利空間。因此該筆交易受到另一名攻擊者的三明治攻擊(sandwich attack),即本事件的攻擊者也是另一個三明治事件的受害者。該三明治攻擊者獲利3.2769697165652474ETH,但是給了礦工2.405295771958891249ETH,淨獲利0.8716739446063562ETH。

而第3 步攻擊涉及的交易則由於在uniswap 池子中大量售出MFund,創造了套利空間,所以被back-running 而成為flashbots 交易。該searcher 獲利0.13858054192600666ETH,其中交給礦工0.099085087477094764ETH,淨獲利0.03949545444891189ETH。0x3. 總結及安全建議Towards A First Step to Understand Flash Loan and Its Applications in DeFi Ecosystem (SBC 2021).

0x3. 總結及安全建議

0x3. 總結及安全建議

0x3. 總結及安全建議

  • 攻擊者利用通縮代幣的特性控制了平台持有代幣的數量,影響了獎勵代幣的計算發放,由此獲利ETH 55.9484578158357 個。而這原因在於,Sanshu Inu 平台在引入通縮代幣時缺乏一定的安全考量,導致攻擊者有空可趁。

  • 項目上線前,需要找有資質的安全公司進行安全審計。我們可以看到,由於defi 的money lego 屬性,很多defi 項目之間可以隨意組合,從而產生了互相影響,而這正是defi 領域安全事件頻發的原因。因此,項目方所需關注的安全問題不僅僅局限於自己項目,也同樣需要考慮在與其他項目交互過程中存在的安全漏洞。

BlockSec 團隊以核心安全技術驅動,長期關注DeFi 安全、數字貨幣反洗錢和基於隱私計算的數字資產存管,為DApp 項目方提供合約安全和數字資產安全服務。團隊發表20 多篇頂級安全學術論文(CCS, USENIX Security, S&P),合夥人獲得AMiner 全球最具影響力的安全和隱私學者稱號(2011-2020 排名全球第六). 研究成果獲得中央電視台、新華社和海外媒體的報導。獨立發現數十個DeFi 安全漏洞和威脅,獲得2019 年美國美國國立衛生研究院隱私計算比賽(SGX 賽道) 全球第一名。團隊以技術驅動,秉持開放共贏理念,與社區夥伴攜手共建安全DeFi 生態。

https://www.blocksecteam.com/
contact@blocksecteam.com

BlockSec
作者文库