Compare commits

..

8 Commits

Author SHA1 Message Date
six 0ddb7309f1 Merge branch 'main' into RemoveRemote 2023-12-02 13:15:28 +00:00
Anon f414239258 Upload files to "frontend" 2023-08-25 05:41:51 +00:00
Anon f3af7e726f Update frontend/RobotoMono.css 2023-08-25 05:41:29 +00:00
Anon 3034ca6027 Update frontend/index.html 2023-08-25 05:38:54 +00:00
Anon 2f4bb4683d Unicode issue fix 2023-08-25 05:37:07 +00:00
Anon ce3416d7d3 Add frontend/web3.min_1.8.0.js 2023-08-25 05:32:49 +00:00
Anon cee0782a85 Add frontend/FontAwesomev5.15.4.css 2023-08-25 05:27:20 +00:00
Anon f67cb4a42b Add frontend/RobotoMono.css 2023-08-25 05:25:40 +00:00
15 changed files with 284 additions and 6330 deletions

View File

@ -1,8 +1,10 @@
# DCTF v0.2 # DCTF v0.1
The first decentralized CTF engine, used by CCTF The first decentralized CTF engine, used by CCTF
Deployment: TBA Testnet deployment on Moonbase Alpha: https://moonbase.moonscan.io/address/0x70f0cec3c99103113d96ed8ad82ae6a8d9a735a0#code
Testnet Hall of Fame on Moonbase Alpha: https://moonbase.moonscan.io/address/0xb70780843be242474025f185bf26dddadfc27f43#code
Main team contributors: six, Silur, Bazsi Main team contributors: six, Silur, Bazsi
@ -12,10 +14,11 @@ Hackathon contributors: SI, username, Anon, GuyFromUniversity, ZK, Metafaka team
- Finish the Vault - Finish the Vault
- Finish the Hall of Fame with multi-management DAO style setup (approval needed for valid flag?) - Finish the Hall of Fame with multi-management DAO style setup (approval needed for valid flag?)
- Check and fix main FE - contract integration, partially done, we need remote removals - Architect the topology, research best way so all features work together
- Check and fix FE - contract integration, partially done, we need remote removals
- Add FE missing functions - Add FE missing functions
- Re-architect in a way we don't need to redeploy - Re-architect in a way we don't need to redeploy
- Get version X ready - Deploy version X
# Workshop at Hacktivity 2023 # Workshop at Hacktivity 2023

View File

@ -1,6 +1,10 @@
// 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.
// Currently taken from and being hacked: https://git.hsbp.org/money36/PCM_CCTF_challenge/src/branch/main
pragma solidity ^0.8.17; pragma solidity ^0.8.17;
contract CryptoCTF10 { contract CryptoCTFX {
enum PlayerStatus { enum PlayerStatus {
Unverified, Unverified,
Verified, Verified,
@ -33,7 +37,7 @@ contract CryptoCTF10 {
} }
struct Challenge { struct Challenge {
address obscuredFlag; // essentially the public key of the flag, the flag being a private key 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;
@ -55,26 +59,38 @@ contract CryptoCTF10 {
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);
/* CTF Manager functions */
// 1. Create a contest
function createContest(uint contestID, string memory password) 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].password = password; contests[contestID].password = password;
} }
// 2. Set the contest's deadline
function setContestDeadline(uint contestID, uint256 deadline) external onlyExistingContest(contestID) onlyAdmin(contestID) {
contests[contestID].deadline = deadline;
}
// 3. Add the public keys of the challenges and their relevant data
function addOrUpdateChallenge(uint contestID, uint challengeID, address obscuredFlag, uint worth, uint256 descriptionFingerprint, bool onlyFirstSolver, string memory skill) external onlyExistingContest(contestID) onlyAdmin(contestID) {
require(obscuredFlag != address(0), "The obscured flag value must not be 0");
contests[contestID].challenges[challengeID] = Challenge(obscuredFlag, worth, descriptionFingerprint, onlyFirstSolver, skill);
emit ChallengeAddedOrUpdated(contestID, challengeID);
}
function setPlayerStatus(uint contestID, address player, PlayerStatus status) external onlyExistingContest(contestID) onlyAdmin(contestID) {
contests[contestID].players[player].status = status;
}
function setAdmin(uint contestID, address newAdmin) external onlyExistingContest(contestID) onlyAdmin(contestID) { function setAdmin(uint contestID, address newAdmin) external onlyExistingContest(contestID) onlyAdmin(contestID) {
require(newAdmin != address(0)); require(newAdmin != address(0));
contests[contestID].admin = newAdmin; contests[contestID].admin = newAdmin;
} }
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) { /* CTF Player functions */
require(obscuredFlag != address(0), "The obscured flag value must not be 0");
contests[contestID].challenges[challengeID] = Challenge(obscuredFlag, worth, descriptionFingerprint, onlyFirstSolver, skill);
emit ChallengeAddedOrUpdated(contestID, challengeID);
}
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");
@ -82,10 +98,7 @@ contract CryptoCTF10 {
contests[contestID].players[msg.sender].status = PlayerStatus.Verified; contests[contestID].players[msg.sender].status = PlayerStatus.Verified;
} }
function setPlayerStatus(uint contestID, address player, PlayerStatus status) external onlyExistingContest(contestID) onlyAdmin(contestID) { // You can use six's eth_keygen to generate the signature
contests[contestID].players[player].status = status;
}
function submitFlag(uint contestID, uint challengeID, 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;
@ -104,6 +117,7 @@ contract CryptoCTF10 {
emit ChallengeSolved(contestID, challengeID, msg.sender); emit ChallengeSolved(contestID, challengeID, msg.sender);
} }
/* CTF ECDSA related functions */
function recoverSigner(bytes32 messageHash, bytes memory signature) public pure returns (address) { function recoverSigner(bytes32 messageHash, bytes memory signature) public pure returns (address) {
(bytes32 r, bytes32 s, uint8 v) = splitSignature(signature); (bytes32 r, bytes32 s, uint8 v) = splitSignature(signature);
return ecrecover(messageHash, v, r, s); return ecrecover(messageHash, v, r, s);
@ -118,6 +132,7 @@ contract CryptoCTF10 {
} }
} }
/* CTF View functions for feedback and FE */
function getContestDeadline(uint contestID) external view onlyExistingContest(contestID) returns (uint256) { function getContestDeadline(uint contestID) external view onlyExistingContest(contestID) returns (uint256) {
return contests[contestID].deadline; return contests[contestID].deadline;
} }
@ -129,4 +144,4 @@ contract CryptoCTF10 {
function getPlayerScore(uint contestID, address player) external view onlyExistingContest(contestID) returns (uint) { function getPlayerScore(uint contestID, address player) external view onlyExistingContest(contestID) returns (uint) {
return contests[contestID].players[player].score; return contests[contestID].players[player].score;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,65 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>CryptoCTF zero-knowledge flag-submission encoder v0.5</title>
<script type="text/javascript" src="bn.js"></script>
<script type="text/javascript" src="nano-ethereum-signer-mod.js"></script>
</head>
<body>
<label for="inp-contestant-address">contestant's address:</label> <input id="inp-contestant-address" type="text" size="42" maxlength="42" pattern="0x[0-9a-fA-F]{40}" required placeholder="0x0000000000000000000000000000000000000000" autocomplete="cryptocurrency address" title="The cryptocurrency address of the contestant who is submitting the flag. It will be used as the message that is signed using an ECDSA signature scheme. It is incorporated to prevent submission forgery and theft. The resulting signature will be accepted by the CCTF smart-contract from only this address."/> <input id="inp-only-checksum-address" type="checkbox" checked autocomplete="checksum address" title="As an optional mechanism for protection against typos in the contestant's address field, this control panel can be set to reject an address value that fails the checksum test."/> <label for="inp-only-checksum-address">only accept correct checksum address</label><br/>
<label for="inp-flag">flag:</label> <input id="inp-flag" type="text" size="48" pattern="CCTF\{[ -~]*\}" required placeholder="CCTF{…}" autocomplete="flag" title="The flag for the challenge in question: a piece of data that can be found through solving the problem. It can be an outstanding character sequence of the form CCTF{…} that can be stumbled upon; otherwise its location/calculation (e.g. the deciphered message) and its formatting (e.g. hexadecimal) are precisely specified, and formatting always includes enclosing by CCTF{…}. The flag will be used as the secret key for signing using an ECDSA signature scheme." accesskey="f"/> <label for="outp-obscured-flag">⇒ obscured flag: </label><input id="outp-obscured-flag" type="text" size="42" maxlength="42" readonly title="The obscured flag: data to allow zero-knowledge verification of knowledge of the flag. It is the elliptic-curve public key related to the flag as the private key. It is the thing to be loaded into the CCTF smart-contract for the respective challenge."/><br />
<label for="outp-signature">⇒ signature: </label><input id="outp-signature" type="text" size="132" maxlength="132" readonly title="The signature: a zero-knowledge proof of knowledge of the flag, bound to the given address. It's an ECDSA signature of the address as the message (hash) with the flag as the key. It is to be passed to the CCTF smart-contract's flag submission function."/><!--<br />
<label for="inp-contract-address">CCTF smart-contract address:</label> <input id="inp-contract-address" type="text" size="42" maxlength="42" pattern="0x[0-9a-fA-F]{40}" placeholder="0x0000000000000000000000000000000000000000"/><br/>
<label for="inp-contest-id">contest ID:</label> <input id="inp-contest-id" type="text" size="66" pattern="0x[0-9a-fA-F]+|[0-9]+" placeholder="0x0000000000000000000000000000000000000000000000000000000000000000"/><br/>
<label for="inp-challenge-id">challenge ID:</label> <input id="inp-challenge-id" type="integer" size="4" placeholder="0" accesskey="c"/>-->
<script type="text/javascript">
var inpContestantAddress = document.querySelector("#inp-contestant-address");
var inpOnlyChecksumAddress = document.querySelector("#inp-only-checksum-address");
var inpFlag = document.querySelector("#inp-flag");
var outpObscuredFlag = document.querySelector("#outp-obscured-flag");
var outpSignature = document.querySelector("#outp-signature");
var secp256k1n = new BN('115792089237316195423570985008687907852837564279074904382605163141518161494337', 10);
function getPrivateKey() {
var s = inpFlag.value;
var h = "0x";
if (s.slice(0, 5) !== "CCTF{" || s.slice(-1) !== "}")
return null;
for (i in s) {
var c = s.charCodeAt(i);
if (c < 32 || c > 126)
return null;
h += c.toString(16).padStart(2, "0");
}
return "0x" + new BN(keccak256(h).slice(2), 16).mod(secp256k1n.sub(new BN(1))).add(new BN(1)).toString(16).padStart(64, 0);
}
function updateOutputValues(ev) {
var k = getPrivateKey();
if (k === null) {
outpObscuredFlag.value = "";
outpSignature.value = "";
} else {
outpObscuredFlag.value = addressFromKey(k);
var m = inpContestantAddress.value;
if (!/^0x[0-9a-fA-F]{40}$/.test(m) || inpOnlyChecksumAddress.checked && m !== addressChecksum(m)) {
outpSignature.value = "";
} else {
outpSignature.value = signMessage(m, k);
}
}
}
inpContestantAddress.oninput = updateOutputValues;
inpOnlyChecksumAddress.oninput = updateOutputValues;
inpFlag.oninput = updateOutputValues;
updateOutputValues();
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,48 @@
/* cyrillic-ext */
@font-face {
font-family: 'Roboto Mono';
font-style: normal;
font-weight: 400;
src: url(L0xuDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vq_SeW4Ep0.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto Mono';
font-style: normal;
font-weight: 400;
src: url(L0xuDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vq_QOW4Ep0.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek */
@font-face {
font-family: 'Roboto Mono';
font-style: normal;
font-weight: 400;
src: url(L0xuDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vq_R-W4Ep0.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto Mono';
font-style: normal;
font-weight: 400;
src: url(L0xuDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vq_S-W4Ep0.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto Mono';
font-style: normal;
font-weight: 400;
src: url(L0xuDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vq_SuW4Ep0.woff2) format('woff2');
unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto Mono';
font-style: normal;
font-weight: 400;
src: url(L0xuDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vq_ROW4.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View File

@ -1,121 +1,121 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<title>CCTF Frontend by Metafaka</title> <title>CCTF Frontend</title>
<link rel="icon" type="image/png" href="cctf-icon.png" sizes="96x96"> <link rel="icon" type="image/png" href="cctf-icon.png" sizes="96x96">
<link href="https://fonts.googleapis.com/css?family=Roboto Mono" rel="stylesheet"> <link href="RobotoMono.css" rel="stylesheet">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css" integrity="sha384-DyZ88mC6Up2uqS4h/KRgHuoeGwBcD4Ng9SiP4dIRy0EXTlnuz47vAwmeGwVChigm" crossorigin="anonymous"> <link rel="stylesheet" href="FontAwesomev5.15.4.css">
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
</head> </head>
<body> <body>
<div class="top"> <div class="top">
<div class="top_logo"> <div class="top_logo">
<img src="cctf-logo.png" id="logo" alt="CCTF logo" width="200" height="49"> <img src="cctf-logo.png" id="logo" alt="CCTF logo" width="200" height="49">
</div> </div>
<div class="top_left"> <div class="top_left">
<div> <div>
<i style="margin: 10px;" class="fas fa-users"></i> <i style="margin: 10px;" class="fas fa-users"></i>
</div> </div>
<div style="padding-right: 18px; line-height: 14px;"> <div style="padding-right: 18px; line-height: 14px;">
<span id="header_uppercase">PLAYERS</span><br> <span id="header_uppercase">PLAYERS</span><br>
<span id="players">loading...</span> <span id="players">Loading...</span>
</div> </div>
<div> <div>
<i style="margin: 10px;" class="far fa-flag"></i> <i style="margin: 10px;" class="far fa-flag"></i>
</div> </div>
<div style="line-height: 14px;"> <div style="line-height: 14px;">
<span id="header_uppercase">FOUND FLAGS</span><br> <span id="header_uppercase">FOUND FLAGS</span><br>
<span id="submissions">loading...</span> <span id="submissions">Loading...</span>
</div> </div>
</div> </div>
<div class="top_center" id="toplist"> <div class="top_center" id="toplist">
<div class="topitem"> <div class="topitem">
<span id="remaining_time" style="font-size: 28px; font-weight: 200">--:--:--</span> <span id="remaining_time" style="font-size: 28px; font-weight: 200">--:--:--</span>
</div> </div>
</div> </div>
<div class="top_right"> <div class="top_right">
<div class="topitem"> <div class="topitem">
<!-- Trigger/Open The Modal --> <!-- Trigger/Open The Modal -->
<div style="margin: 0 18px; cursor: pointer" id="myBtn"> <div style="margin: 0 18px; cursor: pointer" id="myBtn">
<i style="margin-right: 2px;" class="fas fa-bolt"></i> <i style="margin-right: 2px;" class="fas fa-bolt"></i>
<span>Getting Started</span> <span>Getting Started</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="left"> <div class="left">
<div class="left-content"> <div class="left-content">
<h1>My Account</h1> <h1>My Account</h1>
<div id="account_locked"> <div id="account_locked">
<button id="account_enable"><img id="metamask" src="metamask.svg">Enable account</button> <button id="account_enable"><img id="metamask" src="metamask.svg">Enable account</button>
</div> </div>
<div id="account_unlocked" style="display: none"> <div id="account_unlocked" style="display: none">
<div id="user"></div> <div id="user"></div>
<div id="unverified" style="display: none"> <div id="unverified" style="display: none">
<h1>Register</h1> <h1>Register</h1>
<input type="text" id="playerName" placeholder="Your name..."> <input type="text" id="playerName" placeholder="Your name...">
<br> <br>
<span style="font-size: 14px;" id="myBtn">I have read the f#%@ken manual: </span><input type="checkbox" id="myCheck"> <span style="font-size: 14px;" id="myBtn">I have read the f#%@ken manual: </span><input type="checkbox" id="myCheck">
<button id="register"><i class="fab fa-ethereum" style="font-size: 16px; margin-right: 8px;"></i>Submit</button> <button id="register"><i class="fab fa-ethereum" style="font-size: 16px; margin-right: 8px;"></i>Submit</button>
</div> </div>
<div id="verified" style="display: none"> <div id="verified" style="display: none">
<h1>My Points</h1> <h1>My Points</h1>
<span id="holding">0</span> <span id="holding">0</span>
<h1>Challenges</h1> <h1>Challenges</h1>
<p>Challenge 1</p> <p>Challenge 1</p>
<p>Challenge 2</p> <p>Challenge 2</p>
<p>Challenge 3</p> <p>Challenge 3</p>
<p>Challenge 4</p> <p>Challenge 4</p>
<p>Challenge 5</p> <p>Challenge 5</p>
<p>Challenge 6</p> <p>Challenge 6</p>
</div> </div>
<div id="banned" style="display: none"> <div id="banned" style="display: none">
<h1>BANNED</h1> <h1>BANNED</h1>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="main"> <div class="main">
<div id="loading">Loading...</div> <div id="loading">Loading...</div>
<h2>Leaderboard</h2> <h2>Leaderboard</h2>
<table id="rank_list"></table> <table id="rank_list"></table>
</div> </div>
<!-- The Modal --> <!-- The Modal -->
<div id="myModal" class="modal"> <div id="myModal" class="modal">
<!-- Modal content --> <!-- Modal content -->
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<span class="close">&times;</span> <span class="close">&times;</span>
<h2>Getting Started</h2> <h2>Getting Started</h2>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<h3>The Game</h3> <h3>The Game</h3>
<p>Soooo much fun!</p> <p>Soooo much fun!</p>
<h3>Contract Address</h3> <h3>Contract Address</h3>
<p><a href="https://moonbase.moonscan.io/address/0x919f68cc35ce5d49a45c94dc44e7bf444f9a7531" target="_blank">0x919f68cc35ce5d49a45c94dc44e7bf444f9a7531</a></p> <p><a href="https://moonbase.moonscan.io/address/0x919f68cc35ce5d49a45c94dc44e7bf444f9a7531" target="_blank">0x919f68cc35ce5d49a45c94dc44e7bf444f9a7531</a></p>
<h3>Questions?</h3> <h3>Questions?</h3>
<p>Answers.</p> <p>Answers.</p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
</div> </div>
</div> </div>
</div> </div>
<script language="javascript" type="text/javascript" src="https://cdn.jsdelivr.net/gh/ethereum/web3.js@1.8.0/dist/web3.min.js"></script> <script language="javascript" type="text/javascript" src="web3.min_1.8.0.js"></script>
<script language="javascript" type="text/javascript" src="abi.js"></script> <script language="javascript" type="text/javascript" src="abi.js"></script>
<script language="javascript" type="text/javascript" src="script.js"></script> <script language="javascript" type="text/javascript" src="script.js"></script>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long