From 2f2ab941a27a66c4517a7a5679220aa612e95581 Mon Sep 17 00:00:00 2001 From: meelunae Date: Fri, 15 Mar 2024 12:39:33 +0100 Subject: [PATCH 1/4] FEATURE: Defining multiple flags in challenge for CTFd --- index.js | 2 +- lib/generators/ctfd.js | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index c218114..59049ba 100644 --- a/index.js +++ b/index.js @@ -48,7 +48,7 @@ const questions = [ { type: 'input', name: 'ctfKey', - message: 'Secret key URL to ctf.key file?', + message: 'Secret key URL to ctf.key file? (Note: for CTFd you can provide a comma-separated string for multiple flags)', default: 'https://raw.githubusercontent.com/bkimminich/juice-shop/master/ctf.key' }, { diff --git a/lib/generators/ctfd.js b/lib/generators/ctfd.js index 834bf02..aee7528 100644 --- a/lib/generators/ctfd.js +++ b/lib/generators/ctfd.js @@ -40,7 +40,10 @@ function createCtfdExport (challenges, { insertHints, insertHintUrls, insertHint } */ - return new Promise((resolve, reject) => { + // In the flags section of the returned data we iterate through the result of string splitting by comma, and compute the hash of the single flag key + challenge name. + // Format expected is: challenge3,challenge description,category3,100,dynamic,visible,0,"flag1,flag2,flag3","tag1,tag2,tag3","hint1,hint2,hint3","{""initial"":100, ""minimum"":10, ""decay"":10}" + + return new Promise((resolve, reject) => { try { const data = [] for (const key in challenges) { @@ -55,7 +58,7 @@ function createCtfdExport (challenges, { insertHints, insertHintUrls, insertHint type: 'standard', state: 'visible', max_attempts: 0, - flags: hmacSha1(ctfKey, challenge.name), + flags: `"${ctfKey.split(",").map(key => `${hmacSha1(key, challenge.name)}`).join(",")}"`, tags: challenge.tags ? `"${challenge.tags}"` : '', hints: insertChallengeHints(challenge), // hint_cost: insertChallengeHintCosts(challenge), From 69098fccd781dc0adef598d6e234efe49f0d755f Mon Sep 17 00:00:00 2001 From: meelunae Date: Fri, 15 Mar 2024 13:26:05 +0100 Subject: [PATCH 2/4] Changed way single flag is handled --- lib/generators/ctfd.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/generators/ctfd.js b/lib/generators/ctfd.js index aee7528..9d1b83a 100644 --- a/lib/generators/ctfd.js +++ b/lib/generators/ctfd.js @@ -42,7 +42,7 @@ function createCtfdExport (challenges, { insertHints, insertHintUrls, insertHint // In the flags section of the returned data we iterate through the result of string splitting by comma, and compute the hash of the single flag key + challenge name. // Format expected is: challenge3,challenge description,category3,100,dynamic,visible,0,"flag1,flag2,flag3","tag1,tag2,tag3","hint1,hint2,hint3","{""initial"":100, ""minimum"":10, ""decay"":10}" - + // If we provide a single key with no commas, we do not incapsulate the output in a "" pair. return new Promise((resolve, reject) => { try { const data = [] @@ -58,7 +58,7 @@ function createCtfdExport (challenges, { insertHints, insertHintUrls, insertHint type: 'standard', state: 'visible', max_attempts: 0, - flags: `"${ctfKey.split(",").map(key => `${hmacSha1(key, challenge.name)}`).join(",")}"`, + flags: ctfKey.split(",").length === 1 ? hmacSha1(ctfKey, challenge.name) : `"${ctfKey.split(",").map(key => `${hmacSha1(key, challenge.name)}`).join(",")}"` , tags: challenge.tags ? `"${challenge.tags}"` : '', hints: insertChallengeHints(challenge), // hint_cost: insertChallengeHintCosts(challenge), From 1acf25f0c5d4585b3c6fde7a4c73e66b3abab494 Mon Sep 17 00:00:00 2001 From: meelunae Date: Fri, 15 Mar 2024 13:35:23 +0100 Subject: [PATCH 3/4] Linting changes --- lib/generators/ctfd.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/generators/ctfd.js b/lib/generators/ctfd.js index 9d1b83a..bb68845 100644 --- a/lib/generators/ctfd.js +++ b/lib/generators/ctfd.js @@ -40,10 +40,10 @@ function createCtfdExport (challenges, { insertHints, insertHintUrls, insertHint } */ - // In the flags section of the returned data we iterate through the result of string splitting by comma, and compute the hash of the single flag key + challenge name. - // Format expected is: challenge3,challenge description,category3,100,dynamic,visible,0,"flag1,flag2,flag3","tag1,tag2,tag3","hint1,hint2,hint3","{""initial"":100, ""minimum"":10, ""decay"":10}" - // If we provide a single key with no commas, we do not incapsulate the output in a "" pair. - return new Promise((resolve, reject) => { + // In the flags section of the returned data we iterate through the result of string splitting by comma, and compute the hash of the single flag key + challenge name. + // Format expected is: challenge3,challenge description,category3,100,dynamic,visible,0,"flag1,flag2,flag3","tag1,tag2,tag3","hint1,hint2,hint3","{""initial"":100, ""minimum"":10, ""decay"":10}" + // If we provide a single key with no commas, we do not incapsulate the output in a "" pair. + return new Promise((resolve, reject) => { try { const data = [] for (const key in challenges) { @@ -58,7 +58,7 @@ function createCtfdExport (challenges, { insertHints, insertHintUrls, insertHint type: 'standard', state: 'visible', max_attempts: 0, - flags: ctfKey.split(",").length === 1 ? hmacSha1(ctfKey, challenge.name) : `"${ctfKey.split(",").map(key => `${hmacSha1(key, challenge.name)}`).join(",")}"` , + flags: ctfKey.split(',').length === 1 ? hmacSha1(ctfKey, challenge.name) : `"${ctfKey.split(',').map(key => `${hmacSha1(key, challenge.name)}`).join(',')}"`, tags: challenge.tags ? `"${challenge.tags}"` : '', hints: insertChallengeHints(challenge), // hint_cost: insertChallengeHintCosts(challenge), From 6c43731451e16e67f797d0b1b6490140d6706226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Kimminich?= Date: Tue, 19 Mar 2024 00:07:24 +0100 Subject: [PATCH 4/4] Rephrase and extend documentation (of multi-key support for CTFd) --- README.md | 2 +- index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 687d5b1..2e71b25 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ desired configuration in a file with the following format: ```yaml ctfFramework: CTFd | FBCTF | RootTheBox juiceShopUrl: https://juice-shop.herokuapp.com -ctfKey: https://raw.githubusercontent.com/bkimminich/juice-shop/master/ctf.key # can also be actual key instead URL +ctfKey: https://raw.githubusercontent.com/bkimminich/juice-shop/master/ctf.key # can also be actual key or comma-separated list of keys (CTFd only) instead of URL countryMapping: https://raw.githubusercontent.com/bkimminich/juice-shop/master/config/fbctf.yml # ignored for CTFd and RootTheBox insertHints: none | free | paid insertHintUrls: none | free | paid # optional for FBCTF; "paid" handled as "free" for CTFd diff --git a/index.js b/index.js index 59049ba..b557a16 100644 --- a/index.js +++ b/index.js @@ -48,7 +48,7 @@ const questions = [ { type: 'input', name: 'ctfKey', - message: 'Secret key URL to ctf.key file? (Note: for CTFd you can provide a comma-separated string for multiple flags)', + message: 'URL to ctf.key file secret key (CTFd only) comma-separated list of secret keys?', default: 'https://raw.githubusercontent.com/bkimminich/juice-shop/master/ctf.key' }, {