All incidents

Eterna Buyback Treasury Drain

Share
Nov 15, 2023 03:46 UTCAttackLoss: 0.3 BNBPending manual check1 exploit txWindow: Atomic
Estimated Impact
0.3 BNB
Label
Attack
Exploit Tx
1
Addresses
2
Attack Window
Atomic
Nov 15, 2023 03:46 UTC → Nov 15, 2023 03:46 UTC

Exploit Transactions

TX 1BSC
0x8b528372b743b4b8c4eb0904c96529482653187c19e13afaa22f3ba4e08fbfbb
Nov 15, 2023 03:46 UTCExplorer

Victim Addresses

0xe1747a23c44f445062078e3c528c9f4c28c50a51BSC
0x3407c5398256cc242a7a22c373d9f252bab37458BSC

Loss Breakdown

0.301BNB

Similar Incidents

Root Cause Analysis

Eterna Buyback Treasury Drain

1. Incident Overview TL;DR

On BSC block 33503912, transaction 0x8b528372b743b4b8c4eb0904c96529482653187c19e13afaa22f3ba4e08fbfbb exploited Eterna's EHX token by forcing its contract to spend treasury BNB on a fixed-size buyback that any non-AMM sender could trigger. The attacker used a public DODO flash loan of 5.589328092301986679 WBNB, bought EHX, then repeatedly sent dust EHX amounts to the EHX/WBNB Pancake pair and immediately called the pair's public skim(address) function to recover most of the transferred tokens.

Each loop spent 0.001 BNB from the EHX contract treasury, burned the bought-back EHX to the dead address, and ratcheted the pair price upward. After 300 dust loops and one final sell-triggered buyback, the attacker sold the inflated EHX position back into WBNB, repaid the flash loan, and kept 0.131914943781835584 BNB net profit after gas. The root cause is a deterministic public spend primitive in Token._transfer(): arbitrary users can trigger a fixed treasury buyback that is unrelated to transfer size, and the Pancake pair's permissionless skim() makes the trigger loop economically cheap.

2. Key Background

EHX is a fee-on-transfer token whose verified source sets totalFees = 250 and a fixed buyBackAmount = 10**15, which is 0.001 BNB. When a transfer comes from a non-AMM address and the token contract holds more than buyBackAmount * 10 native BNB, the token unconditionally spends treasury BNB on a buyback before finishing the user's transfer.

The bought-back EHX is not returned to users or retained in treasury. swapETHForTokens() routes the purchased EHX directly to the dead address, so every forced buyback removes EHX from circulation while injecting more WBNB into the pair's reserves. That pushes the EHX price upward if repeated often enough.

The other critical ingredient is the Pancake pair's public skim(address) behavior. When a fee-on-transfer token is sent to the pair, the pair can temporarily hold a balance surplus above its stored reserves. Anyone can call skim() to pull that surplus out. In this incident, that let the attacker recycle most of the dust EHX used to re-trigger the next fixed-size buyback.

The relevant EHX source behavior is visible in the verified token contract:

if (canBuyBack && address(this).balance > buyBackAmount * 10 && !automatedMarketMakerPairs[from] && !swapping) {
    buyBackTokens(buyBackAmount);
}

function buyBackTokens(uint256 amount) private lockTheSwap {
    if (amount > 0) {
        swapETHForTokens(amount);
    }
}

function swapETHForTokens(uint256 amount) private {
    address[] memory path = new address[](2);
    path[0] = uniswapV2Router.WETH();
    path[1] = address(this);

    uniswapV2Router.swapExactETHForTokensSupportingFeeOnTransferTokens{value: amount}(
        0,
        path,
        deadAddress,
        block.timestamp
    );
}

3. Vulnerability Analysis & Root Cause Summary

This incident is an ATTACK, not a benign MEV unwind. The vulnerable design is that EHX couples every qualifying non-AMM transfer to a fixed treasury spend of 0.001 BNB, regardless of the transfer's economic size. That means a user sending a dust-sized EHX transfer can force the same treasury outflow as a large real trade. Because the token spends before completing the transfer and because the attacker can repeatedly recover most of the dust via Pancake skim(), the treasury spend becomes a public loopable primitive. The violated invariant is straightforward: an unprivileged user must not be able to deterministically force disproportionate treasury spending through dust-sized public actions. The code-level breakpoint is the unconditional buyback branch in Token._transfer(). Once that branch is reachable, the only remaining requirement is access to public liquidity and the ability to cycle dust transfers through the pair.

4. Detailed Root Cause Analysis

The ACT pre-state immediately before the exploit was fully public and reconstructible. The EHX contract already held enough native BNB to satisfy the buyback arm condition, the EHX/WBNB pair had live liquidity, and the DODO pool at 0xfeafe253802b77456b4627f8c2306a9cebb5d681 could fund the flash loan. No privileged keys, private order flow, or privileged contract roles were needed.

The attacker path began with a public flash loan and an initial buy of EHX. The exploit helper contract borrowed 5.589328092301986679 WBNB, swapped into EHX, and then started the dust loop. The loop mechanics are visible directly in the seed trace:

Token::transferFrom(0x9D0d28f7b9a9e6D55abb9e41a87df133F316C68C,
                    PancakePair: [0x3407c5398256cc242a7a22c373D9F252BaB37458],
                    4349498877701)
PancakeRouter::swapExactETHForTokensSupportingFeeOnTransferTokens{value: 1000000000000000}(
    0,
    [WBNB, EHX],
    0x000000000000000000000000000000000000dEaD,
    ...
)
emit Transfer(from: PancakePair: [0x3407c5398256cc242a7a22c373D9F252BaB37458],
              to: 0x9D0d28f7b9a9e6D55abb9e41a87df133F316C68C,
              value: 2446593118707)

This excerpt shows the core exploit cycle:

  1. The attacker sends 4349498877701 raw EHX units to the pair.
  2. Because the sender is not an AMM pair and the treasury is funded, EHX immediately spends 0.001 BNB on swapExactETHForTokensSupportingFeeOnTransferTokens, routing the bought EHX to 0x000000000000000000000000000000000000dEaD.
  3. The attacker then uses the pair's permissionless excess-balance handling to recover 2446593118707 raw EHX units.

The attacker therefore only loses 1902905758994 raw EHX units per loop while forcing a full 0.001 BNB treasury spend each time. Repeating that cycle 300 times drained approximately 0.300 BNB, and the final exit sale triggered one additional buyback for a total treasury loss of 0.301 BNB.

The balance diff confirms the treasury depletion and burn side effects:

{
  "native_balance_deltas": [
    {
      "address": "0xe1747a23c44f445062078e3c528c9f4c28c50a51",
      "delta_wei": "-301000000000000000"
    }
  ],
  "erc20_balance_deltas": [
    {
      "token": "0xe1747a23c44f445062078e3c528c9f4c28c50a51",
      "holder": "0x000000000000000000000000000000000000dead",
      "delta": "18466827989974706400"
    }
  ]
}

That evidence matches the intended exploit effect exactly: native BNB leaves the EHX contract, while dead-address EHX balance increases due to forced buybacks. The price impact accumulates because each buyback adds WBNB to the pair and removes EHX from market circulation. Once the attacker had driven the pair to a sufficiently favorable state, they sold nearly the whole flash-loaned EHX position back into WBNB and exited.

The final trace segment shows the exit, repayment, and profit:

PancakePair::swap(5800154493083822263, 0, 0x9D0d28f7b9a9e6D55abb9e41a87df133F316C68C, 0x)
WBNB::transfer(0xFeAFe253802b77456B4627F8c2306a9CeBb5d681, 5589328092301986679)
WBNB::balanceOf(0x9D0d28f7b9a9e6D55abb9e41a87df133F316C68C) -> 210826400781835584
WBNB::transfer(0xddaaEDcf226729def824CC5c14382c5980844D1F, 210826400781835584)

The attacker received 5.800154493083822263 WBNB from the final sale, repaid 5.589328092301986679 WBNB to the DODO pool, and forwarded the remaining 0.210826400781835584 WBNB to the exploit EOA. After 0.078911457 BNB of gas spend, the net profit was 0.131914943781835584 BNB.

5. Adversary Flow Analysis

The adversary execution is a single-transaction ACT sequence with three on-chain stages:

  1. Flash-loan funding The EOA 0xddaaedcf226729def824cc5c14382c5980844d1f called helper contract 0x9d0d28f7b9a9e6d55abb9e41a87df133f316c68c, which borrowed 5.589328092301986679 WBNB from the public DODO pool 0xfeafe253802b77456b4627f8c2306a9cebb5d681.

  2. Buyback spam and price ramp The helper swapped the borrowed WBNB into EHX, then repeated 300 cycles of:

    • transfer 4349498877701 raw EHX units to the pair 0x3407c5398256cc242a7a22c373d9f252bab37458,
    • let EHX's _transfer() force a 0.001 BNB treasury buyback to the dead address,
    • recover 2446593118707 raw EHX units via the pair's public surplus handling.
  3. Exit and profit realization After the pair price had been pushed up, the helper sold 13048.496062231756949226 EHX back into WBNB, repaid the original flash loan, and transferred the residual 0.210826400781835584 WBNB to the EOA.

The exploit worked because every step was permissionless:

  • the flash-loan pool was public,
  • the Pancake router and pair were public,
  • the EHX trigger condition depended only on sender type and treasury balance,
  • skim() was public,
  • and the attacker did not need any real attacker-side artifact beyond a fresh helper contract to bundle the calls.

6. Impact & Losses

The measurable protocol-side loss was the EHX treasury's native BNB depletion:

  • BNB: 301000000000000000 raw wei (0.301 BNB), decimal = 18

Additional state impacts were material even though they are not recorded as the primary loss field:

  • the dead address received 18.4668279899747064 EHX from forced buybacks,
  • the EHX/WBNB pair's WBNB reserve was driven down to 0.208598435610846125 WBNB after the attacker's exit,
  • and the attacker realized 0.131914943781835584 BNB net profit after gas.

The affected public protocol components were the EHX token contract at 0xe1747a23c44f445062078e3c528c9f4c28c50a51 and the EHX/WBNB Pancake pair at 0x3407c5398256cc242a7a22c373d9f252bab37458.

7. References

  1. Seed exploit transaction: 0x8b528372b743b4b8c4eb0904c96529482653187c19e13afaa22f3ba4e08fbfbb on BSC block 33503912
  2. Victim token contract: 0xe1747a23c44f445062078e3c528c9f4c28c50a51 (verified EHX source)
  3. Exploited Pancake pair: 0x3407c5398256cc242a7a22c373d9f252bab37458 (BscScan similar-match verified PancakePair)
  4. Public flash-loan pool: 0xfeafe253802b77456b4627f8c2306a9cebb5d681
  5. Public router used in the flow: 0x10ed43c718714eb63d5aa57b78b54704e256024e
  6. Validator evidence set:
    • collected tx metadata for the seed transaction
    • opcode-level seed trace showing flash-loan funding, dust loops, final sale, repayment, and profit transfer
    • balance-diff artifact showing -301000000000000000 wei on the EHX treasury and +18466827989974706400 EHX on the dead address
    • auditor-added BscScan verification evidence for the pair at /workspace/session/artifacts/auditor/iter_1/pair_verification_bscscan.txt