All incidents

FPR Custody Admin-Seizure Drain

Share
Dec 14, 2022 18:28 UTCAttackLoss: 29,852.04 USDTPending manual check4 exploit txWindow: 1h 37m
Estimated Impact
29,852.04 USDT
Label
Attack
Exploit Tx
4
Addresses
4
Attack Window
1h 37m
Dec 14, 2022 18:28 UTC → Dec 14, 2022 20:06 UTC

Exploit Transactions

TX 1BSC
0xec1b969e1435a1449dd5179404c54b5c60e49f15a1bf6bf8922e8d2978102f4a
Dec 14, 2022 18:28 UTCExplorer
TX 2BSC
0x1b66170220287bd90f72a97368f8dea2420a24c9585e9f39bf236af6d2a7dde6
Dec 14, 2022 18:29 UTCExplorer
TX 3BSC
0x43da4322052b045f442cdfc03bcccc797d3bba467beda501222c35d8fd0ebd81
Dec 14, 2022 18:29 UTCExplorer
TX 4BSC
0x1f8e814029a073c52a8668e6ff5bb3264445a8b29886cc9e3ca8ed5f89ccacd3
Dec 14, 2022 20:06 UTCExplorer

Victim Addresses

0x81c5664be54d89e725ef155f14cf34e6213297b7BSC
0xe2f0a9b60858f436e1f74d8cdbe03625b9bcc532BSC
0x39eb555f5f7afd11224ca10e406dba05b4e21bd3BSC
0xba5b235cddaac2595bce6bab79274f57fb82bf27BSC

Loss Breakdown

29,852.04USDT

Similar Incidents

Root Cause Analysis

FPR Custody Admin-Seizure Drain

1. Incident Overview TL;DR

Across four attacker-crafted BNB Chain transactions, the attacker cluster centered on EOA 0xe3104e645bc3f6fd821930a6a39ee509a0e87d3b repeatedly seized control of FPR custody contracts, withdrew the contracts' token or LP balances, and liquidated the recovered assets into USDT. The observed helper contracts were 0xe3293f89fd3b9336ac2d514ec4a90477ca94b0d8 and 0x5dd07f8b12b8d5dbdf3664c2fa7c37da5048b462, and the four seed transactions realized 29852036609404116752868 raw USDT units in aggregate.

The root cause is an unauthenticated setAdmin(address) function that rewrites the CurrentOwner storage slot without checking msg.sender. Because remaining(address,address) only checks msg.sender == CurrentOwner before transferring the contract's full ERC20 balance to an arbitrary recipient, any unprivileged caller can first set itself as owner and then drain the custody contract.

2. Key Background

The affected contracts are small FPR-related custody contracts on BNB Chain:

  • 0x81c5664be54d89e725ef155f14cf34e6213297b7
  • 0xe2f0a9b60858f436e1f74d8cdbe03625b9bcc532
  • 0x39eb555f5f7afd11224ca10e406dba05b4e21bd3
  • 0xba5b235cddaac2595bce6bab79274f57fb82bf27

The first three contracts store time-allocation state such as startTime, oneDay, nintyDay, tokenAddr, recAddress, CurrentOwner, and lastTime. The fourth stores signAddress, tokenAddr, CurrentOwner, and user-order mappings. Despite serving slightly different business flows, all four expose the same dangerous administrative pair: setAdmin(address) and remaining(address,address).

The representative exploit used victim contract 0x81c5664be54d89e725ef155f14cf34e6213297b7, FPR token 0xa9c7ec037797dc6e3f9255ffde422da6bf96024d, PancakeRouter 0x10ed43c718714eb63d5aa57b78b54704e256024e, and USDT 0x55d398326f99059ff775485246999027b3197955. Before tx 0xec1b969e1435a1449dd5179404c54b5c60e49f15a1bf6bf8922e8d2978102f4a, the victim still held 29729739764442 raw FPR units, making the custody balance immediately recoverable once ownership was seized.

3. Vulnerability Analysis & Root Cause Summary

This incident is an ATTACK-category access-control failure. The intended invariant is straightforward: only the incumbent owner should be able to change CurrentOwner, and contract-held tokens or LP tokens should leave the custody contract only through a legitimately authorized path that preserves the custody policy. The code breaks that invariant because setAdmin(address) has selector 0x704b6c02 and performs a direct write to CurrentOwner with no authorization check. The companion function remaining(address,address) treats CurrentOwner as the only authorization source and then transfers the contract's full balance of any supplied token address to an arbitrary recipient. Once an attacker can rewrite CurrentOwner, the owner gate in remaining no longer provides any protection. The exploit is therefore deterministic: become owner, withdraw the victim-held asset, and liquidate it through public AMM liquidity. The same primitive exists across all four identified custody contracts, which is why the attacker reused the same flow multiple times.

4. Detailed Root Cause Analysis

The representative victim decompilation shows the exact breakpoint:

function setAdmin(address arg0) public payable {
    CurrentOwner = (address(arg0)) | (uint96(CurrentOwner));
}

function remaining(address arg0, address arg1) public payable {
    require(msg.sender == (address(CurrentOwner)), "Ownable: caller is not the owner");
    address var_b = address(this);
    (bool success, bytes memory ret0) = address(arg1).Unresolved_70a08231(var_b); // balanceOf(this)
    (bool success, bytes memory ret0) = address(arg1).{ value: 0 ether }adfepixw(); // transfer(arg0, fullBalance)
}

The same unauthenticated setAdmin(address) and owner-gated remaining(address,address) pair also appears in the LP-locker contract 0xba5b235cddaac2595bce6bab79274f57fb82bf27, showing the issue is systemic rather than isolated to one instance.

The pre-state for the ACT opportunity is BNB Chain block 23904139, before helper deployment tx 0x033def1674a3b5593dcf34d0e9fd79359e4db52c6c9b4fc2706d76a79b48d5d1. At that point the vulnerable custody contracts were already deployed, held recoverable balances, and exposed publicly callable bytecode. No privileged information or privileged keys were required; the attacker only needed standard transaction submission and public on-chain state.

The seed trace for tx 0xec1b969e1435a1449dd5179404c54b5c60e49f15a1bf6bf8922e8d2978102f4a confirms the exploit sequence:

0x81c5664be54d89E725ef155F14cf34e6213297B7::setAdmin(0xe3293F89FD3B9336Ac2d514Ec4a90477ca94b0d8)
0x81c5664be54d89E725ef155F14cf34e6213297B7::remaining(0xe3293F89FD3B9336Ac2d514Ec4a90477ca94b0d8, BEP20FPR: [0xA9c7ec037797DC6E3F9255fFDe422DA6bF96024d])
BEP20FPR::transfer(0xe3293F89FD3B9336Ac2d514Ec4a90477ca94b0d8, 29729739764442)
BEP20USDT::transfer(0xE3104e645BC3f6fD821930a6a39EE509a0E87D3b, 26274795847172541865812)

The corresponding balance-diff artifact shows the same state transition numerically:

{
  "victim_fpr_before": "29729739764442",
  "victim_fpr_after": "1",
  "attacker_usdt_before": "0",
  "attacker_usdt_after": "26274795847172541865812"
}

This proves the end-to-end mechanism. First, slot 0 is rewritten to an attacker-controlled address. Second, remaining transfers the victim contract's full FPR balance out, leaving only one unit of dust. Third, the helper liquidates the recovered FPR through PancakeRouter and the attacker EOA receives USDT proceeds. The same logic explains the other seed transactions and the LP-locker drain, where the recovered asset is LP-derived value rather than only raw FPR.

5. Adversary Flow Analysis

The adversary strategy is a reusable single-transaction drain flow: deploy or reuse a helper contract, seize ownership with setAdmin, withdraw with remaining, and liquidate the recovered asset.

The observed lifecycle is:

  1. Helper deployment:
    • 0x033def1674a3b5593dcf34d0e9fd79359e4db52c6c9b4fc2706d76a79b48d5d1 created helper 0xe3293f89fd3b9336ac2d514ec4a90477ca94b0d8.
    • 0x1f8e814029a073c52a8668e6ff5bb3264445a8b29886cc9e3ca8ed5f89ccacd3 created helper 0x5dd07f8b12b8d5dbdf3664c2fa7c37da5048b462.
  2. Unauthorized admin seizure and withdrawal:
    • 0xec1b969e1435a1449dd5179404c54b5c60e49f15a1bf6bf8922e8d2978102f4a
    • 0x1b66170220287bd90f72a97368f8dea2420a24c9585e9f39bf236af6d2a7dde6
    • 0x43da4322052b045f442cdfc03bcccc797d3bba467beda501222c35d8fd0ebd81
    • 0x1f8e814029a073c52a8668e6ff5bb3264445a8b29886cc9e3ca8ed5f89ccacd3
  3. Asset liquidation:
    • Recovered FPR was sold through PancakeRouter into USDT.
    • In the LP-locker case, LP tokens were redeemed into component assets and the FPR leg was also sold into USDT.

The attacker cluster is defensibly identified. Creator-lookup data ties helper 0xe3293f89fd3b9336ac2d514ec4a90477ca94b0d8 to EOA 0xe3104e645bc3f6fd821930a6a39ee509a0e87d3b, and the seed traces show that helper executing the exploit path against victim contracts. The same EOA sent all four seed transactions, making the cluster attribution coherent across the full incident.

6. Impact & Losses

The observed attacker cluster extracted value from four FPR-related custody contracts and realized the proceeds as USDT. The recorded aggregate loss is:

[
  {
    "token_symbol": "USDT",
    "amount": "29852036609404116752868",
    "decimal": 18
  }
]

For the representative exploit transaction alone, the attacker EOA's USDT balance increased by 26274795847172541865812 raw units, while the victim custody contract's FPR balance fell from 29729739764442 to 1. The repeated reuse of the same primitive across multiple contracts shows the vulnerability was permissionless and repeatable by any unprivileged adversary.

7. References

  • Tx 0x033def1674a3b5593dcf34d0e9fd79359e4db52c6c9b4fc2706d76a79b48d5d1: helper deployment creating 0xe3293f89fd3b9336ac2d514ec4a90477ca94b0d8
  • Tx 0xec1b969e1435a1449dd5179404c54b5c60e49f15a1bf6bf8922e8d2978102f4a: representative exploit trace and balance diff
  • Tx 0x1b66170220287bd90f72a97368f8dea2420a24c9585e9f39bf236af6d2a7dde6: repeated custody drain
  • Tx 0x43da4322052b045f442cdfc03bcccc797d3bba467beda501222c35d8fd0ebd81: repeated custody drain
  • Tx 0x1f8e814029a073c52a8668e6ff5bb3264445a8b29886cc9e3ca8ed5f89ccacd3: LP-locker drain and helper creation for 0x5dd07f8b12b8d5dbdf3664c2fa7c37da5048b462
  • Decompilations:
    • 0x81c5664be54d89e725ef155f14cf34e6213297b7
    • 0xe2f0a9b60858f436e1f74d8cdbe03625b9bcc532
    • 0x39eb555f5f7afd11224ca10e406dba05b4e21bd3
    • 0xba5b235cddaac2595bce6bab79274f57fb82bf27
  • Helper creator attribution: 0xe3293f89fd3b9336ac2d514ec4a90477ca94b0d8 created by 0xe3104e645bc3f6fd821930a6a39ee509a0e87d3b