diff --git a/contracts/CCTF_2023.sol b/contracts/CCTF_2023.sol index b0d0c87..b3f5eb1 100644 --- a/contracts/CCTF_2023.sol +++ b/contracts/CCTF_2023.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Authors: Anonz team, developed at Polkadot Metaverse Championship, as part of their CCTF track solution. // Based on Six's and Silur's CCTF 2022 code. -pragma solidity ^0.8.10; +// Currently taken from and being hacked: https://git.hsbp.org/money36/PCM_CCTF_challenge/src/branch/main +pragma solidity ^0.8.17; contract CryptoCTFX { enum PlayerStatus { @@ -26,7 +27,7 @@ contract CryptoCTFX { } modifier onlyOpen(uint contestID) { - require(contests[contestID].submissionsOpen, "Submissions are not open for this contest at this time"); + require(block.timestamp < contests[contestID].deadline, "Submissions are not open for this contest at this time"); _; } @@ -36,7 +37,7 @@ contract CryptoCTFX { } struct Challenge { - address obscuredFlag; // public key of the flag + address obscuredFlag; // essentially the public key of the flag, the flag being a private key uint worth; uint256 descriptionFingerprint; bool onlyFirstSolver; @@ -47,9 +48,10 @@ contract CryptoCTFX { address admin; mapping (uint => Challenge) challenges; mapping (address => Player) players; - bool submissionsOpen; + uint256 deadline; mapping (address => mapping (uint => bool)) solves; // address -> challengeID -> solved/not mapping (uint => bool) anySolves; // challengeID -> solved/not + string password; } mapping (uint => Contest) public contests; @@ -57,10 +59,10 @@ contract CryptoCTFX { event ChallengeAddedOrUpdated(uint contestID, uint indexed challengeID); event ChallengeSolved(uint contestID, uint indexed challengeID, address indexed solver); - function createContest(uint contestID) external { + function createContest(uint contestID, string memory password) external { require(contests[contestID].admin == address(0), "This contest ID has already been registered"); contests[contestID].admin = msg.sender; - contests[contestID].submissionsOpen = false; + contests[contestID].password = password; } function setAdmin(uint contestID, address newAdmin) external onlyExistingContest(contestID) onlyAdmin(contestID) { @@ -68,8 +70,8 @@ contract CryptoCTFX { contests[contestID].admin = newAdmin; } - function setSubmissionsStatus(uint contestID, bool open) external onlyExistingContest(contestID) onlyAdmin(contestID) { - contests[contestID].submissionsOpen = open; + function setContestDeadline(uint contestID, uint256 deadline) external onlyExistingContest(contestID) onlyAdmin(contestID) { + contests[contestID].deadline = deadline; } function addOrUpdateChallenge(uint contestID, uint challengeID, address obscuredFlag, uint worth, uint256 descriptionFingerprint, bool onlyFirstSolver, string memory skill) external onlyExistingContest(contestID) onlyAdmin(contestID) { @@ -80,7 +82,7 @@ contract CryptoCTFX { function register(uint contestID, string memory password) external onlyExistingContest(contestID) { require(contests[contestID].players[msg.sender].status == PlayerStatus.Unverified, "You are already registered or banned in this contest"); - require(keccak256(abi.encodePacked("I_read_it")) == keccak256(abi.encodePacked(password))); + require(keccak256(abi.encodePacked(password)) == keccak256(abi.encodePacked(contests[contestID].password)), "Wrong password"); contests[contestID].players[msg.sender].status = PlayerStatus.Verified; } @@ -88,11 +90,11 @@ contract CryptoCTFX { contests[contestID].players[player].status = status; } - function submitFlag(uint contestID, uint challengeID, bytes32 messageHash, bytes memory signature) external onlyExistingContest(contestID) onlyExistingChallenge(contestID, challengeID) onlyOpen(contestID) { + function submitFlag(uint contestID, uint challengeID, bytes memory signature) external onlyExistingContest(contestID) onlyExistingChallenge(contestID, challengeID) onlyOpen(contestID) { require(contests[contestID].players[msg.sender].status == PlayerStatus.Verified, "You are unverified or banned in this contest"); // the correct signature is an ECDSA signature where (1) the message (hash) is the sender address and (2) the private key is the flag; // (2) is checked by testing against the public key, which can then be public information - address recoveredSigner = recoverSigner(messageHash, signature); + address recoveredSigner = recoverSigner(bytes32(uint256(uint160(msg.sender))), signature); require(recoveredSigner != address(0), "Invalid signature"); require(recoveredSigner == contests[contestID].challenges[challengeID].obscuredFlag, "Wrong answer"); require(!contests[contestID].solves[msg.sender][challengeID], "You have already solved this challenge of this contest"); @@ -120,6 +122,10 @@ contract CryptoCTFX { } } + function getContestDeadline(uint contestID) external view onlyExistingContest(contestID) returns (uint256) { + return contests[contestID].deadline; + } + function getPlayerStatus(uint contestID, address player) external view onlyExistingContest(contestID) returns (PlayerStatus) { return contests[contestID].players[player].status; }