/
ChallengeMothership.sol
235 lines (194 loc) · 7.31 KB
/
ChallengeMothership.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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
/// @title Hack the Mothership
/// @author https://twitter.com/nicobevi_eth
/// @notice A big alien float is near the Earth! You and an anon group of scientists have been working on a global counteroffensive against the invader. Hack the Mothership, save the earth
/// @custom:url https://www.ctfprotocol.com/tracks/eko2022/hack-the-mothership
contract Mothership {
address public leader;
SpaceShip[] public fleet;
mapping(address => SpaceShip) public captainRegisteredShip;
bool public hacked;
constructor() {
leader = msg.sender;
address[5] memory captains = [
0x0000000000000000000000000000000000000001,
0x0000000000000000000000000000000000000002,
0x0000000000000000000000000000000000000003,
0x0000000000000000000000000000000000000004,
0x0000000000000000000000000000000000000005
];
// Adding standard modules
address cleaningModuleAddress = address(new CleaningModule());
address refuelModuleAddress = address(new RefuelModule());
address leadershipModuleAddress = address(new LeadershipModule());
for (uint8 i = 0; i < 5; i++) {
SpaceShip _spaceship = new SpaceShip(
captains[i],
address(this),
cleaningModuleAddress,
refuelModuleAddress,
leadershipModuleAddress
);
fleet.push(_spaceship);
captainRegisteredShip[captains[i]] = _spaceship;
}
}
function addSpaceShipToFleet(SpaceShip spaceship) external {
require(leader == msg.sender, "You are not our leader");
fleet.push(spaceship);
captainRegisteredShip[spaceship.captain()] = spaceship;
}
function _isFleetMember(SpaceShip spaceship) private view returns (bool isFleetMember) {
uint8 len = uint8(fleet.length);
for (uint8 i; i < len; ++i) {
if (address(fleet[i]) == address(spaceship)) {
isFleetMember = true;
break;
}
}
}
/**
* A new captain will be promoted if:
* 1. Ship is part of the fleet
* 2. Ship has no captain
* 3. The new captain is not a captain already
*/
function assignNewCaptainToShip(address _newCaptain) external {
SpaceShip spaceship = SpaceShip(msg.sender);
require(_isFleetMember(spaceship), "You're not part of the fleet");
require(spaceship.captain() == address(0), "Ship has a captain");
require(address(captainRegisteredShip[_newCaptain]) == address(0), "You're a captain already");
// register ship to captain
captainRegisteredShip[_newCaptain] = spaceship;
// Communicate that new captain has been approved to ship
spaceship.newCaptainPromoted(_newCaptain);
}
/**
* A captain will be assigned as leader of the fleet if:
* 1. The proposed leader is a spaceship captain
* 2. All the other ships approve the promotion
*/
function promoteToLeader(address _leader) external {
SpaceShip leaderSpaceship = captainRegisteredShip[_leader];
// should have a registered ship
require(address(leaderSpaceship) != address(0), "is not a captain");
// should be approved by other captains
uint8 len = uint8(fleet.length);
for (uint8 i; i < len; ++i) {
SpaceShip spaceship = fleet[i];
// ignore captain ship
if (address(spaceship) == address(leaderSpaceship)) {
continue;
}
// should not revert if captain approves the new leader
LeadershipModule(address(spaceship)).isLeaderApproved(_leader);
}
// remove captain from his ship
delete captainRegisteredShip[_leader];
leaderSpaceship.newCaptainPromoted(address(0));
leader = _leader;
}
function hack() external {
require(leader == msg.sender, "You are not our leader");
hacked = true;
}
function fleetLength() external view returns (uint256) {
return fleet.length;
}
/**
* ...the rest of the code is lost
*/
}
contract SpaceShip {
address public captain;
address[] public crew;
Mothership public mothership;
mapping(bytes4 => address) public modules;
constructor(
address _captain,
address _mothership,
address _cleaningModuleAddress,
address _refuelModuleAddress,
address _leadershipModuleAddress
) {
captain = _captain;
mothership = Mothership(_mothership);
// Adding standard modules
modules[CleaningModule.replaceCleaningCompany.selector] = _cleaningModuleAddress;
modules[RefuelModule.addAlternativeRefuelStationsCodes.selector] = _refuelModuleAddress;
modules[LeadershipModule.isLeaderApproved.selector] = _leadershipModuleAddress;
}
function _isCrewMember(address member) private view returns (bool isCrewMember) {
uint256 len = uint256(crew.length);
for (uint256 i; i < len; ++i) {
if (crew[i] == member) {
isCrewMember = true;
break;
}
}
}
function newCaptainPromoted(address _captain) external {
require(msg.sender == address(mothership), "You are not our mother");
captain = _captain;
}
function askForNewCaptain(address _newCaptain) external {
require(_isCrewMember(msg.sender), "Not part of the crew");
require(captain == address(0), "We have a captain already");
mothership.assignNewCaptainToShip(_newCaptain);
}
/**
* This SpaceShip model has an advanced module system
* Only the captain can upgrade the ship
*/
function addModule(bytes4 _moduleSig, address _moduleAddress) external {
require(msg.sender == captain, "You are not our captain");
modules[_moduleSig] = _moduleAddress;
}
// solhint-disable-next-line no-complex-fallback
fallback() external {
bytes4 sig4 = msg.sig;
address module = modules[sig4];
require(module != address(0), "invalid module");
// call the module
// solhint-disable-next-line avoid-low-level-calls
(bool success,) = module.delegatecall(msg.data);
if (!success) {
// return response error
assembly {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
}
}
contract CleaningModule {
address private cleaningCompany;
function replaceCleaningCompany(address _cleaningCompany) external {
cleaningCompany = _cleaningCompany;
}
/**
* ...the rest of the code is lost
*/
}
contract RefuelModule {
uint256 private mainRefuelStation;
uint256[] private alternativeRefuelStationsCodes;
function addAlternativeRefuelStationsCodes(uint256 refuelStationCode) external {
alternativeRefuelStationsCodes.push(refuelStationCode);
}
/**
* ...the rest of the code is lost
*/
}
contract LeadershipModule {
function isLeaderApproved(address) external pure {
revert("We don't want a new leader :(");
}
/**
* ...the rest of the code is lost
*/
}
/**
* ...the rest of the code is lost
*/