【漏洞分析】Penpie 攻擊事件:重入攻擊構造獎勵金額

ACai_sec發表於2024-09-05

背景資訊

2024 年 9月 3日,Penpie 合約遭受重入攻擊,攻擊者在重入階段向合約新增流動性來冒充獎勵金額,從而獲取合約內原有的獎勵代幣。資產損失高達 2734 萬美元。

2024 年 5月,Penpie 平臺新增了推出了無需許可的資產池功能,即允許 Pendle 上的使用者可以在該平臺上自建任何 PT 或 YT 代幣的 LP 資金池,使用者在 Penpie 平臺上存入 LP 後,可以額外多獲得一份代幣獎勵。

  • X 告警:https://x.com/PeckShieldAlert/status/1831072230651941093
  • 前置交易(Create Pool):https://app.blocksec.com/explorer/tx/eth/0xfda0dde38fa4c5b0e13c506782527a039d3a87f93f9208c104ee569a642172d2
  • 其中一筆攻擊交易:https://app.blocksec.com/explorer/tx/eth/0x56e09abb35ff12271fdb38ff8a23e4d4a7396844426a94c4d3af2e8b7a0a2813
  • 被攻擊合約:https://etherscan.io/address/0x6e799758cee75dae3d84e09d40dc416ecf713652

Trace 分析

攻擊者首先在前置交易中新建了一個 market,並將 SY 地址設定為攻擊合約 0x4af4

image

隨後在攻擊交易中,攻擊者閃電貸了四種資產(由於四種資產的操作類似,我們選擇其中一種資產 wstETH 進行分析)

image

閃電貸內進行了這幾類操作

image

batchHarvestMarketRewards 函式中進行了重入攻擊

image

代幣流向分析

  1. 0x6e79.batchHarvestMarketRewards:
    1. redeemRewards:
      1. [Reentrancy] addLiquiditySingleTokenKeepYt:deposit 16010 wstETH to [Pendle: RouterV4], get 8860 [MarketToken]
      2. [Reentrancy] depositMarket:deposite 1751 [MarketToken] to [0x6e79], received 1751 [StakingToken]
    2. queueNewRewards:Claim 1751 [MarketToken] to 0xd128
  2. multiclaim:Claim 1751 [MarketToken] from 0xd128
  3. withdrawMarket:burn 1715 [StakingToken], get 1715 [MarketToken]
  4. removeLiquiditySingleToken:burn 10611 [MarketToken], get 18733 wstETH
  5. transfer:Repay flashloan

漏洞分析

CreatePool

任何使用者都可以在 Pendle 上註冊 Pool(market)

https://etherscan.io/address/0x588f5e5d85c85cac5de4a1616352778ecd9110d3#code

image

其中的 onlyVerifiedMarket 檢查,會檢查 pool 地址是否在 allMarkets 中。而任何人都可以建立池子,繞過這個限制。

https://vscode.blockscan.com/ethereum/0x45cF29F501d218Ad045EB8d622B69968E2d4Ef5C

image

batchHarvestMarketRewards

batchHarvestMarketRewards 函式中,透過計算呼叫 market.redeemRewards 函式前後的 MarketToken 數量差值,來得到作為獎勵代幣的 wstETH 數量。

攻擊者利用這個設計缺陷,呼叫 0x6e79.batchHarvestMarketRewards 函式觸發重入攻擊,使得 bounsTokens 的值增大。

https://vscode.blockscan.com/ethereum/0xff51c6b493c1e4df4e491865352353eadff0f9f8

batchHarvestMarketRewards(Part1)

image

redeemRewards

由於 market 合約為攻擊者建立的合約,其 SY 在建立時被設為了攻擊合約的地址。

https://vscode.blockscan.com/ethereum/0x40789E8536C668c6A249aF61c81b9dfaC3EB8F32

image

函式呼叫流程

redeemRewards -> _redeemRewards -> _updateAndDistributeRewards -> _updateAndDistributeRewardsForTwo -> _updateRewardIndex -> _redeemExternalReward -> StandardizedYield.claimRewards

SY 為攻擊合約地址,在 claimRewards 函式中進行重入。

image

[Reentrancy] addLiquiditySingleTokenKeepYt & depositMarket

[Reentrancy] addLiquiditySingleTokenKeepYt:deposit 16010 wstETH to [Pendle: RouterV4], get 8860 [MarketToken]
[Reentrancy] depositMarket:deposite 1751 [MarketToken] to [0x6e79], received 1751 [StakingToken]

重入攻擊 trace,透過 addLiquiditySingleTokenKeepYtdepositMarket 操作將 wstETH 轉換為 MarketToken ,並質押到 0x6e79合約中。

image

batchHarvestMarketRewards(Part2)

透過重入攻擊,使得合約在計算 originalBonusBalance 獎勵數量時誤以為獲得了 1751 的獎勵(實際上並沒有獲得任何獎勵,餘額多出來的部分是重入的時候新增流動性那部分)。

image

originalBonusBalanceleftBonusBalance 的值會按照 _harvestBatchMarketRewards -> _sendRewards -> _queueRewarder 的呼叫路徑傳遞到 _queueRewarder 函式中。

此時合約會向 0xd128 地址傳送 1751 _rewardToken

攻擊者在透過重入新增流動性時,所新增的代幣數量 1751 等於 0x6e79 合約中代幣餘額的數量 1751,其目的是構造“新增獎勵”的數量等於“賬戶餘額”,使得接下來的 queueRewarder 函式將 0x6e79 合約中的所有代幣轉移到 0xd128。

image

queueNewRewards

queueNewRewards:Claim 1751 [MarketToken] to 0xd128

0xd128 從 0x6e79 處轉移獎勵代幣。其中0xd128是rewardPool合約。

image

multiclaim

multiclaim:get 1751 [MarketToken] from 0xd128

攻擊者從 0xd128 合約中領取獎勵(完成獲利,這筆資金的來源是 0x6e79 合約的餘額)

image

withdrawMarket

withdrawMarket:burn 1751 [StakingToken], get 1751 [MarketToken]

取回在重入中透過 depositMarket 存入的 1751 [MarketToken]

image

removeLiquiditySingleToken

removeLiquiditySingleToken:burn 10611 [MarketToken], get 18733 wstETH

此時攻擊者手裡持有原來的 8860 ,加上攻擊所得 1751,一共持有 10611 [MarketToken]

最終攻擊者移除 10611 流動性,獲得 18733 的 wstETH。

image

Repay flashloan

向閃電貸歸還 16010 wstETH,獲利 2723 wstETH。

後記

這次的攻擊事件影響挺大的,涉及的金額也是巨大。在事件發生以後,許多安全從業人員都對這件事情進行了分析,我也第一時間嘗試著從 trace 去分析這個攻擊事件。由於當時事發不久,還沒有廠商公佈詳細的漏洞分析結果,再加上個人叛逆的心態想著難道不參考別人的分析報告我就分析不出來了嗎,這次的攻擊事件分析是在一天的時間內硬啃 trace 分析得來的。這樣的分析對我來說進行得並不容易,且最終輸出的分析文件,也會缺乏了一些對專案架構與設計的理解,有骨沒肉,讀起來很乾巴。我反思了一下我為何會落入如此窘境,歸根究底還是對專案的不熟悉。在不熟悉專案的前提下做的攻擊分析,有形無意,味如嚼蠟。這是一個不可忽視的問題,我需要想想辦法。

相關文章