All incidents

EEECOIN Public Helper LP Drain

Share
Nov 30, 2023 09:05 UTCAttackLoss: 69,877.08 USDTPending manual check2 exploit txWindow: 13m 36s
Estimated Impact
69,877.08 USDT
Label
Attack
Exploit Tx
2
Addresses
2
Attack Window
13m 36s
Nov 30, 2023 09:05 UTC → Nov 30, 2023 09:19 UTC

Exploit Transactions

TX 1BSC
0x5c4dd4c4764fb0804c8e1b778899f4412bd9db21da5bda9c710b6b52c5756bc7
Nov 30, 2023 09:05 UTCExplorer
TX 2BSC
0x7312d9f9c13fc69f00f58e92a112a3e7f036ced7e65f7e0fa67382488d5557dc
Nov 30, 2023 09:19 UTCExplorer

Victim Addresses

0x5002f2d9ac1763f9cf02551b3a72a42e792ae9eaBSC
0x0506e571aba3dd4c9d71bed479a4e6d40d95c833BSC

Loss Breakdown

69,877.08USDT

Similar Incidents

Root Cause Analysis

EEECOIN Public Helper LP Drain

1. Incident Overview TL;DR

On BNB Smart Chain block 33940984, attacker EOA 0xb06d402705ad5156b42e4279903cbd7771cf59c9 used a freshly deployed wrapper contract 0x9a16b5375e79e409a8bfdb17cfe568e533c2d7c5 to flash-borrow 750000000000000000000000 USDT from pair 0xa75c7eef342fc4c024253aa912f92c8f4c0401b0, buy EEE from pair 0x0506e571aba3dd4c9d71bed479a4e6d40d95c833, and repeatedly call helper 0x5002f2d9ac1763f9cf02551b3a72a42e792ae9ea through public selector swap(address,uint256). Each profitable helper call consumed LP already owned by the helper, redeemed USDT from the EEE/USDT pair, and routed most of that USDT back to the attacker path. The wrapper then sold the remaining EEE, repaid 751950000000000000000000 USDT to the flash-loan pair, and transferred 22814429976888383296284 USDT to the attacker EOA.

The root cause is an anyone-can-take asset-drain primitive in helper 0x5002. The helper exposes a public function that monetizes LP inventory held by the helper itself rather than caller-owned LP or caller-scoped accounting. Because that inventory and the entrypoint were both publicly observable, any unprivileged actor could reproduce the same drain.

2. Key Background

EEECOIN uses token 0x297f3996ce5c2dcd033c77098ca9e1acc3c3c3ee against USDT 0x55d398326f99059ff775485246999027b3197955 in pair 0x0506e571aba3dd4c9d71bed479a4e6d40d95c833. The helper contract 0x5002f2d9ac1763f9cf02551b3a72a42e792ae9ea is unverified on BscScan, but its collected selector table exposes public getters token(), router(), uniswapPair(), USDT(), plus state-changing functions swap(address,uint256) and withdrawtoken().

Direct call history into the helper before the exploit shows that it was not private infrastructure. In the sampled pre-exploit window, the helper received 34 successful top-level calls from many unrelated EOAs, with 23 successful swap(address,uint256) calls and 11 successful withdrawtoken() calls. LP transfer history for pair 0x0506 also shows repeated mint_to_helper events into 0x5002 before the exploit block, so the helper was already holding EEE/USDT LP inventory in public pre-state.

The attacker did not need privileged roles, a pre-existing LP position, or attacker-controlled victim-side contracts. The only adversary-crafted transactions were:

  1. Deployment of wrapper 0x9a16b5375e79e409a8bfdb17cfe568e533c2d7c5 in tx 0x5c4dd4c4764fb0804c8e1b778899f4412bd9db21da5bda9c710b6b52c5756bc7.
  2. The exploit transaction 0x7312d9f9c13fc69f00f58e92a112a3e7f036ced7e65f7e0fa67382488d5557dc.

3. Vulnerability Analysis & Root Cause Summary

The vulnerability is a public helper function that spends protocol-owned LP without binding redemption rights to the caller. The invariant that should hold is simple: LP held by helper 0x5002 and the USDT claimable from that LP are protocol-owned inventory, so arbitrary callers must not be able to redeem them unless the caller supplies its own LP or an equivalent credited balance. The exploit breaks that invariant because helper swap(address,uint256) accepts caller-supplied EEE, but the liquidity redeemed by the function comes from helper-owned LP balances already sitting in 0x5002.

The runtime bytecode provides a concrete breakpoint. Selector 0xd004f0f7 dispatches into bytecode entry 0x1ee0, and later the same function constructs a call with selector 0xbaa2abde, the router signature for removeLiquidity(address,address,uint256,uint256,uint256,address,uint256), with ADDRESS pushed as the liquidity recipient. The same function also reaches selectors 0x5c11d795 and 0xe8e33700, matching swapExactTokensForTokensSupportingFeeOnTransferTokens and addLiquidity. This matches the observed trace: helper LP is burned, a portion of recovered USDT is swapped back into EEE and re-added as LP, and the rest is paid out.

This is an ATTACK root-cause category. The design violates three explicit security principles from the incident artifacts: protocol-owned assets must not be spendable through public entrypoints without caller-scoped authorization; payout logic must be tied to caller-owned positions or explicit accounting rather than global inventory; and public helper contracts must not expose sensitive inventory redemption as an unrestricted primitive.

Helper bytecode disassembly excerpt:

00001ee0: JUMPDEST
00001ee1: PUSH1 0x1a
00001ee3: SLOAD
...
00004921: ADDRESS
00004922: PUSH1 0xa4
...
00004932: PUSH4 0xbaa2abde
00004947: CALL

The weakness is therefore not a private-key compromise, governance action, or hidden off-chain dependency. It is a public on-chain redemption path over helper-held inventory.

4. Detailed Root Cause Analysis

The exploit sequence starts from a publicly reconstructible pre-state immediately before tx 0x7312d9f9c13fc69f00f58e92a112a3e7f036ced7e65f7e0fa67382488d5557dc. At that point, helper 0x5002 already held EEE/USDT LP minted to itself from earlier public transactions, and its public getters resolved to token 0x297f3996ce5c2dcd033c77098ca9e1acc3c3c3ee, pair 0x0506e571aba3dd4c9d71bed479a4e6d40d95c833, router 0x8d3814cff3d544e6294237949d64af6362a64450, and USDT 0x55d398326f99059ff775485246999027b3197955.

The wrapper first flash-borrowed USDT and bought EEE from pair 0x0506. The beginning of the exploit logs shows the borrowed USDT moving in, then the pair returning EEE to the attacker wrapper:

log 89  USDT Transfer  flashloan_pair -> attacker_wrapper  750000000000000000000000
log 90  USDT Transfer  attacker_wrapper -> EEE/USDT pair   750000000000000000000000
log 92  EEE  Transfer  EEE/USDT pair -> attacker_wrapper   49400000000000000000000000

The wrapper then approved helper 0x5002 and invoked swap(address,uint256). In the first profitable cycle it sent 3000000000000000000000000 EEE to the helper. The exploit trace shows that this call did not redeem caller-owned LP; instead it spent LP already held by 0x5002, burned it through the router, and routed USDT back to the attacker path:

Exploit transaction decoded logs, first profitable helper cycle:

log 98   EEE  Transfer  attacker_wrapper -> helper         3000000000000000000000000
log 100  LP   Transfer  helper -> EEE/USDT pair           709487622794734353930052
log 105  Burn           amount0=2999999999999999999999997 amount1=271744575945722198320450
log 124  USDT Transfer  helper -> attacker_wrapper        176633974364719428908295

The structured call summary confirms the exact same pattern at the function-call level. The first eight helper invocations spent helper-owned LP and paid USDT to the attacker wrapper in the following amounts:

swap amount 3000000 EEE  -> helper LP spent 709487622794734353930052 -> attacker USDT 176633974364719428908295
swap amount  800000 EEE  -> helper LP spent 198443093638887334158280 -> attacker USDT  51824909552683541526585
swap amount  800000 EEE  -> helper LP spent 201279429608454377303024 -> attacker USDT  53318840805456293308981
swap amount  800000 EEE  -> helper LP spent 204584377217400210199218 -> attacker USDT  55086404736390576733205
swap amount  800000 EEE  -> helper LP spent 208531274703041120848776 -> attacker USDT  57235106166749671815781
swap amount  800000 EEE  -> helper LP spent 213408305794268415308340 -> attacker USDT  59947021073714119063652
swap amount  800000 EEE  -> helper LP spent 219746551834412503351518 -> attacker USDT  63565358756079262545891
swap amount  800000 EEE  -> helper LP spent 228692214209079841314795 -> attacker USDT  68852814521095489393894

The trace contains one additional final swap(address,uint256) call with _amount = 800000000000000000000000, but that ninth call performs no LP spend and produces no attacker USDT payout. The economically relevant drain is the eight LP-spending redemptions above.

LP-transfer history proves those redeemed LP tokens were not introduced by the attacker during the exploit. Before the exploit block, helper 0x5002 had already accumulated many inbound mint_to_helper events from unrelated public transactions. During the exploit tx, the same pair emits alternating helper -> pair LP burns and mint_to_helper replenishments, confirming that the helper repeatedly burns its own LP, partially recycles proceeds, and still leaves substantial USDT payouts for the caller.

The exploit ends with the attacker selling its remaining EEE back into pair 0x0506, repaying the flash-loan pair, and transferring net profit to the attacker EOA:

log 351  USDT Transfer  attacker_wrapper -> flashloan_pair  751950000000000000000000
log 352  USDT Transfer  attacker_wrapper -> attacker_eoa     22814429976888383296284

The deterministic exploit conditions are therefore:

  1. Helper 0x5002 must already hold LP for pair 0x0506.
  2. Public selector swap(address,uint256) must remain callable.
  3. The attacker must source EEE to feed the helper, which the observed transaction achieves with a public flash swap and market buy.

5. Adversary Flow Analysis

The attacker strategy is a two-transaction ACT flow on BNB Smart Chain.

First, EOA 0xb06d402705ad5156b42e4279903cbd7771cf59c9 deployed wrapper 0x9a16b5375e79e409a8bfdb17cfe568e533c2d7c5 in block 33940712. This wrapper exists only to orchestrate the flash-loan callback and public helper calls.

Second, in block 33940984, the same EOA called the wrapper with calldata selector 0x007826c7. The wrapper:

  1. Borrowed 750000000000000000000000 USDT from flash-loan pair 0xa75c7eef342fc4c024253aa912f92c8f4c0401b0.
  2. Sent that USDT into pair 0x0506 and bought 49400000000000000000000000 EEE.
  3. Approved helper 0x5002 to pull EEE.
  4. Called helper swap(address,uint256) repeatedly, first with 3000000000000000000000000 EEE and then with eight 800000000000000000000000 EEE attempts.
  5. Received helper-routed USDT back into the wrapper after each profitable call.
  6. Sold the remaining EEE back into pair 0x0506.
  7. Repaid 751950000000000000000000 USDT to the flash-loan pair.
  8. Sent the residual 22814429976888383296284 USDT profit to the attacker EOA.

The attacker-related accounts are defensible and complete for this incident:

  • EOA 0xb06d402705ad5156b42e4279903cbd7771cf59c9: deployment sender and final profit recipient.
  • Contract 0x9a16b5375e79e409a8bfdb17cfe568e533c2d7c5: attacker wrapper that directly called helper 0x5002.

The victim-side components are helper 0x5002f2d9ac1763f9cf02551b3a72a42e792ae9ea, router 0x8d3814cff3d544e6294237949d64af6362a64450, pair 0x0506e571aba3dd4c9d71bed479a4e6d40d95c833, token 0x297f3996ce5c2dcd033c77098ca9e1acc3c3c3ee, and USDT 0x55d398326f99059ff775485246999027b3197955.

6. Impact & Losses

The measurable victim-side loss is borne by pair 0x0506e571aba3dd4c9d71bed479a4e6d40d95c833, whose USDT balance dropped by 69877078436649028165218 units in the exploit transaction. The seed balance-diff artifact also shows where that value went:

[
  {
    "holder": "0x0506e571aba3dd4c9d71bed479a4e6d40d95c833",
    "delta": "-69877078436649028165218"
  },
  {
    "holder": "0xb06d402705ad5156b42e4279903cbd7771cf59c9",
    "delta": "22814429976888383296284"
  },
  {
    "holder": "0xa75c7eef342fc4c024253aa912f92c8f4c0401b0",
    "delta": "1950000000000000000000"
  }
]

That loss was split among attacker profit, helper payout addresses 0xe568a4ce2eb77d230e1473d2cfd5b5e2129f69a8 and 0xfef7b2b4fd8f9fdca24713999a5e76c044ccfc0d, and the flash-loan fee retained by the lending pair. Gas paid by the attacker EOA was 0.009747507 BNB, which does not change the positive-profit conclusion. The incident therefore converted helper-held LP and underlying pair reserves into immediately withdrawable USDT through a public entrypoint.

7. References

  1. Exploit deployment tx: 0x5c4dd4c4764fb0804c8e1b778899f4412bd9db21da5bda9c710b6b52c5756bc7
  2. Exploit tx: 0x7312d9f9c13fc69f00f58e92a112a3e7f036ced7e65f7e0fa67382488d5557dc
  3. Helper contract: 0x5002f2d9ac1763f9cf02551b3a72a42e792ae9ea
  4. EEE/USDT pair: 0x0506e571aba3dd4c9d71bed479a4e6d40d95c833
  5. Router used by helper: 0x8d3814cff3d544e6294237949d64af6362a64450
  6. EEE token: 0x297f3996ce5c2dcd033c77098ca9e1acc3c3c3ee
  7. USDT token: 0x55d398326f99059ff775485246999027b3197955
  8. Flash-loan pair: 0xa75c7eef342fc4c024253aa912f92c8f4c0401b0
  9. Evidence used: exploit transaction call summary, decoded logs, helper/router bytecode summaries and disassembly, helper address activity summary, helper LP-transfer history, and seed balance diff for the exploit transaction.
EEECOIN Public Helper LP Drain | Clara