diff --git a/.github/scripts/docker-create.sh b/.github/scripts/docker-create.sh index 107d64466..02d8259cd 100755 --- a/.github/scripts/docker-create.sh +++ b/.github/scripts/docker-create.sh @@ -7,7 +7,7 @@ Help() { # Display Help echo "A versatile script to create a docker image for testing. Call this script with no arguments to simply create a local image that you can use to test your changes. For more complex use see the below help section" echo - echo "Syntax: docker-create.sh [-h (help)|-t (test)|-p (publish)|-e (herokud)|-f (herokup) [tag={tag}|message={message}|buildarg={buildarg}|springProfile={springProfile}]" + echo "Syntax: docker-create.sh [-h (help)|-t (test)|-p (publish)|-e (herokud)|-f (herokup)|-n (notag) [tag={tag}|message={message}|buildarg={buildarg}|springProfile={springProfile}]" echo "options: (All optional)" echo "tag= Write a custom tag that will be added to the container when it is build locally." echo "message= Write a message used for the actual tag-message in git" @@ -70,7 +70,7 @@ Heroku_publish_prod(){ # Set option to local if no option provided script_mode="local" # Parse provided options -while getopts ":htpef*" option; do +while getopts ":htpefn*" option; do case $option in h) # display Help Help @@ -88,13 +88,10 @@ while getopts ":htpef*" option; do f) # Helper script_mode="heroku_p" ;; - \?) # Invalid option - echo "Error: Invalid option" - echo - Help - exit + n) #notags + disable_tagging_in_git="true" ;; - -*) # Anything else + \?|\*) # Invalid option echo "Error: Invalid option" echo Help @@ -156,6 +153,12 @@ echo "Spring profile: $springProfile" echo "Version tag: $tag" echo "buildarg supplied: $buildarg" +if test -n "${disable_tagging_in_git+x}"; then + echo "tagging is disabled" +else + disable_tagging_in_git="false" +fi + if [[ $script_mode == "heroku_d" ]] ; then Heroku_publish_demo elif [[ $script_mode == "heroku_p" ]]; then @@ -276,9 +279,13 @@ commit_and_tag() { echo "committing changes and new pom file with version ${tag}" git commit -am "Update POM file with new version: ${tag}" git push - echo "tagging version with tag ${tag} and message ${message}" - git tag -a $tag -m "${message}" - git push --tags + if [[ "$disable_tagging_in_git" == "true" ]]; then + echo "Skip git tagging" + else + echo "tagging version with tag '${tag}' and message '${message}'" + git tag -a $tag -m "${message}" + git push --tags + fi else return fi diff --git a/.github/workflows/container_test.yml b/.github/workflows/container_test.yml index 9640e7598..77d8232c0 100644 --- a/.github/workflows/container_test.yml +++ b/.github/workflows/container_test.yml @@ -6,8 +6,6 @@ name: Docker container test on: # Triggers the workflow on push or pull request events but only for the master branch push: - pull_request: - branches: [ master ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: diff --git a/README.md b/README.md index 787352731..f2e336f5c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Welcome to the OWASP WrongSecrets p0wnable app. With this app, we have packed various ways of how to not store your secrets. These can help you to realize whether your secret management is ok. The challenge is to find all the different secrets by means of various tools and techniques. -Can you solve all the 21 challenges? +Can you solve all the 22 challenges? ![screenshot.png](screenshot.png) ## Support @@ -17,7 +17,7 @@ Need support? Contact us via [OWASP Slack](https://owasp.slack.com/archives/C02K ## Basic docker exercises -_Can be used for challenges 1-4, 8, 12-21_ +_Can be used for challenges 1-4, 8, 12-22_ For the basic docker exercises you currently require: @@ -47,6 +47,7 @@ Now you can try to find the secrets by means of solving the challenge offered at - [localhost:8080/challenge/19](http://localhost:8080/challenge/19) - [localhost:8080/challenge/20](http://localhost:8080/challenge/20) - [localhost:8080/challenge/21](http://localhost:8080/challenge/21) +- [localhost:8080/challenge/22](http://localhost:8080/challenge/22) Note that these challenges are still very basic, and so are their explanations. Feel free to file a PR to make them look better ;-). @@ -63,7 +64,7 @@ You can test them out at [https://wrongsecrets.herokuapp.com/](https://wrongsecr ## Basic K8s exercise -_Can be used for challenges 1-6, 8, 12-21_ +_Can be used for challenges 1-6, 8, 12-22_ ### Minikube based @@ -110,7 +111,7 @@ now you can use the provided IP address and port to further play with the K8s va ## Vault exercises with minikube -_Can be used for challenges 1-8, 12-21_ +_Can be used for challenges 1-8, 12-22_ Make sure you have the following installed: - minikube with docker (or comment out line 8 and work at your own k8s setup), @@ -121,15 +122,15 @@ Make sure you have the following installed: - vault [Install from here](https://www.vaultproject.io/downloads), - grep, Cat, and Sed -Run `./k8s-vault-minkube-start.sh`, when the script is done, then the challenges will wait for you at . This will allow you to run challenges 1-8, 12-21. +Run `./k8s-vault-minkube-start.sh`, when the script is done, then the challenges will wait for you at . This will allow you to run challenges 1-8, 12-22. When you stopped the `k8s-vault-minikube-start.sh` script and want to resume the port forward run: `k8s-vault-minikube-resume.sh`. This is because if you run the start script again it will replace the secret in the vault and not update the secret-challenge application with the new secret. ## Cloud Challenges -_Can be used for challenges 1-21_ +_Can be used for challenges 1-22_ -**READ THIS**: Given that the exercises below contain IAM privilege escalation exercises, +**READ THIS**: Given that the exercises below contain IAM privilege escalation exercises, never run this on an account which is related to your production environment or can influence your account-over-arching resources. ### Running WrongSecrets in AWS @@ -147,6 +148,7 @@ Follow the steps in [the README in the Azure subfolder](azure/README.md). ### Running Challenge15 in your own cloud only When you want to include your own Canarytokens for your cloud-deployment, do the following: + 1. Fork the project. 2. Make sure you use the [GCP ingress](/gcp/k8s-vault-gcp-ingress-start.sh) or [AWS ingress](aws/k8s-aws-alb-script.sh) scripts to generate an ingress for your project. 3. Go to [canarytokens.org](https://canarytokens.org/generate) and select `AWS Keys`, in the webHook URL field add `/canaries/tokencallback`. diff --git a/pom.xml b/pom.xml index bbd2021ba..11baf0ac4 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.owasp wrongsecrets - 1.4.6-SNAPSHOT + challenge22t1-SNAPSHOT OWASP WrongSecrets Examples with how to not use secrets https://owasp.org/www-project-wrongsecrets/ diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge22.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge22.java new file mode 100644 index 000000000..f3b468e79 --- /dev/null +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge22.java @@ -0,0 +1,41 @@ + +package org.owasp.wrongsecrets.challenges.docker; + +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.Spoiler; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.List; + +import static org.owasp.wrongsecrets.RuntimeEnvironment.Environment.DOCKER; + +@Component +@Order(22) +@Slf4j +public class Challenge22 extends Challenge { + + private final BinaryExecutionHelper binaryExecutionHelper; + + public Challenge22(ScoreCard scoreCard) { + super(scoreCard); + this.binaryExecutionHelper = new BinaryExecutionHelper(22); + } + + @Override + public Spoiler spoiler() { + return new Spoiler(binaryExecutionHelper.executeCommand("", "wrongsecrets-rust")); + } + + @Override + public boolean answerCorrect(String answer) { + return binaryExecutionHelper.executeCommand(answer, "wrongsecrets-rust").equals("This is correct! Congrats!"); + } + + public List supportedRuntimeEnvironments() { + return List.of(DOCKER); + } +} diff --git a/src/main/resources/executables/wrongsecrets-rust b/src/main/resources/executables/wrongsecrets-rust new file mode 100755 index 000000000..67a7efb3f Binary files /dev/null and b/src/main/resources/executables/wrongsecrets-rust differ diff --git a/src/main/resources/executables/wrongsecrets-rust-arm b/src/main/resources/executables/wrongsecrets-rust-arm new file mode 100755 index 000000000..63549f087 Binary files /dev/null and b/src/main/resources/executables/wrongsecrets-rust-arm differ diff --git a/src/main/resources/executables/wrongsecrets-rust-linux b/src/main/resources/executables/wrongsecrets-rust-linux new file mode 100755 index 000000000..9cb101d87 Binary files /dev/null and b/src/main/resources/executables/wrongsecrets-rust-linux differ diff --git a/src/main/resources/executables/wrongsecrets-rust-linux-arm b/src/main/resources/executables/wrongsecrets-rust-linux-arm new file mode 100755 index 000000000..f39d8d9bb Binary files /dev/null and b/src/main/resources/executables/wrongsecrets-rust-linux-arm differ diff --git a/src/main/resources/explanations/challenge19.adoc b/src/main/resources/explanations/challenge19.adoc index bc873ad7b..ea12d2b1a 100644 --- a/src/main/resources/explanations/challenge19.adoc +++ b/src/main/resources/explanations/challenge19.adoc @@ -1,4 +1,4 @@ -=== Obfuscating in binaries part 1: the C binary +=== Hiding in binaries part 1: the C binary We need to put a secret in a mobile app! Nobody will notice the secret in our compiled code! This is a misbelief we have often encountered when presenting on mobile security topics. diff --git a/src/main/resources/explanations/challenge20.adoc b/src/main/resources/explanations/challenge20.adoc index 1d561b90d..45aca83fa 100644 --- a/src/main/resources/explanations/challenge20.adoc +++ b/src/main/resources/explanations/challenge20.adoc @@ -1,4 +1,4 @@ -=== Obfuscating in binaries part 2: the C++ binary +=== Hiding in binaries part 2: the C++ binary Similar like hiding secrets in an application written in C, you end up in a similar situation with C++. Can you find the secret in our binary? diff --git a/src/main/resources/explanations/challenge21.adoc b/src/main/resources/explanations/challenge21.adoc index ea452d99f..52f401e27 100644 --- a/src/main/resources/explanations/challenge21.adoc +++ b/src/main/resources/explanations/challenge21.adoc @@ -1,4 +1,4 @@ -=== Obfuscating part 3: the Go binary +=== Hiding in binaries part 3: the Go binary Our third language of choice for a compiled application is Go. With the rise of its popularity, we see an increase of secrets hidden inside the binaries. Can you find the secret in our binary? diff --git a/src/main/resources/explanations/challenge22.adoc b/src/main/resources/explanations/challenge22.adoc new file mode 100644 index 000000000..c80c223f7 --- /dev/null +++ b/src/main/resources/explanations/challenge22.adoc @@ -0,0 +1,5 @@ +=== Hiding in binaries part 4: the Rust binary + +Similar like hiding secrets in an application written in C, you can do this in Rust. Ghidra is not that good at analysing Rust by default, though... Can you find the secret in our binary? + +Let's debunk the "secrets are hard to find in native compiled applications" myth for Rust: can you find the secret in https://github.com/commjoen/wrongsecrets/tree/master/src/main/resources/executables/wrongsecrets-rust[wrongsecrets-rust] (or https://github.com/commjoen/wrongsecrets/tree/master/src/main/resources/executables/wrongsecrets-rust-arm[wrongsecrets-rust-arm], https://github.com/commjoen/wrongsecrets/tree/master/src/main/resources/executables/wrongsecrets-rust-linux[wrongsecrets-rust-linux])? diff --git a/src/main/resources/explanations/challenge22_hint.adoc b/src/main/resources/explanations/challenge22_hint.adoc new file mode 100644 index 000000000..27768a0d0 --- /dev/null +++ b/src/main/resources/explanations/challenge22_hint.adoc @@ -0,0 +1,23 @@ +This challenge is specifically looking at a secret in a Rust binary based on a https://doc.rust-lang.org/cargo/reference/profiles.html#release[release profile]. + +You can solve this challenge using the following steps: + +1. Find the secrets with https://ghidra-sre.org/[Ghidra]. +- Install https://ghidra-sre.org/[Ghidra]. +- Start it whit `ghidraRun`. +- Load the application `wrongsecrets-rust` into ghidra by choosing a new project, then import the file and then doubleclick on it. +- Allow the Ghidra to analyze the application. +- Now import https://gist.github.com/str4d/e541f4c28e2bca80d222434ac1a204f4[demangle script] and run it via the Ghidra Script manager to demangle the functions. +- Find the `main` function in the `rust` namespace +- Find the argument that needs to be compared (in our example that is `local_80` as defined in `std::env::args((env *)&local_80);`) +- Find where the argument is compared (in our example that is `iVar1 = __stubs::_memcmp(local_80,puVar2,0x3b);`) +- Now search the input it is compared to (`puVar2`) its value. Can you find the secret? +- Alternatively: Go to the data type manager in the bottom left, now filter for `string`, now right-click at `string` as a member of `wrongsecrets-rust` and select `find uses of`. Then, filter for known keywords: you should easily be able to find the secret now! + +2. Find the secrets with https://www.radare.org[radare2]. +- Install https://www.radare.org[radare2] with either `brew install radare2` on Mac or follow these steps: `git clone https://github.com/radareorg/radare2; cd radare2 ; sys/install.sh` +- Launch r2 analysis with `$ r2 -AAA wrongsecrets-rust` +- Print the entrypoint `s sym.rust::main::h66ace6a84e548891` and then `pdf`. (not the default `main`!) +- Find the argument that needs to be compared with `pdf | grep memcmp` (in our example that is `r12`). +- Try to find how this argument is prepared. Can you spot the secret? +- Alternatively: after launching radare2, run `iz | grep secret` and find the string. diff --git a/src/main/resources/explanations/challenge22_reason.adoc b/src/main/resources/explanations/challenge22_reason.adoc new file mode 100644 index 000000000..707e34e86 --- /dev/null +++ b/src/main/resources/explanations/challenge22_reason.adoc @@ -0,0 +1,7 @@ +*Why Using binaries to hide a secret will only delay an attacker.* + +With beautiful free Reverse engineering applications as Ghidra, not a lot of things remain safe. Anyone who can load the executable in Ghidra or Radare2 can easily start doing a reconnaissance and find secrets within your binary. + +Encrypting the secret with a key embedded in the binary, and other funny puzzles do delay an attacker and just make it fun finding the secret. Be aware that, if the secret needs to be used by the executable, it eventually needs to be in memory ready to be executed. + +Still need to have a secret in the binary? Make sure it can only be retrieved remotely after authenticating against a server. diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge22Test.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge22Test.java new file mode 100644 index 000000000..051bf6a0c --- /dev/null +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge22Test.java @@ -0,0 +1,25 @@ +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.junit.jupiter.MockitoExtension; +import org.owasp.wrongsecrets.ScoreCard; +import org.owasp.wrongsecrets.challenges.Spoiler; + +@ExtendWith(MockitoExtension.class) +class Challenge22Test { + + @Mock + private ScoreCard scoreCard; + + @Test + void spoilerShouldNotCrash() { + var challenge = new Challenge22(scoreCard); + + Assertions.assertThat(challenge.spoiler()).isNotEqualTo(new Spoiler(BinaryExecutionHelper.ERROR_EXECUTION)); + Assertions.assertThat(challenge.answerCorrect(challenge.spoiler().solution())).isTrue(); + } + +}