Location>code7788 >text

[Vulnerability Analysis] Penpie Attack: Re-entry Attack Constructing Reward Amounts

Popularity:403 ℃/2024-09-05 23:33:23

background information

On September 3, 2024, Penpie contracts were subject to a reentry attack in which the attacker added liquidity to the contract during the reentry phase to impersonate the reward amount, thereby accessing the original reward tokens within the contract. Asset losses amounted to $27.34 million.

In May 2024, the Penpie platform added the launch of a license-free asset pooling feature, which allowed users on Pendle to create their own LP pools of any PT or YT tokens on the platform, with users receiving an additional token bonus for depositing LPs on the Penpie platform.

  • X Warning:/PeckShieldAlert/status/1831072230651941093
  • Pre-transactions (Create Pool):/explorer/tx/eth/0xfda0dde38fa4c5b0e13c506782527a039d3a87f93f9208c104ee569a642172d2
  • One of the attack deals:/explorer/tx/eth/0x56e09abb35ff12271fdb38ff8a23e4d4a7396844426a94c4d3af2e8b7a0a2813
  • Attacked contract:/address/0x6e799758cee75dae3d84e09d40dc416ecf713652

Trace Analysis

The attacker first creates a new market in the front-loaded transaction, and puts theSY Address set to attack contract 0x4af4

image

Subsequently, in the attack transaction, the attacker flash-lent four assets (we chose one of them, wstETH, to analyze due to the similarity of the operation of the four assets)

image

These types of operations are carried out within the flash loans

image

existbatchHarvestMarketRewards A reentrant attack was performed in the function

image

Token flow analysis

    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
  1. multiclaim:Claim 1751 [MarketToken] from 0xd128
  2. withdrawMarket:burn 1715 [StakingToken], get 1715 [MarketToken]
  3. removeLiquiditySingleToken:burn 10611 [MarketToken], get 18733 wstETH
  4. transfer:Repay flashloan

Vulnerability Analysis

CreatePool

Any user can register a Pool on Pendle (market)

/address/0x588f5e5d85c85cac5de4a1616352778ecd9110d3#code

image

includedonlyVerifiedMarket check, which checks to see if the pool address is in theallMarkets center. And anyone can create pools to bypass this restriction.

/ethereum/0x45cF29F501d218Ad045EB8d622B69968E2d4Ef5C

image

batchHarvestMarketRewards

existbatchHarvestMarketRewards function by computing the call to The difference in the number of MarketTokens before and after the function is used to get the number of wstETH as reward tokens.

An attacker exploits this design flaw by calling function triggers a reentry attack that makes thebounsTokens The value of is increased.

/ethereum/0xff51c6b493c1e4df4e491865352353eadff0f9f8

batchHarvestMarketRewards(Part1)

image

redeemRewards

Since the market contract is an attacker-created contract, itsSY is set to the address of the attack contract when it is created.

/ethereum/0x40789E8536C668c6A249aF61c81b9dfaC3EB8F32

image

function call flow

redeemRewards -> _redeemRewards -> _updateAndDistributeRewards -> _updateAndDistributeRewardsForTwo -> _updateRewardIndex -> _redeemExternalReward ->

SY is the address of the attack contract in theclaimRewards function for reentry.

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]

Reentry Attack trace, byaddLiquiditySingleTokenKeepYt cap (a poem)depositMarket The operation converts wstETH to a MarketToken and pledges it to the 0x6e79 contract.

image

batchHarvestMarketRewards(Part2)

With the reentry attack, the contract is made to compute theoriginalBonusBalance The number of rewards was incorrectly assumed to be 1751 (in fact, no rewards were earned, and the excess balance was the portion of the reentry that added mobility).

image

originalBonusBalance cap (a poem)leftBonusBalance The value of the_harvestBatchMarketRewards -> _sendRewards -> _queueRewarder The call path is passed to the_queueRewarder function.

At this point, the contract sends the address 0xd128 to the1751 _rewardToken

The number of tokens added by an attacker when adding liquidity via reentry 1751 equals the number of tokens in the 0x6e79 contract balance1751The purpose is to construct the number of "New Rewards" equal to the "Account Balance", so that the followingqueueRewarder The function transfers all tokens in contract 0x6e79 to 0xd128.

image

queueNewRewards

queueNewRewards:Claim 1751 [MarketToken] to 0xd128

0xd128 transfers reward tokens from 0x6e79. Where 0xd128 is the rewardPool contract.

image

multiclaim

multiclaim:get 1751 [MarketToken] from 0xd128

The attacker receives the reward from the 0xd128 contract (to complete the profit, the source of this money is the balance of the 0x6e79 contract)

image

withdrawMarket

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

Retrieval is done on reentry via thedepositMarket incoming1751 [MarketToken]

image

removeLiquiditySingleToken

removeLiquiditySingleToken:burn 10611 [MarketToken], get 18733 wstETH

At this point the attacker is holding the original8860 Plus the proceeds of the attack.1751The total number of holdings10611 [MarketToken]

Final Attacker Removal10611 Mobility, access to18733 The wstETH.

image

Repay flashloan

Return to Lightning Loans16010 wstETH, take profit2723 wstETH。

postscript

The impact of this attack is quite large, and the amount of money involved is also huge. After the incident, many security practitioners have analyzed this matter, and I also tried to analyze this attack from trace at the first time. As the incident occurred soon, there is no vendor to publish detailed vulnerability analysis results, coupled with personal rebellious mentality thinking that I can not analyze it without referring to other people's analysis reports, the analysis of this attack was in a day's time to gnaw on the trace analysis came. This analysis is not easy for me to carry out, and the final output of the analysis of the document, but also lacks some understanding of the project architecture and design, there is a bone without flesh, read very dry. I reflected on why I fell into such a dilemma, and it all boils down to unfamiliarity with the project. Attack analysis done without familiarity with the project is tangible and tasteless. This was a problem that could not be ignored and I needed to think of something.