From ed790cdf9dd7bff5c1c781e4d3fa6ffddfb3e080 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 05:25:48 +0000 Subject: [PATCH 1/4] feat: add Java binary challenges and variants Agent-Logs-Url: https://github.com/OWASP/wrongsecrets/sessions/f2ea090d-47bb-4e0a-ad4c-179c568545a8 Co-authored-by: commjoen <1457214+commjoen@users.noreply.github.com> --- .../challenges/docker/Challenge65.java | 18 +++++ .../challenges/docker/Challenge66.java | 18 +++++ .../BinaryExecutionHelper.java | 70 +++++++++++++++++++ .../resources/explanations/challenge65.adoc | 5 ++ .../explanations/challenge65_hint.adoc | 7 ++ .../explanations/challenge65_reason.adoc | 5 ++ .../resources/explanations/challenge66.adoc | 5 ++ .../explanations/challenge66_hint.adoc | 7 ++ .../explanations/challenge66_reason.adoc | 5 ++ .../wrong-secrets-configuration.yaml | 26 +++++++ .../challenges/docker/Challenge65Test.java | 25 +++++++ .../challenges/docker/Challenge66Test.java | 25 +++++++ 12 files changed, 216 insertions(+) create mode 100644 src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge65.java create mode 100644 src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge66.java create mode 100644 src/main/resources/explanations/challenge65.adoc create mode 100644 src/main/resources/explanations/challenge65_hint.adoc create mode 100644 src/main/resources/explanations/challenge65_reason.adoc create mode 100644 src/main/resources/explanations/challenge66.adoc create mode 100644 src/main/resources/explanations/challenge66_hint.adoc create mode 100644 src/main/resources/explanations/challenge66_reason.adoc create mode 100644 src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge65Test.java create mode 100644 src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge66Test.java diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge65.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge65.java new file mode 100644 index 0000000000..00de5e2f0b --- /dev/null +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge65.java @@ -0,0 +1,18 @@ +package org.owasp.wrongsecrets.challenges.docker; + +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; +import org.owasp.wrongsecrets.challenges.docker.binaryexecution.BinaryExecutionHelper; +import org.owasp.wrongsecrets.challenges.docker.binaryexecution.MuslDetectorImpl; +import org.springframework.stereotype.Component; + +/** This challenge is about finding a secret hardcoded in a plain Java CLI JAR. */ +@Component +public class Challenge65 extends FixedAnswerChallenge { + + @Override + public String getAnswer() { + BinaryExecutionHelper binaryExecutionHelper = + new BinaryExecutionHelper(65, new MuslDetectorImpl()); + return binaryExecutionHelper.executeJavaJar("", "wrongsecrets-java.jar"); + } +} diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge66.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge66.java new file mode 100644 index 0000000000..70f85564fc --- /dev/null +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge66.java @@ -0,0 +1,18 @@ +package org.owasp.wrongsecrets.challenges.docker; + +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; +import org.owasp.wrongsecrets.challenges.docker.binaryexecution.BinaryExecutionHelper; +import org.owasp.wrongsecrets.challenges.docker.binaryexecution.MuslDetectorImpl; +import org.springframework.stereotype.Component; + +/** This challenge is about finding a secret hidden in an obfuscated Java CLI JAR. */ +@Component +public class Challenge66 extends FixedAnswerChallenge { + + @Override + public String getAnswer() { + BinaryExecutionHelper binaryExecutionHelper = + new BinaryExecutionHelper(66, new MuslDetectorImpl()); + return binaryExecutionHelper.executeJavaJar("", "wrongsecrets-java-obfuscated.jar"); + } +} diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/binaryexecution/BinaryExecutionHelper.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/binaryexecution/BinaryExecutionHelper.java index 9a6b802944..5eb6695b42 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/binaryexecution/BinaryExecutionHelper.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/binaryexecution/BinaryExecutionHelper.java @@ -13,6 +13,7 @@ import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; +import org.springframework.core.io.ClassPathResource; import org.springframework.util.ResourceUtils; /** Helper for classes to execute binaries as part of the Binary challenges. */ @@ -111,6 +112,37 @@ public String executeCommand(String guess, String fileName) { } } + /** + * Execute a Java CLI packaged as a JAR with the actual guess. + * + * @param guess containing the guess + * @param fileName of the JAR to be used (pre-defined, make sure it is never user input + * controlled) + * @return the actual answer + */ + public String executeJavaJar(String guess, String fileName) { + BinaryInstructionForFile binaryInstructionForFile; + if (Strings.isNullOrEmpty(guess)) { + binaryInstructionForFile = BinaryInstructionForFile.Spoil; + } else { + binaryInstructionForFile = BinaryInstructionForFile.Guess; + } + try { + File jarFile = createTempJar(fileName); + String result = executeJavaJar(jarFile, binaryInstructionForFile, guess); + deleteFile(jarFile); + log.info( + "stdout challenge {}: {}", + challengeNumber, + result.lines().collect(Collectors.joining(""))); + return result; + } catch (Exception e) { + log.warn("Error executing Java JAR:", e); + executionException = e; + return ERROR_EXECUTION; + } + } + @SuppressFBWarnings( value = "COMMAND_INJECTION", justification = "We check for various injection methods and counter those") @@ -146,6 +178,33 @@ private String executeCommand( } } + @SuppressFBWarnings( + value = "COMMAND_INJECTION", + justification = "We check for various injection methods and counter those") + private String executeJavaJar(File jarFile, BinaryInstructionForFile binaryInstructionForFile, String guess) + throws IOException, InterruptedException { + if (!jarFile.getPath().contains("wrongsecrets") + || stringContainsCommandChainToken(jarFile.getPath()) + || stringContainsCommandChainToken(guess)) { + return BinaryExecutionHelper.ERROR_EXECUTION; + } + + ProcessBuilder ps; + if (binaryInstructionForFile.equals(BinaryInstructionForFile.Spoil)) { + ps = new ProcessBuilder("java", "-jar", jarFile.getPath(), "spoil"); + } else { + ps = new ProcessBuilder("java", "-jar", jarFile.getPath(), guess); + } + ps.redirectErrorStream(true); + Process pr = ps.start(); + try (BufferedReader in = + new BufferedReader(new InputStreamReader(pr.getInputStream(), StandardCharsets.UTF_8))) { + String result = in.readLine(); + pr.waitFor(); + return result; + } + } + private boolean stringContainsCommandChainToken(String testString) { String[] tokens = {"!", "&", "|", "<", ">", ";"}; boolean found = false; @@ -248,6 +307,17 @@ private File createTempExecutable(String fileName) throws IOException { return execFile; } + private File createTempJar(String fileName) throws IOException { + File execFile = File.createTempFile("c-exec-" + fileName.replace('.', '-'), ".jar"); + try { + FileUtils.copyInputStreamToFile( + new ClassPathResource("executables/" + fileName).getInputStream(), execFile); + } catch (IOException e) { + FileUtils.copyFile(retrieveFile(fileName), execFile); + } + return execFile; + } + @SuppressFBWarnings( value = "COMMAND_INJECTION", justification = "We check for various injection methods and counter those") diff --git a/src/main/resources/explanations/challenge65.adoc b/src/main/resources/explanations/challenge65.adoc new file mode 100644 index 0000000000..8229add588 --- /dev/null +++ b/src/main/resources/explanations/challenge65.adoc @@ -0,0 +1,5 @@ +=== Hiding in binaries part 6: the plain Java CLI + +Compiled Java applications can hide secrets too, even when they are only distributed as runnable JARs. Can you find the secret in our plain Java CLI? + +Try downloading and inspecting https://github.com/OWASP/wrongsecrets/tree/master/src/main/resources/executables/wrongsecrets-java.jar[wrongsecrets-java.jar]. Run it locally with `java -jar wrongsecrets-java.jar spoil` or `java -jar wrongsecrets-java.jar `. diff --git a/src/main/resources/explanations/challenge65_hint.adoc b/src/main/resources/explanations/challenge65_hint.adoc new file mode 100644 index 0000000000..0e5ef7eb0b --- /dev/null +++ b/src/main/resources/explanations/challenge65_hint.adoc @@ -0,0 +1,7 @@ +This challenge uses a plain Java CLI JAR. + +You can solve it by: + +1. Extracting the JAR and looking at the compiled classes or bundled metadata. +2. Using tools like `strings`, CFR, `javap`, JADX, or IntelliJ's decompiler. +3. Running the JAR with `spoil` or trying to understand how it compares your input. diff --git a/src/main/resources/explanations/challenge65_reason.adoc b/src/main/resources/explanations/challenge65_reason.adoc new file mode 100644 index 0000000000..c935ff2ed5 --- /dev/null +++ b/src/main/resources/explanations/challenge65_reason.adoc @@ -0,0 +1,5 @@ +*Why shipping a secret inside a plain JAR is still shipping the secret to the attacker.* + +Java bytecode is straightforward to decompile. If a secret is embedded in a class, an attacker can recover it from the JAR with static analysis or by observing the program at runtime. + +If a client-side executable needs a secret to do its job, assume the secret can be extracted. Prefer retrieving secrets from a trusted backend after proper authentication and authorization. diff --git a/src/main/resources/explanations/challenge66.adoc b/src/main/resources/explanations/challenge66.adoc new file mode 100644 index 0000000000..dc8378816a --- /dev/null +++ b/src/main/resources/explanations/challenge66.adoc @@ -0,0 +1,5 @@ +=== Hiding in binaries part 7: the obfuscated Java CLI + +Obfuscation might slow someone down, but it does not stop them from recovering embedded secrets. Can you find the harder secret in our obfuscated Java CLI? + +Try downloading and inspecting https://github.com/OWASP/wrongsecrets/tree/master/src/main/resources/executables/wrongsecrets-java-obfuscated.jar[wrongsecrets-java-obfuscated.jar]. Run it locally with `java -jar wrongsecrets-java-obfuscated.jar spoil` or `java -jar wrongsecrets-java-obfuscated.jar `. diff --git a/src/main/resources/explanations/challenge66_hint.adoc b/src/main/resources/explanations/challenge66_hint.adoc new file mode 100644 index 0000000000..b8aeb99a68 --- /dev/null +++ b/src/main/resources/explanations/challenge66_hint.adoc @@ -0,0 +1,7 @@ +This challenge uses an obfuscated Java CLI JAR. + +You can solve it by: + +1. Decompiling the classes and following the code that reconstructs the secret. +2. Looking for encoded byte arrays, reflection, and helper methods that decode data at runtime. +3. Running the JAR and tracing what happens when `spoil` is passed in. diff --git a/src/main/resources/explanations/challenge66_reason.adoc b/src/main/resources/explanations/challenge66_reason.adoc new file mode 100644 index 0000000000..c2596e56e3 --- /dev/null +++ b/src/main/resources/explanations/challenge66_reason.adoc @@ -0,0 +1,5 @@ +*Why obfuscation is only a speed bump.* + +Encoding, reflection, and light obfuscation can make reverse engineering less convenient, but they do not create real secrecy. The executable still contains everything it needs to recover the secret. + +If the application can derive the secret locally, a determined attacker can do the same. Protect secrets by moving trust decisions and secret material to controlled server-side systems. diff --git a/src/main/resources/wrong-secrets-configuration.yaml b/src/main/resources/wrong-secrets-configuration.yaml index 00993f2350..6871933e11 100644 --- a/src/main/resources/wrong-secrets-configuration.yaml +++ b/src/main/resources/wrong-secrets-configuration.yaml @@ -987,3 +987,29 @@ configurations: category: *bin ctf: enabled: true + + - name: Challenge 65 + short-name: "challenge-65" + sources: + - class-name: "org.owasp.wrongsecrets.challenges.docker.Challenge65" + explanation: "explanations/challenge65.adoc" + hint: "explanations/challenge65_hint.adoc" + reason: "explanations/challenge65_reason.adoc" + environments: *all_envs + difficulty: *normal + category: *bin + ctf: + enabled: true + + - name: Challenge 66 + short-name: "challenge-66" + sources: + - class-name: "org.owasp.wrongsecrets.challenges.docker.Challenge66" + explanation: "explanations/challenge66.adoc" + hint: "explanations/challenge66_hint.adoc" + reason: "explanations/challenge66_reason.adoc" + environments: *all_envs + difficulty: *master + category: *bin + ctf: + enabled: true diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge65Test.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge65Test.java new file mode 100644 index 0000000000..2ea564f989 --- /dev/null +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge65Test.java @@ -0,0 +1,25 @@ +package org.owasp.wrongsecrets.challenges.docker; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.owasp.wrongsecrets.Challenges.ErrorResponses.EXECUTION_ERROR; + +import org.junit.jupiter.api.Test; +import org.owasp.wrongsecrets.challenges.Spoiler; + +class Challenge65Test { + + @Test + void spoilerShouldNotCrash() { + var challenge = new Challenge65(); + + assertThat(challenge.spoiler()).isNotEqualTo(new Spoiler(EXECUTION_ERROR)); + assertThat(challenge.answerCorrect(challenge.spoiler().solution())).isTrue(); + } + + @Test + void incorrectAnswerShouldNotSolveChallenge() { + var challenge = new Challenge65(); + + assertThat(challenge.answerCorrect("wrong answer")).isFalse(); + } +} diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge66Test.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge66Test.java new file mode 100644 index 0000000000..839214dc92 --- /dev/null +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge66Test.java @@ -0,0 +1,25 @@ +package org.owasp.wrongsecrets.challenges.docker; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.owasp.wrongsecrets.Challenges.ErrorResponses.EXECUTION_ERROR; + +import org.junit.jupiter.api.Test; +import org.owasp.wrongsecrets.challenges.Spoiler; + +class Challenge66Test { + + @Test + void spoilerShouldNotCrash() { + var challenge = new Challenge66(); + + assertThat(challenge.spoiler()).isNotEqualTo(new Spoiler(EXECUTION_ERROR)); + assertThat(challenge.answerCorrect(challenge.spoiler().solution())).isTrue(); + } + + @Test + void incorrectAnswerShouldNotSolveChallenge() { + var challenge = new Challenge66(); + + assertThat(challenge.answerCorrect("wrong answer")).isFalse(); + } +} From 2c07848c84646ea38cec8e3204d9e0141a05ec30 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 06:02:36 +0000 Subject: [PATCH 2/4] chore: add Java challenge artifacts Agent-Logs-Url: https://github.com/OWASP/wrongsecrets/sessions/f2ea090d-47bb-4e0a-ad4c-179c568545a8 Co-authored-by: commjoen <1457214+commjoen@users.noreply.github.com> --- .gitignore | 6 ++++++ .../binaryexecution/BinaryExecutionHelper.java | 12 ++++++++++-- .../executables/wrongsecrets-java-ctf.jar | Bin 0 -> 3234 bytes .../wrongsecrets-java-obfuscated-ctf.jar | Bin 0 -> 4032 bytes .../executables/wrongsecrets-java-obfuscated.jar | Bin 0 -> 3981 bytes .../resources/executables/wrongsecrets-java.jar | Bin 0 -> 3207 bytes 6 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/executables/wrongsecrets-java-ctf.jar create mode 100644 src/main/resources/executables/wrongsecrets-java-obfuscated-ctf.jar create mode 100644 src/main/resources/executables/wrongsecrets-java-obfuscated.jar create mode 100644 src/main/resources/executables/wrongsecrets-java.jar diff --git a/.gitignore b/.gitignore index b964337051..ed502d9ba1 100644 --- a/.gitignore +++ b/.gitignore @@ -78,6 +78,12 @@ src/main/resources/executables/decrypt/decrypt src/main/resources/executables/wrongsecrets-dotnet src/main/resources/executables/wrongsecrets-dotnet* +# Challenge 65/66 +!src/main/resources/executables/wrongsecrets-java.jar +!src/main/resources/executables/wrongsecrets-java-ctf.jar +!src/main/resources/executables/wrongsecrets-java-obfuscated.jar +!src/main/resources/executables/wrongsecrets-java-obfuscated-ctf.jar + # Challenge 59 k8s/challenge53/executables/wrongsecrets-challenge53-c k8s/challenge53/executables/wrongsecrets-challenge53-c* diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/binaryexecution/BinaryExecutionHelper.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/binaryexecution/BinaryExecutionHelper.java index 5eb6695b42..541b861de2 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/binaryexecution/BinaryExecutionHelper.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/binaryexecution/BinaryExecutionHelper.java @@ -6,7 +6,11 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.io.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -181,7 +185,8 @@ private String executeCommand( @SuppressFBWarnings( value = "COMMAND_INJECTION", justification = "We check for various injection methods and counter those") - private String executeJavaJar(File jarFile, BinaryInstructionForFile binaryInstructionForFile, String guess) + private String executeJavaJar( + File jarFile, BinaryInstructionForFile binaryInstructionForFile, String guess) throws IOException, InterruptedException { if (!jarFile.getPath().contains("wrongsecrets") || stringContainsCommandChainToken(jarFile.getPath()) @@ -307,6 +312,9 @@ private File createTempExecutable(String fileName) throws IOException { return execFile; } + @SuppressFBWarnings( + value = "PATH_TRAVERSAL_IN", + justification = "The jar file name is hardcoded at the caller level") private File createTempJar(String fileName) throws IOException { File execFile = File.createTempFile("c-exec-" + fileName.replace('.', '-'), ".jar"); try { diff --git a/src/main/resources/executables/wrongsecrets-java-ctf.jar b/src/main/resources/executables/wrongsecrets-java-ctf.jar new file mode 100644 index 0000000000000000000000000000000000000000..03e4294cecf88bede5e8edb10ed02722312a89cf GIT binary patch literal 3234 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 Date: Mon, 11 May 2026 06:05:30 +0000 Subject: [PATCH 3/4] chore: polish Java jar helper Agent-Logs-Url: https://github.com/OWASP/wrongsecrets/sessions/f2ea090d-47bb-4e0a-ad4c-179c568545a8 Co-authored-by: commjoen <1457214+commjoen@users.noreply.github.com> --- .../docker/binaryexecution/BinaryExecutionHelper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/binaryexecution/BinaryExecutionHelper.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/binaryexecution/BinaryExecutionHelper.java index 541b861de2..74af6bae40 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/binaryexecution/BinaryExecutionHelper.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/binaryexecution/BinaryExecutionHelper.java @@ -117,7 +117,7 @@ public String executeCommand(String guess, String fileName) { } /** - * Execute a Java CLI packaged as a JAR with the actual guess. + * Execute a Java CLI packaged as a JAR for either secret retrieval or guess validation. * * @param guess containing the guess * @param fileName of the JAR to be used (pre-defined, make sure it is never user input @@ -316,7 +316,7 @@ private File createTempExecutable(String fileName) throws IOException { value = "PATH_TRAVERSAL_IN", justification = "The jar file name is hardcoded at the caller level") private File createTempJar(String fileName) throws IOException { - File execFile = File.createTempFile("c-exec-" + fileName.replace('.', '-'), ".jar"); + File execFile = File.createTempFile("java-jar-" + fileName.replace('.', '-'), ".jar"); try { FileUtils.copyInputStreamToFile( new ClassPathResource("executables/" + fileName).getInputStream(), execFile); From 928795e28845bbd9d9e231347b95251164ac4e1f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 07:02:10 +0000 Subject: [PATCH 4/4] docs: expand challenge 66 hint steps Agent-Logs-Url: https://github.com/OWASP/wrongsecrets/sessions/ffd37450-0343-442a-abee-851241cb0eff Co-authored-by: commjoen <1457214+commjoen@users.noreply.github.com> --- .../explanations/challenge66_hint.adoc | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/resources/explanations/challenge66_hint.adoc b/src/main/resources/explanations/challenge66_hint.adoc index b8aeb99a68..24476669cd 100644 --- a/src/main/resources/explanations/challenge66_hint.adoc +++ b/src/main/resources/explanations/challenge66_hint.adoc @@ -2,6 +2,19 @@ This challenge uses an obfuscated Java CLI JAR. You can solve it by: -1. Decompiling the classes and following the code that reconstructs the secret. -2. Looking for encoded byte arrays, reflection, and helper methods that decode data at runtime. -3. Running the JAR and tracing what happens when `spoil` is passed in. +1. Decompile the JAR with a Java decompiler such as CFR, JADX, or IntelliJ IDEA: +- Download `wrongsecrets-java-obfuscated.jar`. +- Open it in your decompiler of choice. +- Find the main class and trace what happens when the program receives the `spoil` argument. +- Look for helper methods that rebuild the secret at runtime. + +2. Inspect the bytecode from the command line: +- Run `jar tf wrongsecrets-java-obfuscated.jar` to list the classes in the JAR. +- Extract it with `jar xf wrongsecrets-java-obfuscated.jar`. +- Run `javap -c -p io/github/owasp/wrongsecrets/WrongSecretsObfuscated.class` on the extracted class. +- Look for the encoded byte array, the XOR key, and the method that decodes the secret. + +3. Run the JAR locally and observe its behavior: +- Execute `java -jar wrongsecrets-java-obfuscated.jar spoil`. +- If you want to understand the guessing flow, also run `java -jar wrongsecrets-java-obfuscated.jar wronganswer`. +- Compare the runtime behavior with what you found in the decompiled code to recover the secret.