All incidents

RANT LP Drain Root Cause

Share
Jul 05, 2025 15:16 UTCAttackLoss: 102,509,423.18 RANTPending manual check1 exploit txWindow: Atomic
Estimated Impact
102,509,423.18 RANT
Label
Attack
Exploit Tx
1
Addresses
2
Attack Window
Atomic
Jul 05, 2025 15:16 UTC → Jul 05, 2025 15:16 UTC

Exploit Transactions

TX 1BSC
0x2d9c1a00cf3d2fda268d0d11794ad2956774b156355e16441d6edb9a448e5a99
Jul 05, 2025 15:16 UTCExplorer

Victim Addresses

0xc321ac21a07b3d593b269acdace69c3762ca2dd0BSC
0x42a93c3af7cb1bbc757dd2ec4977fd6d7916ba1dBSC

Loss Breakdown

102,509,423.18RANT

Similar Incidents

Root Cause Analysis

RANT LP Drain Root Cause

1. Incident Overview TL;DR

On BSC block 52974382, transaction 0x2d9c1a00cf3d2fda268d0d11794ad2956774b156355e16441d6edb9a448e5a99 used a single permissionless transaction to flash-borrow WBNB, buy RANT from the WBNB/RANT PancakePair, trigger RANT's public sell hook, and dump back into the manipulated pool. The exploitable condition is inside RANTToken: a normal transfer-to-token sell path calls _sellBurnLiquidityPairTokens(amount), which debits the pair's RANT balance, sends part to 0xdead and part to rant_node, and then calls pair.sync(). That lets any unprivileged trader force a reserve reduction that they did not pay for and immediately arbitrage the resulting price jump.

2. Key Background

RANT is a token with custom transfer logic layered on top of a PancakeSwap V2-style pair. Its verified source shows special handling for pair interactions and for transfers whose recipient is the token contract itself. The victim LP was the public WBNB/RANT pair at 0x42a93c3af7cb1bbc757dd2ec4977fd6d7916ba1d, whose metadata confirms token0=WBNB and token1=RANT. The flash-liquidity source was the verified PancakeV3Pool at 0x172fcd41e0913e95784454622d1c3724f546f849, whose token1 is WBNB.

3. Vulnerability Analysis & Root Cause Summary

The vulnerability is a permissionless LP-drain hook embedded in RANT's public sell path. In the non-pair branch of RANTToken._transfer, any transfer to address(this) can invoke _sellBurnLiquidityPairTokens(amount) before the token routes the sale onward through rant_center. That helper computes noteAmount and deadAmount directly from the caller-chosen amount, then transfers those tokens out of uniswapPair rather than from the seller's balance. After draining the pair, it calls pair.sync(), which updates reserves to the reduced RANT balance and moves the spot price in the attacker's favor. The attack therefore does not depend on privileged roles, private keys, or attacker-side incident artifacts. It is an ACT opportunity because any unprivileged actor can source temporary WBNB, acquire RANT, trigger the public hook, and exit against the manipulated pair.

4. Detailed Root Cause Analysis

The critical victim code path is:

if (!isWhiteList(sender) && !isWhiteList(recipient)) {
    require(recipient == address(this), "wrong address");
    if (!lockburn) {
        _sellBurnLiquidityPairTokens(amount);
    }
    super._transfer(sender, address(rant_center), amount);
    rant_center.sell_rant(amount, sender);
}

The LP drain happens inside the helper:

(uint256 noteAmount, uint256 deadAmount) = caculateSellBurnToAmount(_amount);
super._transfer(uniswapPair, address(0xdead), deadAmount);
super._transfer(uniswapPair, address(rant_node), noteAmount);
rant_node.depositBonusToken(noteAmount);
IUniswapV2Pair(uniswapPair).sync();

caculateSellBurnToAmount derives both drain amounts directly from _amount, so the seller controls the magnitude of the reserve theft. The drained tokens come from uniswapPair, not from the caller. The seed trace shows the exploit flow invoking the PancakeV3 flash(...) entrypoint and later the victim pair sync(). The collector balance diff confirms the resulting state transition: the pair lost 102509423181903444010952438 RANT, 0x000000000000000000000000000000000000dead gained 9660573064263151791608375 RANT, rant_node gained 1073397007140350199067597 RANT, and the attacker EOA gained 311475873604407652863 wei net.

5. Adversary Flow Analysis

The adversary EOA 0xad2cb8f48e74065a0b884af9c5a4ecbba101be23 submitted the only transaction in its collected block window and created helper contract 0x1e2d48e640243b04a9fa76eb49080e9ab110b4ac. The execution trace then shows working contract 0xfd9267ee6594bd8e82e8030c353870fa1773f7f8 calling PancakeV3Pool.flash to borrow WBNB. That capital was used to buy 96.605739642631517916080650 RANT from the WBNB/RANT pair. The attacker then transferred RANT through the public sell path by sending tokens to the RANT contract, which triggered the LP-draining hook and pair.sync(). With the pair's RANT reserve sharply reduced, the attacker exited back into the same pool at a much higher effective price, repaid the flash loan plus fee, and retained the remaining value as profit.

6. Impact & Losses

The measurable victim loss was borne by the WBNB/RANT LP. The collector balance diff records a reduction of 102509423181903444010952438 RANT from the pair, with part of the drained inventory moved to 0xdead and part to rant_node. The attacker realized a net native balance gain of 311475873604407652863 wei. The affected public components were RANTToken at 0xc321ac21a07b3d593b269acdace69c3762ca2dd0 and the WBNB/RANT PancakePair at 0x42a93c3af7cb1bbc757dd2ec4977fd6d7916ba1d.

7. References

  • Seed transaction: 0x2d9c1a00cf3d2fda268d0d11794ad2956774b156355e16441d6edb9a448e5a99
  • Verified victim source: /workspace/session/artifacts/collector/seed/56/0xc321ac21a07b3d593b269acdace69c3762ca2dd0/src/TEST/RANT.sol
  • Seed trace: /workspace/session/artifacts/collector/seed/56/0x2d9c1a00cf3d2fda268d0d11794ad2956774b156355e16441d6edb9a448e5a99/trace.cast.log
  • Seed balance diff: /workspace/session/artifacts/collector/seed/56/0x2d9c1a00cf3d2fda268d0d11794ad2956774b156355e16441d6edb9a448e5a99/balance_diff.json
  • Pair metadata: /workspace/session/artifacts/collector/iter_1/contract/56/0x42a93c3af7cb1bbc757dd2ec4977fd6d7916ba1d/pair_metadata.json
  • Flash pool metadata: /workspace/session/artifacts/collector/iter_1/contract/56/0x172fcd41e0913e95784454622d1c3724f546f849/verified_metadata.json