All incidents

KB Pair Burn Drain

Share
May 18, 2025 08:21 UTCAttackLoss: 7,204.81 USDTPending manual check1 exploit txWindow: Atomic
Estimated Impact
7,204.81 USDT
Label
Attack
Exploit Tx
1
Addresses
2
Attack Window
Atomic
May 18, 2025 08:21 UTC → May 18, 2025 08:21 UTC

Exploit Transactions

TX 1BSC
0x78f242dee5b8e15a43d23d76bce827f39eb3ac54b44edcd327c5d63de3848daf
May 18, 2025 08:21 UTCExplorer

Victim Addresses

0x1814a8443f37ddd7930a9d8bc4b48353fe589b58BSC
0xdbead75d3610209a093af1d46d5296bbeffd53f5BSC

Loss Breakdown

7,204.81USDT

Similar Incidents

Root Cause Analysis

KB Pair Burn Drain

1. Incident Overview TL;DR

The incident was a single-transaction drain of the KB/USDT PancakeSwap pair on BNB Chain in tx 0x78f242dee5b8e15a43d23d76bce827f39eb3ac54b44edcd327c5d63de3848daf. The attacker used two public USDT flash loans, manipulated KB's custom transfer logic against its own pair, and extracted almost the entire USDT side of the pool.

The root cause is KB's _transfer implementation. When the pair sends KB before launch conditions are met, KB burns tokens from the pair instead of delivering them to the buyer. When the pair receives KB on the sell path, KB again burns from the pair and calls sync() before the incoming seller balance is booked. Those behaviors let an unprivileged actor collapse the pair's KB reserve, record a stale near-zero reserve, and then drain USDT.

2. Key Background

The KB token embeds AMM-specific logic directly in token transfers. That is dangerous because a Uniswap V2 style pair assumes its token balances and recorded reserves only move according to the actual assets sent into or out of the pair during swap settlement.

In a normal fee-on-transfer design, the sender is debited and the recipient is credited consistently, even if a fee is skimmed or burned. KB breaks that model by directly debiting the pair contract's own balance in transfer hooks. It also gates behavior on a spot quote from the same attacked pool via getKBUSDT() and isSwapPrice, so the attacker can manipulate the condition that selects the dangerous branch.

3. Vulnerability Analysis & Root Cause Summary

KB's vulnerability class is an AMM-accounting attack caused by pair-mutating token transfer hooks. In the buy branch, _transfer checks if (swap == sender) and, before launch conditions open, executes super._transfer(sender, destroy, amount), burning the pair's outgoing KB instead of paying the buyer. In the sell branch, _transfer checks if (swap == recipient), burns from the pair again, and then calls IUniswap(swap).sync() before crediting the seller's transfer into the pair. That sequence records an artificially tiny KB reserve while the pair is about to receive more KB. Because PancakePair pricing uses the recorded reserves, the attacker can swap newly credited KB against a stale near-zero reserve and receive nearly all paired USDT. The exploit is deterministic and permissionless because all required venues and calls are public.

Code evidence from the verified KB source:

if (swap == sender) {
    if(getKBUSDT() < isSwapPrice && ttss < isSwapTtss && !isSwap){
        super._transfer(sender, destroy, amount);
    } else {
        super._transfer(sender, recipient, amount);
    }
} else if (swap == recipient) {
    uint256 aaaSum = amount.percentage(100000);
    uint256 sum = amount - aaaSum;
    if(getKBUSDT() < isSwapPrice && !isSwap){
        super._transfer(swap, destroy, sum.percentage(500000));
    } else {
        super._transfer(swap, destroy, sum.percentage(100000));
    }
    IUniswap(swap).sync();
    super._transfer(sender, hhbTo, aaaSum);
    super._transfer(sender, recipient, sum);
}

4. Detailed Root Cause Analysis

Before the exploit, the KB/USDT pair held 955469077115849643881 raw KB units and 7205807872520012958697 raw USDT units. The adversary helper first borrowed 248157126634995412253694 raw USDT from DODO and 100000000000000000000000 raw USDT from Pancake V3.

The first exploit phase used two router buys. The trace shows the helper sending USDT into the pair and the pair attempting to send KB out through PancakePair::swap. When KB handled that outgoing transfer, it executed the buy-path burn logic and emitted transfers from the pair to the dead address rather than to the buyer. The pair therefore accepted the USDT input while its KB side was destroyed. After the two buys, the pair reserve recorded in trace output had already been pushed down sharply.

Trace evidence for the buy-side reserve destruction:

PancakeRouter::swapExactTokensForTokensSupportingFeeOnTransferTokens(144116157450400259173940, ...)
  PancakePair::swap(909861961263064458015, 0, helper, 0x)
    KB::transfer(helper, 909861961263064458015)
      emit Transfer(from: PancakePair, to: 0x000000000000000000000000000000000000dEaD, value: 909861961263064458015)

PancakeRouter::swapExactTokensForTokensSupportingFeeOnTransferTokens(204040969184595153079754, ...)
  PancakePair::swap(26158607120271760914, 0, helper, 0x)

The second exploit phase repeatedly sent the helper's KB back to the pair and called skim(). Because KB's sell path burns from the pair and calls sync() before the sender's transfer is finalized, each loop reduced the pair's recorded KB reserve while preserving the helper's ability to recover balance via skim(). The trace shows repeated PancakePair::skim(...) calls interleaved with PancakePair::sync() calls.

The final setup transfer sent 2980897375759759211 raw KB units to the pair. In that transfer, KB burned 268280763818378329 raw KB units from the pair and then executed sync(), leaving the pair with a recorded KB reserve of only 100000 raw units before the remaining seller transfer was credited. Immediately after that stale reserve was recorded, the attacker invoked pair.swap to withdraw nearly all USDT from the pool.

The balance diff confirms the net result of that mechanism:

{
  "pair_usdt_delta": "-7204807872520012958697",
  "attacker_usdt_delta": "7154807872520012958697",
  "dead_kb_delta": "929310469995577782967"
}

5. Adversary Flow Analysis

The adversary cluster consisted of EOA 0x9943f26831f9b468a7fe5ac531c352baab8af655 and helper contract 0xd995edcab2efe3283514ff111cedc9aaff0349c8. The EOA submitted the exploit transaction and the helper coordinated both flash-loan callbacks and profit forwarding.

The execution flow was:

1. Borrow 248157126634995412253694 USDT from DODO.
2. Borrow 100000000000000000000000 USDT from Pancake V3 inside the DODO callback.
3. Buy KB twice through PancakeRouter, causing KB to burn the pair's outgoing KB instead of paying the buyer.
4. Loop KB->pair transfers plus pair.skim() to keep shrinking the pair's KB side while recovering helper-held KB.
5. Perform the final KB->pair transfer that triggers the sell-path burn and premature sync at 100000 raw KB reserve.
6. Call pair.swap to pull out 355361934507515425212391 raw USDT.
7. Repay Pancake V3 principal plus 50 USDT fee and repay DODO principal.
8. Forward 7154807872520012958697 raw USDT profit to the EOA.

This satisfies the ACT model. Every step relied on public contracts, public state, and permissionless flash-loan and AMM entrypoints. No privileged key, whitelist, or attacker-specific off-chain artifact was required.

6. Impact & Losses

The direct economic loss was the near-total depletion of the KB/USDT pair's USDT side. The pair's USDT balance dropped from 7205807872520012958697 raw units to 1000000000000000000 raw units, a loss of 7204807872520012958697 raw USDT units.

The attacker EOA realized 7154807872520012958697 raw USDT units after loan repayment. Separately, 929310469995577782967 raw KB units were burned to the dead address during the exploit. After settlement, the pair was left with only 1 raw USDT token unit in reserve accounting terms used by the oracle definition.

7. References

  1. Seed transaction metadata for 0x78f242dee5b8e15a43d23d76bce827f39eb3ac54b44edcd327c5d63de3848daf.
  2. Seed execution trace showing both flash loans, router buys, repeated skim() and sync(), and the final drain.
  3. Seed balance diff showing final USDT profit and KB burn totals.
  4. Verified KB token source for 0x1814a8443f37ddd7930a9d8bc4b48353fe589b58.
  5. Explorer source metadata for pair 0xdbead75d3610209a093af1d46d5296bbeffd53f5, used to resolve verification status in the final root-cause artifact.