From 2a64c0f4a21924a3218d4fa2e89818d642297192 Mon Sep 17 00:00:00 2001 From: Nanne Baars Date: Sun, 10 Dec 2023 21:16:08 +0100 Subject: [PATCH 1/5] refactor: simplify challenges when answer is fixed When the answer is always the same we can cache it and the challenge only need to implement one method. This removes the necessity to implement methods `spoiler()` and `answerCorrect()` in every subclass. --- CONTRIBUTING.md | 42 +++++++------------ .../challenges/FixedAnswerChallenge.java | 32 ++++++++++++++ .../challenges/cloud/Challenge10.java | 22 ++++------ .../challenges/cloud/Challenge9.java | 28 +++++-------- .../cloud/challenge11/Challenge11Aws.java | 27 ++++-------- .../cloud/challenge11/Challenge11Azure.java | 39 ++++++----------- .../cloud/challenge11/Challenge11Gcp.java | 28 ++++--------- .../challenges/docker/Challenge0.java | 18 ++------ .../challenges/docker/Challenge1.java | 16 ++----- .../challenges/docker/Challenge12.java | 17 ++------ .../challenges/docker/Challenge14.java | 28 ++----------- .../challenges/docker/Challenge16.java | 17 ++------ .../challenges/docker/Challenge17.java | 18 +++----- .../challenges/docker/Challenge2.java | 22 ++-------- .../challenges/docker/Challenge23.java | 19 +++------ .../challenges/docker/Challenge24.java | 24 ++++------- .../challenges/docker/Challenge28.java | 22 ++++------ .../challenges/docker/Challenge29.java | 14 ++----- .../challenges/docker/Challenge3.java | 16 ++----- .../challenges/docker/Challenge31.java | 19 ++------- .../challenges/docker/Challenge32.java | 14 ++----- .../challenges/docker/Challenge34.java | 22 +++------- .../challenges/docker/Challenge35.java | 14 ++----- .../challenges/docker/Challenge37.java | 21 ++-------- .../challenges/docker/Challenge38.java | 14 ++----- .../challenges/docker/Challenge39.java | 14 ++----- .../challenges/docker/Challenge4.java | 1 - .../challenges/docker/Challenge40.java | 14 ++----- .../challenges/docker/Challenge8.java | 35 ++++++---------- .../challenges/kubernetes/Challenge5.java | 16 ++----- .../challenges/kubernetes/Challenge6.java | 16 ++----- .../challenges/kubernetes/Challenge7.java | 20 ++------- 32 files changed, 207 insertions(+), 462 deletions(-) create mode 100644 src/main/java/org/owasp/wrongsecrets/challenges/FixedAnswerChallenge.java diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4917a7c7d..efc9504e3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -275,36 +275,28 @@ These are the things that you have to keep in mind. import lombok.extern.slf4j.Slf4j; import org.owasp.wrongsecrets.RuntimeEnvironment; import org.owasp.wrongsecrets.ScoreCard; - import org.owasp.wrongsecrets.challenges.Challenge; + import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.owasp.wrongsecrets.challenges.ChallengeTechnology; import org.owasp.wrongsecrets.challenges.Spoiler; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.util.List; /** - * Describe what your challenge does - */ + * Describe what your challenge does + */ @Slf4j @Component - public class Challenge28 implements Challenge { - private final String secret; - public Challenge28() { - secret = "hello world"; - } + public class Challenge28 extends FixedAnswerChallenge { + private final String secret = "hello world"; - //return the plain text secret here - @Override - public Spoiler spoiler() { - return new Spoiler(secret); - } - //here you validate if your answer matches the secret - @Override - public boolean answerCorrect(String answer) { - return secret.equals(answer); - } + public String getAnswer() { + return secret; + } } ``` +If solving the challenge depends on the answer you can implement the interface `Challenge` directly instead of `FixedAnswerChallenge`. For example, see `Challenge36`. + ### Step 3: Adding Test File. Add the **new TestFile** in this folder `wrongsecrets/src/test/java/org/owasp/wrongsecrets/challenges/`. TestFile is required to do **unit testing.** @@ -312,27 +304,23 @@ These are the things that you have to keep in mind. Make sure that this file is also of **Java** type. Here is a unit test for reference: + ```java package org.owasp.wrongsecrets.challenges.docker; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; - import org.junit.jupiter.api.extension.ExtendWith; - import org.mockito.Mock; - import org.mockito.Mockito; - import org.mockito.junit.jupiter.MockitoExtension; - import org.owasp.wrongsecrets.ScoreCard; - @ExtendWith(MockitoExtension.class) + class Challenge28Test { - @Mock - private ScoreCard scoreCard; + @Test void rightAnswerShouldSolveChallenge() { - var challenge = new Challenge28(scoreCard); + var challenge = new Challenge28(); Assertions.assertThat(challenge.solved("wrong answer")).isFalse(); Assertions.assertThat(challenge.solved(challenge.spoiler().solution())).isTrue(); } } ``` + Please note that PRs for new challenges are only accepted when unit tests are added to prove that the challenge works. Normally tests should not immediately leak the actual secret, so leverage the `.spoil()` functionality of your test implementation for this. ### Step 4: Adding explanations, reasons and hints. diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/FixedAnswerChallenge.java b/src/main/java/org/owasp/wrongsecrets/challenges/FixedAnswerChallenge.java new file mode 100644 index 000000000..6e1c63c7e --- /dev/null +++ b/src/main/java/org/owasp/wrongsecrets/challenges/FixedAnswerChallenge.java @@ -0,0 +1,32 @@ +package org.owasp.wrongsecrets.challenges; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import java.util.Objects; + +/** + * Use this class when a challenge where the answer is fixed, meaning it will not change and does + * not depend on the given answer. For example: a hardcoded key or Spring environment variable. + * + *

Why do we make this distinction? Because in the case of the fixed answer we can cache the + * value. It is important to NOT do any reading / calculation in the constructor when using + * this interface. + * + *

NOTE: If the challenge depends on a calculation you can implement {@link Challenge} + */ +public abstract class FixedAnswerChallenge implements Challenge { + + private Supplier cachedAnswer = Suppliers.memoize(() -> getAnswer()); + + @Override + public final Spoiler spoiler() { + return new Spoiler(cachedAnswer.get()); + } + + @Override + public final boolean answerCorrect(String answer) { + return Objects.equals(cachedAnswer.get(), answer); + } + + public abstract String getAnswer(); +} diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/cloud/Challenge10.java b/src/main/java/org/owasp/wrongsecrets/challenges/cloud/Challenge10.java index 5b59d5ce4..9d3a21b4c 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/cloud/Challenge10.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/cloud/Challenge10.java @@ -5,37 +5,31 @@ import java.nio.file.Files; import java.nio.file.Paths; import lombok.extern.slf4j.Slf4j; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** Cloud challenge that leverages the CSI secrets driver of the cloud you are running in. */ @Component @Slf4j -public class Challenge10 implements Challenge { +public class Challenge10 extends FixedAnswerChallenge { private final String awsDefaultValue; - private final String challengeAnswer; + private final String filePath; + private final String fileName; public Challenge10( @Value("${secretmountpath}") String filePath, @Value("${default_aws_value_challenge_10}") String awsDefaultValue, @Value("${FILENAME_CHALLENGE10}") String fileName) { this.awsDefaultValue = awsDefaultValue; - this.challengeAnswer = getCloudChallenge9and10Value(filePath, fileName); + this.filePath = filePath; + this.fileName = fileName; } - /** {@inheritDoc} */ @Override - public Spoiler spoiler() { - return new Spoiler(challengeAnswer); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return challengeAnswer.equals(answer); + public String getAnswer() { + return getCloudChallenge9and10Value(filePath, fileName); } @SuppressFBWarnings( diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/cloud/Challenge9.java b/src/main/java/org/owasp/wrongsecrets/challenges/cloud/Challenge9.java index d8636038e..f3ab8979d 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/cloud/Challenge9.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/cloud/Challenge9.java @@ -5,18 +5,18 @@ import java.nio.file.Files; import java.nio.file.Paths; import lombok.extern.slf4j.Slf4j; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** Cloud challenge which focuses on Terraform and secrets. */ @Component @Slf4j -public class Challenge9 implements Challenge { +public class Challenge9 extends FixedAnswerChallenge { private final String awsDefaultValue; - private final String challengeAnswer; + private final String filePath; + private final String fileName; /** * Cloud challenge which focuses on Terraform and secrets. @@ -31,19 +31,8 @@ public Challenge9( @Value("${default_aws_value_challenge_9}") String awsDefaultValue, @Value("${FILENAME_CHALLENGE9}") String fileName) { this.awsDefaultValue = awsDefaultValue; - this.challengeAnswer = getCloudChallenge9and10Value(filePath, fileName); - } - - /** {@inheritDoc} */ - @Override - public Spoiler spoiler() { - return new Spoiler(challengeAnswer); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return challengeAnswer.equals(answer); + this.filePath = filePath; + this.fileName = fileName; } @SuppressFBWarnings( @@ -60,4 +49,9 @@ private String getCloudChallenge9and10Value(String filePath, String fileName) { return awsDefaultValue; } } + + @Override + public String getAnswer() { + return getCloudChallenge9and10Value(filePath, fileName); + } } diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/cloud/challenge11/Challenge11Aws.java b/src/main/java/org/owasp/wrongsecrets/challenges/cloud/challenge11/Challenge11Aws.java index 74a11b6f9..2381b6f5b 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/cloud/challenge11/Challenge11Aws.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/cloud/challenge11/Challenge11Aws.java @@ -1,15 +1,13 @@ package org.owasp.wrongsecrets.challenges.cloud.challenge11; import com.google.common.base.Strings; -import com.google.common.base.Supplier; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import lombok.extern.slf4j.Slf4j; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import software.amazon.awssdk.regions.Region; @@ -25,13 +23,12 @@ /** Cloud challenge which uses IAM privilelge escalation (differentiating per cloud). */ @Component @Slf4j -public class Challenge11Aws implements Challenge { +public class Challenge11Aws extends FixedAnswerChallenge { private final String awsRoleArn; private final String awsRegion; private final String tokenFileLocation; private final String awsDefaultValue; - private final Supplier challengeAnswer; private final String ctfValue; private final boolean ctfEnabled; @@ -48,32 +45,24 @@ public Challenge11Aws( this.awsDefaultValue = awsDefaultValue; this.ctfValue = ctfValue; this.ctfEnabled = ctfEnabled; - this.challengeAnswer = getChallenge11Value(); } - /** {@inheritDoc} */ @Override - public Spoiler spoiler() { - return new Spoiler(challengeAnswer.get()); + public String getAnswer() { + return getChallenge11Value(); } - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return challengeAnswer.get().equals(answer); - } - - private Supplier getChallenge11Value() { + private String getChallenge11Value() { if (!ctfEnabled) { - return () -> getAWSChallenge11Value(); + return getAWSChallenge11Value(); } else if (!Strings.isNullOrEmpty(ctfValue) && !Strings.isNullOrEmpty(awsDefaultValue) && !ctfValue.equals(awsDefaultValue)) { - return () -> ctfValue; + return ctfValue; } log.info("CTF enabled, skipping challenge11"); - return () -> "please_use_supported_cloud_env"; + return "please_use_supported_cloud_env"; } @SuppressFBWarnings( diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/cloud/challenge11/Challenge11Azure.java b/src/main/java/org/owasp/wrongsecrets/challenges/cloud/challenge11/Challenge11Azure.java index f2f7fa052..4c511e195 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/cloud/challenge11/Challenge11Azure.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/cloud/challenge11/Challenge11Azure.java @@ -1,22 +1,17 @@ package org.owasp.wrongsecrets.challenges.cloud.challenge11; import com.google.common.base.Strings; -import com.google.common.base.Supplier; -import com.google.common.base.Suppliers; import lombok.extern.slf4j.Slf4j; -import org.owasp.wrongsecrets.RuntimeEnvironment; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** Cloud challenge which uses IAM privilelge escalation (differentiating per cloud). */ @Component @Slf4j -public class Challenge11Azure implements Challenge { +public class Challenge11Azure extends FixedAnswerChallenge { private final String azureDefaultValue; - private final Supplier challengeAnswer; private final String azureVaultUri; private final String azureWrongSecret3; private final String ctfValue; @@ -28,43 +23,35 @@ public Challenge11Azure( String azureVaultUri, @Value("${wrongsecret-3}") String azureWrongSecret3, // Exclusively auto-wired for Azure @Value("${default_aws_value_challenge_11}") String ctfValue, - @Value("${ctf_enabled}") boolean ctfEnabled, - RuntimeEnvironment runtimeEnvironment) { + @Value("${ctf_enabled}") boolean ctfEnabled) { + this.azureDefaultValue = azureDefaultValue; this.azureVaultUri = azureVaultUri; this.azureWrongSecret3 = azureWrongSecret3; this.ctfValue = ctfValue; this.ctfEnabled = ctfEnabled; - this.challengeAnswer = Suppliers.memoize(getChallenge11Value(runtimeEnvironment)); - } - - /** {@inheritDoc} */ - @Override - public Spoiler spoiler() { - return new Spoiler(challengeAnswer.get()); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return challengeAnswer.get().equals(answer); } - private Supplier getChallenge11Value(RuntimeEnvironment runtimeEnvironment) { + private String getChallenge11Value() { if (!ctfEnabled) { - return () -> getAzureChallenge11Value(); + return getAzureChallenge11Value(); } else if (!Strings.isNullOrEmpty(ctfValue) && !Strings.isNullOrEmpty(azureDefaultValue) && !ctfValue.equals(azureDefaultValue)) { - return () -> ctfValue; + return ctfValue; } log.info("CTF enabled, skipping challenge11"); - return () -> "please_use_supported_cloud_env"; + return "please_use_supported_cloud_env"; } private String getAzureChallenge11Value() { log.info(String.format("Using Azure Key Vault URI: %s", azureVaultUri)); return azureWrongSecret3; } + + @Override + public String getAnswer() { + return getChallenge11Value(); + } } diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/cloud/challenge11/Challenge11Gcp.java b/src/main/java/org/owasp/wrongsecrets/challenges/cloud/challenge11/Challenge11Gcp.java index 580116e7a..f5b2ae5d3 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/cloud/challenge11/Challenge11Gcp.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/cloud/challenge11/Challenge11Gcp.java @@ -5,22 +5,18 @@ import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; import com.google.cloud.secretmanager.v1.SecretVersionName; import com.google.common.base.Strings; -import com.google.common.base.Supplier; -import com.google.common.base.Suppliers; import java.io.IOException; import lombok.extern.slf4j.Slf4j; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** Cloud challenge which uses IAM privilelge escalation (differentiating per cloud). */ @Component @Slf4j -public class Challenge11Gcp implements Challenge { +public class Challenge11Gcp extends FixedAnswerChallenge { private final String gcpDefaultValue; - private final Supplier challengeAnswer; private final String projectId; private final String ctfValue; private final boolean ctfEnabled; @@ -34,32 +30,24 @@ public Challenge11Gcp( this.projectId = projectId; this.ctfValue = ctfValue; this.ctfEnabled = ctfEnabled; - this.challengeAnswer = Suppliers.memoize(getChallenge11Value()); } - /** {@inheritDoc} */ @Override - public Spoiler spoiler() { - return new Spoiler(challengeAnswer.get()); + public String getAnswer() { + return getChallenge11Value(); } - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return challengeAnswer.get().equals(answer); - } - - private Supplier getChallenge11Value() { + private String getChallenge11Value() { if (!ctfEnabled) { - return () -> getGCPChallenge11Value(); + return getGCPChallenge11Value(); } else if (!Strings.isNullOrEmpty(ctfValue) && !Strings.isNullOrEmpty(gcpDefaultValue) && !ctfValue.equals(gcpDefaultValue)) { - return () -> ctfValue; + return ctfValue; } log.info("CTF enabled, skipping challenge11"); - return () -> "please_use_supported_cloud_env"; + return "please_use_supported_cloud_env"; } private String getGCPChallenge11Value() { diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge0.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge0.java index e9656ca65..0572e2149 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge0.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge0.java @@ -1,26 +1,14 @@ package org.owasp.wrongsecrets.challenges.docker; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.stereotype.Component; /** Introduction challenge to get a user introduced with the setup. */ @Component -public class Challenge0 implements Challenge { +public class Challenge0 extends FixedAnswerChallenge { - /** {@inheritDoc} */ @Override - public Spoiler spoiler() { - return new Spoiler(getData()); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return getData().equals(answer); - } - - private String getData() { + public String getAnswer() { return "The first answer"; } } diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge1.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge1.java index 88bb8631b..c5ac6ea78 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge1.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge1.java @@ -1,22 +1,14 @@ package org.owasp.wrongsecrets.challenges.docker; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.stereotype.Component; /** Challenge to find the hardcoded password in code. */ @Component -public class Challenge1 implements Challenge { +public class Challenge1 extends FixedAnswerChallenge { - /** {@inheritDoc} */ @Override - public Spoiler spoiler() { - return new Spoiler(WrongSecretsConstants.password); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return WrongSecretsConstants.password.equals(answer); + public String getAnswer() { + return WrongSecretsConstants.password; } } diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge12.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge12.java index afd22baf8..a21d2ac7e 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge12.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge12.java @@ -5,15 +5,14 @@ import java.nio.file.Files; import java.nio.file.Paths; import lombok.extern.slf4j.Slf4j; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** Challenge focused on filesystem issues in docker container due to workdir copying. */ @Slf4j @Component -public class Challenge12 implements Challenge { +public class Challenge12 extends FixedAnswerChallenge { private final String dockerMountPath; @@ -21,17 +20,9 @@ public Challenge12(@Value("${challengedockermtpath}") String dockerMountPath) { this.dockerMountPath = dockerMountPath; } - /** {@inheritDoc} */ @Override - public Spoiler spoiler() { - return new Spoiler(getActualData()); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - // log.debug("challenge 12, actualdata: {}, answer: {}", getActualData(), answer); - return getActualData().equals(answer); + public String getAnswer() { + return getActualData(); } @SuppressFBWarnings( diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge14.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge14.java index 4044643e1..c65234fc9 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge14.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge14.java @@ -13,15 +13,14 @@ import org.linguafranca.pwdb.kdbx.simple.SimpleEntry; import org.linguafranca.pwdb.kdbx.simple.SimpleGroup; import org.linguafranca.pwdb.kdbx.simple.SimpleIcon; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** This challenge is about having a weak password for your password manager. */ @Slf4j @Component -public class Challenge14 implements Challenge { +public class Challenge14 extends FixedAnswerChallenge { private final String keepassxPassword; private final String defaultKeepassValue; @@ -36,22 +35,9 @@ public Challenge14( this.filePath = filePath; } - /** {@inheritDoc} */ - @Override - public Spoiler spoiler() { - return new Spoiler(findAnswer()); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return isanswerCorrectInKeeyPassx(answer); - } - @SuppressFBWarnings("PATH_TRAVERSAL_IN") - private String findAnswer() { + public String getAnswer() { if (Strings.isNullOrEmpty(keepassxPassword)) { - // log.debug("Checking secret with values {}", keepassxPassword); return defaultKeepassValue; } KdbxCreds creds = new KdbxCreds(keepassxPassword.getBytes(StandardCharsets.UTF_8)); @@ -72,12 +58,4 @@ private String findAnswer() { } } } - - private boolean isanswerCorrectInKeeyPassx(String answer) { - if (Strings.isNullOrEmpty(keepassxPassword) || Strings.isNullOrEmpty(answer)) { - // log.debug("Checking secret with values {}, {}", keepassxPassword, answer); - return false; - } - return answer.equals(findAnswer()); - } } diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge16.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge16.java index 9097d2d02..e061fed2d 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge16.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge16.java @@ -5,15 +5,14 @@ import java.nio.file.Files; import java.nio.file.Paths; import lombok.extern.slf4j.Slf4j; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** This challenge is about having a secret obfuscated in the front-end code. */ @Slf4j @Component -public class Challenge16 implements Challenge { +public class Challenge16 extends FixedAnswerChallenge { private final String dockerMountPath; @@ -21,17 +20,9 @@ public Challenge16(@Value("${challengedockermtpath}") String dockerMountPath) { this.dockerMountPath = dockerMountPath; } - /** {@inheritDoc} */ @Override - public Spoiler spoiler() { - return new Spoiler(getActualData()); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - // log.debug("challenge 16, actualdata: {}, answer: {}", getActualData(), answer); - return getActualData().equals(answer); + public String getAnswer() { + return getActualData(); } @SuppressFBWarnings( diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge17.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge17.java index dd563a4eb..3e98de0b1 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge17.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge17.java @@ -5,15 +5,14 @@ import java.nio.file.Files; import java.nio.file.Paths; import lombok.extern.slf4j.Slf4j; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** This challenge is about having secrets in copied in bash history as part of a container. */ @Slf4j @Component -public class Challenge17 implements Challenge { +public class Challenge17 extends FixedAnswerChallenge { private final String dockerMountPath; @@ -21,22 +20,15 @@ public Challenge17(@Value("${challengedockermtpath}") String dockerMountPath) { this.dockerMountPath = dockerMountPath; } - /** {@inheritDoc} */ @Override - public Spoiler spoiler() { - return new Spoiler(getActualData()); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return getActualData().equals(answer); + public String getAnswer() { + return getActualData(); } @SuppressFBWarnings( value = "PATH_TRAVERSAL_IN", justification = "The location of the dockerMountPath is based on an Env Var") - public String getActualData() { + private String getActualData() { try { return Files.readString(Paths.get(dockerMountPath, "thirdkey.txt"), StandardCharsets.UTF_8); } catch (Exception e) { diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge2.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge2.java index 01bab1057..4b8b93aaa 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge2.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge2.java @@ -1,7 +1,6 @@ package org.owasp.wrongsecrets.challenges.docker; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -11,7 +10,7 @@ * The javadoc is generated using ChatGPT. */ @Component -public class Challenge2 implements Challenge { +public class Challenge2 extends FixedAnswerChallenge { private final String hardcodedPassword; @@ -24,21 +23,8 @@ public Challenge2(@Value("${password}") String hardcodedPassword) { this.hardcodedPassword = hardcodedPassword; } - /** {@inheritDoc} */ @Override - public Spoiler spoiler() { - return new Spoiler(hardcodedPassword); - } - - /** - * {@inheritDoc} Checks if the provided answer matches the hardcoded password for the challenge. - * - * @param answer The answer provided by the participant. - * @return True if the answer matches the hardcoded password, false otherwise. - */ - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return hardcodedPassword.equals(answer); + public String getAnswer() { + return this.hardcodedPassword; } } diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge23.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge23.java index d2a506f20..20dfb6593 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge23.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge23.java @@ -4,29 +4,20 @@ import lombok.extern.slf4j.Slf4j; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.stereotype.Component; /** This challenge is about finding a secret hardcoded in comments in a front-end. */ @Slf4j @Component -public class Challenge23 implements Challenge { +public class Challenge23 extends FixedAnswerChallenge { - /** {@inheritDoc} */ @Override - public Spoiler spoiler() { - return new Spoiler(getActualData()); + public String getAnswer() { + return getActualData(); } - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - // log.debug("challenge 23, actualdata: {}, answer: {}", getActualData(), answer); - return getActualData().equals(answer); - } - - public String getActualData() { + private String getActualData() { return new String( Base64.decode( Hex.decode( diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge24.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge24.java index d43a383c9..22d1e0740 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge24.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge24.java @@ -3,32 +3,24 @@ import java.nio.charset.StandardCharsets; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.util.encoders.Hex; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.stereotype.Component; /** This challenge is about using a publicly specified key to safeguard data. */ @Slf4j @Component -public class Challenge24 implements Challenge { +public class Challenge24 extends FixedAnswerChallenge { - /** {@inheritDoc} */ - @Override - public Spoiler spoiler() { - return new Spoiler(getActualData()); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return getActualData().equals(answer); - } - - public String getActualData() { + private String getActualData() { return new String( Hex.decode( "3030303130323033203034303530363037203038303930413042203043304430453046203130313131323133203134313531363137203138313931413142203143314431453146203230323132323233203234323532363237203238323932413242203243324432453246203330333133323333203334333533363337203338333933413342203343334433453346" .getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8); } + + @Override + public String getAnswer() { + return getActualData(); + } } diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge28.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge28.java index f78cf1a69..64f662bfa 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge28.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge28.java @@ -3,25 +3,12 @@ import static java.nio.charset.StandardCharsets.UTF_8; import org.bouncycastle.util.encoders.Base64; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.stereotype.Component; /** This challenge is about finding a secret in a Github issue. */ @Component -public class Challenge28 implements Challenge { - - /** {@inheritDoc} */ - @Override - public Spoiler spoiler() { - return new Spoiler(getSecretKey()); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return getSecretKey().equals(answer); - } +public class Challenge28 extends FixedAnswerChallenge { private String getSecretKey() { return new String( @@ -30,4 +17,9 @@ private String getSecretKey() { Base64.decode("WVhOa1ptUndkVmxWU1dGa1ltRnZZWE5rY0dFd04ydHFNakF3TXc9PQ=="), UTF_8)), UTF_8); } + + @Override + public String getAnswer() { + return getSecretKey(); + } } diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge29.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge29.java index a97e548f5..b5e0d1399 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge29.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge29.java @@ -10,23 +10,17 @@ import java.security.spec.PKCS8EncodedKeySpec; import javax.crypto.Cipher; import lombok.extern.slf4j.Slf4j; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.stereotype.Component; /** This challenge is about finding a secret in a Github issue (screenshot). */ @Slf4j @Component -public class Challenge29 implements Challenge { +public class Challenge29 extends FixedAnswerChallenge { @Override - public Spoiler spoiler() { - return new Spoiler(decryptActualAnswer()); - } - - @Override - public boolean answerCorrect(String answer) { - return decryptActualAnswer().equals(answer); + public String getAnswer() { + return decryptActualAnswer(); } private byte[] decode(byte[] encoded, PrivateKey privateKey) throws Exception { diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge3.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge3.java index 8c6f3ed9e..4de8dde20 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge3.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge3.java @@ -1,7 +1,6 @@ package org.owasp.wrongsecrets.challenges.docker; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -9,7 +8,7 @@ * This challenge can be run in CTF mode and is limited to using Docker as a runtime environment. */ @Component -public class Challenge3 implements Challenge { +public class Challenge3 extends FixedAnswerChallenge { private final String hardcodedEnvPassword; @@ -17,15 +16,8 @@ public Challenge3(@Value("${DOCKER_ENV_PASSWORD}") String hardcodedEnvPassword) this.hardcodedEnvPassword = hardcodedEnvPassword; } - /** {@inheritDoc} */ @Override - public Spoiler spoiler() { - return new Spoiler(hardcodedEnvPassword); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return hardcodedEnvPassword.equals(answer); + public String getAnswer() { + return hardcodedEnvPassword; } } diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge31.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge31.java index 82a4b364a..9661c4df2 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge31.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge31.java @@ -3,15 +3,14 @@ import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.UUID; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.stereotype.Component; /** This challenge is about finding a secret in website. */ @Component -public class Challenge31 implements Challenge { +public class Challenge31 extends FixedAnswerChallenge { - private String getanswer() { + public String getAnswer() { String str = "vozvtbeY6++kjJz3tPn84LeM77I="; byte[] arr = Base64.getDecoder().decode(str); @@ -36,16 +35,4 @@ private String getanswer() { return new String(xoredBytes, StandardCharsets.UTF_8); } - - /** {@inheritDoc} */ - @Override - public Spoiler spoiler() { - return new Spoiler(getanswer()); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return getanswer().equals(answer); - } } diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge32.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge32.java index c9b9b3611..6cc6bfb28 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge32.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge32.java @@ -8,8 +8,7 @@ import javax.crypto.spec.SecretKeySpec; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.util.encoders.Base64; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.stereotype.Component; /** @@ -18,16 +17,11 @@ */ @Slf4j @Component -public class Challenge32 implements Challenge { +public class Challenge32 extends FixedAnswerChallenge { @Override - public Spoiler spoiler() { - return new Spoiler(getSolution()); - } - - @Override - public boolean answerCorrect(String answer) { - return getSolution().equals(answer); + public String getAnswer() { + return getSolution(); } private String getSolution() { diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge34.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge34.java index d7f8eef3e..1f776265a 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge34.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge34.java @@ -1,9 +1,7 @@ package org.owasp.wrongsecrets.challenges.docker; -import com.google.common.base.Strings; import lombok.extern.slf4j.Slf4j; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder; import org.springframework.stereotype.Component; @@ -13,28 +11,18 @@ */ @Slf4j @Component -public class Challenge34 implements Challenge { - - private String key; - - @Override - public Spoiler spoiler() { - return new Spoiler(getKey()); - } +public class Challenge34 extends FixedAnswerChallenge { @Override - public boolean answerCorrect(String answer) { - return getKey().equals(answer); + public String getAnswer() { + return getKey(); } private String getKey() { - if (Strings.isNullOrEmpty(key)) { - key = generateKey(); - } log.info( "The key for challenge34 has been initialized, now you can use it for encryption when" + " needed."); - return key; + return generateKey(); } private String generateKey() { diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge35.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge35.java index 2a9e92acb..0a782bb03 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge35.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge35.java @@ -12,23 +12,17 @@ import javax.crypto.spec.SecretKeySpec; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.util.encoders.Base64; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.stereotype.Component; /** This is a challenge based on the idea of leaking a secret trough a vulnerability report. */ @Slf4j @Component -public class Challenge35 implements Challenge { +public class Challenge35 extends FixedAnswerChallenge { @Override - public Spoiler spoiler() { - return new Spoiler(getKey()); - } - - @Override - public boolean answerCorrect(String answer) { - return getKey().equals(answer); + public String getAnswer() { + return getKey(); } private String getKey() { diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge37.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge37.java index f9ff2f775..0b397638a 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge37.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge37.java @@ -1,13 +1,11 @@ package org.owasp.wrongsecrets.challenges.docker; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.util.UUID; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.util.encoders.Base64; import org.owasp.wrongsecrets.BasicAuthentication; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; @@ -17,7 +15,7 @@ */ @Slf4j @Component -public class Challenge37 implements Challenge { +public class Challenge37 extends FixedAnswerChallenge { private String secret; private static final String password = "YjNCbGJpQnpaWE5oYldVPQo="; @@ -38,18 +36,7 @@ public BasicAuthentication challenge37BasicAuth() { } @Override - public Spoiler spoiler() { - return new Spoiler(secret); - } - - @Override - public boolean answerCorrect(String answer) { - return secret.equals(answer); - } - - public String getPassword() { - - return new String(Base64.decode(Base64.decode(Base64.decode(password))), StandardCharsets.UTF_8) - .replaceAll("\\r|\\n", ""); + public String getAnswer() { + return secret; } } diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge38.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge38.java index 67a3d2d16..dc3f8f887 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge38.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge38.java @@ -1,21 +1,15 @@ package org.owasp.wrongsecrets.challenges.docker; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.stereotype.Component; /** This is a challenge based on leaking secrets with the misuse of Git notes. */ @Component -public class Challenge38 implements Challenge { +public class Challenge38 extends FixedAnswerChallenge { @Override - public Spoiler spoiler() { - return new Spoiler(getSolution()); - } - - @Override - public boolean answerCorrect(String answer) { - return getSolution().equals(answer); + public String getAnswer() { + return getSolution(); } private String getSolution() { diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge39.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge39.java index baa94374d..2a907b234 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge39.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge39.java @@ -8,8 +8,7 @@ import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import lombok.extern.slf4j.Slf4j; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.annotation.Order; import org.springframework.core.io.Resource; @@ -19,7 +18,7 @@ @Slf4j @Component @Order(39) -public class Challenge39 implements Challenge { +public class Challenge39 extends FixedAnswerChallenge { private final Resource resource; @@ -28,13 +27,8 @@ public Challenge39(@Value("classpath:executables/secrchallenge.md") Resource res } @Override - public Spoiler spoiler() { - return new Spoiler(getSolution()); - } - - @Override - public boolean answerCorrect(String answer) { - return getSolution().equals(answer); + public String getAnswer() { + return getSolution(); } @SuppressFBWarnings( diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge4.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge4.java index a751a3607..6aee1e2d6 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge4.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge4.java @@ -20,7 +20,6 @@ public Spoiler spoiler() { return new Spoiler(argBasedPassword); } - /** {@inheritDoc} */ @Override public boolean answerCorrect(String answer) { return argBasedPassword.equals(answer) || argBasedPassword.equals("'" + answer + "'"); diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge40.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge40.java index 6701e1fdc..217fb0031 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge40.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge40.java @@ -10,8 +10,7 @@ import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import lombok.extern.slf4j.Slf4j; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.stereotype.Component; @@ -22,7 +21,7 @@ */ @Slf4j @Component -public class Challenge40 implements Challenge { +public class Challenge40 extends FixedAnswerChallenge { private final Resource resource; @@ -31,13 +30,8 @@ public Challenge40(@Value("classpath:executables/secrchallenge.json") Resource r } @Override - public Spoiler spoiler() { - return new Spoiler(getSolution()); - } - - @Override - public boolean answerCorrect(String answer) { - return getSolution().equals(answer); + public String getAnswer() { + return getSolution(); } @SuppressFBWarnings( diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge8.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge8.java index 797dcf6fd..de5875ed1 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge8.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge8.java @@ -4,41 +4,23 @@ import java.security.SecureRandom; import java.util.Random; import lombok.extern.slf4j.Slf4j; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** Challenge which leaks the data in the logs instead of anywhere else. */ @Slf4j @Component -public class Challenge8 implements Challenge { +public class Challenge8 extends FixedAnswerChallenge { private static final String alphabet = "0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"; private final Random secureRandom = new SecureRandom(); - private final String randomValue; + private final String serverCode; public Challenge8(@Value("${challenge_acht_ctf_host_value}") String serverCode) { - if (!Strings.isNullOrEmpty(serverCode) && !serverCode.equals("not_set")) { - randomValue = serverCode; - } else { - randomValue = generateRandomString(); - } - log.info("Initializing challenge 8 with random value {}", randomValue); - } - - /** {@inheritDoc} */ - @Override - public Spoiler spoiler() { - return new Spoiler(randomValue); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return randomValue.equals(answer); + this.serverCode = serverCode; } private String generateRandomString() { @@ -49,4 +31,13 @@ private String generateRandomString() { } return new String(builder); } + + @Override + public String getAnswer() { + if (!Strings.isNullOrEmpty(serverCode) && !serverCode.equals("not_set")) { + return serverCode; + } else { + return generateRandomString(); + } + } } diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/Challenge5.java b/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/Challenge5.java index 57f385fd4..48ff1147d 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/Challenge5.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/Challenge5.java @@ -1,13 +1,12 @@ package org.owasp.wrongsecrets.challenges.kubernetes; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** This challenge is about having a secrets stored as a K8s Configmap. */ @Component -public class Challenge5 implements Challenge { +public class Challenge5 extends FixedAnswerChallenge { private final String configmapK8sSecret; @@ -15,15 +14,8 @@ public Challenge5(@Value("${SPECIAL_K8S_SECRET}") String configmapK8sSecret) { this.configmapK8sSecret = configmapK8sSecret; } - /** {@inheritDoc} */ @Override - public Spoiler spoiler() { - return new Spoiler(configmapK8sSecret); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return configmapK8sSecret.equals(answer); + public String getAnswer() { + return this.configmapK8sSecret; } } diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/Challenge6.java b/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/Challenge6.java index ed316d3d1..37a2a330f 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/Challenge6.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/Challenge6.java @@ -1,13 +1,12 @@ package org.owasp.wrongsecrets.challenges.kubernetes; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** This challenge is about having a secrets stored as a K8s Secret. */ @Component -public class Challenge6 implements Challenge { +public class Challenge6 extends FixedAnswerChallenge { private final String secretK8sSecret; @@ -15,15 +14,8 @@ public Challenge6(@Value("${SPECIAL_SPECIAL_K8S_SECRET}") String secretK8sSecret this.secretK8sSecret = secretK8sSecret; } - /** {@inheritDoc} */ @Override - public Spoiler spoiler() { - return new Spoiler(secretK8sSecret); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return secretK8sSecret.equals(answer); + public String getAnswer() { + return secretK8sSecret; } } diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/Challenge7.java b/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/Challenge7.java index 31dede81a..3df8df803 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/Challenge7.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/Challenge7.java @@ -1,14 +1,13 @@ package org.owasp.wrongsecrets.challenges.kubernetes; import com.google.common.base.Strings; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** This challenge is about having a secrets stored in a misconfigured Hashicorp Vault. */ @Component -public class Challenge7 implements Challenge { +public class Challenge7 extends FixedAnswerChallenge { private final Vaultpassword vaultPassword; private final String vaultPasswordString; @@ -19,21 +18,10 @@ public Challenge7( this.vaultPasswordString = vaultPasswordString; } - private String getAnswer() { + @Override + public String getAnswer() { return vaultPassword != null && !Strings.isNullOrEmpty(vaultPassword.getPasssword()) ? vaultPassword.getPasssword() : vaultPasswordString; } - - /** {@inheritDoc} */ - @Override - public Spoiler spoiler() { - return new Spoiler(getAnswer()); - } - - /** {@inheritDoc} */ - @Override - public boolean answerCorrect(String answer) { - return getAnswer().equals(answer); - } } From 08d3fbe181774d1e12879ec8bc0a6217284f1a8c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Sun, 10 Dec 2023 20:22:27 +0000 Subject: [PATCH 2/5] [pre-commit.ci lite] apply automatic fixes --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index efc9504e3..e9b0e94f1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -291,7 +291,7 @@ These are the things that you have to keep in mind. public String getAnswer() { return secret; - } + } } ``` @@ -311,7 +311,7 @@ Here is a unit test for reference: import org.junit.jupiter.api.Test; class Challenge28Test { - + @Test void rightAnswerShouldSolveChallenge() { var challenge = new Challenge28(); From 3f501f73e024cb54d5fe6e4121339d434bf90e21 Mon Sep 17 00:00:00 2001 From: Jeroen Willemsen Date: Tue, 12 Dec 2023 05:51:52 +0100 Subject: [PATCH 3/5] Update POM file with new version: 1.8.0RC5 --- .github/scripts/.bash_history | 2 +- Dockerfile.web | 4 ++-- okteto/k8s/secret-challenge-ctf-deployment.yml | 2 +- src/main/resources/templates/about.html | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/scripts/.bash_history b/.github/scripts/.bash_history index 3b8eb6994..6398cdb54 100644 --- a/.github/scripts/.bash_history +++ b/.github/scripts/.bash_history @@ -347,7 +347,7 @@ rm -rf jdk-18_linux-x64_bin.deb git rebase -i main git rebase -i master git stash -export tempPassword="oynsXyOEC69q/CkG3pc1J8Z9DdRPKa9RukDuomyJjpc=" +export tempPassword="/waPsuWkuLcXi9M7RwjotyLXWeg89ezO5dKLOq4P2Xg=" mvn run tempPassword k6 npx k6 diff --git a/Dockerfile.web b/Dockerfile.web index 2efcd8147..78311d99d 100644 --- a/Dockerfile.web +++ b/Dockerfile.web @@ -1,5 +1,5 @@ -FROM jeroenwillemsen/wrongsecrets:1.8.0RC4-no-vault -ARG argBasedVersion="1.8.0RC4-no-vault" +FROM jeroenwillemsen/wrongsecrets:1.8.0RC5-no-vault +ARG argBasedVersion="1.8.0RC5-no-vault" ARG CANARY_URLS="http://canarytokens.com/terms/about/s7cfbdakys13246ewd8ivuvku/post.jsp,http://canarytokens.com/terms/about/y0all60b627gzp19ahqh7rl6j/post.jsp" ARG CTF_ENABLED=false ARG HINTS_ENABLED=true diff --git a/okteto/k8s/secret-challenge-ctf-deployment.yml b/okteto/k8s/secret-challenge-ctf-deployment.yml index d18058ee1..59fad7d45 100644 --- a/okteto/k8s/secret-challenge-ctf-deployment.yml +++ b/okteto/k8s/secret-challenge-ctf-deployment.yml @@ -28,7 +28,7 @@ spec: runAsGroup: 2000 fsGroup: 2000 containers: - - image: jeroenwillemsen/wrongsecrets:1.8.0RC4-no-vault + - image: jeroenwillemsen/wrongsecrets:1.8.0RC5-no-vault name: secret-challenge-ctf imagePullPolicy: IfNotPresent securityContext: diff --git a/src/main/resources/templates/about.html b/src/main/resources/templates/about.html index 673e4269e..9c926aa5d 100644 --- a/src/main/resources/templates/about.html +++ b/src/main/resources/templates/about.html @@ -352,7 +352,7 @@

  • (The Apache Software License, Version 2.0) thymeleaf-extras-springsecurity6 (org.thymeleaf.extras:thymeleaf-extras-springsecurity6:3.1.2.RELEASE - http://www.thymeleaf.org/thymeleaf-lib/thymeleaf-extras-springsecurity6)
  • (Public Domain) XZ for Java (org.tukaani:xz:1.9 - https://tukaani.org/xz/java.html)
  • (The Apache Software License, Version 2.0) unbescape (org.unbescape:unbescape:1.1.6.RELEASE - http://www.unbescape.org)
  • -
  • (Apache License, Version 2.0) Bootstrap (org.webjars:bootstrap:5.3.1 - http://webjars.org)
  • +
  • (Apache License, Version 2.0) Bootstrap (org.webjars:bootstrap:5.3.2 - http://webjars.org)
  • (MIT) DataTables (org.webjars:datatables:1.13.5 - http://webjars.org)
  • (MIT License) jquery (org.webjars:jquery:3.7.1 - http://webjars.org)
  • (Apache 2.0) Swagger UI (org.webjars:swagger-ui:5.10.3 - http://webjars.org)
  • From eb639d700a08ed84f633c489f5db955cdb255187 Mon Sep 17 00:00:00 2001 From: Jeroen Willemsen Date: Fri, 15 Dec 2023 12:55:36 +0100 Subject: [PATCH 4/5] Move challenge42 to a new package for consistency --- .../docker/challenge42}/AuditConfiguration.java | 2 +- .../challenges/docker/{ => challenge42}/Challenge42.java | 3 +-- src/main/resources/wrong-secrets-configuration.yaml | 2 +- .../owasp/wrongsecrets/challenges/docker/Challenge42Test.java | 3 ++- 4 files changed, 5 insertions(+), 5 deletions(-) rename src/main/java/org/owasp/wrongsecrets/{ => challenges/docker/challenge42}/AuditConfiguration.java (92%) rename src/main/java/org/owasp/wrongsecrets/challenges/docker/{ => challenge42}/Challenge42.java (87%) diff --git a/src/main/java/org/owasp/wrongsecrets/AuditConfiguration.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/challenge42/AuditConfiguration.java similarity index 92% rename from src/main/java/org/owasp/wrongsecrets/AuditConfiguration.java rename to src/main/java/org/owasp/wrongsecrets/challenges/docker/challenge42/AuditConfiguration.java index 577ac450e..ccce8aaef 100644 --- a/src/main/java/org/owasp/wrongsecrets/AuditConfiguration.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/challenge42/AuditConfiguration.java @@ -1,4 +1,4 @@ -package org.owasp.wrongsecrets; +package org.owasp.wrongsecrets.challenges.docker.challenge42; import groovy.util.logging.Slf4j; import java.util.Map; diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge42.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/challenge42/Challenge42.java similarity index 87% rename from src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge42.java rename to src/main/java/org/owasp/wrongsecrets/challenges/docker/challenge42/Challenge42.java index 7c17dc8bb..025fb06de 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge42.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/challenge42/Challenge42.java @@ -1,8 +1,7 @@ -package org.owasp.wrongsecrets.challenges.docker; +package org.owasp.wrongsecrets.challenges.docker.challenge42; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.owasp.wrongsecrets.AuditConfiguration; import org.owasp.wrongsecrets.challenges.Challenge; import org.owasp.wrongsecrets.challenges.Spoiler; import org.springframework.stereotype.Component; diff --git a/src/main/resources/wrong-secrets-configuration.yaml b/src/main/resources/wrong-secrets-configuration.yaml index bda633888..368bbb105 100644 --- a/src/main/resources/wrong-secrets-configuration.yaml +++ b/src/main/resources/wrong-secrets-configuration.yaml @@ -688,7 +688,7 @@ configurations: - name: Challenge 42 short-name: "challenge-42" sources: - - class-name: "org.owasp.wrongsecrets.challenges.docker.Challenge42" + - class-name: "org.owasp.wrongsecrets.challenges.docker.challenge42.Challenge42" explanation: "explanations/challenge42.adoc" hint: "explanations/challenge42_hint.adoc" reason: "explanations/challenge42_reason.adoc" diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge42Test.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge42Test.java index 161a9561c..6dcd32e85 100644 --- a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge42Test.java +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge42Test.java @@ -8,7 +8,8 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.owasp.wrongsecrets.AuditConfiguration; +import org.owasp.wrongsecrets.challenges.docker.challenge42.AuditConfiguration; +import org.owasp.wrongsecrets.challenges.docker.challenge42.Challenge42; @ExtendWith(MockitoExtension.class) public class Challenge42Test { From ef2f19e39d2b1f8805de484083a1d8a38a67155c Mon Sep 17 00:00:00 2001 From: Jeroen Willemsen Date: Fri, 15 Dec 2023 13:12:09 +0100 Subject: [PATCH 5/5] Updated the documentation --- CONTRIBUTING.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e6d0670b7..37cd1e5cb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -267,8 +267,10 @@ First make sure that you have an [Issue](https://github.com/OWASP/wrongsecrets/i Add the **new challenge** in this folder `wrongsecrets/src/main/java/org/owasp/wrongsecrets/challenges/`. These are the things that you have to keep in mind. -- First and foremost make sure your challenge is coded in **Java**. -- Here is an example of a possible Challenge 28: +- First and foremost make sure your challenge is coded in **Java**. +- Use either `FixedAnswerChallenge` as a class to extend or use the `Challenge` interface to imnplement. + +The `FixedAnswerChallenge` can be used for challenges that don't have a dependency on other (sub)systems. Here is an example of a possible Challenge 28: ```java package org.owasp.wrongsecrets.challenges.docker; @@ -294,8 +296,7 @@ These are the things that you have to keep in mind. } } ``` - -If solving the challenge depends on the answer you can implement the interface `Challenge` directly instead of `FixedAnswerChallenge`. For example, see `Challenge36`. +However, if there is a dependency on external components, then you can better implement the interface `Challenge` directly instead of `FixedAnswerChallenge`. For example, see [`Challenge36`](https://github.com/OWASP/wrongsecrets/blob/master/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge36.java), where we have to interact with external binaries. ### Step 3: Adding Test File.