All incidents

StepHeroNFTs Referral Reentrancy

Share
Feb 21, 2025 04:23 UTCAttackLoss: 137.88 BNBPending manual check1 exploit txWindow: Atomic
Estimated Impact
137.88 BNB
Label
Attack
Exploit Tx
1
Addresses
1
Attack Window
Atomic
Feb 21, 2025 04:23 UTC → Feb 21, 2025 04:23 UTC

Exploit Transactions

TX 1BSC
0xef386a69ca6a147c374258a1bf40221b0b6bd9bc449a7016dbe5240644581877
Feb 21, 2025 04:23 UTCExplorer

Victim Addresses

0x9823e10a0bf6f64f59964be1a7f83090bf5728abBSC

Loss Breakdown

137.88BNB

Similar Incidents

Root Cause Analysis

StepHeroNFTs Referral Reentrancy

1. Incident Overview TL;DR

In BNB Smart Chain transaction 0xef386a69ca6a147c374258a1bf40221b0b6bd9bc449a7016dbe5240644581877 at block 46843424, an unprivileged attacker cluster used the StepHero marketplace at 0x9823e10a0bf6f64f59964be1a7f83090bf5728ab as both seller and referral recipient. The attacker borrowed 1000 WBNB from Pancake V3 pool 0x172fcd41e0913e95784454622d1c3724f546f849, unwrapped it to native BNB, bought its own ERC1155 listing through a separate helper contract, and then recursively claimed the marketplace referral reward in native BNB.

The root cause is a checks-effects-interactions failure in the marketplace referral payout path. The victim contract transfers native BNB to msg.sender before zeroing the caller's claimable referral balance, so an attacker-controlled receive hook can reenter claimReferral(address(0)) and drain the same credit repeatedly. The seed balance diff shows the profit receiver 0xfb1cc1548d039f14b02cff9ae86757edd2cdb8a5 ending the transaction with a net gain of 137.876033699999999999 BNB.

2. Key Background

StepHeroNFTs is an unverified marketplace contract that supports ERC1155 listings and native-BNB purchases. The collected seed artifacts show that native BNB was an enabled payment path in the historical state, which matters because the vulnerable payout branch is only reachable when the referrer claims rewards with token == address(0).

The attack also relied on public infrastructure rather than privileged access. Pancake V3 provided permissionless flash liquidity through pool 0x172fcd41e0913e95784454622d1c3724f546f849, and the marketplace listing and purchase functions were callable by arbitrary addresses. Referral rewards were tracked per (token, claimer) pair, so once the attacker made its seller contract the referrer, the same contract became eligible to claim the new BNB reward.

The relevant adversary cluster in the seed transaction consists of:

  • EOA 0xfb1cc1548d039f14b02cff9ae86757edd2cdb8a5, which funded deployment and received final profit.
  • Wrapper/orchestrator 0xd4c80700ca911d5d3026a595e12aa4174f4cacb3, created in the seed transaction.
  • Seller/referrer helper 0xb4c32404de3367ca94385ac5b952a7a84b5bdf76, which received repeated BNB payouts and seller proceeds.
  • Buyer helper 0x8f327e60fb2a7928c879c135453bd2b4ed6b0fe9, which executed the purchase as a distinct buyer.

3. Vulnerability Analysis & Root Cause Summary

This incident is an ATTACK-class ACT opportunity caused by reentrancy in the marketplace's native-BNB referral claim path. The core invariant is straightforward: for any payout token and claimant, claimReferral(token) must reduce the stored claimable amount to zero before any external transfer is made. If that invariant holds, the same reward cannot be claimed twice in one transaction.

The recorded breakpoint is the victim's decompiled claimReferral(address) implementation (func_06B7 in the auditor's analysis), where the contract loads the referral balance for (token, msg.sender), calls the payout helper func_2D1E(msg.sender, amount, token), and only then writes the storage slot back to zero. When token is the zero address, the payout helper performs a raw native-BNB transfer to msg.sender. That means control returns to attacker code before state is cleared.

The on-chain trace confirms the runtime consequence of that ordering. After the attacker self-buys its listing, the marketplace sends a 3 BNB referral payout to the seller/referrer helper. That helper's fallback immediately reenters claimReferral(address(0)), causing the same 3 BNB amount to be paid again and again before the marketplace finally completes the original call stack.

4. Detailed Root Cause Analysis

The attack sequence starts from block 46843423, the pre-state immediately before the exploit transaction. The seed metadata and trace show a single adversary-crafted transaction containing the complete exploit path:

0xb4c32404de3367ca94385ac5b952a7a84b5bdf76 -> 0x172fcd41e0913e95784454622d1c3724f546f849  flash(...)
0xb4c32404de3367ca94385ac5b952a7a84b5bdf76 -> 0x9823e10a0bf6f64f59964be1a7f83090bf5728ab  0xded4de3a(...)
0x8f327e60fb2a7928c879c135453bd2b4ed6b0fe9 -> 0x9823e10a0bf6f64f59964be1a7f83090bf5728ab  0x60acd67f(...), value 1000 BNB

Those calls establish the seller/referrer position, execute the self-purchase, and create a fresh native-BNB referral balance. The root cause becomes observable immediately afterward. In the nested call tree, the marketplace repeatedly enters claimReferral(0x0000000000000000000000000000000000000000) while the attacker helper repeatedly receives native BNB in its fallback:

0xB4C32404de3367Ca94385ac5b952a7a84B5BdF76::fallback{value: 3000000000000000000}()
0x9823E10A0bF6F64F59964bE1A7f83090bf5728aB::claimReferral(0x0000000000000000000000000000000000000000)
0xB4C32404de3367Ca94385ac5b952a7a84B5BdF76::fallback{value: 3000000000000000000}()
0x9823E10A0bF6F64F59964bE1A7f83090bf5728aB::claimReferral(0x0000000000000000000000000000000000000000)
emit ReferralClaimed(param0: 0xB4C32404de3367Ca94385ac5b952a7a84B5BdF76, param1: 0x0000000000000000000000000000000000000000, param2: 3000000000000000000)

This pattern recurs throughout the seed trace. Earlier trace offsets also show repeated value transfers of exactly 3000000000000000000 wei from the marketplace to 0xb4c32404de3367ca94385ac5b952a7a84b5bdf76, followed later by a 970000000000000000000 wei seller settlement. The referral payout therefore occurs before the marketplace has finalized internal accounting for the same referral balance.

The attack succeeds because the attacker controls both the credited referrer and the code that receives native BNB. By the time the marketplace eventually zeroes the referral slot, the contract has already honored the same claim many times. The seed balance diff shows the concrete victim-side loss:

{
  "address": "0x9823e10a0bf6f64f59964be1a7f83090bf5728ab",
  "before_wei": "138699325579296300000",
  "after_wei": "699325579296300000",
  "delta_wei": "-138000000000000000000"
}

That loss is consistent with the repeated 3 BNB payouts plus normal marketplace settlement. The same balance diff records the attacker's EOA profit receiver with a 137876033699999999999 wei net gain after gas, which matches the incident summary in root_cause.json.

5. Adversary Flow Analysis

The adversary flow is a single-transaction flash-loan-funded self-trade with recursive referral claiming.

  1. The attacker EOA 0xfb1c...b8a5 submits the exploit transaction and deploys a wrapper that immediately invokes the seller/referrer helper.
  2. The seller/referrer helper calls Pancake V3 flash and receives 1000 WBNB, then unwraps it into native BNB.
  3. The same helper lists an ERC1155 item on StepHero through selector 0xded4de3a, making itself the seller.
  4. The helper deploys a distinct buyer contract and funds it with 1000 BNB so the marketplace purchase is not blocked by seller checks.
  5. The buyer contract calls the marketplace purchase selector 0x60acd67f with the seller/referrer helper set as the referrer. This credits a 3 BNB native referral reward to the helper.
  6. The helper calls claimReferral(address(0)). Each native payout reaches the helper fallback, which immediately calls claimReferral(address(0)) again while the same stored reward remains uncleared.
  7. After the recursive loop, the helper receives the normal 970 BNB seller proceeds, rewraps enough BNB to repay 1000.1 WBNB to Pancake V3, and forwards the remaining profit to the original EOA.

The seed trace and balance diff show that each of these steps happened on-chain in one atomic execution path. No privileged account, private key compromise, or non-public component was required, so the incident is correctly classified as an ACT opportunity.

6. Impact & Losses

The measurable loss is native BNB drained from the StepHero marketplace referral pool. The validated impact from root_cause.json and the seed balance diff is:

  • Token: BNB
  • Amount: 137876033699999999999 wei
  • Decimal: 18

This equals 137.876033699999999999 BNB net profit to the attacker cluster after gas. The marketplace's native balance fell from 138.6993255792963 BNB to 0.6993255792963 BNB during the exploit transaction, demonstrating that the referral accounting flaw had direct treasury impact.

7. References

  • Seed transaction metadata: 0xef386a69ca6a147c374258a1bf40221b0b6bd9bc449a7016dbe5240644581877
  • Victim marketplace: 0x9823e10a0bf6f64f59964be1a7f83090bf5728ab
  • Flash-loan pool: 0x172fcd41e0913e95784454622d1c3724f546f849
  • Profit receiver EOA: 0xfb1cc1548d039f14b02cff9ae86757edd2cdb8a5
  • Seller/referrer helper: 0xb4c32404de3367ca94385ac5b952a7a84b5bdf76
  • Buyer helper: 0x8f327e60fb2a7928c879c135453bd2b4ed6b0fe9
  • Supporting evidence artifacts:
    • Seed metadata
    • Seed trace
    • Seed balance diff