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 01/13] 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 02/13] 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 03/13] 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 04/13] 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. From 63dc675a7497050db2690df42529abf65c3c2726 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 15 May 2026 10:07:38 +0000 Subject: [PATCH 05/13] docs: expand challenge 66 explanation steps Agent-Logs-Url: https://github.com/OWASP/wrongsecrets/sessions/f5613696-4b1f-4899-844f-53b020e7c5e3 Co-authored-by: commjoen <1457214+commjoen@users.noreply.github.com> --- src/main/resources/explanations/challenge66.adoc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/resources/explanations/challenge66.adoc b/src/main/resources/explanations/challenge66.adoc index dc8378816a..558ac6e893 100644 --- a/src/main/resources/explanations/challenge66.adoc +++ b/src/main/resources/explanations/challenge66.adoc @@ -2,4 +2,10 @@ 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 `. +To solve it: + +. Download and inspect https://github.com/OWASP/wrongsecrets/tree/master/src/main/resources/executables/wrongsecrets-java-obfuscated.jar[wrongsecrets-java-obfuscated.jar]. +. Run `java -jar wrongsecrets-java-obfuscated.jar spoil` to see how the CLI behaves when it is asked to reveal the secret. +. Decompile the JAR with a Java decompiler such as CFR, JADX, or IntelliJ IDEA and trace the main class. +. Look for the encoded byte array, XOR key, and helper methods that reconstruct the secret at runtime. +. Once you recover the secret, submit it with `java -jar wrongsecrets-java-obfuscated.jar `. From bfb629e9e4a32f9c4ac14b2dc4b9ba87c21168fb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 21:03:35 +0000 Subject: [PATCH 06/13] docs: refine challenge 66 reverse-engineering hints Agent-Logs-Url: https://github.com/OWASP/wrongsecrets/sessions/338d4353-a2d0-48a3-a0bb-2dea0c76d235 Co-authored-by: commjoen <1457214+commjoen@users.noreply.github.com> --- .../explanations/challenge66_hint.adoc | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/resources/explanations/challenge66_hint.adoc b/src/main/resources/explanations/challenge66_hint.adoc index 24476669cd..1f9977b842 100644 --- a/src/main/resources/explanations/challenge66_hint.adoc +++ b/src/main/resources/explanations/challenge66_hint.adoc @@ -2,19 +2,19 @@ This challenge uses an obfuscated Java CLI JAR. You can solve it by: -1. Decompile the JAR with a Java decompiler such as CFR, JADX, or IntelliJ IDEA: +1. Find where the obfuscated data lives: - 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. +- Run `jar tf wrongsecrets-java-obfuscated.jar` and locate `io/github/owasp/wrongsecrets/WrongSecretsObfuscated.class`. +- Open that class in CFR, JADX, IntelliJ IDEA, or another decompiler. +- Look for the static fields that hold the XOR key and the encoded secret bytes. -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. +2. Inspect the exact decoding logic: +- Run `javap -c -p -classpath wrongsecrets-java-obfuscated.jar io.github.owasp.wrongsecrets.WrongSecretsObfuscated`. +- In the output, find the `static { ... }` block that fills `XOR_KEY_CHARS` and `ENCODED_SECRET`. +- Then find `decodeSecret()` and note that each encoded byte is XORed with one byte from the key, repeating the key with modulo arithmetic. -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. +3. Rebuild the secret yourself: +- Convert the `XOR_KEY_CHARS` values into bytes. +- Copy the `ENCODED_SECRET` byte values from the bytecode or decompiled source. +- XOR each encoded byte with the matching key byte, wrapping around when you reach the end of the key. +- Decode the resulting byte array as UTF-8 to recover the secret, then submit that value as the answer. From 9011cbebdc4ccdf96d86d4a6ed48be971f86d583 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 06:58:44 +0000 Subject: [PATCH 07/13] docs: refine challenge 65 reverse-engineering hints Agent-Logs-Url: https://github.com/OWASP/wrongsecrets/sessions/3245d1dc-b5e2-46b4-ada6-17e234140815 Co-authored-by: commjoen <1457214+commjoen@users.noreply.github.com> --- .../explanations/challenge65_hint.adoc | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/resources/explanations/challenge65_hint.adoc b/src/main/resources/explanations/challenge65_hint.adoc index 0e5ef7eb0b..e3d8a5a65f 100644 --- a/src/main/resources/explanations/challenge65_hint.adoc +++ b/src/main/resources/explanations/challenge65_hint.adoc @@ -2,6 +2,17 @@ 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. +1. Find the compiled class that holds the secret: +- Download `wrongsecrets-java.jar`. +- Run `jar tf wrongsecrets-java.jar` and locate `io/github/owasp/wrongsecrets/WrongSecretsPlain.class`. +- Open that class in CFR, JADX, IntelliJ IDEA, or another decompiler. + +2. Inspect how the secret is stored: +- Run `javap -c -p -classpath wrongsecrets-java.jar io.github.owasp.wrongsecrets.WrongSecretsPlain`. +- Find the `getSecret()` method and look at the `ldc` instruction it uses. +- Notice that the secret is stored as a plain string constant instead of being obfuscated. + +3. Recover the value and submit it: +- Copy the string returned by `getSecret()` from the decompiler or bytecode output. +- If you want another quick check, tools like `strings wrongsecrets-java.jar` can also help expose readable constants. +- Submit the recovered string as the answer. From 4b139bc2669bb7b9aadb64a7fb83bad499e09a0d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 07:07:21 +0000 Subject: [PATCH 08/13] docs: refocus challenge 65 explanation Agent-Logs-Url: https://github.com/OWASP/wrongsecrets/sessions/7c6014c5-01eb-4f64-b9a9-363ed64c06ea Co-authored-by: commjoen <1457214+commjoen@users.noreply.github.com> --- src/main/resources/explanations/challenge65.adoc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/resources/explanations/challenge65.adoc b/src/main/resources/explanations/challenge65.adoc index 8229add588..84dd7fbc3d 100644 --- a/src/main/resources/explanations/challenge65.adoc +++ b/src/main/resources/explanations/challenge65.adoc @@ -1,5 +1,7 @@ === 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? +Runnable JARs are not a safe place to hide secrets. Just like Android APKs, they are archives that ship bytecode and resources directly to the attacker, which makes embedded strings, constants, and helper methods straightforward to inspect with common reverse-engineering tools. -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 `. +If a client-side Java artifact needs a secret to work, assume that secret can be extracted once the file is downloaded. Keep real secrets on a trusted backend and only release them after proper authentication and authorization. + +If you want more Java and Android reverse-engineering practice, explore the https://github.com/OWASP/MASTG-Hacking-Playground[OWASP MASTG Hacking Playground]. From be88c3f8ac4e1b052091b3a540a6a781fc047973 Mon Sep 17 00:00:00 2001 From: Jeroen Willemsen Date: Mon, 18 May 2026 09:50:03 +0200 Subject: [PATCH 09/13] Apply suggestion from @commjoen --- src/main/resources/explanations/challenge66.adoc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/explanations/challenge66.adoc b/src/main/resources/explanations/challenge66.adoc index 558ac6e893..d97f91cee8 100644 --- a/src/main/resources/explanations/challenge66.adoc +++ b/src/main/resources/explanations/challenge66.adoc @@ -5,7 +5,6 @@ Obfuscation might slow someone down, but it does not stop them from recovering e To solve it: . Download and inspect https://github.com/OWASP/wrongsecrets/tree/master/src/main/resources/executables/wrongsecrets-java-obfuscated.jar[wrongsecrets-java-obfuscated.jar]. -. Run `java -jar wrongsecrets-java-obfuscated.jar spoil` to see how the CLI behaves when it is asked to reveal the secret. . Decompile the JAR with a Java decompiler such as CFR, JADX, or IntelliJ IDEA and trace the main class. . Look for the encoded byte array, XOR key, and helper methods that reconstruct the secret at runtime. . Once you recover the secret, submit it with `java -jar wrongsecrets-java-obfuscated.jar `. From 20d311b9e1e14cbc70eb31858b578f3a631d8731 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 08:02:42 +0000 Subject: [PATCH 10/13] fix: ship java challenge jars in desktop images Agent-Logs-Url: https://github.com/OWASP/wrongsecrets/sessions/84886970-be86-48ff-984d-b416ea66922f Co-authored-by: commjoen <1457214+commjoen@users.noreply.github.com> --- Dockerfile_webdesktop | 1 + Dockerfile_webdesktopk8s | 1 + 2 files changed, 2 insertions(+) diff --git a/Dockerfile_webdesktop b/Dockerfile_webdesktop index 70e4e632f0..bfd4cd9f78 100644 --- a/Dockerfile_webdesktop +++ b/Dockerfile_webdesktop @@ -24,6 +24,7 @@ RUN --mount=type=secret,id=mysecret \ WORKDIR /config/Desktop COPY src/main/resources/executables/*linux-mus* /var/tmp/wrongsecrets/ +COPY src/main/resources/executables/wrongsecrets-java*.jar /var/tmp/wrongsecrets/ COPY src/main/resources/executables/decrypt/ /var/tmp/wrongsecrets/decrypt/ COPY src/main/resources/executables/wrongsecrets-advanced-c-windows.exe /var/tmp/wrongsecrets/ COPY src/main/resources/executables/secrchallenge.md /var/tmp/wrongsecrets/ diff --git a/Dockerfile_webdesktopk8s b/Dockerfile_webdesktopk8s index 70e4e632f0..bfd4cd9f78 100644 --- a/Dockerfile_webdesktopk8s +++ b/Dockerfile_webdesktopk8s @@ -24,6 +24,7 @@ RUN --mount=type=secret,id=mysecret \ WORKDIR /config/Desktop COPY src/main/resources/executables/*linux-mus* /var/tmp/wrongsecrets/ +COPY src/main/resources/executables/wrongsecrets-java*.jar /var/tmp/wrongsecrets/ COPY src/main/resources/executables/decrypt/ /var/tmp/wrongsecrets/decrypt/ COPY src/main/resources/executables/wrongsecrets-advanced-c-windows.exe /var/tmp/wrongsecrets/ COPY src/main/resources/executables/secrchallenge.md /var/tmp/wrongsecrets/ From ddc0fb13c989e44c631a6528cfc221e2fda9af6d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 08:14:01 +0000 Subject: [PATCH 11/13] docs: refocus challenge 65 explanation and reason Agent-Logs-Url: https://github.com/OWASP/wrongsecrets/sessions/24a041b5-fd38-429d-a6b5-f8f141ed817d Co-authored-by: commjoen <1457214+commjoen@users.noreply.github.com> --- src/main/resources/explanations/challenge65.adoc | 9 ++++++--- src/main/resources/explanations/challenge65_reason.adoc | 8 +++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/resources/explanations/challenge65.adoc b/src/main/resources/explanations/challenge65.adoc index 84dd7fbc3d..c66936700e 100644 --- a/src/main/resources/explanations/challenge65.adoc +++ b/src/main/resources/explanations/challenge65.adoc @@ -1,7 +1,10 @@ === Hiding in binaries part 6: the plain Java CLI -Runnable JARs are not a safe place to hide secrets. Just like Android APKs, they are archives that ship bytecode and resources directly to the attacker, which makes embedded strings, constants, and helper methods straightforward to inspect with common reverse-engineering tools. +Plain strings inside a Java CLI are easy to recover once the JAR is downloaded. Can you find the secret hidden in our plain Java CLI? -If a client-side Java artifact needs a secret to work, assume that secret can be extracted once the file is downloaded. Keep real secrets on a trusted backend and only release them after proper authentication and authorization. +To solve it: -If you want more Java and Android reverse-engineering practice, explore the https://github.com/OWASP/MASTG-Hacking-Playground[OWASP MASTG Hacking Playground]. +. Download and inspect https://github.com/OWASP/wrongsecrets/tree/master/src/main/resources/executables/wrongsecrets-java.jar[wrongsecrets-java.jar]. +. Decompile the JAR or inspect the main class with a Java decompiler such as CFR, JADX, IntelliJ IDEA, or `javap`. +. Look for the class that returns the secret and identify the plain string embedded in the CLI. +. Once you recover the secret, you can submit it in the box below or validate it with `java -jar wrongsecrets-java.jar `. diff --git a/src/main/resources/explanations/challenge65_reason.adoc b/src/main/resources/explanations/challenge65_reason.adoc index c935ff2ed5..04997f4192 100644 --- a/src/main/resources/explanations/challenge65_reason.adoc +++ b/src/main/resources/explanations/challenge65_reason.adoc @@ -1,5 +1,7 @@ -*Why shipping a secret inside a plain JAR is still shipping the secret to the attacker.* +*Why runnable JARs and Android APKs should not be used to hide secrets.* -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. +Runnable JARs are not a safe place to hide secrets. Just like Android APKs, they are archives that ship bytecode and resources directly to the attacker, which makes embedded strings, constants, and helper methods straightforward to inspect with common reverse-engineering tools. -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. +If a client-side Java artifact needs a secret to work, assume that secret can be extracted once the file is downloaded. Keep real secrets on a trusted backend and only release them after proper authentication and authorization. + +If you want more Java and Android reverse-engineering practice, explore the https://github.com/OWASP/MASTG-Hacking-Playground[OWASP MASTG Hacking Playground]. From a1670fb7614997611721f9f08a56a1f23d5b2e27 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 08:14:48 +0000 Subject: [PATCH 12/13] docs: clarify challenge 65 validation step Agent-Logs-Url: https://github.com/OWASP/wrongsecrets/sessions/24a041b5-fd38-429d-a6b5-f8f141ed817d Co-authored-by: commjoen <1457214+commjoen@users.noreply.github.com> --- src/main/resources/explanations/challenge65.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/explanations/challenge65.adoc b/src/main/resources/explanations/challenge65.adoc index c66936700e..fb687e10b7 100644 --- a/src/main/resources/explanations/challenge65.adoc +++ b/src/main/resources/explanations/challenge65.adoc @@ -7,4 +7,4 @@ To solve it: . Download and inspect https://github.com/OWASP/wrongsecrets/tree/master/src/main/resources/executables/wrongsecrets-java.jar[wrongsecrets-java.jar]. . Decompile the JAR or inspect the main class with a Java decompiler such as CFR, JADX, IntelliJ IDEA, or `javap`. . Look for the class that returns the secret and identify the plain string embedded in the CLI. -. Once you recover the secret, you can submit it in the box below or validate it with `java -jar wrongsecrets-java.jar `. +. Once you recover the exact secret value, you can submit it in the box below or validate it with `java -jar wrongsecrets-java.jar `. From 82f3b54812a3f46ef1e506c9a51b662af4f153fd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 08:15:26 +0000 Subject: [PATCH 13/13] docs: fix challenge 65 jar link Agent-Logs-Url: https://github.com/OWASP/wrongsecrets/sessions/24a041b5-fd38-429d-a6b5-f8f141ed817d Co-authored-by: commjoen <1457214+commjoen@users.noreply.github.com> --- src/main/resources/explanations/challenge65.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/explanations/challenge65.adoc b/src/main/resources/explanations/challenge65.adoc index fb687e10b7..25c250771b 100644 --- a/src/main/resources/explanations/challenge65.adoc +++ b/src/main/resources/explanations/challenge65.adoc @@ -4,7 +4,7 @@ Plain strings inside a Java CLI are easy to recover once the JAR is downloaded. To solve it: -. Download and inspect https://github.com/OWASP/wrongsecrets/tree/master/src/main/resources/executables/wrongsecrets-java.jar[wrongsecrets-java.jar]. +. Download and inspect https://github.com/OWASP/wrongsecrets/raw/master/src/main/resources/executables/wrongsecrets-java.jar[wrongsecrets-java.jar]. . Decompile the JAR or inspect the main class with a Java decompiler such as CFR, JADX, IntelliJ IDEA, or `javap`. . Look for the class that returns the secret and identify the plain string embedded in the CLI. . Once you recover the exact secret value, you can submit it in the box below or validate it with `java -jar wrongsecrets-java.jar `.