# FFIST: crafted transfer recipient manipulates pair reserves for drain

FFIST token's transfer logic let attacker craft a recipient address to zero out pair reserves, then sync and swap to drain ~$110k.

- Payout: Real-world hack
- Severity: high
- Program: FFIST
- Analysis by: DeFiHackLabs
- Disclosed: 2023-07-20
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2023-07/FFIST_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20230720-ffist
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity vuln:accounting-error vuln:business-logic

**Target:** BEP-20 token contract and PancakeSwap V2 pair
**Root cause:** FFIST transfer logic mishandles a computed recipient address (derived from lastAirdropAddress, block.number and the pair), allowing a zero-value transfer to alter the pair's tracked reserves before sync().
**Steps:**
1. Fund attacker with 0.01 WBNB; approve Router for WBNB and FFIST.
2. Swap WBNB->USDT->FFIST via Router to acquire FFIST.
3. Compute `to = address(uint160(address(this)) ^ (uint160(FFIST.lastAirdropAddress()) | uint160(block.number)) ^ uint160(Pair))` and call `FFIST.transfer(to, 0)`.
4. Call `Uni_Pair_V2(Pair).sync()` to commit manipulated reserves.
5. Swap FFIST->USDT->WBNB via Router to extract profit.
**Exploitation:** Attacker flash-funded minimal WBNB, bought FFIST, then used a zero-value transfer to a specially computed address to corrupt the pair's reserve accounting, called sync() to lock in the skewed reserves, and swapped back to WBNB for ~$110k profit.
**Insight:** Tokens with custom transfer/airdrop logic that branch on recipient address can be abused with zero-value transfers to a computed address; always check whether transfer() side effects can desync AMM reserves before sync().

