All incidents

PHIL Public Mint Drain

Share
Dec 14, 2023 11:04 UTCAttackLoss: 2.1 WBNBPending manual check3 exploit txWindow: 2m 9s
Estimated Impact
2.1 WBNB
Label
Attack
Exploit Tx
3
Addresses
2
Attack Window
2m 9s
Dec 14, 2023 11:04 UTC → Dec 14, 2023 11:06 UTC

Exploit Transactions

TX 1BSC
0x20ecd8310a2cc7f7774aa5a045c8a99ad84a8451d6650f24e0911e9f4355b13a
Dec 14, 2023 11:04 UTCExplorer
TX 2BSC
0x4596dedc9bc6a9296c2348811d4c8192f1f8934da7567d290c92ee6710f1e02e
Dec 14, 2023 11:06 UTCExplorer
TX 3BSC
0xfd5c08353466b7ab0e9c0b274803a4414c36ed0dec0aeec6231f336b12bee166
Dec 14, 2023 11:06 UTCExplorer

Victim Addresses

0x4308d314096878d3bf16c9d8db86101f70bbebf1BSC
0xb8b408a6bd3e43fcde7d7abc381ef10bcccd5349BSC

Loss Breakdown

2.1WBNB

Similar Incidents

Root Cause Analysis

PHIL Public Mint Drain

1. Incident Overview TL;DR

On BNB Smart Chain, an unprivileged EOA exploited PHIL token contract 0x4308d314096878d3bf16c9d8db86101f70bbebf1 by calling simpleToken() in transaction 0x20ecd8310a2cc7f7774aa5a045c8a99ad84a8451d6650f24e0911e9f4355b13a. That call minted 120000000e18 PHIL to the caller with no authorization check. The same EOA then approved PancakeSwap V3 router 0x13f4ea83d0bd40e75c8222255bc855a974568dd4 in transaction 0x4596dedc9bc6a9296c2348811d4c8192f1f8934da7567d290c92ee6710f1e02e and dumped 21000e18 PHIL into the PHIL/WBNB 0.05% pool 0xb8b408a6bd3e43fcde7d7abc381ef10bcccd5349 in transaction 0xfd5c08353466b7ab0e9c0b274803a4414c36ed0dec0aeec6231f336b12bee166.

The root cause is a permissionless mint primitive in PHIL. simpleToken() overwrites both totalSupply and balances[msg.sender] with the fixed constant 120000000e18, emits a mint-style Transfer(address(0), msg.sender, amount), and performs no ownership, role, nonce, or one-time checks. Because the PHIL/WBNB PancakeSwap V3 pool already held WBNB liquidity, the freshly minted PHIL was immediately saleable, producing 2097725808690958892 wei of net BNB profit after fees.

2. Key Background

PHIL is a BEP20-style token deployed at 0x4308d314096878d3bf16c9d8db86101f70bbebf1 with name PhilC and symbol PHIL. Its market liquidity sat in PancakeSwap V3 pool 0xb8b408a6bd3e43fcde7d7abc381ef10bcccd5349, where token0 is PHIL, token1 is WBNB 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c, and the fee tier is 500 (0.05%).

Before the exploit sequence, the pool already held 2170776549750000000 wei of WBNB. That matters because the mint bug alone does not create profit unless a live market exists to absorb the inflated PHIL. PancakeSwap's router and the WBNB token are public protocol components, so no privileged integration or private orderflow was required.

The seed transaction metadata shows the exploit began from EOA 0x835b45d38cbdccf99e609436ff38e31ac05bc502 at BSC block 34345321 with direct calldata 0x2a64e635 to PHIL. The surrounding sequence and later repeat mints from the same EOA and a second EOA show that this was not an admin-only setup path or a one-off initializer.

3. Vulnerability Analysis & Root Cause Summary

This incident is an ATTACK-category ACT exploit rooted in broken mint authority and broken supply accounting inside PHIL. The critical safety invariant is simple: only authorized code paths should create PHIL supply, and any mint path must preserve consistent accounting across totalSupply and user balances. PHIL violates that invariant by exposing simpleToken() publicly and by hard-resetting state to a fixed mint amount instead of performing controlled incremental mint logic.

The updated auditor artifacts reconstruct the victim logic from PHIL runtime bytecode because the token is unverified on BscScan. The dispatch table routes selector 0x2a64e635 into a body at program counter 0x0a32, and the only gate before entry is the standard non-payable CALLVALUE == 0 check. Inside that body, the bytecode computes 120000000 * 10^18, stores it into slot 0x00 as totalSupply, stores the same value into keccak256(caller, 0x01) as balances[msg.sender], and emits a Transfer(address(0), caller, amount) event. There is no owner check, no minter role check, no one-time guard, and no attempt to preserve pre-existing balances or additive supply.

Because PancakeSwap already quoted PHIL against WBNB, the public mint was economically exploitable immediately. Any unprivileged EOA could mint PHIL, approve the router, and dump a chosen tranche into the live pool. The exploit therefore satisfies the ACT model: public state, public contracts, no privileged keys, and direct profit extraction from on-chain liquidity.

4. Detailed Root Cause Analysis

The exploit is deterministic from the bytecode and transaction evidence.

First, the PHIL runtime dispatch table shows that simpleToken() is reachable from any caller without an authorization branch:

00000063: PUSH4 0x2a64e635
00000068: EQ
00000069: PUSH2 0x026f
0000006c: JUMPI
...
0000026f: JUMPDEST
00000270: CALLVALUE
00000271: DUP1
00000272: ISZERO
00000273: PUSH2 0x027b
00000276: JUMPI
...
0000027d: PUSH2 0x0284
00000280: PUSH2 0x0a32
00000283: JUMP

Second, the mint body at 0x0a32 computes and stores the fixed tranche:

00000a32: JUMPDEST
00000a33: PUSH1 0x12
00000a35: PUSH1 0xff
00000a37: AND
00000a38: PUSH1 0x0a
00000a3a: EXP
00000a3b: PUSH4 0x07270e00
00000a40: MUL
00000a41: PUSH1 0x00
00000a43: DUP2
00000a44: SWAP1
00000a45: SSTORE
...
00000a91: PUSH1 0x00
00000a93: KECCAK256
00000a94: DUP2
00000a95: SWAP1
00000a96: SSTORE
...
00000af4: LOG3

0x07270e00 is 120000000, and the preceding EXP computes 10^18, so the stored value is exactly 120000000e18. The PHIL code-analysis artifact reconstructs the effective Solidity as:

function simpleToken() external {
    uint256 amount = 120000000 * 10**18;
    totalSupply = amount;
    balances[msg.sender] = amount;
    emit Transfer(address(0), msg.sender, amount);
}

The seed trace confirms that the live exploit call actually executed that path:

[26697] 0x4308D314096878D3bf16C9d8DB86101F70BBebF1::simpleToken()
  ├─ emit Transfer(param0: 0x0000000000000000000000000000000000000000, param1: 0x835B45D38cbDccf99E609436FF38E31Ac05bc502, param2: 120000000000000000000000000 [1.2e26])
  └─ ← [Stop]

From there, monetization required no additional vulnerability. The attacker approved the public PancakeSwap V3 router and swapped 21000000000000000000000 units of PHIL into the live PHIL/WBNB pool. Follow-up evidence shows the pool's WBNB balance fell from 2170776549750000000 wei to 72124815059041108 wei while the router returned 2098651734690958892 wei of WBNB before unwrap. This converted an arbitrary public mint into immediately spendable value.

Repeatability is also evidenced on chain. The same EOA called simpleToken() again in tx 0x59e1fc20b24e00131a6bbc141b4f48af3c2c35b874c25bb9443d7c3daa03623d, and another EOA did the same in tx 0xecdb8ea680b855f012de669bacc3cf94ae4096ebff852763c5d0c9a5fdd4c6af. That proves the bug was not tied to a single attacker identity or a one-time initialization window.

5. Adversary Flow Analysis

The adversary flow is a three-transaction single-chain sequence:

  1. 0x20ecd8310a2cc7f7774aa5a045c8a99ad84a8451d6650f24e0911e9f4355b13a at block 34345321

    • Caller: 0x835b45d38cbdccf99e609436ff38e31ac05bc502
    • Target: PHIL 0x4308d314096878d3bf16c9d8db86101f70bbebf1
    • Input: 0x2a64e635
    • Result: attacker receives 120000000e18 PHIL directly from the token contract.
  2. 0x4596dedc9bc6a9296c2348811d4c8192f1f8934da7567d290c92ee6710f1e02e at block 34345361

    • Caller: same EOA
    • Target: PHIL
    • Selector: 0x095ea7b3
    • Approved spender: PancakeSwap V3 router 0x13f4ea83d0bd40e75c8222255bc855a974568dd4
    • Approved amount: 2^256 - 1
  3. 0xfd5c08353466b7ab0e9c0b274803a4414c36ed0dec0aeec6231f336b12bee166 at block 34345364

    • Caller: same EOA
    • Target: PancakeSwap V3 router
    • Router call: multicall(uint256,bytes[])
    • Swap subcall selector: 0x04e45aaf
    • Unwrap selector: 0x49404b7c
    • Amount in: 21000e18 PHIL
    • Gross WBNB out: 2098651734690958892 wei

The adversary decision point was not about bypassing access control; it was simply how much minted PHIL to sell without over-shooting slippage. The realized sale used 21000e18 PHIL, leaving the attacker with the remainder of the minted tranche and extracting almost all WBNB from the pool in one swap.

6. Impact & Losses

The measurable loss is the WBNB removed from the PHIL/WBNB pool. The recorded pool loss is 2098651734690958892 wei of WBNB, which equals about 96.68% of the pool's pre-swap WBNB liquidity. That loss transferred directly to the attacker's route and was then unwrapped to native BNB.

Net attacker profit after gas was 2097725808690958892 wei of BNB. The fee breakdown for the three transactions is:

mint fee    = 143283000000000 wei
approve fee = 139191000000000 wei
swap fee    = 643452000000000 wei
total fee   = 925926000000000 wei
net profit  = 2097725808690958892 wei

The broader impact is larger than the realized swap. Because simpleToken() is permissionless and repeatable, the exploit opportunity remained open to the same attacker or any other unprivileged EOA until the vulnerable token or its market was neutralized.

7. References

  • Seed exploit transaction: 0x20ecd8310a2cc7f7774aa5a045c8a99ad84a8451d6650f24e0911e9f4355b13a
  • Approval transaction: 0x4596dedc9bc6a9296c2348811d4c8192f1f8934da7567d290c92ee6710f1e02e
  • Swap transaction: 0xfd5c08353466b7ab0e9c0b274803a4414c36ed0dec0aeec6231f336b12bee166
  • Repeat mint transactions: 0x59e1fc20b24e00131a6bbc141b4f48af3c2c35b874c25bb9443d7c3daa03623d, 0xecdb8ea680b855f012de669bacc3cf94ae4096ebff852763c5d0c9a5fdd4c6af
  • Victim token: PHIL 0x4308d314096878d3bf16c9d8db86101f70bbebf1
  • Victim liquidity pool: PancakeSwap V3 PHIL/WBNB 0.05% pool 0xb8b408a6bd3e43fcde7d7abc381ef10bcccd5349
  • Router: PancakeSwap V3 router 0x13f4ea83d0bd40e75c8222255bc855a974568dd4
  • Wrapped asset: WBNB 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c
  • Supporting evidence artifacts: PHIL runtime disassembly, PHIL bytecode reconstruction, seed trace, seed balance diff, and the auditor follow-up on-chain evidence summary