parent
a57a23a4ed
commit
db60d71f1b
|
@ -1,7 +1,8 @@
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Authors: Anonz team, developed at Polkadot Metaverse Championship, as part of their CCTF track solution.
|
// 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.
|
// 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 {
|
contract CryptoCTFX {
|
||||||
enum PlayerStatus {
|
enum PlayerStatus {
|
||||||
|
@ -26,7 +27,7 @@ contract CryptoCTFX {
|
||||||
}
|
}
|
||||||
|
|
||||||
modifier onlyOpen(uint contestID) {
|
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 {
|
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;
|
uint worth;
|
||||||
uint256 descriptionFingerprint;
|
uint256 descriptionFingerprint;
|
||||||
bool onlyFirstSolver;
|
bool onlyFirstSolver;
|
||||||
|
@ -47,9 +48,10 @@ contract CryptoCTFX {
|
||||||
address admin;
|
address admin;
|
||||||
mapping (uint => Challenge) challenges;
|
mapping (uint => Challenge) challenges;
|
||||||
mapping (address => Player) players;
|
mapping (address => Player) players;
|
||||||
bool submissionsOpen;
|
uint256 deadline;
|
||||||
mapping (address => mapping (uint => bool)) solves; // address -> challengeID -> solved/not
|
mapping (address => mapping (uint => bool)) solves; // address -> challengeID -> solved/not
|
||||||
mapping (uint => bool) anySolves; // challengeID -> solved/not
|
mapping (uint => bool) anySolves; // challengeID -> solved/not
|
||||||
|
string password;
|
||||||
}
|
}
|
||||||
|
|
||||||
mapping (uint => Contest) public contests;
|
mapping (uint => Contest) public contests;
|
||||||
|
@ -57,10 +59,10 @@ contract CryptoCTFX {
|
||||||
event ChallengeAddedOrUpdated(uint contestID, uint indexed challengeID);
|
event ChallengeAddedOrUpdated(uint contestID, uint indexed challengeID);
|
||||||
event ChallengeSolved(uint contestID, uint indexed challengeID, address indexed solver);
|
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");
|
require(contests[contestID].admin == address(0), "This contest ID has already been registered");
|
||||||
contests[contestID].admin = msg.sender;
|
contests[contestID].admin = msg.sender;
|
||||||
contests[contestID].submissionsOpen = false;
|
contests[contestID].password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setAdmin(uint contestID, address newAdmin) external onlyExistingContest(contestID) onlyAdmin(contestID) {
|
function setAdmin(uint contestID, address newAdmin) external onlyExistingContest(contestID) onlyAdmin(contestID) {
|
||||||
|
@ -68,8 +70,8 @@ contract CryptoCTFX {
|
||||||
contests[contestID].admin = newAdmin;
|
contests[contestID].admin = newAdmin;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSubmissionsStatus(uint contestID, bool open) external onlyExistingContest(contestID) onlyAdmin(contestID) {
|
function setContestDeadline(uint contestID, uint256 deadline) external onlyExistingContest(contestID) onlyAdmin(contestID) {
|
||||||
contests[contestID].submissionsOpen = open;
|
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) {
|
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) {
|
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(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;
|
contests[contestID].players[msg.sender].status = PlayerStatus.Verified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,11 +90,11 @@ contract CryptoCTFX {
|
||||||
contests[contestID].players[player].status = status;
|
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");
|
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;
|
// 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
|
// (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 != address(0), "Invalid signature");
|
||||||
require(recoveredSigner == contests[contestID].challenges[challengeID].obscuredFlag, "Wrong answer");
|
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");
|
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) {
|
function getPlayerStatus(uint contestID, address player) external view onlyExistingContest(contestID) returns (PlayerStatus) {
|
||||||
return contests[contestID].players[player].status;
|
return contests[contestID].players[player].status;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue