All incidents

Public Swap Helper Drain

Share
Jan 04, 2025 05:51 UTCAttackLoss: 27,995.39 USDTPending manual check1 exploit txWindow: Atomic
Estimated Impact
27,995.39 USDT
Label
Attack
Exploit Tx
1
Addresses
1
Attack Window
Atomic
Jan 04, 2025 05:51 UTC → Jan 04, 2025 05:51 UTC

Exploit Transactions

TX 1BSC
0x61da5b502a62d7e9038d73e31ceb3935050430a7f9b7e29b9b3200db3095f91d
Jan 04, 2025 05:51 UTCExplorer

Victim Addresses

0xb040d88e61ea79a1289507d56938a6ad9955349cBSC

Loss Breakdown

27,995.39USDT

Similar Incidents

Root Cause Analysis

Public Swap Helper Drain

1. Incident Overview TL;DR

At BNB Chain block 45462898, an unprivileged attacker exploited contract 0xb040d88e61ea79a1289507d56938a6ad9955349c by deploying a short-lived wrapper contract that queried the helper's full 98# token balance and then called the helper's public swap entry point with the attacker as the payout recipient. The helper sold its own 98# inventory through PancakeRouter and the downstream pair transferred 27995389614557976722846 raw USDT units to the attacker EOA 0x67a5f6bd9f8763c7e6c4ea0b54d1b14b9e5ee7e2. The root cause is straightforward: the helper exposed an anyone-callable swap function that could dispose of contract-held assets and redirect proceeds to an arbitrary recipient without any authorization check.

2. Key Background

The victim component is a custom swap helper at 0xb040d88e61ea79a1289507d56938a6ad9955349c. It already held a large balance of token 98# at 0xc0ddfd66420ccd3a337a17dd5d94eb54ab87523f, and its public swap path routed through PancakeRouter 0x10ed43c718714eb63d5aa57b78b54704e256024e into BNB Chain USDT 0x55d398326f99059ff775485246999027b3197955.

The attacker did not need a signature, allowance, ownership role, or prior state change inside the helper. The only prerequisites were that the helper still held inventory and that the public path remained usable. The observed swap settled through Pancake pair 0xa0ad4b45dc432e950f9e62aaa46995ce40ef4a11, which is where the final USDT transfer originated.

3. Vulnerability Analysis & Root Cause Summary

This is an access-control failure on an asset-disposal function. The helper contains many privileged or configuration-style entry points, but the exploited selector 0x81e3516d is not guarded by the same authorization path. Instead, the dispatcher jumps directly into logic that assembles a PancakeRouter call and forwards attacker-controlled parameters, including the recipient address.

The intended safety invariant is that only an authorized operator should be able to liquidate assets owned by the helper or redirect the proceeds away from the owner-controlled destination. That invariant breaks when any caller can invoke the public swap path with a chosen token path, amount, and recipient. Once that happens, the router simply treats the helper as the token source because the helper already owns the assets and already has the necessary swap configuration in place. The exploit is therefore deterministic and permissionless: if the helper holds swappable inventory, any searcher can convert it into value payable to themselves.

4. Detailed Root Cause Analysis

The collected runtime disassembly shows the vulnerable dispatch and router handoff:

00000137: PUSH4 0x81e3516d
0000013c: EQ
0000013d: PUSH2 0x0518
00000140: JUMPI
...
000012dc: JUMPDEST
000012dd: PUSH20 0x10ed43c718714eb63d5aa57b78b54704e256024e
000012f2: PUSH4 0x5c11d795
...
0000133f: CALL

In operational terms, the exploit transaction deployed a transient constructor wrapper, read the helper's current 98# balance, and immediately used that value as amountIn for the helper call. The seed trace captures the exact sequence:

→ new <unknown>@0xf455c70916252939f92616C8312F131fE37D013F(...)
  ├─ Token::balanceOf(0xB040D88e61EA79a1289507d56938a6AD9955349C)
  │  └─ ← 97555900794950304298569411189
  ├─ 0xB040D88e61EA79a1289507d56938a6AD9955349C::swapTokensForTokens(
  │    [98#, USDT],
  │    97555900794950304298569411189,
  │    0,
  │    0x67A5f6bd9F8763c7E6C4EA0b54D1b14B9e5ee7E2
  │  )

The downstream trace then shows the helper calling PancakeRouter's swapExactTokensForTokensSupportingFeeOnTransferTokens, which transfers the helper's 98# inventory into pair 0xa0ad4b45dc432e950f9e62aaa46995ce40ef4a11 and sends the resulting USDT to the attacker-chosen recipient. The balance diff confirms the economic result: the attacker gains 27995389614557976722846 raw USDT units while the pair loses the same amount. No privileged actor participates anywhere in this sequence.

5. Adversary Flow Analysis

The adversary flow has three concrete stages.

First, EOA 0x67a5f6bd9f8763c7e6c4ea0b54d1b14b9e5ee7e2 sends transaction 0x61da5b502a62d7e9038d73e31ceb3935050430a7f9b7e29b9b3200db3095f91d and creates transient contract 0xf455c70916252939f92616c8312f131fe37d013f.

Second, the transient contract reads the helper's entire 98# balance and invokes the helper's public swap function with path [98#, USDT], amountOutMin = 0, and the attacker EOA as recipient. That call succeeds because the helper imposes no caller check on selector 0x81e3516d.

Third, PancakeRouter forwards the swap to pair 0xa0ad4b45dc432e950f9e62aaa46995ce40ef4a11, which emits the final transfer of 27995389614557976722846 USDT units to the attacker. The exploit completes in one transaction, with no setup beyond calldata construction and normal gas payment.

6. Impact & Losses

The measurable loss is 27995389614557976722846 raw USDT units (18 decimals) redirected to the attacker. The helper's exploited 98# inventory is also fully drained along the swap path, but the directly quantified loss in the collected artifacts is the USDT value extracted from the downstream pair and realized by the attacker.

Gas cost does not change the exploit classification. The balance diff shows the attacker paid 18280700000000000 wei in native gas, while the received USDT amount remained overwhelmingly positive on a net basis.

7. References

  1. Seed transaction: 0x61da5b502a62d7e9038d73e31ceb3935050430a7f9b7e29b9b3200db3095f91d
  2. Helper contract: 0xb040d88e61ea79a1289507d56938a6ad9955349c
  3. Attacker EOA: 0x67a5f6bd9f8763c7e6c4ea0b54d1b14b9e5ee7e2
  4. Transient exploit contract: 0xf455c70916252939f92616c8312f131fe37d013f
  5. PancakeRouter: 0x10ed43c718714eb63d5aa57b78b54704e256024e
  6. Pancake pair: 0xa0ad4b45dc432e950f9e62aaa46995ce40ef4a11
  7. Supporting evidence:
    • /workspace/session/artifacts/collector/seed/56/0x61da5b502a62d7e9038d73e31ceb3935050430a7f9b7e29b9b3200db3095f91d/metadata.json
    • /workspace/session/artifacts/collector/seed/56/0x61da5b502a62d7e9038d73e31ceb3935050430a7f9b7e29b9b3200db3095f91d/trace.cast.log
    • /workspace/session/artifacts/collector/seed/56/0x61da5b502a62d7e9038d73e31ceb3935050430a7f9b7e29b9b3200db3095f91d/balance_diff.json
    • /workspace/session/artifacts/auditor/iter_0/b040_runtime_disassembly.txt