Projects STRLCPY wrongsecrets Commits 5620d549
🤬
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■ ■
    .github/FUNDING.yml
    1 1  custom: https://owasp.org/donate/?reponame=www-project-wrongsecrets&title=OWASP+wrongsecrets
     2 +github: OWASP
    2 3   
  • ■ ■ ■ ■ ■ ■
    .github/dependabot.yml
    skipped 17 lines
    18 18   schedule:
    19 19   interval: "monthly"
    20 20  
     21 + # check our npm
     22 + - package-ecosystem: "npm"
     23 + directory: "/js"
     24 + schedule:
     25 + interval: "monthly"
     26 +
     27 + # Check our tf -aws
     28 + - package-ecosystem: "terraform"
     29 + directory: "/aws"
     30 + schedule:
     31 + interval: "monthly"
     32 +
     33 + # Check our tf -azure
     34 + - package-ecosystem: "terraform"
     35 + directory: "/azure"
     36 + schedule:
     37 + interval: "monthly"
     38 +
     39 + # Check our tf -gcp
     40 + - package-ecosystem: "terraform"
     41 + directory: "/gcp"
     42 + schedule:
     43 + interval: "monthly"
     44 + 
  • ■ ■ ■ ■ ■ ■
    .github/scripts/docker-create-and-push.sh
    1  -#!/bin/bash
    2  - 
    3  -if [ $# -eq 0 ]
    4  - then
    5  - echo "No arguments supplied, please supply a tag eg 'docker-create-and-push.sh <tag=tag, message=\"message\" buildarg=\"buildarg\"> '"
    6  - exit
    7  -fi
    8  - 
    9  -for ARGUMENT in "$@"
    10  -do
    11  - KEY=$(echo $ARGUMENT | cut -f1 -d=)
    12  - KEY_LENGTH=${#KEY}
    13  - VALUE="${ARGUMENT:$KEY_LENGTH+1}"
    14  - export "$KEY"="$VALUE"
    15  -done
    16  - 
    17  -if test -n "${tag+x}"; then
    18  - echo "tag is set"
    19  -else
    20  - SCRIPT_PATH=$(dirname $(dirname $(dirname $(readlink -f "$0"))))
    21  - tag=`docker run -it -v ${SCRIPT_PATH}:/data --workdir /data quay.io/pantheon-public/autotag:latest -n`
    22  - echo "Autotagging with new version: ${tag}"
    23  -fi
    24  - 
    25  -if test -n "${buildarg+x}"; then
    26  - echo "buildarg is set"
    27  -else
    28  - buildarg="argBasedPassword='this is on your command line'"
    29  - echo "setting buildarg to ${buildarg}"
    30  -fi
    31  -echo "Version tag: $tag"
    32  -echo "tag message: $message"
    33  -echo "buildarg supplied: $buildarg"
    34  - 
    35  -echo "check if al required binaries are installed"
    36  -source ../../scripts/check-available-commands.sh
    37  - 
    38  -checkCommandsAvailable java git docker mvn gsed
    39  - 
    40  -echo "Start building assets required for container"
    41  - 
    42  -echo "generating challenge 12-data"
    43  -openssl rand -base64 32 | tr -d '\n' > yourkey.txt
    44  -echo "generating challenge 16-data"
    45  -SECENDKEYPART1=$(openssl rand -base64 5 | tr -d '\n')
    46  -SECENDKEYPART2=$(openssl rand -base64 3 | tr -d '\n')
    47  -SECENDKEYPART3=$(openssl rand -base64 2 | tr -d '\n')
    48  -SECENDKEYPART4=$(openssl rand -base64 3 | tr -d '\n')
    49  -echo -n "${SECENDKEYPART1}9${SECENDKEYPART2}6${SECENDKEYPART3}2${SECENDKEYPART4}7" > secondkey.txt
    50  -printf "function secret() { \n var password = \"$SECENDKEYPART1\" + 9 + \"$SECENDKEYPART2\" + 6 + \"$SECENDKEYPART3\" + 2 + \"$SECENDKEYPART4\" + 7;\n return password;\n }\n" > ../../js/index.js
    51  -echo "generating challenge 17"
    52  -rm thirdkey.txt
    53  -openssl rand -base64 32 | tr -d '\n' > thirdkey.txt
    54  -answer=$(<thirdkey.txt)
    55  -answerRegexSafe="$(printf '%s' "$answer" | gsed -e 's/[]\/$*.^|[]/\\&/g' | gsed ':a;N;$!ba;s,\n,\\n,g')"
    56  -gsed -i "s/Placeholder Password, find the real one in the history of the container/$answerRegexSafe/g" ../../src/main/resources/.bash_history
    57  - 
    58  -# preps for #178:
    59  -#echo "Building and publishing to maven central, did you set: a settings.xml file with:"
    60  -#echo "<settings>"
    61  -#echo " <servers>"
    62  -#echo " <server>"
    63  -#echo " <id>ossrh</id>"
    64  -#echo " <username>your-jira-id</username>"
    65  -#echo " <password>your-jira-pwd</password>"
    66  -#echo " </server>"
    67  -#echo " </servers>"
    68  -#echo "</settings>"
    69  - 
    70  -echo "Building and updating pom.xml file so we can use it in our docker"
    71  -cd ../.. && mvn clean && mvn --batch-mode release:update-versions -DdevelopmentVersion=${tag}-SNAPSHOT && mvn install
    72  -git add pom.xml
    73  -cd .github/scripts
    74  -docker buildx create --name mybuilder
    75  -docker buildx use mybuilder
    76  -echo "creating containers"
    77  -docker buildx build --platform linux/amd64,linux/arm64 -t jeroenwillemsen/addo-example:$tag-no-vault --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=without-vault" --push ./../../.
    78  -docker buildx build --platform linux/amd64,linux/arm64 -t jeroenwillemsen/addo-example:$tag-local-vault --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=local-vault" --push ./../../.
    79  -docker buildx build --platform linux/amd64,linux/arm64 -t jeroenwillemsen/addo-example:$tag-k8s-vault --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=kubernetes-vault" --push ./../../.
    80  -docker buildx build --platform linux/amd64,linux/arm64 -t jeroenwillemsen/wrongsecrets:$tag-no-vault --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=without-vault" --push ./../../.
    81  -docker buildx build --platform linux/amd64,linux/arm64 -t jeroenwillemsen/wrongsecrets:$tag-local-vault --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=local-vault" --push ./../../.
    82  -docker buildx build --platform linux/amd64,linux/arm64 -t jeroenwillemsen/wrongsecrets:$tag-k8s-vault --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=kubernetes-vault" --push ./../../.
    83  -cd ../..
    84  -echo "restoring temporal change"
    85  -git restore js/index.js
    86  -git restore src/main/resources/.bash_history
    87  -echo "committing changes and new pom file with version ${tag}"
    88  -git commit -am "Update POM file with new version: ${tag}"
    89  -git push
    90  -echo "tagging version"
    91  -git tag -a $tag -m "${message}"
    92  -git push --tags
    93  - 
    94  -echo "Don't forget to update experiment-bed"
    95  -echo "git checkout experiment-bed && git merge master --no-edit"
    96  -echo "git push"
    97  - 
    98  -#staging (https://arcane-scrubland-42646.herokuapp.com/)
    99  -echo "Completed docker upload for X86, now taking care of heroku, do yourself: update Dockerfile.web, then run 'heroku container:login'"
    100  -echo "then for the test container: 'heroku container:push --recursive --arg argBasedVersion=${tag}heroku --app arcane-scrubland-42646' and 'heroku container:release web --app arcane-scrubland-42646'"
    101  -echo "then for the prd container:'heroku container:push --recursive --arg argBasedVersion=${tag}heroku --arg CANARY_URLS=http://canarytokens.com/feedback/images/traffic/tgy3epux7jm59n0ejb4xv4zg3/submit.aspx,http://canarytokens.com/traffic/cjldn0fsgkz97ufsr92qelimv/post.jsp --app=wrongsecrets' and release 'heroku container:release web --app=wrongsecrets'"
    102  -#want to release? do heroku container:release web --app=wrongsecrets
    103  - 
    104  - 
  • ■ ■ ■ ■ ■ ■
    .github/scripts/docker-create.sh
     1 +#!/bin/bash
     2 + 
     3 +################################################################################
     4 +# Help #
     5 +################################################################################
     6 +Help() {
     7 + # Display Help
     8 + 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"
     9 + echo
     10 + echo "Syntax: docker-create.sh [-h (help)|-t (test)|-p (publish)|-e (herokud)|-f (herokup)|-g (fly)|-n (notag) [tag={tag}|message={message}|buildarg={buildarg}|springProfile={springProfile}]"
     11 + echo "options: (All optional)"
     12 + echo "tag= Write a custom tag that will be added to the container when it is build locally."
     13 + echo "message= Write a message used for the actual tag-message in git"
     14 + echo "buildarg= Write a build argument here that will be used as the answer to challenge 4."
     15 + echo "springProfile= Specify a certain build. Options: without-vault, local-vault, kubernetes-vault"
     16 + echo
     17 +}
     18 + 
     19 +################################################################################
     20 +# Heroku helpers #
     21 +################################################################################
     22 + 
     23 +break_on_tag(){
     24 + if test -n "${tag+x}"; then
     25 + echo "tag is set"
     26 + else
     27 + echo "tag ${tag} was not set properly, aborting"
     28 + exit
     29 + fi
     30 +}
     31 +heroku_check_container() {
     32 + break_on_tag
     33 + echo "validating dockerfile to contain tag "${tag}" (should be part of '$(head -n 1 ../../Dockerfile.web)')"
     34 + if [[ "$(head -n 1 ../../Dockerfile.web)" != *"${tag}"* ]]; then
     35 + echo "tag ${tag} in dockerfile FROM was not set properly, aborting"
     36 + exit
     37 + fi
     38 + echo "Check if all required binaries are installed"
     39 + source ../../scripts/check-available-commands.sh
     40 + checkCommandsAvailable heroku
     41 +}
     42 + 
     43 +Heroku_publish_demo() {
     44 + echo "preparing heroku deployment to demo"
     45 + heroku_check_container
     46 + heroku container:login
     47 + echo "heroku deployment to demo"
     48 + cd ../..
     49 + heroku container:push --recursive --arg argBasedVersion=${tag}heroku --app arcane-scrubland-42646
     50 + heroku container:release web --app arcane-scrubland-42646
     51 + heroku container:push --recursive --arg argBasedVersion=${tag}heroku,CTF_ENABLED=true,HINTS_ENABLED=false --app wrongsecrets-ctf
     52 + heroku container:release web --app wrongsecrets-ctf
     53 + exit
     54 +}
     55 + 
     56 +Heroku_publish_prod(){
     57 + echo "preparing heroku deployment to prod"
     58 + heroku_check_container
     59 + heroku container:login
     60 + echo "heroku deployment to prod"
     61 + cd ../..
     62 + heroku container:push --recursive --arg argBasedVersion=${tag}heroku,CANARY_URLS=http://canarytokens.com/feedback/images/traffic/tgy3epux7jm59n0ejb4xv4zg3/submit.aspx,http://canarytokens.com/traffic/cjldn0fsgkz97ufsr92qelimv/post.jsp --app=wrongsecrets
     63 + heroku container:release web --app=wrongsecrets
     64 + exit
     65 +}
     66 + 
     67 +Fly_publish(){
     68 + echo "Publishing to Fly.io (wrongsecrets.fly.dev)"
     69 + echo "Check if all required binaries are installed"
     70 + source ../../scripts/check-available-commands.sh
     71 + checkCommandsAvailable fly
     72 + break_on_tag
     73 + echo "validating fly.toml to contain tag "${tag}" (should be part of '$(cat ../../fly.toml | grep argBasedVersion)')"
     74 + if [[ "$(cat ../../fly.toml | grep argBasedVersion)" != *"${tag}"* ]]; then
     75 + echo "tag ${tag} in fly.toml not properly set, aborting"
     76 + exit
     77 + fi
     78 + cd ../.. && fly deploy
     79 + exit
     80 +}
     81 + 
     82 +################################################################################
     83 +################################################################################
     84 +# Main program #
     85 +################################################################################
     86 +################################################################################
     87 + 
     88 +# Set options
     89 +#############################
     90 +# Set option to local if no option provided
     91 +script_mode="local"
     92 +# Parse provided options
     93 +while getopts ":htpefgn*" option; do
     94 + case $option in
     95 + h) # display Help
     96 + Help
     97 + exit
     98 + ;;
     99 + t) # set script to test mode
     100 + script_mode="test"
     101 + ;;
     102 + p) # set script to publish mode
     103 + script_mode="publish"
     104 + ;;
     105 + e) # Helper
     106 + script_mode="heroku_d"
     107 + ;;
     108 + f) # Helper
     109 + script_mode="heroku_p"
     110 + ;;
     111 + g) #Helper
     112 + script_mode="fly_p"
     113 + ;;
     114 + n) #notags
     115 + disable_tagging_in_git="true"
     116 + ;;
     117 + \?|\*) # Invalid option
     118 + echo "Error: Invalid option"
     119 + echo
     120 + Help
     121 + exit
     122 + ;;
     123 + esac
     124 +done
     125 + 
     126 +# Check all arguments added to the command
     127 +################################################
     128 +for ARGUMENT in "$@";
     129 +do
     130 + if [[ $ARGUMENT != "-h" && $ARGUMENT != "-t" && $ARGUMENT != "-p" && $ARGUMENT != "-e" && $ARGUMENT != "-f" && $ARGUMENT != "-g" ]]
     131 + then
     132 + KEY=$(echo "$ARGUMENT" | cut -f1 -d=)
     133 + KEY_LENGTH=${#KEY}
     134 + VALUE="${ARGUMENT:$KEY_LENGTH+1}"
     135 + export "$KEY"="$VALUE"
     136 + fi
     137 +done
     138 + 
     139 +if test -n "${tag+x}"; then
     140 + echo "tag is set"
     141 +else
     142 + SCRIPT_PATH=$(dirname $(dirname $(dirname $(readlink -f "$0"))))
     143 + tag="local-test"
     144 + echo "Setting default tag: ${tag}"
     145 +fi
     146 + 
     147 +if test -n "${message+x}"; then
     148 + echo "message is set"
     149 +else
     150 + SCRIPT_PATH=$(dirname $(dirname $(dirname $(readlink -f "$0"))))
     151 + message="local testcontainer build"
     152 + echo "Setting default message: ${message}"
     153 +fi
     154 + 
     155 + 
     156 + 
     157 +if test -n "${buildarg+x}"; then
     158 + echo "buildarg is set"
     159 +else
     160 + buildarg="argBasedPassword='this is on your command line'"
     161 + echo "Setting buildarg to ${buildarg}"
     162 +fi
     163 + 
     164 +if test -n "${springProfile+x}"; then
     165 + if [[ $springProfile == 'local-vault' ]] || [[ $springProfile == 'without-vault' ]] || [[ $springProfile == 'kubernetes-vault' ]]; then
     166 + echo "Setting springProfile to $springProfile"
     167 + else
     168 + echo "Please specify a springProfile of without-vault, local-vault or kubernetes-vault as a springProfile"
     169 + exit 1
     170 + fi
     171 +else
     172 + springProfile="All"
     173 +fi
     174 + 
     175 +echo "Spring profile: $springProfile"
     176 +echo "Version tag: $tag"
     177 +echo "buildarg supplied: $buildarg"
     178 + 
     179 +if test -n "${disable_tagging_in_git+x}"; then
     180 + echo "tagging is disabled"
     181 +else
     182 + disable_tagging_in_git="false"
     183 +fi
     184 + 
     185 +if [[ $script_mode == "heroku_d" ]] ; then
     186 + Heroku_publish_demo
     187 +elif [[ $script_mode == "heroku_p" ]]; then
     188 + Heroku_publish_prod
     189 +elif [[ $script_mode == "fly_p" ]]; then
     190 + Fly_publish
     191 +fi
     192 +
     193 + 
     194 +local_extra_info() {
     195 + if [[ $script_mode == "local" ]] ; then
     196 + echo ""
     197 + echo "⚠️⚠️ This script is running in local mode, with no arguments this script will build your current code and package into a docker container for easy local testing"
     198 + echo "If the container gets built correctly you can run the container with the command: docker run -p 8080:8080 jeroenwillemsen/wrongsecrets:local-test, if there are errors the script should tell you what to do ⚠️⚠️"
     199 + echo ""
     200 + fi
     201 +}
     202 + 
     203 +check_required_install() {
     204 + echo "Check if all required binaries are installed"
     205 + source ../../scripts/check-available-commands.sh
     206 + checkCommandsAvailable java docker mvn git curl
     207 + echo "Checking if gsed or sed is installed"
     208 + if [ -x "$(command -v "gsed")" ] ; then
     209 + echo "gsed is installed"
     210 + findAndReplace="gsed"
     211 + elif [ -x "$(command -v "sed")" ] ; then
     212 + echo "sed is installed"
     213 + findAndReplace="sed"
     214 + else
     215 + echo "Error: sed or gsed is not installed, please install one of these"
     216 + exit 1
     217 + fi
     218 +}
     219 + 
     220 +check_os() {
     221 + echo "Checking for compatible operating system"
     222 + unameOut="$(uname -s)"
     223 + case "${unameOut}" in
     224 + Darwin*)
     225 + echo "OSX detected 🍎"
     226 + ;;
     227 + Linux*)
     228 + echo "Linux detected 🐧"
     229 + ;;
     230 + MINGW64*|CYGWIN)
     231 + echo "Windows detected 🗔"
     232 + ;;
     233 + *)
     234 + echo "🛑🛑 Unknown operating system, this script has only been tests on Windows, Mac OS and Ubuntu. Please be aware there may be some issues 🛑🛑"
     235 + ;;
     236 + esac
     237 +}
     238 + 
     239 +check_correct_launch_location() {
     240 + if [[ "$(pwd)" != *"scripts"* ]]; then
     241 + echo "🛑🛑 Please run the script from the scripts folder as it causes issues with the steps that cannot be expected 🛑🛑"
     242 + echo "🛑🛑 You are currently running it from $(pwd) 🛑🛑"
     243 + exit 1
     244 + fi
     245 +}
     246 + 
     247 +generate_test_data() {
     248 + echo "Generating challenge 12-data"
     249 + openssl rand -base64 32 | tr -d '\n' > yourkey.txt
     250 + echo "Generating challenge 16-data"
     251 + SECENDKEYPART1=$(openssl rand -base64 5 | tr -d '\n')
     252 + SECENDKEYPART2=$(openssl rand -base64 3 | tr -d '\n')
     253 + SECENDKEYPART3=$(openssl rand -base64 2 | tr -d '\n')
     254 + SECENDKEYPART4=$(openssl rand -base64 3 | tr -d '\n')
     255 + echo -n "${SECENDKEYPART1}9${SECENDKEYPART2}6${SECENDKEYPART3}2${SECENDKEYPART4}7" > secondkey.txt
     256 + printf "function secret() { \n var password = \"$SECENDKEYPART1\" + 9 + \"$SECENDKEYPART2\" + 6 + \"$SECENDKEYPART3\" + 2 + \"$SECENDKEYPART4\" + 7;\n return password;\n }\n" > ../../js/index.js
     257 + echo "Generating challenge 17"
     258 + rm thirdkey.txt
     259 + openssl rand -base64 32 | tr -d '\n' > thirdkey.txt
     260 + answer=$(<thirdkey.txt)
     261 + answerRegexSafe="$(printf '%s' "$answer" | $findAndReplace -e 's/[]\/$*.^|[]/\\&/g' | $findAndReplace ':a;N;$!ba;s,\n,\\n,g')"
     262 + $findAndReplace -i "s/Placeholder Password, find the real one in the history of the container/$answerRegexSafe/g" ../../src/main/resources/.bash_history
     263 +}
     264 + 
     265 +build_update_pom() {
     266 + echo "Building and updating pom.xml file so we can use it in our docker"
     267 + cd ../.. && mvn clean && mvn --batch-mode release:update-versions -DdevelopmentVersion=${tag}-SNAPSHOT && mvn install -DskipTests
     268 + cd .github/scripts
     269 + docker buildx create --name mybuilder
     270 + docker buildx use mybuilder
     271 +}
     272 + 
     273 +create_containers() {
     274 + echo "Creating containers"
     275 + if [[ "$script_mode" == "publish" ]]; then
     276 + docker buildx build --platform linux/amd64,linux/arm64 -t jeroenwillemsen/addo-example:$tag-no-vault --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=without-vault" --push ./../../.
     277 + docker buildx build --platform linux/amd64,linux/arm64 -t jeroenwillemsen/addo-example:$tag-local-vault --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=local-vault" --push ./../../.
     278 + docker buildx build --platform linux/amd64,linux/arm64 -t jeroenwillemsen/addo-example:$tag-k8s-vault --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=kubernetes-vault" --push ./../../.
     279 + docker buildx build --platform linux/amd64,linux/arm64 -t jeroenwillemsen/wrongsecrets:$tag-no-vault --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=without-vault" --push ./../../.
     280 + docker buildx build --platform linux/amd64,linux/arm64 -t jeroenwillemsen/wrongsecrets:$tag-local-vault --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=local-vault" --push ./../../.
     281 + docker buildx build --platform linux/amd64,linux/arm64 -t jeroenwillemsen/wrongsecrets:$tag-k8s-vault --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=kubernetes-vault" --push ./../../.
     282 + cd ../..
     283 + docker buildx build --platform linux/amd64,linux/arm64 -t jeroenwillemsen/wrongsecrets-desktop:$tag -f Dockerfile.webdesktop --push .
     284 + elif [[ "$script_mode" == "test" ]]; then
     285 + docker buildx build -t jeroenwillemsen/wrongsecrets:$tag --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=without-vault" --load ./../../.
     286 + else
     287 + if [[ "$springProfile" != "All" ]]; then
     288 + docker buildx build -t jeroenwillemsen/wrongsecrets:$tag-$springProfile --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=$springProfile" --load ./../../.
     289 + else
     290 + docker buildx build -t jeroenwillemsen/wrongsecrets:$tag-no-vault --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=without-vault" --load ./../../.
     291 + docker buildx build -t jeroenwillemsen/wrongsecrets:$tag-local-vault --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=local-vault" --load ./../../.
     292 + docker buildx build -t jeroenwillemsen/wrongsecrets:$tag-k8s-vault --build-arg "$buildarg" --build-arg "PORT=8081" --build-arg "argBasedVersion=$tag" --build-arg "spring_profile=kubernetes-vault" --load ./../../.
     293 + fi
     294 + fi
     295 +}
     296 + 
     297 +restore_temp_change() {
     298 + echo "Restoring temporal change"
     299 + git restore ../../js/index.js
     300 + git restore ../../pom.xml
     301 + git restore ../../src/main/resources/.bash_history
     302 +}
     303 + 
     304 +commit_and_tag() {
     305 + if [[ "$script_mode" == "publish" ]]; then
     306 + echo "committing changes and new pom file with version ${tag}"
     307 + git commit -am "Update POM file with new version: ${tag}"
     308 + git push
     309 + if [[ "$disable_tagging_in_git" == "true" ]]; then
     310 + echo "Skip git tagging"
     311 + else
     312 + echo "tagging version with tag '${tag}' and message '${message}'"
     313 + git tag -a $tag -m "${message}"
     314 + git push --tags
     315 + fi
     316 + else
     317 + return
     318 + fi
     319 +}
     320 + 
     321 +echo_next_steps() {
     322 + if [[ "$script_mode" == "publish" ]]; then
     323 + echo "Don't forget to update experiment-bed"
     324 + echo "git checkout experiment-bed && git merge master --no-edit"
     325 + echo "git push"
     326 + 
     327 + #staging (https://arcane-scrubland-42646.herokuapp.com/)
     328 + echo "Completed docker upload for X86, now taking care of heroku, do yourself: update Dockerfile.web, then run 'heroku container:login'"
     329 + echo "then for the test container: 'heroku container:push --recursive --arg argBasedVersion=${tag}heroku --app arcane-scrubland-42646' and 'heroku container:release web --app arcane-scrubland-42646'"
     330 + echo "then for the prd container:'heroku container:push --recursive --arg argBasedVersion=${tag}heroku --arg CANARY_URLS=http://canarytokens.com/feedback/images/traffic/tgy3epux7jm59n0ejb4xv4zg3/submit.aspx,http://canarytokens.com/traffic/cjldn0fsgkz97ufsr92qelimv/post.jsp --app=wrongsecrets' and release 'heroku container:release web --app=wrongsecrets'"
     331 + #want to release? do heroku container:release web --app=wrongsecrets
     332 + fi
     333 +}
     334 + 
     335 +test() {
     336 + source ../../scripts/assert.sh
     337 + if [[ "$script_mode" == "test" ]]; then
     338 + echo "Running the tests"
     339 + echo "Starting the docker container"
     340 + docker run -d -p 8080:8080 jeroenwillemsen/wrongsecrets:local-test
     341 + until $(curl --output /dev/null --silent --head --fail http://localhost:8080); do
     342 + printf '.'
     343 + sleep 5
     344 + done
     345 + response=$(curl localhost:8080)
     346 + assert_contain "$response" "Wondering what a secret is?"
     347 + if [ "$?" == 0 ]; then
     348 + log_success "The container test completed successfully"
     349 + else
     350 + log_failure "The container test has failed, this means that when we built your changes and ran a basic sanity test on the homepage it failed. Please build the container locally and double check the container is running correctly."
     351 + fi
     352 + echo "Testing complete"
     353 + else
     354 + return
     355 + fi
     356 +}
     357 + 
     358 +local_extra_info
     359 +check_correct_launch_location
     360 +check_os
     361 +check_required_install
     362 +generate_test_data
     363 +build_update_pom
     364 +create_containers
     365 +restore_temp_change
     366 +commit_and_tag
     367 +echo_next_steps
     368 +test
     369 + 
  • ■ ■ ■ ■ ■ ■
    .github/workflows/container_test.yml
     1 +# This is a basic workflow to help you get started with Actions
     2 + 
     3 +name: Docker container test
     4 + 
     5 +# Controls when the workflow will run
     6 +on:
     7 + # Triggers the workflow on push or pull request events but only for the master branch
     8 + push:
     9 + 
     10 + # Allows you to run this workflow manually from the Actions tab
     11 + workflow_dispatch:
     12 + 
     13 +# A workflow run is made up of one or more jobs that can run sequentially or in parallel
     14 +jobs:
     15 + test:
     16 + name: Container test
     17 + runs-on: ubuntu-latest
     18 + # Steps represent a sequence of tasks that will be executed as part of the job
     19 + steps:
     20 + - name: Setup Maven Action
     21 + uses: "s4u/[email protected]"
     22 + with:
     23 + java-version: 18
     24 + maven-version: 3.8.5
     25 + - uses: actions/checkout@v3
     26 + - name: Navigate to test script and run
     27 + run: cd .github/scripts && bash docker-create.sh -t
     28 + 
     29 + 
  • ■ ■ ■ ■ ■ ■
    .github/workflows/minikube-vault-test.yml
    skipped 17 lines
    18 18   - uses: actions/checkout@v3
    19 19   - uses: innovationnorway/setup-vault@v1
    20 20   with:
    21  - version: '~1.9'
     21 + version: '>1.9'
    22 22   - name: Start minikube
    23 23   uses: medyagh/setup-minikube@master
    24 24   with:
    skipped 1 lines
    26 26   driver: docker
    27 27   kubernetes-version: v1.22.5
    28 28   - name: Setup helm
    29  - uses: azure/setup-helm@v3.0
     29 + uses: azure/setup-helm@v3.3
    30 30   id: install
    31 31   - name: test script
    32 32   run: |
    skipped 2 lines
  • ■ ■ ■ ■ ■
    Dockerfile.web
    1  -FROM jeroenwillemsen/wrongsecrets:1.4.6-no-vault
     1 +FROM jeroenwillemsen/wrongsecrets:1.5.2-no-vault
    2 2   
    3  -ARG argBasedVersion="1.4.6"
     3 +ARG argBasedVersion="1.5.2"
    4 4  ARG CANARY_URLS="http://canarytokens.com/terms/about/s7cfbdakys13246ewd8ivuvku/post.jsp,http://canarytokens.com/terms/about/y0all60b627gzp19ahqh7rl6j/post.jsp"
     5 +ARG CTF_ENABLED=false
     6 +ARG HINTS_ENABLED=true
     7 +#ONLY OVERRIDE THE ARGS BELOW WHEN YOU ARE SETTING UP A CTF!
     8 +ARG CTF_KEY=TRwzkRJnHOTckssAeyJbysWgP!Qc2T
     9 +ARG CHALLENGE_5_VALUE=if_you_see_this_please_use_k8s
     10 +ARG CHALLENGE_6_VALUE=if_you_see_this_please_use_k8s
     11 +ARG CHALLENGE_7_VALUE=if_you_see_this_please_use_K8S_and_Vault
     12 +ARG CHALLENGE_9_VALUE=if_you_see_this_please_use_AWS_Setup
     13 +ARG CHALLENGE_10_VALUE=if_you_see_this_please_use
     14 +ARG CHALLENGE_11_VALUE=if_you_see_this_please_use
    5 15  ENV APP_VERSION=$argBasedVersion
    6 16  ENV K8S_ENV=Heroku(Docker)
    7 17  ENV canarytokenURLs=$CANARY_URLS
     18 +ENV ctf_enabled=$CTF_ENABLED
     19 +ENV ctf_key=$CTF_KEY
     20 +ENV hints_enabled=$HINTS_ENABLED
    8 21  ENV challengedockermtpath="/var/helpers"
    9 22  ENV keepasspath="/var/helpers/alibabacreds.kdbx"
     23 +ENV SPECIAL_K8S_SECRET=$CHALLENGE_5_VALUE
     24 +ENV SPECIAL_SPECIAL_K8S_SECRET=$CHALLENGE_6_VALUE
     25 +ENV vaultpassword=$CHALLENGE_7_VALUE
     26 +ENV default_aws_value_challenge_9=$CHALLENGE_9_VALUE
     27 +ENV default_aws_value_challenge_10=$CHALLENGE_10_VALUE
     28 +ENV default_aws_value_challenge_11=$CHALLENGE_11_VALUE
    10 29  COPY .github/scripts/ /var/helpers
    11 30  COPY src/test/resources/alibabacreds.kdbx /var/helpers
    12 31  CMD java -Xms128m -Xmx128m -Xss512k -jar -Dserver.port=$PORT -XX:MaxRAMPercentage=75 -XX:MinRAMPercentage=25 -Dspring.profiles.active=without-vault application.jar
    skipped 1 lines
  • ■ ■ ■ ■ ■ ■
    Dockerfile.webdesktop
     1 +FROM lscr.io/linuxserver/webtop:latest
     2 + 
     3 +RUN \
     4 + echo "**** install packages ****" && \
     5 + apk add --no-cache keepassxc radare2 && \
     6 + echo "**** cleanup ****" && \
     7 + rm -rf \
     8 + /tmp/*
     9 + 
     10 +RUN mkdir /home/wrongsecrets
     11 +COPY src/main/resources/executables/ /home/wrongsecrets/
     12 +COPY src/test/resources/alibabacreds.kdbx /var/tmp/helpers
     13 + 
  • ■ ■ ■ ■ ■
    README.md
    skipped 1 lines
    2 2   
    3 3  # OWASP WrongSecrets [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Want%20to%20dive%20into%20secrets%20management%20and%20do%20some%20hunting?%20try%20this&url=https://github.com/commjoen/wrongsecrets&hashtags=secretsmanagement,secrets,hunting,p0wnableapp,OWASP,WrongSecrets)
    4 4   
    5  -[![Java checkstyle and testing](https://github.com/commjoen/wrongsecrets/actions/workflows/main.yml/badge.svg)](https://github.com/commjoen/wrongsecrets/actions/workflows/main.yml) [![Terraform FMT](https://github.com/commjoen/wrongsecrets/actions/workflows/terraform.yml/badge.svg)](https://github.com/commjoen/wrongsecrets/actions/workflows/terraform.yml) [![Test minikube script (k8s)](https://github.com/commjoen/wrongsecrets/actions/workflows/minikube-k8s-test.yml/badge.svg)](https://github.com/commjoen/wrongsecrets/actions/workflows/minikube-k8s-test.yml) [![Test minikube script (k8s&vault)](https://github.com/commjoen/wrongsecrets/actions/workflows/minikube-vault-test.yml/badge.svg)](https://github.com/commjoen/wrongsecrets/actions/workflows/minikube-vault-test.yml) [![OWASP Lab Project](https://img.shields.io/badge/OWASP-lab%20project-48A646.svg)](https://owasp.org/projects/)[![Discussions](https://img.shields.io/github/discussions/commjoen/wrongsecrets)](https://github.com/commjoen/wrongsecrets/discussions)
     5 +[![Java checkstyle and testing](https://github.com/commjoen/wrongsecrets/actions/workflows/main.yml/badge.svg)](https://github.com/commjoen/wrongsecrets/actions/workflows/main.yml) [![Terraform FMT](https://github.com/commjoen/wrongsecrets/actions/workflows/terraform.yml/badge.svg)](https://github.com/commjoen/wrongsecrets/actions/workflows/terraform.yml) [![Test minikube script (k8s)](https://github.com/commjoen/wrongsecrets/actions/workflows/minikube-k8s-test.yml/badge.svg)](https://github.com/commjoen/wrongsecrets/actions/workflows/minikube-k8s-test.yml) [![Test minikube script (k8s&vault)](https://github.com/commjoen/wrongsecrets/actions/workflows/minikube-vault-test.yml/badge.svg)](https://github.com/commjoen/wrongsecrets/actions/workflows/minikube-vault-test.yml) [![Docker container test](https://github.com/commjoen/wrongsecrets/actions/workflows/container_test.yml/badge.svg)](https://github.com/commjoen/wrongsecrets/actions/workflows/container_test.yml)
     6 +[![OWASP Lab Project](https://img.shields.io/badge/OWASP-lab%20project-48A646.svg)](https://owasp.org/projects/)
     7 +[![Discussions](https://img.shields.io/github/discussions/commjoen/wrongsecrets)](https://github.com/commjoen/wrongsecrets/discussions)
    6 8   
    7 9  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.
    8 10   
    9  -Can you solve all the 21 challenges?
     11 +Can you solve all the 23 challenges?
    10 12  ![screenshot.png](screenshot.png)
    11 13   
    12 14  ## Support
    skipped 8 lines
    21 23   
    22 24  ## Basic docker exercises
    23 25   
    24  -_Can be used for challenges 1-4, 8, 12-21_
     26 +_Can be used for challenges 1-4, 8, 12-23_
    25 27   
    26 28  For the basic docker exercises you currently require:
    27 29   
    skipped 3 lines
    31 33  You can install it by doing:
    32 34   
    33 35  ```bash
    34  -docker run -p 8080:8080 jeroenwillemsen/wrongsecrets:1.4.6-no-vault
     36 +docker run -p 8080:8080 jeroenwillemsen/wrongsecrets:1.5.2-no-vault
    35 37  ```
    36 38   
    37 39  Now you can try to find the secrets by means of solving the challenge offered at:
    skipped 13 lines
    51 53  - [localhost:8080/challenge/19](http://localhost:8080/challenge/19)
    52 54  - [localhost:8080/challenge/20](http://localhost:8080/challenge/20)
    53 55  - [localhost:8080/challenge/21](http://localhost:8080/challenge/21)
     56 +- [localhost:8080/challenge/22](http://localhost:8080/challenge/22)
     57 +- [localhost:8080/challenge/23](http://localhost:8080/challenge/23)
    54 58   
    55 59  Note that these challenges are still very basic, and so are their explanations. Feel free to file a PR to make them look better ;-).
    56 60   
    skipped 8 lines
    65 69   
    66 70  [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)
    67 71   
     72 +### Running on Fly.io
     73 + 
     74 +You can test them out at [https://wrongsecrets.fly.dev](https://wrongsecrets.fly.dev) as well! Please understand that we run on a free-tier instance, we cannot give any guarantees. Please do not fuzz and/or try to bring it down: you would be spoiling it for others that want to testdrive it.
     75 + 
    68 76  ## Basic K8s exercise
    69 77   
    70  -_Can be used for challenges 1-6, 8, 12-21_
     78 +_Can be used for challenges 1-6, 8, 12-23_
    71 79   
    72 80  ### Minikube based
    73 81   
    skipped 40 lines
    114 122   
    115 123  ## Vault exercises with minikube
    116 124   
    117  -_Can be used for challenges 1-8, 12-21_
     125 +_Can be used for challenges 1-8, 12-23_
    118 126  Make sure you have the following installed:
    119 127   
    120 128  - minikube with docker (or comment out line 8 and work at your own k8s setup),
    skipped 4 lines
    125 133  - vault [Install from here](https://www.vaultproject.io/downloads),
    126 134  - grep, Cat, and Sed
    127 135   
    128  -Run `./k8s-vault-minkube-start.sh`, when the script is done, then the challenges will wait for you at <http://localhost:8080> . This will allow you to run challenges 1-8, 12-21.
     136 +Run `./k8s-vault-minkube-start.sh`, when the script is done, then the challenges will wait for you at <http://localhost:8080> . This will allow you to run challenges 1-8, 12-22.
    129 137   
    130 138  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.
    131 139   
    132 140  ## Cloud Challenges
    133 141   
    134  -_Can be used for challenges 1-21_
     142 +_Can be used for challenges 1-23_
    135 143   
    136 144  **READ THIS**: Given that the exercises below contain IAM privilege escalation exercises,
    137 145  never run this on an account which is related to your production environment or can influence your account-over-arching resources.
    skipped 13 lines
    151 159  ### Running Challenge15 in your own cloud only
    152 160   
    153 161  When you want to include your own Canarytokens for your cloud-deployment, do the following:
     162 + 
    154 163  1. Fork the project.
    155 164  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.
    156 165  3. Go to [canarytokens.org](https://canarytokens.org/generate) and select `AWS Keys`, in the webHook URL field add `<your-domain-created-at-step1>/canaries/tokencallback`.
    skipped 31 lines
    188 197  - [Ruben Kruiver @RubenAtBinx](https://github.com/RubenAtBinx)
    189 198  - [Finn @f3rn0s](https://github.com/f3rn0s)
    190 199  - [Alex Bender @alex-bender](https://github.com/alex-bender)
     200 +- [Rick M @kingthorin](https://github.com/kingthorin)
    191 201   
    192 202  Testers:
    193 203   
    skipped 21 lines
    215 225  Want to know if your tool detects everything? We will keep track of the embedded secrets in [this issue](https://github.com/commjoen/wrongsecrets/issues/201) and have a [branch](https://github.com/commjoen/wrongsecrets/tree/experiment-bed) in which we put additional secrets for your tool to detect.
    216 226  The branch will contain a Docker container generation script using which you can eventually test your container secret scanning.
    217 227   
     228 +## CTF
     229 + 
     230 +### CTFD Support
     231 + 
     232 +NOTE: CTFD support is experimental, and now works based on the [Juiceshop CTF CLI](https://github.com/juice-shop/juice-shop-ctf).
     233 +NOTE-II: https://wrongsecrets-ctf.herokuapp.com is based on a free heroku instance, which takes time to warm up. Initial creation of the zip file for CTFD requires you to visit [https://wrongsecrets-ctf.herokuapp.com/api/Challenges](https://wrongsecrets-ctf.herokuapp.com/api/Challenges) once before executing the steps below.
     234 + 
     235 +Follow the following steps:
     236 + 
     237 +```shell
     238 + npm install -g juice-shop-ctf-cli
     239 + juice-shop-ctf #choose ctfd and https://wrongsecrets-ctf.herokuapp.com as domain. No trailing slash! The key is 'TRwzkRJnHOTckssAeyJbysWgP!Qc2T', feel free to enable hints. We do not support snippets or links/urls to code or hints.
     240 + docker run -p 8001:8000 -it ctfd/ctfd:3.4.3
     241 +```
     242 + 
     243 +Now visit the CTFD instance at [http://localhost:8001](http://localhost:8001) and setup your CTF. Then use the administrative backup function to import the zipfile you created with the juice-shop-ctf command.
     244 +Game on using [https://wrongsecrets-ctf.herokuapp.com](https://wrongsecrets-ctf.herokuapp.com) !
     245 +Want to setup your own? You can! Watch out for people finding your key though, so secure it properly: make sure the running container with the actual ctf-key is not exposed to the audience, similar to our heroku container.
     246 + 
     247 +## FBCTF Support (Experimental!)
     248 + 
     249 +NOTE: FBCTF support is experimental.
     250 + 
     251 +follow the same step as with CTFD, only now choose fbctfd and as a url for the countrymapping choose `https://raw.githubusercontent.com/commjoen/wrongsecrets/79a982558016c8ce70948a8106f9a2ee5b5b9eea/config/fbctf.yml`. Then follow [https://github.com/facebookarchive/fbctf/wiki/Quick-Setup-Guide](https://github.com/facebookarchive/fbctf/wiki/Quick-Setup-Guide) to run the FBCTF.
     252 + 
     253 + 
     254 + 
    218 255  ## Notes on development
    219 256   
    220 257  For development on local machine use the `local` profile `./mvnw spring-boot:run -Dspring-boot.run.profiles=local`
    skipped 54 lines
    275 312   
    276 313  If you want to move existing cloud challenges to another cloud: extend Challenge classes in the `org.owasp.wrongsecrets.challenges.cloud` package and make sure you add the required Terraform in a folder with the separate cloud identified. Make sure that the environment is added to `org.owasp.wrongsecrets.RuntimeEnvironment`. Collaborate with the others at the project to get your container running so you can test at the cloud account.
    277 314   
     315 +### Local testing
     316 + 
     317 +If you have made some changes to the codebase or added a new challenge and would like to see exactly how the container will look after merge for testing, we have a script that makes this very easy. Follow the steps below:
     318 + 
     319 +1. Ensure you have bash installed and open.
     320 +2. Navigate to .github/scripts.
     321 +3. Run the docker-create script `bash docker-create.sh`.
     322 +4. Follow any instructions given, you made need to install/change packages.
     323 +5. Run the newly created container `docker run -p 8080:8080 jeroenwillemsen/wrongsecrets:local-test`
     324 + 
     325 +## Want to play, but are not allowed to install the tools?
     326 + 
     327 +If you want to play the challenges, but cannot install tools like keepass, Radare, etc. But are allowed to run Docker containers, try the following:
     328 + 
     329 +```shell
     330 +docker run -d \
     331 + --name=webtop \
     332 + --security-opt seccomp=unconfined `#optional` \
     333 + -e PUID=1000 \
     334 + -e PGID=1000 \
     335 + -e TZ=Europe/London \
     336 + -e SUBFOLDER=/ `#optional` \
     337 + -e KEYBOARD=en-us-qwerty `#optional` \
     338 + -p 3000:3000 \
     339 + -v /var/run/docker.sock:/var/run/docker.sock `#optional` \
     340 + --shm-size="1gb" `#optional` \
     341 + --restart unless-stopped \
     342 + jeroenwillemsen/wrongsecrets-desktop:<VERSION HERE>
     343 +```
     344 + 
     345 +Note: be careful with trying to deploy the `jeroenwillemsen/wrongsecrets-desktop` container to Heroku ;-).
    278 346   
    279 347  ## Further reading on secrets management
    280 348   
    skipped 8 lines
  • ■ ■ ■ ■
    aws/k8s/secret-challenge-vault-deployment.yml
    skipped 36 lines
    37 37   volumeAttributes:
    38 38   secretProviderClass: "wrongsecrets-aws-secretsmanager"
    39 39   containers:
    40  - - image: jeroenwillemsen/wrongsecrets:1.4.6-k8s-vault
     40 + - image: jeroenwillemsen/wrongsecrets:1.5.2-k8s-vault
    41 41   imagePullPolicy: IfNotPresent
    42 42   ports:
    43 43   - containerPort: 8080
    skipped 31 lines
  • ■ ■ ■ ■
    azure/k8s/secret-challenge-vault-deployment.yml.tpl
    skipped 34 lines
    35 35   volumeAttributes:
    36 36   secretProviderClass: "azure-wrongsecrets-vault"
    37 37   containers:
    38  - - image: jeroenwillemsen/wrongsecrets:1.4.6-k8s-vault
     38 + - image: jeroenwillemsen/wrongsecrets:1.5.2-k8s-vault
    39 39   imagePullPolicy: IfNotPresent
    40 40   ports:
    41 41   - containerPort: 8080
    skipped 36 lines
  • ■ ■ ■ ■ ■ ■
    config/.lycheeignore
    skipped 2 lines
    3 3   
    4 4  # This is used as an example when creating a pull request
    5 5  https://github.com/Your_Github_Handle.*
     6 +https://wrongsecrets-ctf.herokuapp.com/api/Challenges
     7 + 
  • ■ ■ ■ ■ ■ ■
    config/fbctf.yml
     1 +ctf:
     2 + showFlagsInNotifications: true
     3 + showCountryDetailsInNotifications: both
     4 + countryMapping:
     5 + challenge1:
     6 + name: Canada
     7 + code: CA
     8 + challenge2:
     9 + name: Austria
     10 + code: AT
     11 + challenge3:
     12 + name: Israel
     13 + code: IL
     14 + challenge4:
     15 + name: Russian Federation
     16 + code: RU
     17 + challenge5:
     18 + name: Honduras
     19 + code: HN
     20 + challenge6:
     21 + name: Guatemala
     22 + code: GT
     23 + challenge7:
     24 + name: Germany
     25 + code: DE
     26 + challenge8:
     27 + name: Uruguay
     28 + code: UY
     29 + challenge9:
     30 + name: Myanmar
     31 + code: MM
     32 + challenge10:
     33 + name: Costa Rica
     34 + code: CR
     35 + challenge11:
     36 + name: Paraguay
     37 + code: PY
     38 + challenge12:
     39 + name: Slovakia
     40 + code: SK
     41 + challenge13:
     42 + name: Madagascar
     43 + code: MG
     44 + challenge14:
     45 + name: Belize
     46 + code: BZ
     47 + challenge15:
     48 + name: Korea (Democratic People's Republic of)
     49 + code: KP
     50 + challenge16:
     51 + name: Korea
     52 + code: KR
     53 + challenge17:
     54 + name: Belarus
     55 + code: BY
     56 + challenge18:
     57 + name: Bolivia
     58 + code: BO
     59 + challenge19:
     60 + name: Switzerland
     61 + code: CH
     62 + challenge20:
     63 + name: Peru
     64 + code: PE
     65 + challenge21:
     66 + name: Ukraine
     67 + code: UA
     68 + challenge22:
     69 + name: United States of America
     70 + code: US
     71 + challenge23:
     72 + name: Turkey
     73 + code: TR
     74 + challenge24:
     75 + name: Suriname
     76 + code: SR
     77 + challenge25:
     78 + name: Colombia
     79 + code: CO
     80 + challenge26:
     81 + name: Poland
     82 + code: PL
     83 + challenge27:
     84 + name: Ecuador
     85 + code: EC
     86 + challenge28:
     87 + name: Sri Lanka
     88 + code: LK
     89 + challenge29:
     90 + name: Eritrea
     91 + code: ER
     92 + challenge30:
     93 + name: Panama
     94 + code: PA
     95 + 
  • ■ ■ ■ ■ ■ ■
    ctf-instructions.md
     1 +# CTF Instructions
     2 + 
     3 +So you want to play a CTF with WrongSecrets? This is the place to read up all about it.
     4 +Our CTF setup makes use of the [Juice Shop CTF CLI extension](https://github.com/juice-shop/juice-shop-ctf), which you
     5 +can read all about at [here](https://pwning.owasp-juice.shop/part1/ctf.html).
     6 + 
     7 +The difference between Juiceshop and WrongSecrets, is that WrongSecrets is more of a secrets-hunter game. Thiss means
     8 +that your contestants will try to find the CTF key soon after a few challenges. That is why we should separate out the
     9 +actual container for which the CTF scores are generated, from the container where the challenges live in.
     10 + 
     11 +You can see this practice already here in our repository: Our standard [Dockerfile](/Dockerfile) does not contain any
     12 +CTF entries, our Heroku [Dockerfile.web](/Dockerfile.web) does contain them.
     13 +So make sure you host your actual scoring Dockerfile.web at a place where your contestants cannot enter the container (
     14 +image) in order to extract the CTF key.
     15 + 
     16 +## Setting up CTFs
     17 + 
     18 +There are 3 flavors of CTF to be setup: Docker/Heroku, K8S, Cloud based.
     19 + 
     20 +### Docker or Heroku CTF
     21 + 
     22 +When doing a Docker or Heroku based CTF, you can follow
     23 +the [instructions in the readme](https://github.com/commjoen/wrongsecrets#ctfd-support).
     24 +If you want to use your own CTF key, you can build a container with the following
     25 +arguments `CTF_ENABLED=true,HINTS_ENABLED=false,CTF_KEY=<YOURNEWKEYHERE>`. Just make sure you provide the same key
     26 +to `juice-shop-ctf` when you run it.
     27 + 
     28 +Want to make it a little more exciting? Override the Dockerfile with your preferred values, so that copying from online
     29 +hosted solutions no longer works!
     30 + 
     31 +### K8s based CTF
     32 + 
     33 +TODO as #https://github.com/commjoen/wrongsecrets/issues/372
     34 + 
     35 +### Cloud based CTF
     36 + 
     37 +TODO as #https://github.com/commjoen/wrongsecrets/issues/372
     38 + 
     39 + 
  • ■ ■ ■ ■ ■ ■
    fly.toml
     1 +# fly.toml file generated for wrongsecrets on 2022-08-27T22:42:28+02:00
     2 + 
     3 +app = "wrongsecrets"
     4 +kill_signal = "SIGINT"
     5 +kill_timeout = 5
     6 +processes = []
     7 + 
     8 +[build]
     9 + dockerfile = "Dockerfile"
     10 + 
     11 +[build.args]
     12 + argBasedVersion="1.5.2"
     13 + spring_profile="without-vault"
     14 + argBasedEnv="Fly(Docker)"
     15 + 
     16 +[env]
     17 + K8S_ENV="Fly(Docker)"
     18 + 
     19 +[experimental]
     20 + allowed_public_ports = []
     21 + auto_rollback = true
     22 + CMD = "java -Xms128m -Xmx128m -Xss512k -jar -XX:MaxRAMPercentage=75 -XX:MinRAMPercentage=25 -Dspring.profiles.active=without-vault application.jar"
     23 + 
     24 +[[services]]
     25 + http_checks = []
     26 + internal_port = 8080
     27 + processes = ["app"]
     28 + protocol = "tcp"
     29 + script_checks = []
     30 + [services.concurrency]
     31 + hard_limit = 25
     32 + soft_limit = 20
     33 + type = "connections"
     34 + 
     35 + [[services.ports]]
     36 + force_https = true
     37 + handlers = ["http"]
     38 + port = 80
     39 + 
     40 + [[services.ports]]
     41 + handlers = ["tls", "http"]
     42 + port = 443
     43 + 
     44 + [[services.tcp_checks]]
     45 + grace_period = "1s"
     46 + interval = "15s"
     47 + restart_limit = 0
     48 + timeout = "2s"
     49 + 
  • ■ ■ ■ ■
    gcp/k8s/secret-challenge-vault-deployment.yml.tpl
    skipped 36 lines
    37 37   volumeAttributes:
    38 38   secretProviderClass: "wrongsecrets-gcp-secretsmanager"
    39 39   containers:
    40  - - image: jeroenwillemsen/wrongsecrets:1.4.6-k8s-vault
     40 + - image: jeroenwillemsen/wrongsecrets:1.5.2-k8s-vault
    41 41   imagePullPolicy: IfNotPresent
    42 42   ports:
    43 43   - containerPort: 8080
    skipped 33 lines
  • ■ ■ ■ ■ ■
    gcp/k8s-vault-gcp-start.sh
    skipped 10 lines
    11 11  echo "This script is based on the steps defined in https://learn.hashicorp.com/tutorials/vault/kubernetes-minikube. Vault is awesome!"
    12 12   
    13 13  export GCP_PROJECT=$(gcloud config list --format 'value(core.project)' 2>/dev/null)
     14 +export USE_GKE_GCLOUD_AUTH_PLUGIN=True
    14 15   
    15 16  kubectl get configmaps | grep 'secrets-file' &>/dev/null
    16 17  if [ $? == 0 ]; then
    skipped 57 lines
  • ■ ■ ■ ■ ■
    gcp/versions.tf
    1 1  terraform {
    2  - required_version = ">= 0.14.0"
     2 + required_version = ">= 1.0.0"
    3 3   
    4 4   required_providers {
    5 5   google = {
    skipped 7 lines
    13 13   local = ">= 1.4"
    14 14   random = ">= 2.1"
    15 15   kubernetes = ">= 1.11"
    16  - shell = {
    17  - source = "scottwinkler/shell"
    18  - version = "1.7.7"
    19  - }
    20 16   }
    21 17   
    22 18   # For shared state:
    skipped 8 lines
  • ■ ■ ■ ■ ■
    heroku.yml
    1 1  build:
    2 2   docker:
    3 3   web: Dockerfile.web
     4 + 
  • ■ ■ ■ ■ ■
    js/package-lock.json
    skipped 8 lines
    9 9   "version": "1.3.1",
    10 10   "license": "MIT",
    11 11   "devDependencies": {
    12  - "javascript-obfuscator": "^3.1.0"
     12 + "javascript-obfuscator": "^4.0.0"
    13 13   }
    14 14   },
    15 15   "node_modules/@javascript-obfuscator/escodegen": {
    skipped 21 lines
    37 37   "dev": true,
    38 38   "engines": {
    39 39   "node": ">=4.0"
    40  - }
    41  - },
    42  - "node_modules/@nuxtjs/opencollective": {
    43  - "version": "0.3.2",
    44  - "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz",
    45  - "integrity": "sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==",
    46  - "dev": true,
    47  - "dependencies": {
    48  - "chalk": "^4.1.0",
    49  - "consola": "^2.15.0",
    50  - "node-fetch": "^2.6.1"
    51  - },
    52  - "bin": {
    53  - "opencollective": "bin/opencollective.js"
    54  - },
    55  - "engines": {
    56  - "node": ">=8.0.0",
    57  - "npm": ">=5.0.0"
    58 40   }
    59 41   },
    60 42   "node_modules/@types/minimatch": {
    skipped 196 lines
    257 239   "version": "0.0.1",
    258 240   "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
    259 241   "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
    260  - "dev": true
    261  - },
    262  - "node_modules/consola": {
    263  - "version": "2.15.3",
    264  - "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz",
    265  - "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==",
    266 242   "dev": true
    267 243   },
    268 244   "node_modules/crypt": {
    skipped 504 lines
    773 749   }
    774 750   },
    775 751   "node_modules/javascript-obfuscator": {
    776  - "version": "3.1.0",
    777  - "resolved": "https://registry.npmjs.org/javascript-obfuscator/-/javascript-obfuscator-3.1.0.tgz",
    778  - "integrity": "sha512-rbv0lx4Zj4LQIE720eqbrh+9PmvUXJWXoQQC5bxqaQfV6WwBZTJlhNnfZFyEHPtdJpmgKfUgW0BB5lera2Msmw==",
     752 + "version": "4.0.0",
     753 + "resolved": "https://registry.npmjs.org/javascript-obfuscator/-/javascript-obfuscator-4.0.0.tgz",
     754 + "integrity": "sha512-vS/8w/9eKISzwXNLd+OLMCCwjD+dFMdOlCDOo919iR/MWdBs+7u1ybpwRoWOmODToPQKVYw5GasvZoIiPs5nPw==",
    779 755   "dev": true,
    780 756   "hasInstallScript": true,
    781 757   "dependencies": {
    782 758   "@javascript-obfuscator/escodegen": "2.3.0",
    783 759   "@javascript-obfuscator/estraverse": "5.4.0",
    784  - "@nuxtjs/opencollective": "0.3.2",
    785 760   "acorn": "8.7.0",
    786 761   "assert": "2.0.0",
    787 762   "chalk": "4.1.2",
    skipped 8 lines
    796 771   "md5": "2.3.0",
    797 772   "mkdirp": "1.0.4",
    798 773   "multimatch": "5.0.0",
     774 + "opencollective-postinstall": "2.0.3",
    799 775   "process": "0.11.10",
    800 776   "reflect-metadata": "0.1.13",
    801 777   "source-map-support": "0.5.21",
    skipped 94 lines
    896 872   "url": "https://github.com/sponsors/sindresorhus"
    897 873   }
    898 874   },
    899  - "node_modules/node-fetch": {
    900  - "version": "2.6.7",
    901  - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
    902  - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
    903  - "dev": true,
    904  - "dependencies": {
    905  - "whatwg-url": "^5.0.0"
    906  - },
    907  - "engines": {
    908  - "node": "4.x || >=6.0.0"
    909  - },
    910  - "peerDependencies": {
    911  - "encoding": "^0.1.0"
    912  - },
    913  - "peerDependenciesMeta": {
    914  - "encoding": {
    915  - "optional": true
    916  - }
    917  - }
    918  - },
    919 875   "node_modules/object-inspect": {
    920 876   "version": "1.12.0",
    921 877   "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
    skipped 44 lines
    966 922   },
    967 923   "funding": {
    968 924   "url": "https://github.com/sponsors/ljharb"
     925 + }
     926 + },
     927 + "node_modules/opencollective-postinstall": {
     928 + "version": "2.0.3",
     929 + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
     930 + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
     931 + "dev": true,
     932 + "bin": {
     933 + "opencollective-postinstall": "index.js"
    969 934   }
    970 935   },
    971 936   "node_modules/optionator": {
    skipped 143 lines
    1115 1080   "node": ">=8"
    1116 1081   }
    1117 1082   },
    1118  - "node_modules/tr46": {
    1119  - "version": "0.0.3",
    1120  - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
    1121  - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
    1122  - "dev": true
    1123  - },
    1124 1083   "node_modules/tslib": {
    1125 1084   "version": "2.3.1",
    1126 1085   "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
    skipped 50 lines
    1177 1136   "node": ">= 0.10"
    1178 1137   }
    1179 1138   },
    1180  - "node_modules/webidl-conversions": {
    1181  - "version": "3.0.1",
    1182  - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
    1183  - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
    1184  - "dev": true
    1185  - },
    1186  - "node_modules/whatwg-url": {
    1187  - "version": "5.0.0",
    1188  - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
    1189  - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
    1190  - "dev": true,
    1191  - "dependencies": {
    1192  - "tr46": "~0.0.3",
    1193  - "webidl-conversions": "^3.0.0"
    1194  - }
    1195  - },
    1196 1139   "node_modules/which-boxed-primitive": {
    1197 1140   "version": "1.0.2",
    1198 1141   "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
    skipped 59 lines
    1258 1201   "resolved": "https://registry.npmjs.org/@javascript-obfuscator/estraverse/-/estraverse-5.4.0.tgz",
    1259 1202   "integrity": "sha512-CZFX7UZVN9VopGbjTx4UXaXsi9ewoM1buL0kY7j1ftYdSs7p2spv9opxFjHlQ/QGTgh4UqufYqJJ0WKLml7b6w==",
    1260 1203   "dev": true
    1261  - },
    1262  - "@nuxtjs/opencollective": {
    1263  - "version": "0.3.2",
    1264  - "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz",
    1265  - "integrity": "sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==",
    1266  - "dev": true,
    1267  - "requires": {
    1268  - "chalk": "^4.1.0",
    1269  - "consola": "^2.15.0",
    1270  - "node-fetch": "^2.6.1"
    1271  - }
    1272 1204   },
    1273 1205   "@types/minimatch": {
    1274 1206   "version": "3.0.5",
    skipped 147 lines
    1422 1354   "version": "0.0.1",
    1423 1355   "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
    1424 1356   "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
    1425  - "dev": true
    1426  - },
    1427  - "consola": {
    1428  - "version": "2.15.3",
    1429  - "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz",
    1430  - "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==",
    1431 1357   "dev": true
    1432 1358   },
    1433 1359   "crypt": {
    skipped 350 lines
    1784 1710   }
    1785 1711   },
    1786 1712   "javascript-obfuscator": {
    1787  - "version": "3.1.0",
    1788  - "resolved": "https://registry.npmjs.org/javascript-obfuscator/-/javascript-obfuscator-3.1.0.tgz",
    1789  - "integrity": "sha512-rbv0lx4Zj4LQIE720eqbrh+9PmvUXJWXoQQC5bxqaQfV6WwBZTJlhNnfZFyEHPtdJpmgKfUgW0BB5lera2Msmw==",
     1713 + "version": "4.0.0",
     1714 + "resolved": "https://registry.npmjs.org/javascript-obfuscator/-/javascript-obfuscator-4.0.0.tgz",
     1715 + "integrity": "sha512-vS/8w/9eKISzwXNLd+OLMCCwjD+dFMdOlCDOo919iR/MWdBs+7u1ybpwRoWOmODToPQKVYw5GasvZoIiPs5nPw==",
    1790 1716   "dev": true,
    1791 1717   "requires": {
    1792 1718   "@javascript-obfuscator/escodegen": "2.3.0",
    1793 1719   "@javascript-obfuscator/estraverse": "5.4.0",
    1794  - "@nuxtjs/opencollective": "0.3.2",
    1795 1720   "acorn": "8.7.0",
    1796 1721   "assert": "2.0.0",
    1797 1722   "chalk": "4.1.2",
    skipped 8 lines
    1806 1731   "md5": "2.3.0",
    1807 1732   "mkdirp": "1.0.4",
    1808 1733   "multimatch": "5.0.0",
     1734 + "opencollective-postinstall": "2.0.3",
    1809 1735   "process": "0.11.10",
    1810 1736   "reflect-metadata": "0.1.13",
    1811 1737   "source-map-support": "0.5.21",
    skipped 63 lines
    1875 1801   "minimatch": "^3.0.4"
    1876 1802   }
    1877 1803   },
    1878  - "node-fetch": {
    1879  - "version": "2.6.7",
    1880  - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
    1881  - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
    1882  - "dev": true,
    1883  - "requires": {
    1884  - "whatwg-url": "^5.0.0"
    1885  - }
    1886  - },
    1887 1804   "object-inspect": {
    1888 1805   "version": "1.12.0",
    1889 1806   "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
    skipped 27 lines
    1917 1834   "has-symbols": "^1.0.1",
    1918 1835   "object-keys": "^1.1.1"
    1919 1836   }
     1837 + },
     1838 + "opencollective-postinstall": {
     1839 + "version": "2.0.3",
     1840 + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
     1841 + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
     1842 + "dev": true
    1920 1843   },
    1921 1844   "optionator": {
    1922 1845   "version": "0.8.3",
    skipped 104 lines
    2027 1950   "has-flag": "^4.0.0"
    2028 1951   }
    2029 1952   },
    2030  - "tr46": {
    2031  - "version": "0.0.3",
    2032  - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
    2033  - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
    2034  - "dev": true
    2035  - },
    2036 1953   "tslib": {
    2037 1954   "version": "2.3.1",
    2038 1955   "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
    skipped 40 lines
    2079 1996   "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz",
    2080 1997   "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==",
    2081 1998   "dev": true
    2082  - },
    2083  - "webidl-conversions": {
    2084  - "version": "3.0.1",
    2085  - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
    2086  - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
    2087  - "dev": true
    2088  - },
    2089  - "whatwg-url": {
    2090  - "version": "5.0.0",
    2091  - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
    2092  - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
    2093  - "dev": true,
    2094  - "requires": {
    2095  - "tr46": "~0.0.3",
    2096  - "webidl-conversions": "^3.0.0"
    2097  - }
    2098 1999   },
    2099 2000   "which-boxed-primitive": {
    2100 2001   "version": "1.0.2",
    skipped 34 lines
  • ■ ■ ■ ■
    js/package.json
    skipped 11 lines
    12 12   "author": "",
    13 13   "license": "MIT",
    14 14   "devDependencies": {
    15  - "javascript-obfuscator": "^3.1.0"
     15 + "javascript-obfuscator": "^4.0.0"
    16 16   }
    17 17  }
    18 18   
  • ■ ■ ■ ■
    k8s/secret-challenge-deployment.yml
    skipped 27 lines
    28 28   runAsGroup: 2000
    29 29   fsGroup: 2000
    30 30   containers:
    31  - - image: jeroenwillemsen/wrongsecrets:1.4.6-no-vault
     31 + - image: jeroenwillemsen/wrongsecrets:1.5.2-no-vault
    32 32   imagePullPolicy: IfNotPresent
    33 33   ports:
    34 34   - containerPort: 8080
    skipped 23 lines
  • ■ ■ ■ ■
    k8s/secret-challenge-vault-deployment.yml
    skipped 29 lines
    30 30   runAsNonRoot: true
    31 31   serviceAccountName: vault
    32 32   containers:
    33  - - image: jeroenwillemsen/wrongsecrets:1.4.6-k8s-vault
     33 + - image: jeroenwillemsen/wrongsecrets:1.5.2-k8s-vault
    34 34   imagePullPolicy: IfNotPresent
    35 35   ports:
    36 36   - containerPort: 8080
    skipped 27 lines
  • ■ ■ ■ ■ ■ ■
    pom.xml
    skipped 3 lines
    4 4   <parent>
    5 5   <groupId>org.springframework.boot</groupId>
    6 6   <artifactId>spring-boot-starter-parent</artifactId>
    7  - <version>2.7.1</version>
     7 + <version>2.7.2</version>
    8 8   <relativePath /> <!-- lookup parent from repository -->
    9 9   </parent>
    10 10   <groupId>org.owasp</groupId>
    11 11   <artifactId>wrongsecrets</artifactId>
    12  - <version>1.4.6-SNAPSHOT</version>
     12 + <version>1.5.2-SNAPSHOT</version>
    13 13   <name>OWASP WrongSecrets</name>
    14 14   <description>Examples with how to not use secrets</description>
    15 15   <url>https://owasp.org/www-project-wrongsecrets/</url>
    skipped 27 lines
    43 43   <maven.compiler.target>18</maven.compiler.target>
    44 44   <spring.cloud-version>2021.0.3</spring.cloud-version>
    45 45   <lombok.version>1.18.24</lombok.version>
    46  - <aws.sdk.version>2.17.223</aws.sdk.version>
    47  - <asciidoctorj.version>2.5.4</asciidoctorj.version>
     46 + <aws.sdk.version>2.17.244</aws.sdk.version>
     47 + <asciidoctorj.version>2.5.5</asciidoctorj.version>
    48 48   <jruby.version>9.3.6.0</jruby.version>
    49 49   <bootstrap.version>5.1.3</bootstrap.version>
    50 50   <github.button.version>2.14.1</github.button.version>
    51  - <gcp.sdk.version>25.4.0</gcp.sdk.version>
     51 + <gcp.sdk.version>26.0.0</gcp.sdk.version>
    52 52   <thymeleaf-spring5.version>3.0.15.RELEASE</thymeleaf-spring5.version>
    53 53   <thymeleaf.version>3.0.15.RELEASE</thymeleaf.version>
    54 54   <thymeleaf.layout>3.1.0</thymeleaf.layout>
    55 55   <asciidoctor.maven.plugin.version>2.2.2</asciidoctor.maven.plugin.version>
    56  - <azure.keyvault.version>4.4.3</azure.keyvault.version>
     56 + <azure.keyvault.version>4.4.4</azure.keyvault.version>
    57 57   <azure.identity.version>1.5.3</azure.identity.version>
    58 58   <azure.keyvault.spring.version>2.3.5</azure.keyvault.spring.version>
    59 59   <spring.security.version>5.7.2</spring.security.version>
    60  - <cyclonedx.core.version>7.1.5</cyclonedx.core.version>
     60 + <cyclonedx.core.version>7.2.0</cyclonedx.core.version>
    61 61   <KeePassJava2.version>2.1.4</KeePassJava2.version>
    62 62   <system-stubs-jupiter.version>2.0.1</system-stubs-jupiter.version>
    63 63   <dependency-check-maven.version>7.0.4</dependency-check-maven.version>
    skipped 31 lines
    95 95   <version>${spring.security.version}</version>
    96 96   </dependency>
    97 97   <dependency>
     98 + <groupId>org.springframework.security</groupId>
     99 + <artifactId>spring-security-test</artifactId>
     100 + <version>${spring.security.version}</version>
     101 + <scope>test</scope>
     102 + </dependency>
     103 + <dependency>
    98 104   <groupId>org.springframework.boot</groupId>
    99 105   <artifactId>spring-boot-starter-web</artifactId>
    100 106   </dependency>
    skipped 98 lines
    199 205   <version>${dependency-check-maven.version}</version>
    200 206   <type>maven-plugin</type>
    201 207   </dependency>
     208 + <dependency>
     209 + <groupId>com.h2database</groupId>
     210 + <artifactId>h2</artifactId>
     211 + <version>2.1.214</version>
     212 + </dependency>
    202 213   </dependencies>
    203 214   
    204 215   <dependencyManagement>
    skipped 52 lines
    257 268   <dependency>
    258 269   <groupId>com.puppycrawl.tools</groupId>
    259 270   <artifactId>checkstyle</artifactId>
    260  - <version>10.3.1</version>
     271 + <version>10.3.2</version>
    261 272   </dependency>
    262 273   </dependencies>
    263 274   </plugin>
    skipped 64 lines
    328 339   <plugin>
    329 340   <groupId>org.cyclonedx</groupId>
    330 341   <artifactId>cyclonedx-maven-plugin</artifactId>
    331  - <version>2.7.0</version>
     342 + <version>2.7.1</version>
    332 343   <executions>
    333 344   <execution>
    334 345   <phase>install</phase>
    skipped 61 lines
    396 407   <plugin>
    397 408   <groupId>org.codehaus.mojo</groupId>
    398 409   <artifactId>exec-maven-plugin</artifactId>
    399  - <version>3.0.0</version>
     410 + <version>3.1.0</version>
    400 411   <executions>
    401 412   <execution>
    402 413   <phase>generate-resources</phase>
    skipped 29 lines
  • ■ ■ ■ ■ ■ ■
    scripts/assert.sh
     1 +#!/usr/bin/env bash
     2 + 
     3 +#####################################################################
     4 +##
     5 +## title: Assert Extension
     6 +##
     7 +## description:
     8 +## Assert extension of shell (bash, ...)
     9 +## with the common assert functions
     10 +## Function list based on:
     11 +## http://junit.sourceforge.net/javadoc/org/junit/Assert.html
     12 +## Log methods : inspired by
     13 +## - https://natelandau.com/bash-scripting-utilities/
     14 +## author: Mark Torok
     15 +##
     16 +## date: 07. Dec. 2016
     17 +##
     18 +## license: MIT
     19 +##
     20 +#####################################################################
     21 + 
     22 +if command -v tput &>/dev/null && tty -s; then
     23 + RED=$(tput setaf 1)
     24 + GREEN=$(tput setaf 2)
     25 + MAGENTA=$(tput setaf 5)
     26 + NORMAL=$(tput sgr0)
     27 + BOLD=$(tput bold)
     28 +else
     29 + RED=$(echo -en "\e[31m")
     30 + GREEN=$(echo -en "\e[32m")
     31 + MAGENTA=$(echo -en "\e[35m")
     32 + NORMAL=$(echo -en "\e[00m")
     33 + BOLD=$(echo -en "\e[01m")
     34 +fi
     35 + 
     36 +log_header() {
     37 + printf "\n${BOLD}${MAGENTA}========== %s ==========${NORMAL}\n" "$@" >&2
     38 +}
     39 + 
     40 +log_success() {
     41 + printf "${GREEN}✔ %s${NORMAL}\n" "$@" >&2
     42 +}
     43 + 
     44 +log_failure() {
     45 + printf "${RED}✖ %s${NORMAL}\n" "$@" >&2
     46 +}
     47 + 
     48 + 
     49 +assert_eq() {
     50 + local expected="$1"
     51 + local actual="$2"
     52 + local msg="${3-}"
     53 + 
     54 + if [ "$expected" == "$actual" ]; then
     55 + return 0
     56 + else
     57 + [ "${#msg}" -gt 0 ] && log_failure "$expected == $actual :: $msg" || true
     58 + return 1
     59 + fi
     60 +}
     61 + 
     62 +assert_not_eq() {
     63 + local expected="$1"
     64 + local actual="$2"
     65 + local msg="${3-}"
     66 + 
     67 + if [ ! "$expected" == "$actual" ]; then
     68 + return 0
     69 + else
     70 + [ "${#msg}" -gt 0 ] && log_failure "$expected != $actual :: $msg" || true
     71 + return 1
     72 + fi
     73 +}
     74 + 
     75 +assert_true() {
     76 + local actual="$1"
     77 + local msg="${2-}"
     78 + 
     79 + assert_eq true "$actual" "$msg"
     80 + return "$?"
     81 +}
     82 + 
     83 +assert_false() {
     84 + local actual="$1"
     85 + local msg="${2-}"
     86 + 
     87 + assert_eq false "$actual" "$msg"
     88 + return "$?"
     89 +}
     90 + 
     91 +assert_array_eq() {
     92 + 
     93 + declare -a expected=("${!1-}")
     94 + # echo "AAE ${expected[@]}"
     95 + 
     96 + declare -a actual=("${!2}")
     97 + # echo "AAE ${actual[@]}"
     98 + 
     99 + local msg="${3-}"
     100 + 
     101 + local return_code=0
     102 + if [ ! "${#expected[@]}" == "${#actual[@]}" ]; then
     103 + return_code=1
     104 + fi
     105 + 
     106 + local i
     107 + for (( i=1; i < ${#expected[@]} + 1; i+=1 )); do
     108 + if [ ! "${expected[$i-1]}" == "${actual[$i-1]}" ]; then
     109 + return_code=1
     110 + break
     111 + fi
     112 + done
     113 + 
     114 + if [ "$return_code" == 1 ]; then
     115 + [ "${#msg}" -gt 0 ] && log_failure "(${expected[*]}) != (${actual[*]}) :: $msg" || true
     116 + fi
     117 + 
     118 + return "$return_code"
     119 +}
     120 + 
     121 +assert_array_not_eq() {
     122 + 
     123 + declare -a expected=("${!1-}")
     124 + declare -a actual=("${!2}")
     125 + 
     126 + local msg="${3-}"
     127 + 
     128 + local return_code=1
     129 + if [ ! "${#expected[@]}" == "${#actual[@]}" ]; then
     130 + return_code=0
     131 + fi
     132 + 
     133 + local i
     134 + for (( i=1; i < ${#expected[@]} + 1; i+=1 )); do
     135 + if [ ! "${expected[$i-1]}" == "${actual[$i-1]}" ]; then
     136 + return_code=0
     137 + break
     138 + fi
     139 + done
     140 + 
     141 + if [ "$return_code" == 1 ]; then
     142 + [ "${#msg}" -gt 0 ] && log_failure "(${expected[*]}) == (${actual[*]}) :: $msg" || true
     143 + fi
     144 + 
     145 + return "$return_code"
     146 +}
     147 + 
     148 +assert_empty() {
     149 + local actual=$1
     150 + local msg="${2-}"
     151 + 
     152 + assert_eq "" "$actual" "$msg"
     153 + return "$?"
     154 +}
     155 + 
     156 +assert_not_empty() {
     157 + local actual=$1
     158 + local msg="${2-}"
     159 + 
     160 + assert_not_eq "" "$actual" "$msg"
     161 + return "$?"
     162 +}
     163 + 
     164 +assert_contain() {
     165 + local haystack="$1"
     166 + local needle="${2-}"
     167 + local msg="${3-}"
     168 + 
     169 + if [ -z "${needle:+x}" ]; then
     170 + return 0;
     171 + fi
     172 + 
     173 + if [ -z "${haystack##*$needle*}" ]; then
     174 + return 0
     175 + else
     176 + [ "${#msg}" -gt 0 ] && log_failure "$haystack doesn't contain $needle :: $msg" || true
     177 + return 1
     178 + fi
     179 +}
     180 + 
     181 +assert_not_contain() {
     182 + local haystack="$1"
     183 + local needle="${2-}"
     184 + local msg="${3-}"
     185 + 
     186 + if [ -z "${needle:+x}" ]; then
     187 + return 0;
     188 + fi
     189 + 
     190 + if [ "${haystack##*$needle*}" ]; then
     191 + return 0
     192 + else
     193 + [ "${#msg}" -gt 0 ] && log_failure "$haystack contains $needle :: $msg" || true
     194 + return 1
     195 + fi
     196 +}
     197 + 
     198 +assert_gt() {
     199 + local first="$1"
     200 + local second="$2"
     201 + local msg="${3-}"
     202 + 
     203 + if [[ "$first" -gt "$second" ]]; then
     204 + return 0
     205 + else
     206 + [ "${#msg}" -gt 0 ] && log_failure "$first > $second :: $msg" || true
     207 + return 1
     208 + fi
     209 +}
     210 + 
     211 +assert_ge() {
     212 + local first="$1"
     213 + local second="$2"
     214 + local msg="${3-}"
     215 + 
     216 + if [[ "$first" -ge "$second" ]]; then
     217 + return 0
     218 + else
     219 + [ "${#msg}" -gt 0 ] && log_failure "$first >= $second :: $msg" || true
     220 + return 1
     221 + fi
     222 +}
     223 + 
     224 +assert_lt() {
     225 + local first="$1"
     226 + local second="$2"
     227 + local msg="${3-}"
     228 + 
     229 + if [[ "$first" -lt "$second" ]]; then
     230 + return 0
     231 + else
     232 + [ "${#msg}" -gt 0 ] && log_failure "$first < $second :: $msg" || true
     233 + return 1
     234 + fi
     235 +}
     236 + 
     237 +assert_le() {
     238 + local first="$1"
     239 + local second="$2"
     240 + local msg="${3-}"
     241 + 
     242 + if [[ "$first" -le "$second" ]]; then
     243 + return 0
     244 + else
     245 + [ "${#msg}" -gt 0 ] && log_failure "$first <= $second :: $msg" || true
     246 + return 1
     247 + fi
     248 +}
     249 + 
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/InMemoryScoreCard.java
    skipped 6 lines
    7 7   
    8 8  public class InMemoryScoreCard implements ScoreCard {
    9 9   
    10  - private final int maxPoints;
     10 + private final int maxNumberOfChallenges;
    11 11   private final Set<Challenge> solvedChallenges = new HashSet<>();
    12 12   
    13 13   public InMemoryScoreCard(int numberOfChallenge) {
    14  - maxPoints = numberOfChallenge * 50;
     14 + maxNumberOfChallenges = numberOfChallenge;
    15 15   }
    16 16   
    17 17   @Override
    skipped 8 lines
    26 26   
    27 27   @Override
    28 28   public float getProgress() {
    29  - return (100 / (float) maxPoints) * getTotalReceivedPoints();
     29 + return ((float) 100 / maxNumberOfChallenges) * solvedChallenges.size();
    30 30   }
    31 31   
    32 32   @Override
    33 33   public int getTotalReceivedPoints() {
    34  - return solvedChallenges.size() * 50;
     34 + return solvedChallenges.stream().map(challenge -> challenge.difficulty() * (100 + (challenge.difficulty() - 1) * 25)).reduce(0, Integer::sum);
    35 35   }
    36 36   
    37 37   @Override
    skipped 5 lines
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/RuntimeEnvironment.java
    skipped 10 lines
    11 11  import java.util.List;
    12 12  import java.util.Map;
    13 13   
    14  -import static org.owasp.wrongsecrets.RuntimeEnvironment.Environment.AWS;
    15  -import static org.owasp.wrongsecrets.RuntimeEnvironment.Environment.DOCKER;
    16  -import static org.owasp.wrongsecrets.RuntimeEnvironment.Environment.GCP;
    17  -import static org.owasp.wrongsecrets.RuntimeEnvironment.Environment.AZURE;
    18  -import static org.owasp.wrongsecrets.RuntimeEnvironment.Environment.K8S;
    19  -import static org.owasp.wrongsecrets.RuntimeEnvironment.Environment.VAULT;
    20  -import static org.owasp.wrongsecrets.RuntimeEnvironment.Environment.HEROKU_DOCKER;
     14 +import static org.owasp.wrongsecrets.RuntimeEnvironment.Environment.*;
    21 15   
    22 16  @Component
    23 17  public class RuntimeEnvironment {
    24 18   
     19 + @Value("${ctf_enabled}")
     20 + private boolean ctfModeEnabled;
     21 + 
     22 + @Value("${SPECIAL_K8S_SECRET}")
     23 + private String challenge5Value; //used to determine if k8s/vault challenges are overriden;
     24 + 
     25 + @Value("${default_aws_value_challenge_9}")
     26 + private String defaultChallenge9Value; //used to determine if the cloud challenge values are overriden
     27 + 
    25 28   private static final Map<Environment, List<Environment>> envToOverlappingEnvs = Map.of(
    26  - HEROKU_DOCKER, List.of(DOCKER, HEROKU_DOCKER),
    27  - DOCKER, List.of(DOCKER, HEROKU_DOCKER),
    28  - GCP, List.of(DOCKER, K8S, VAULT),
    29  - AWS, List.of(DOCKER, K8S, VAULT),
    30  - AZURE, List.of(DOCKER, K8S, VAULT),
    31  - VAULT, List.of(DOCKER, K8S),
    32  - K8S, List.of(DOCKER)
     29 + FLY_DOCKER, List.of(DOCKER, FLY_DOCKER),
     30 + HEROKU_DOCKER, List.of(DOCKER, HEROKU_DOCKER),
     31 + DOCKER, List.of(DOCKER, HEROKU_DOCKER),
     32 + GCP, List.of(DOCKER, K8S, VAULT),
     33 + AWS, List.of(DOCKER, K8S, VAULT),
     34 + AZURE, List.of(DOCKER, K8S, VAULT),
     35 + VAULT, List.of(DOCKER, K8S),
     36 + K8S, List.of(DOCKER)
    33 37   );
    34 38   
    35 39   public enum Environment {
    36  - DOCKER("Docker"), HEROKU_DOCKER("Heroku(Docker)"), GCP("gcp"), AWS("aws"), AZURE("azure"), VAULT("k8s-with-vault"), K8S("k8s");
     40 + DOCKER("Docker"), HEROKU_DOCKER("Heroku(Docker)"), FLY_DOCKER("Fly(Docker)"), GCP("gcp"), AWS("aws"), AZURE("azure"), VAULT("k8s-with-vault"), K8S("k8s");
    37 41   
    38 42   private final String id;
    39 43   
    skipped 9 lines
    49 53   @Getter
    50 54   private final Environment runtimeEnvironment;
    51 55   
     56 + private boolean isK8sUnlockedInCTFMode() {
     57 + String defaultValueChallenge5 = "if_you_see_this_please_use_k8s";
     58 + return ctfModeEnabled && !challenge5Value.equals(defaultValueChallenge5);
     59 + }
     60 + 
     61 + private boolean isCloudUnlockedInCTFMode() {
     62 + String defaultValueAWSValue = "if_you_see_this_please_use_AWS_Setup";
     63 + return ctfModeEnabled && !defaultChallenge9Value.equals(defaultValueAWSValue);
     64 + }
     65 + 
    52 66   @Autowired
    53 67   public RuntimeEnvironment(@Value("${K8S_ENV}") String currentRuntimeEnvironment) {
    54 68   this.runtimeEnvironment = Environment.fromId(currentRuntimeEnvironment);
    skipped 4 lines
    59 73   }
    60 74   
    61 75   public boolean canRun(Challenge challenge) {
     76 + if (isCloudUnlockedInCTFMode()) {
     77 + return true;
     78 + }
     79 + if (isK8sUnlockedInCTFMode()) {
     80 + return challenge.supportedRuntimeEnvironments().contains(runtimeEnvironment)
     81 + || challenge.supportedRuntimeEnvironments().contains(DOCKER) || challenge.supportedRuntimeEnvironments().contains(K8S)
     82 + || challenge.supportedRuntimeEnvironments().contains(VAULT);
     83 + }
    62 84   return challenge.supportedRuntimeEnvironments().contains(runtimeEnvironment)
    63  - || !Collections.disjoint(envToOverlappingEnvs.get(runtimeEnvironment), challenge.supportedRuntimeEnvironments());
     85 + || !Collections.disjoint(envToOverlappingEnvs.get(runtimeEnvironment), challenge.supportedRuntimeEnvironments());
    64 86   }
    65 87   
    66 88  }
    skipped 1 lines
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/StatsController.java
    skipped 14 lines
    15 15   @Autowired
    16 16   private SessionConfiguration sessionConfiguration;
    17 17   
     18 + @Value("${hints_enabled}")
     19 + private boolean hintsEnabled;
     20 + @Value("${reason_enabled}")
     21 + private boolean reasonEnabled;
     22 + @Value("${ctf_enabled}")
     23 + private boolean ctfModeEnabled;
     24 + 
    18 25   @Value("${canarytokenURLs}")
    19 26   private String[] canaryTokenURLs;
    20 27   
    skipped 3 lines
    24 31   model.addAttribute("sessioncounter", sessionConfiguration.getCounter());
    25 32   model.addAttribute("lastCanaryToken", canaryCounter.getLastToken());
    26 33   model.addAttribute("canarytokenURLs", canaryTokenURLs);
     34 + model.addAttribute("hintsEnabled", hintsEnabled);
     35 + model.addAttribute("reasonEnabled", reasonEnabled);
     36 + model.addAttribute("ctfModeEnabled",ctfModeEnabled);
    27 37   return "stats";
    28 38   }
    29 39  }
    skipped 1 lines
  • ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/WrongSecretsApplication.java
    skipped 18 lines
    19 19   @Bean
    20 20   @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
    21 21   public InMemoryScoreCard scoreCard() {
    22  - return new InMemoryScoreCard(11);
     22 + return new InMemoryScoreCard(22);
    23 23   }
    24 24   
    25 25   
    skipped 3 lines
  • ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/canaries/CanariesController.java
    skipped 29 lines
    30 30   }
    31 31   log.info("Canarytoken called, with manage_url {}", canaryToken.getManageUrl());
    32 32   log.info("Total number of canary callback calls: {}", canaryCounter.getTotalCount());
    33  - /*
    34  - todo:
    35  - - follow 3 of baeldung.com/spring-server-sent-events, but make sure you register the emitter per connection
    36  - - and in a map lookup which emiter you can use for the given connection to send the event.
    37  - */
    38 33   return new ResponseEntity<>("all good", HttpStatus.ACCEPTED);
    39 34   }
    40 35   
    skipped 8 lines
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/Challenge.java
    skipped 18 lines
    19 19   
    20 20   public abstract List<Environment> supportedRuntimeEnvironments();
    21 21   
     22 + public abstract int difficulty();
     23 + 
     24 + public abstract String getTech();
     25 + 
    22 26   public boolean solved(String answer) {
    23 27   var correctAnswer = answerCorrect(answer);
    24 28   if (correctAnswer) {
    skipped 18 lines
  • ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/ChallengeUI.java
    skipped 37 lines
    38 38   return challengeNumber;
    39 39   }
    40 40   
     41 + public String getTech() {
     42 + return challenge.getTech();
     43 + }
     44 + 
    41 45   public Integer next() {
    42 46   return challengeNumber + 1;
    43 47   }
    skipped 21 lines
    65 69   .collect(Collectors.joining());
    66 70   }
    67 71   
     72 + public int difficulty() {
     73 + return challenge.difficulty();
     74 + }
     75 + 
    68 76   public boolean isChallengeEnabled() {
    69 77   return runtimeEnvironment.canRun(challenge);
    70 78   }
    71 79   
    72 80   public static List<ChallengeUI> toUI(List<Challenge> challenges, RuntimeEnvironment environment) {
    73 81   return challenges.stream()
    74  - .sorted(Comparator.comparingInt(challenge -> Integer.parseInt(challenge.getClass().getSimpleName().replace("Challenge",""))))
     82 + .sorted(Comparator.comparingInt(challenge -> Integer.parseInt(challenge.getClass().getSimpleName().replace("Challenge", ""))))
    75 83   .map(challenge -> new ChallengeUI(challenge, challenges.indexOf(challenge) + 1, environment))
    76 84   .toList();
    77 85   }
    skipped 2 lines
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/ChallengesAPIController.java
     1 +package org.owasp.wrongsecrets.challenges;
     2 + 
     3 +import com.nimbusds.jose.shaded.json.JSONArray;
     4 +import com.nimbusds.jose.shaded.json.JSONObject;
     5 +import lombok.extern.slf4j.Slf4j;
     6 +import org.asciidoctor.Asciidoctor;
     7 +import org.asciidoctor.OptionsBuilder;
     8 +import org.owasp.wrongsecrets.RuntimeEnvironment;
     9 +import org.owasp.wrongsecrets.ScoreCard;
     10 +import org.owasp.wrongsecrets.asciidoc.TemplateGenerator;
     11 +import org.springframework.http.MediaType;
     12 +import org.springframework.util.ResourceUtils;
     13 +import org.springframework.web.bind.annotation.GetMapping;
     14 +import org.springframework.web.bind.annotation.RestController;
     15 + 
     16 +import java.io.BufferedReader;
     17 +import java.io.IOException;
     18 +import java.io.InputStreamReader;
     19 +import java.util.ArrayList;
     20 +import java.util.List;
     21 + 
     22 +@Slf4j
     23 +@RestController
     24 +public class ChallengesAPIController {
     25 + 
     26 + private final ScoreCard scoreCard;
     27 + private final List<ChallengeUI> challenges;
     28 + 
     29 + private final List<String> descriptions;
     30 + 
     31 + private final List<String> hints;
     32 + 
     33 + private final TemplateGenerator templateGenerator;
     34 + 
     35 + private final RuntimeEnvironment runtimeEnvironment;
     36 + 
     37 + public ChallengesAPIController(ScoreCard scoreCard, List<ChallengeUI> challenges, RuntimeEnvironment runtimeEnvironment, TemplateGenerator templateGenerator) {
     38 + this.scoreCard = scoreCard;
     39 + this.challenges = challenges;
     40 + this.descriptions = new ArrayList<>();
     41 + this.hints = new ArrayList<>();
     42 + this.runtimeEnvironment = runtimeEnvironment;
     43 + this.templateGenerator = templateGenerator;
     44 + }
     45 + 
     46 + 
     47 + @GetMapping(value = {"/api/Challenges", "/api/challenges"}, produces = MediaType.APPLICATION_JSON_VALUE)
     48 + public String getChallenges() {
     49 + if (descriptions.size() == 0) {
     50 + initiaLizeHintsAndDescriptions();
     51 + }
     52 + JSONObject json = new JSONObject();
     53 + JSONArray jsonArray = new JSONArray();
     54 + for (int i = 0; i < challenges.size(); i++) {
     55 + JSONObject jsonChallenge = new JSONObject();
     56 + jsonChallenge.put("id", i);
     57 + jsonChallenge.put("name", challenges.get(i).getName());
     58 + jsonChallenge.put("key", challenges.get(i).getExplanation());
     59 + jsonChallenge.put("category", getCategory(challenges.get(i)) + " - " + challenges.get(i).getTech());
     60 + jsonChallenge.put("description", descriptions.get(i));
     61 + jsonChallenge.put("hint", hints.get(i));
     62 + jsonChallenge.put("solved", scoreCard.getChallengeCompleted(challenges.get(i).getChallenge()));
     63 + jsonChallenge.put("disabledEnv", getDisabledEnv(challenges.get(i)));
     64 + jsonChallenge.put("difficulty", challenges.get(i).getChallenge().difficulty());
     65 + jsonArray.add(jsonChallenge);
     66 + }
     67 + json.put("status", "success");
     68 + json.put("data", jsonArray);
     69 + String result = json.toJSONString();
     70 + log.info("returning {}", result);
     71 + return result;
     72 + }
     73 + 
     74 + private String getCategory(ChallengeUI challengeUI) {
     75 + return switch (challengeUI.getChallenge().supportedRuntimeEnvironments().get(0)) {
     76 + case DOCKER, HEROKU_DOCKER, FLY_DOCKER -> "Docker";
     77 + case GCP, AWS, AZURE -> "Cloud";
     78 + case VAULT -> "Vault";
     79 + case K8S -> "Kubernetes";
     80 + };
     81 + }
     82 + 
     83 + private void initiaLizeHintsAndDescriptions() {
     84 + log.info("Initialize hints and descriptions");
     85 + challenges.forEach(challengeUI -> { //note requires mvn install to generate the html files!
     86 + try {
     87 + String hint = templateGenerator.generate("explanations/" + challengeUI.getExplanation() + "_hint");
     88 + hints.add(hint);
     89 + String description = templateGenerator.generate("explanations/" + challengeUI.getExplanation());
     90 + descriptions.add(description);
     91 + } catch (IOException e) {
     92 + String rawHint = extractResource("classpath:explanations/" + challengeUI.getExplanation() + "_hint.adoc");
     93 + String hint = Asciidoctor.Factory.create().convert(rawHint, OptionsBuilder.options().build());
     94 + hints.add(hint);
     95 + String rawDescription = extractResource("classpath:explanations/" + challengeUI.getExplanation() + ".adoc");
     96 + String description = Asciidoctor.Factory.create().convert(rawDescription, OptionsBuilder.options().build());
     97 + descriptions.add(description);
     98 + throw new RuntimeException(e);
     99 + }
     100 + 
     101 + });
     102 + }
     103 + 
     104 + private String extractResource(String resourceName) {
     105 + try {
     106 + var resource = ResourceUtils.getURL(resourceName);
     107 + final StringBuilder resourceStringbuilder = new StringBuilder();
     108 + new BufferedReader(
     109 + new InputStreamReader(resource.openStream())
     110 + ).lines().forEach(s -> {
     111 + resourceStringbuilder.append(s);
     112 + });
     113 + return resourceStringbuilder.toString();
     114 + } catch (IOException e) {
     115 + throw new RuntimeException(e);
     116 + }
     117 + }
     118 + 
     119 + private String getDisabledEnv(ChallengeUI challenge) {
     120 + if (runtimeEnvironment.canRun(challenge.getChallenge())) {
     121 + return runtimeEnvironment.getRuntimeEnvironment().name();
     122 + }
     123 + return null;
     124 + }
     125 + 
     126 +}
     127 + 
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/ChallengesController.java
    1 1  package org.owasp.wrongsecrets.challenges;
    2 2   
     3 +import com.nimbusds.jose.crypto.impl.HMAC;
    3 4  import org.owasp.wrongsecrets.RuntimeEnvironment;
    4 5  import org.owasp.wrongsecrets.ScoreCard;
     6 +import org.spongycastle.crypto.CryptoException;
    5 7  import org.springframework.beans.factory.annotation.Value;
     8 +import org.springframework.security.crypto.codec.Hex;
    6 9  import org.springframework.stereotype.Controller;
    7 10  import org.springframework.ui.Model;
    8 11  import org.springframework.web.bind.annotation.GetMapping;
    skipped 1 lines
    10 13  import org.springframework.web.bind.annotation.PathVariable;
    11 14  import org.springframework.web.bind.annotation.PostMapping;
    12 15   
     16 +import javax.crypto.Mac;
     17 +import javax.crypto.spec.SecretKeySpec;
     18 +import java.nio.charset.StandardCharsets;
     19 +import java.security.InvalidKeyException;
     20 +import java.security.NoSuchAlgorithmException;
    13 21  import java.util.List;
    14 22  import java.util.stream.Collectors;
    15 23   
    skipped 3 lines
    19 27   private final ScoreCard scoreCard;
    20 28   private final List<ChallengeUI> challenges;
    21 29   private final RuntimeEnvironment runtimeEnvironment;
     30 + 
    22 31   @Value("${hints_enabled}")
    23 32   private boolean hintsEnabled;
    24 33   @Value("${reason_enabled}")
    25 34   private boolean reasonEnabled;
    26 35   
     36 + @Value("${ctf_enabled}")
     37 + private boolean ctfModeEnabled;
     38 + 
     39 + @Value("${ctf_key}")
     40 + private String ctfKey;
     41 + 
    27 42   public ChallengesController(ScoreCard scoreCard, List<ChallengeUI> challenges, RuntimeEnvironment runtimeEnvironment) {
    28 43   this.scoreCard = scoreCard;
    29 44   this.challenges = challenges;
    skipped 7 lines
    37 52   
    38 53   @GetMapping("/spoil-{id}")
    39 54   public String spoiler(Model model, @PathVariable Integer id) {
    40  - var challenge = challenges.get(id - 1).getChallenge();
    41  - model.addAttribute("spoiler", challenge.spoiler());
     55 + if (!ctfModeEnabled) {
     56 + var challenge = challenges.get(id - 1).getChallenge();
     57 + model.addAttribute("spoiler", challenge.spoiler());
     58 + } else {
     59 + model.addAttribute("spoiler", new Spoiler("Spoils are disabled in CTF mode"));
     60 + }
    42 61   return "spoil";
    43 62   }
    44 63   
    skipped 33 lines
    78 97   var challenge = challenges.get(id - 1);
    79 98   
    80 99   if (challenge.getChallenge().solved(challengeForm.solution())) {
    81  - model.addAttribute("answerCorrect", "Your answer is correct!");
     100 + if (ctfModeEnabled) {
     101 + String code = generateCode(challenge);
     102 + model.addAttribute("answerCorrect", "Your answer is correct! " + "fill in the following code in CTF scoring: " + code);
     103 + } else {
     104 + model.addAttribute("answerCorrect", "Your answer is correct!");
     105 + }
    82 106   } else {
    83 107   model.addAttribute("answerIncorrect", "Your answer is incorrect, try harder ;-)");
    84 108   }
    skipped 3 lines
    88 112   enrichWithHintsAndReasons(model);
    89 113   fireEnding(model);
    90 114   return "challenge";
     115 + }
     116 + 
     117 + private String generateCode(ChallengeUI challenge) {
     118 + SecretKeySpec secretKeySpec = new SecretKeySpec(ctfKey.getBytes(StandardCharsets.UTF_8), "HmacSHA1");
     119 + try {
     120 + Mac mac = Mac.getInstance("HmacSHA1");
     121 + mac.init(secretKeySpec);
     122 + byte[] result = mac.doFinal(challenge.getName().getBytes(StandardCharsets.UTF_8));
     123 + return new String(Hex.encode(result));
     124 + } catch (NoSuchAlgorithmException | InvalidKeyException e) {
     125 + throw new RuntimeException(e);
     126 + }
    91 127   }
    92 128   
    93 129   private void includeScoringStatus(Model model, Challenge challenge) {
    skipped 39 lines
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/cloud/Challenge10.java
    skipped 26 lines
    27 27   
    28 28   public Challenge10(ScoreCard scoreCard,
    29 29   @Value("${secretmountpath}") String filePath,
    30  - @Value("${default_aws_value}") String awsDefaultValue,
     30 + @Value("${default_aws_value_challenge_10}") String awsDefaultValue,
    31 31   RuntimeEnvironment runtimeEnvironment) {
    32 32   super(scoreCard, runtimeEnvironment);
    33 33   this.awsDefaultValue = awsDefaultValue;
    skipped 21 lines
    55 55   
    56 56   public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
    57 57   return List.of(GCP, AWS, AZURE);
     58 + }
     59 + 
     60 + @Override
     61 + public int difficulty() {
     62 + return 4;
     63 + }
     64 + 
     65 + @Override
     66 + public String getTech() {
     67 + return "CSI-Driver";
    58 68   }
    59 69  }
    60 70   
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/cloud/Challenge11.java
    skipped 45 lines
    46 46   private final String azureVaultUri;
    47 47   private final String azureWrongSecret3;
    48 48   
     49 + private final String ctfValue;
     50 + 
     51 + private final boolean ctfEnabled;
     52 + 
    49 53   public Challenge11(ScoreCard scoreCard,
    50 54   @Value("${AWS_ROLE_ARN}") String awsRoleArn,
    51 55   @Value("${AWS_WEB_IDENTITY_TOKEN_FILE}") String tokenFileLocation,
    skipped 4 lines
    56 60   @Value("${azure.keyvault.uri}") String azureVaultUri,
    57 61   @Value("${wrongsecret-3}") String azureWrongSecret3, // Exclusively auto-wired for Azure
    58 62   @Value("${GCP_PROJECT_ID}") String projectId,
     63 + @Value("${default_aws_value_challenge_11}") String ctfValue,
     64 + @Value("${ctf_enabled}") boolean ctfEnabled,
    59 65   RuntimeEnvironment runtimeEnvironment) {
    60 66   super(scoreCard, runtimeEnvironment);
    61 67   this.awsRoleArn = awsRoleArn;
    skipped 5 lines
    67 73   this.projectId = projectId;
    68 74   this.azureVaultUri = azureVaultUri;
    69 75   this.azureWrongSecret3 = azureWrongSecret3;
     76 + this.ctfValue = ctfValue;
     77 + this.ctfEnabled = ctfEnabled;
    70 78   this.challengeAnswer = getChallenge11Value(runtimeEnvironment);
    71 79   }
    72 80   
    skipped 11 lines
    84 92   return List.of(AWS, GCP, AZURE);
    85 93   }
    86 94   
     95 + @Override
     96 + public int difficulty() {
     97 + return 4;
     98 + }
     99 + 
     100 + @Override
     101 + public String getTech() {
     102 + return "IAM Privilege escalation";
     103 + }
     104 + 
    87 105   private String getChallenge11Value(RuntimeEnvironment runtimeEnvironment) {
    88 106   if (runtimeEnvironment != null && runtimeEnvironment.getRuntimeEnvironment() != null) {
     107 + if (ctfEnabled && ctfValue != awsDefaultValue) {
     108 + return ctfValue;
     109 + }
    89 110   return switch (runtimeEnvironment.getRuntimeEnvironment()) {
    90 111   case AWS -> getAWSChallenge11Value();
    91 112   case GCP -> getGCPChallenge11Value();
    skipped 10 lines
    102 123   try { //based on https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/sts/src/main/java/com/example/sts
    103 124   String webIDentityToken = Files.readString(Paths.get(tokenFileLocation));
    104 125   StsClient stsClient = StsClient.builder()
    105  - .region(Region.of(awsRegion))
    106  - .build();
     126 + .region(Region.of(awsRegion))
     127 + .build();
    107 128   AssumeRoleWithWebIdentityRequest webIdentityRequest = AssumeRoleWithWebIdentityRequest.builder()
    108  - .roleArn(awsRoleArn)
    109  - .roleSessionName("WrongsecretsApp")
    110  - .webIdentityToken(webIDentityToken)
    111  - .build();
     129 + .roleArn(awsRoleArn)
     130 + .roleSessionName("WrongsecretsApp")
     131 + .webIdentityToken(webIDentityToken)
     132 + .build();
    112 133   
    113 134   AssumeRoleWithWebIdentityResponse tokenResponse = stsClient.assumeRoleWithWebIdentity(webIdentityRequest);
    114 135   log.info("The token value is " + tokenResponse.credentials().sessionToken());
    115 136   SsmClient ssmClient = SsmClient.builder()
    116  - .region(Region.of(awsRegion))
    117  - .credentialsProvider(StsAssumeRoleWithWebIdentityCredentialsProvider.builder()
    118  - .stsClient(stsClient)
    119  - .refreshRequest(webIdentityRequest)
    120  - .build())
    121  - .build();
     137 + .region(Region.of(awsRegion))
     138 + .credentialsProvider(StsAssumeRoleWithWebIdentityCredentialsProvider.builder()
     139 + .stsClient(stsClient)
     140 + .refreshRequest(webIdentityRequest)
     141 + .build())
     142 + .build();
    122 143   GetParameterRequest parameterRequest = GetParameterRequest.builder()
    123  - .name("wrongsecretvalue")
    124  - .withDecryption(true)
    125  - .build();
     144 + .name("wrongsecretvalue")
     145 + .withDecryption(true)
     146 + .build();
    126 147   GetParameterResponse parameterResponse = ssmClient.getParameter(parameterRequest);
    127 148   log.info("The parameter value is " + parameterResponse.parameter().value());
    128 149   ssmClient.close();
    skipped 44 lines
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/cloud/Challenge9.java
    skipped 26 lines
    27 27   
    28 28   public Challenge9(ScoreCard scoreCard,
    29 29   @Value("${secretmountpath}") String filePath,
    30  - @Value("${default_aws_value}") String awsDefaultValue,
     30 + @Value("${default_aws_value_challenge_9}") String awsDefaultValue,
    31 31   RuntimeEnvironment runtimeEnvironment) {
    32 32   super(scoreCard, runtimeEnvironment);
    33 33   this.awsDefaultValue = awsDefaultValue;
    skipped 21 lines
    55 55   
    56 56   public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
    57 57   return List.of(GCP, AWS, AZURE);
     58 + }
     59 + 
     60 + @Override
     61 + public int difficulty() {
     62 + return 3;
     63 + }
     64 + 
     65 + @Override
     66 + public String getTech() {
     67 + return "Terraform";
    58 68   }
    59 69  }
    60 70   
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge1.java
    skipped 32 lines
    33 33   public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
    34 34   return List.of(DOCKER);
    35 35   }
     36 + 
     37 + @Override
     38 + public int difficulty() {
     39 + return 1;
     40 + }
     41 + 
     42 + @Override
     43 + public String getTech() {
     44 + return "Git";
     45 + }
    36 46  }
    37 47   
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge12.java
    skipped 41 lines
    42 42   return List.of(RuntimeEnvironment.Environment.DOCKER);
    43 43   }
    44 44   
     45 + @Override
     46 + public int difficulty() {
     47 + return 3;
     48 + }
     49 + 
     50 + @Override
     51 + public String getTech() {
     52 + return "Docker";
     53 + }
     54 + 
    45 55   private String getActualData() {
    46 56   try {
    47 57   return Files.readString(Paths.get(dockerMountPath, "yourkey.txt"));
    skipped 7 lines
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge13.java
    skipped 47 lines
    48 48   return List.of(RuntimeEnvironment.Environment.DOCKER);
    49 49   }
    50 50   
     51 + @Override
     52 + public int difficulty() {
     53 + return 3;
     54 + }
     55 + 
     56 + @Override
     57 + public String getTech() {
     58 + return "CI/CD";
     59 + }
     60 + 
    51 61   private boolean isKeyCorrect(String base64EncodedKey) {
    52 62   if (Strings.isEmpty(base64EncodedKey) || Strings.isEmpty(plainText) || Strings.isEmpty(cipherText)) {
    53 63   log.info("Checking secret with values {}, {}, {}", base64EncodedKey, plainText, cipherText);
    skipped 26 lines
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge14.java
    skipped 53 lines
    54 54   return List.of(RuntimeEnvironment.Environment.DOCKER);
    55 55   }
    56 56   
     57 + @Override
     58 + public int difficulty() {
     59 + return 4;
     60 + }
     61 + 
     62 + @Override
     63 + public String getTech() {
     64 + return "Password manager";
     65 + }
     66 + 
    57 67   private String findAnswer() {
    58 68   if (Strings.isEmpty(keepassxPassword)) {
    59 69   log.info("Checking secret with values {}", keepassxPassword);
    skipped 24 lines
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge15.java
    skipped 48 lines
    49 49   return List.of(RuntimeEnvironment.Environment.DOCKER);
    50 50   }
    51 51   
     52 + @Override
     53 + public int difficulty() {
     54 + return 2;
     55 + }
     56 + 
     57 + @Override
     58 + public String getTech() {
     59 + return "Git";
     60 + }
     61 + 
    52 62   private String quickDecrypt(String cipherText) {
    53 63   try {
    54 64   final byte[] keyData = Base64.getDecoder().decode(encryptionKey);
    skipped 29 lines
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge16.java
    skipped 41 lines
    42 42   return List.of(RuntimeEnvironment.Environment.DOCKER);
    43 43   }
    44 44   
     45 + @Override
     46 + public int difficulty() {
     47 + return 3;
     48 + }
     49 + 
     50 + @Override
     51 + public String getTech() {
     52 + return "Front-end";
     53 + }
     54 + 
    45 55   public String getActualData() {
    46 56   try {
    47 57   return Files.readString(Paths.get(dockerMountPath, "secondkey.txt"));
    skipped 7 lines
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge17.java
    skipped 41 lines
    42 42   return List.of(RuntimeEnvironment.Environment.DOCKER);
    43 43   }
    44 44   
     45 + @Override
     46 + public int difficulty() {
     47 + return 3;
     48 + }
     49 + 
     50 + @Override
     51 + public String getTech() {
     52 + return "Docker";
     53 + }
     54 + 
    45 55   public String getActualData() {
    46 56   try {
    47 57   return Files.readString(Paths.get(dockerMountPath, "thirdkey.txt"));
    skipped 7 lines
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge18.java
    skipped 64 lines
    65 65   public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
    66 66   return List.of(DOCKER);
    67 67   }
     68 + 
     69 + @Override
     70 + public int difficulty() {
     71 + return 5;
     72 + }
     73 + 
     74 + @Override
     75 + public String getTech() {
     76 + return "Cryptography";
     77 + }
    68 78  }
    69 79   
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge19.java
    skipped 38 lines
    39 39   public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
    40 40   return List.of(DOCKER);
    41 41   }
     42 + 
     43 + @Override
     44 + public int difficulty() {
     45 + return 4;
     46 + }
     47 + 
     48 + @Override
     49 + public String getTech() {
     50 + return "Binary";
     51 + }
    42 52  }
    43 53   
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge2.java
    skipped 36 lines
    37 37   public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
    38 38   return List.of(DOCKER);
    39 39   }
     40 + 
     41 + @Override
     42 + public int difficulty() {
     43 + return 1;
     44 + }
     45 + 
     46 + @Override
     47 + public String getTech() {
     48 + return "Git";
     49 + }
    40 50  }
    41 51   
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge20.java
    skipped 38 lines
    39 39   public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
    40 40   return List.of(DOCKER);
    41 41   }
     42 + 
     43 + @Override
     44 + public int difficulty() {
     45 + return 4;
     46 + }
     47 + 
     48 + @Override
     49 + public String getTech() {
     50 + return "Binary";
     51 + }
    42 52  }
    43 53   
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge21.java
    skipped 38 lines
    39 39   public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
    40 40   return List.of(DOCKER);
    41 41   }
     42 + 
     43 + @Override
     44 + public int difficulty() {
     45 + return 5;
     46 + }
     47 + 
     48 + @Override
     49 + public String getTech() {
     50 + return "Binary";
     51 + }
    42 52  }
    43 53   
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge22.java
     1 + 
     2 +package org.owasp.wrongsecrets.challenges.docker;
     3 + 
     4 +import lombok.extern.slf4j.Slf4j;
     5 +import org.owasp.wrongsecrets.RuntimeEnvironment;
     6 +import org.owasp.wrongsecrets.ScoreCard;
     7 +import org.owasp.wrongsecrets.challenges.Challenge;
     8 +import org.owasp.wrongsecrets.challenges.Spoiler;
     9 +import org.springframework.core.annotation.Order;
     10 +import org.springframework.stereotype.Component;
     11 + 
     12 +import java.util.List;
     13 + 
     14 +import static org.owasp.wrongsecrets.RuntimeEnvironment.Environment.DOCKER;
     15 + 
     16 +@Component
     17 +@Order(22)
     18 +@Slf4j
     19 +public class Challenge22 extends Challenge {
     20 + 
     21 + private final BinaryExecutionHelper binaryExecutionHelper;
     22 + 
     23 + public Challenge22(ScoreCard scoreCard) {
     24 + super(scoreCard);
     25 + this.binaryExecutionHelper = new BinaryExecutionHelper(22);
     26 + }
     27 + 
     28 + @Override
     29 + public Spoiler spoiler() {
     30 + return new Spoiler(binaryExecutionHelper.executeCommand("", "wrongsecrets-rust"));
     31 + }
     32 + 
     33 + @Override
     34 + public boolean answerCorrect(String answer) {
     35 + return binaryExecutionHelper.executeCommand(answer, "wrongsecrets-rust").equals("This is correct! Congrats!");
     36 + }
     37 + 
     38 + public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
     39 + return List.of(DOCKER);
     40 + }
     41 + 
     42 + @Override
     43 + public int difficulty() {
     44 + return 5;
     45 + }
     46 + 
     47 + @Override
     48 + public String getTech() {
     49 + return "Binary";
     50 + }
     51 +}
     52 + 
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge23.java
     1 +package org.owasp.wrongsecrets.challenges.docker;
     2 + 
     3 + 
     4 +import lombok.extern.slf4j.Slf4j;
     5 +import org.owasp.wrongsecrets.RuntimeEnvironment;
     6 +import org.owasp.wrongsecrets.ScoreCard;
     7 +import org.owasp.wrongsecrets.challenges.Challenge;
     8 +import org.owasp.wrongsecrets.challenges.Spoiler;
     9 +import org.spongycastle.util.encoders.Base64;
     10 +import org.spongycastle.util.encoders.Hex;
     11 +import org.springframework.core.annotation.Order;
     12 +import org.springframework.stereotype.Component;
     13 + 
     14 +import java.util.List;
     15 + 
     16 +@Slf4j
     17 +@Component
     18 +@Order(23)
     19 +public class Challenge23 extends Challenge {
     20 + 
     21 + public Challenge23(ScoreCard scoreCard) {
     22 + super(scoreCard);
     23 + }
     24 + 
     25 + @Override
     26 + public Spoiler spoiler() {
     27 + return new Spoiler(getActualData());
     28 + }
     29 + 
     30 + @Override
     31 + public boolean answerCorrect(String answer) {
     32 + log.info("challenge 23, actualdata: {}, answer: {}", getActualData(), answer);
     33 + return getActualData().equals(answer);
     34 + }
     35 + 
     36 + @Override
     37 + public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
     38 + return List.of(RuntimeEnvironment.Environment.DOCKER);
     39 + }
     40 + 
     41 + @Override
     42 + public int difficulty() {
     43 + return 1;
     44 + }
     45 + 
     46 + @Override
     47 + public String getTech() {
     48 + return "Front-end";
     49 + }
     50 + 
     51 + public String getActualData() {
     52 + return new String(Base64.decode(Hex.decode(Base64.decode("NTYzMjY4MzU1MTMyMzk3NDYyNTc1Njc1NjQ0ODRlNDI2MzMxNDI2ODYzMzM0ZTdhNjQzMjM5Nzk1YTQ1NDY3OTVhNTU0YTY4NWE0NDRkMzA0ZTU2Mzg2Yg=="))));
     53 + 
     54 + }
     55 +}
     56 + 
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge3.java
    skipped 36 lines
    37 37   public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
    38 38   return List.of(DOCKER);
    39 39   }
     40 + 
     41 + @Override
     42 + public int difficulty() {
     43 + return 1;
     44 + }
     45 + 
     46 + @Override
     47 + public String getTech() {
     48 + return "Docker";
     49 + }
    40 50  }
    41 51   
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge4.java
    skipped 38 lines
    39 39   return List.of(DOCKER);
    40 40   }
    41 41   
     42 + @Override
     43 + public int difficulty() {
     44 + return 2;
     45 + }
     46 + 
     47 + @Override
     48 + public String getTech() {
     49 + return "Docker";
     50 + }
     51 + 
    42 52  }
    43 53   
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge8.java
    skipped 44 lines
    45 45   return List.of(DOCKER);
    46 46   }
    47 47   
     48 + @Override
     49 + public int difficulty() {
     50 + return 2;
     51 + }
     52 + 
     53 + @Override
     54 + public String getTech() {
     55 + return "Logging";
     56 + }
     57 + 
    48 58   private String generateRandomString(int length) {
    49 59   StringBuilder builder = new StringBuilder(length);
    50 60   for (int i = 0; i < length; i++) {
    skipped 6 lines
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/Challenge5.java
    skipped 36 lines
    37 37   public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
    38 38   return List.of(K8S);
    39 39   }
     40 + 
     41 + @Override
     42 + public int difficulty() {
     43 + return 2;
     44 + }
     45 + 
     46 + @Override
     47 + public String getTech() {
     48 + return "Configmaps";
     49 + }
    40 50  }
    41 51   
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/Challenge6.java
    skipped 36 lines
    37 37   public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
    38 38   return List.of(K8S);
    39 39   }
     40 + 
     41 + @Override
     42 + public int difficulty() {
     43 + return 2;
     44 + }
     45 + 
     46 + @Override
     47 + public String getTech() {
     48 + return "Secrets";
     49 + }
    40 50  }
    41 51   
  • ■ ■ ■ ■ ■ ■
    src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/Challenge7.java
    skipped 41 lines
    42 42   public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
    43 43   return List.of(RuntimeEnvironment.Environment.VAULT);
    44 44   }
     45 + 
     46 + @Override
     47 + public int difficulty() {
     48 + return 4;
     49 + }
     50 + 
     51 + @Override
     52 + public String getTech() {
     53 + return "Vault";
     54 + }
    45 55  }
    46 56   
  • ■ ■ ■ ■ ■ ■
    src/main/resources/application.properties
    skipped 7 lines
    8 8  DOCKER_ENV_PASSWORD=if_you_see_this_please_use_docker_instead
    9 9  vaultpassword=if_you_see_this_please_use_K8S_and_Vault
    10 10  default_aws_value=if_you_see_this_please_use_AWS_Setup
     11 +default_aws_value_challenge_9=if_you_see_this_please_use_AWS_Setup
     12 +default_aws_value_challenge_10=if_you_see_this_please_use_AWS_Setup
     13 +default_aws_value_challenge_11=if_you_see_this_please_use_AWS_Setup
    11 14  default_gcp_value=if_you_see_this_please_use_GCP_Setup
    12 15  default_azure_value=if_you_see_this_please_use_Azure_Setup
    13 16  AWS_ROLE_ARN=if_you_see_this_please_use_AWS_Setup
    skipped 11 lines
    25 28  server.servlet.session.tracking-modes=COOKIE
    26 29  asciidoctor.enabled=false
    27 30  hints_enabled=true
     31 +ctf_enabled=false
     32 +ctf_key=TRwzkRJnHOTckssAeyJbysWgP!Qc2T
    28 33  reason_enabled=true
    29 34  plainText13=This is not the secret
    30 35  cipherText13=hRZqOEB0V0kU6JhEXdm8UH32VDAbAbdRxg5RMpo/fA8caUCvJhs=
    skipped 18 lines
    49 54  #---
    50 55  spring.config.activate.on-profile=local
    51 56  challengedockermtpath=./
     57 +asciidoctor.enabled=true
    52 58  #---
    53 59  spring.config.activate.on-profile=local-vault
    54 60  wrongsecretvalue=wrongsecret
    skipped 9 lines
    64 70  spring.config.activate.on-profile=without-vault
    65 71  wrongsecretvalue=wrongsecret
    66 72  spring.cloud.vault.enabled=false
    67  -asciidoctor.enabled=true
     73 +asciidoctor.enabled=false
     74 +#---
     75 +spring.config.activate.on-profile=without-vault-ctf-emulation
     76 +wrongsecretvalue=wrongsecret
     77 +spring.cloud.vault.enabled=false
     78 +asciidoctor.enabled=false
     79 +ctf_enabled=true
     80 +ctf_key=randomtextforkey
     81 +vaultpassword=ACTUAL_ANSWER_CHALLENGE7
     82 +secretmountpath=nothere
     83 +SPECIAL_K8S_SECRET=ACTUAL_ANSWER_CHALLENGE5
     84 +SPECIAL_SPECIAL_K8S_SECRET=ACTUAL_ANSWER_CHALLENGE6
     85 +default_aws_value_challenge_9=ACTUAL_ANSWER_CHALLENGE9
     86 +default_aws_value_challenge_10=ACTUAL_ANSWER_CHALLENGE10
     87 +default_aws_value_challenge_11=ACTUAL_ANSWER_CHALLENGE_11
     88 +K8S_ENV=Heroku(Docker)
    68 89   
  • src/main/resources/executables/wrongsecrets-rust
    Binary file.
  • src/main/resources/executables/wrongsecrets-rust-arm
    Binary file.
  • src/main/resources/executables/wrongsecrets-rust-linux
    Binary file.
  • src/main/resources/executables/wrongsecrets-rust-linux-arm
    Binary file.
  • ■ ■ ■ ■
    src/main/resources/explanations/challenge19.adoc
    1  -=== Obfuscating in binaries part 1: the C binary
     1 +=== Hiding in binaries part 1: the C binary
    2 2   
    3 3  We need to put a secret in a mobile app! Nobody will notice the secret in our compiled code!
    4 4  This is a misbelief we have often encountered when presenting on mobile security topics.
    skipped 3 lines
  • ■ ■ ■ ■
    src/main/resources/explanations/challenge20.adoc
    1  -=== Obfuscating in binaries part 2: the C++ binary
     1 +=== Hiding in binaries part 2: the C++ binary
    2 2   
    3 3  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?
    4 4   
    skipped 2 lines
  • ■ ■ ■ ■
    src/main/resources/explanations/challenge21.adoc
    1  -=== Obfuscating part 3: the Go binary
     1 +=== Hiding in binaries part 3: the Go binary
    2 2   
    3 3  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?
    4 4   
    skipped 2 lines
  • ■ ■ ■ ■ ■ ■
    src/main/resources/explanations/challenge22.adoc
     1 +=== Hiding in binaries part 4: the Rust binary
     2 + 
     3 +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?
     4 + 
     5 +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])?
     6 + 
  • ■ ■ ■ ■ ■ ■
    src/main/resources/explanations/challenge22_hint.adoc
     1 +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].
     2 + 
     3 +You can solve this challenge using the following steps:
     4 + 
     5 +1. Find the secrets with https://ghidra-sre.org/[Ghidra].
     6 +- Install https://ghidra-sre.org/[Ghidra].
     7 +- Start it whit `ghidraRun`.
     8 +- Load the application `wrongsecrets-rust` into ghidra by choosing a new project, then import the file and then doubleclick on it.
     9 +- Allow the Ghidra to analyze the application.
     10 +- Now import https://gist.github.com/str4d/e541f4c28e2bca80d222434ac1a204f4[demangle script] and run it via the Ghidra Script manager to demangle the functions.
     11 +- Find the `main` function in the `rust` namespace
     12 +- Find the argument that needs to be compared (in our example that is `local_80` as defined in `std::env::args((env *)&local_80);`)
     13 +- Find where the argument is compared (in our example that is `iVar1 = __stubs::_memcmp(local_80,puVar2,0x3b);`)
     14 +- Now search the input it is compared to (`puVar2`) its value. Can you find the secret?
     15 +- 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!
     16 + 
     17 +2. Find the secrets with https://www.radare.org[radare2].
     18 +- 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`
     19 +- Launch r2 analysis with `$ r2 -AAA wrongsecrets-rust`
     20 +- Print the entrypoint `s sym.rust::main::h66ace6a84e548891` and then `pdf`. (not the default `main`!)
     21 +- Find the argument that needs to be compared with `pdf | grep memcmp` (in our example that is `r12`).
     22 +- Try to find how this argument is prepared. Can you spot the secret?
     23 +- Alternatively: after launching radare2, run `iz | grep secret` and find the string.
     24 + 
  • ■ ■ ■ ■ ■ ■
    src/main/resources/explanations/challenge22_reason.adoc
     1 +*Why Using binaries to hide a secret will only delay an attacker.*
     2 + 
     3 +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.
     4 + 
     5 +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.
     6 + 
     7 +Still need to have a secret in the binary? Make sure it can only be retrieved remotely after authenticating against a server.
     8 + 
  • ■ ■ ■ ■ ■ ■
    src/main/resources/explanations/challenge23.adoc
     1 +=== Secrets in front-end code part 2
     2 + 
     3 +Sometimes we don't want to forget how to login with test-credentials while working on our front-end code.
     4 +Can you find the test-credentials?
     5 + 
     6 +Note that test-credentialss are sometimes obfuscated in code by Base64 encoding them.
     7 + 
     8 +++++
     9 +<!-- test-credentials = WhyCommentsAsPassswordAreBad345_$"-->
     10 +++++
     11 + 
  • ■ ■ ■ ■ ■ ■
    src/main/resources/explanations/challenge23_hint.adoc
     1 +You can solve this challenge by the following steps:
     2 + 
     3 +1. Find the secret in the front-end
     4 +- Use the developer tools of the browser to see the HTML code of this challenge.
     5 +- Go to the end of the challenge description and look for comments.
     6 +2. Decode the base64 encoded secret
     7 +- Go to the source of Challenge23 and find the actual Base64 encoded answer
     8 +- Use any online/offline decoder to decode the Base64 string, then hex-decode the string, and Base64 decode it again.
     9 + 
  • ■ ■ ■ ■ ■ ■
    src/main/resources/explanations/challenge23_reason.adoc
     1 +*Why having secrets in front-end code is a bad idea*
     2 + 
     3 +Whenever you run a mobile app on your smart-device or a SPA on your web-browser, you should try not to hardcode any secrets in them. An attacker can always take the app, reverse-engineer it, and find the actual secret. Instead ask yourself if the secret can be safely downloaded after authentication, or used in a different way.
     4 + 
     5 +*Why using Single-Page apps or Mobile apps to put client secret in is a bad idea*
     6 + 
     7 +As you can tell by now, you can easily detect any secret that is stored within a Single-Page app or mobile app.
     8 + 
     9 +*Why Base64 encoding is no encryption*
     10 + 
     11 +As you can tell by now, it was rather easy to decode the secret from the Challengefile. This is why Base64 and Hex encoding should never be considered a method to hide a secret. Only use Base64- and/or Hex encoding to ensure you can transport a binary sequence as a String.
     12 + 
  • ■ ■ ■ ■ ■ ■
    src/main/resources/templates/challenge.html
    skipped 2 lines
    3 3  <body>
    4 4  <div class="container" layout:fragment="content">
    5 5   <!--/*@thymesVar id="challenge" type="org.owasp.wrongsecrets.challenges.ChallengeUI"*/-->
    6  - <h1 class="mt-2" th:text="${challenge.name}"/>
     6 + <p class="h1 mt-2"> <span th:text="${challenge.name}"/> <span th:block th:each="i: ${#numbers.sequence(1, challenge.difficulty)}"><span>☆</span></span></p>
    7 7   <p><span th:text="'Welcome to challenge ' + ${challenge.challengeNumber} + '.'"></span> You need to guess the secret
    8 8   that is hidden in <a href="https://github.com/commjoen/wrongsecrets">Java</a>, <a
    9 9   href="https://hub.docker.com/r/jeroenwillemsen/wrongsecrets">Docker</a>, Kubernetes, Vault, AWS or GCP.</p>
    skipped 74 lines
    84 84   </div>
    85 85   <div th:if="${missingEnvWarning} eq 'AWS' or ${missingEnvWarning} eq 'GCP'" class="alert alert-danger"
    86 86   role="alert">
    87  - We are running outside a properly configured AWS environment. Please run this in an AWS/GCP environment as
     87 + We are running outside a properly configured Cloud environment. Please run this in an AWS/Azure/GCP environment as
    88 88   explained in the <a href="https://github.com/commjoen/wrongsecrets#cloud-challenges">README.md</a>.
    89 89   </div>
    90 90   </div>
    skipped 22 lines
  • ■ ■ ■ ■ ■ ■
    src/main/resources/templates/stats.html
    skipped 6 lines
    7 7   <h1>Current Stats</h1>
    8 8   <p>Number of active sessions:</p>
    9 9   <p th:text="${sessioncounter}"></p>
     10 + <p>Hints enabled:<span th:text="${hintsEnabled}"></span></p>
     11 + <p>Reason enabled:<span th:text="${reasonEnabled}"></span></p>
     12 + <p>CTF-mode enabled:<span th:text="${ctfModeEnabled}"></span></p>
     13 + 
    10 14   <p>Number of canary callbacks since boot:</p>
    11 15   <p th:text="${canaryCounter}"></p>
    12 16   <p>Last canary token received:</p>
    skipped 11 lines
  • ■ ■ ■ ■ ■ ■
    src/main/resources/templates/welcome.html
    skipped 16 lines
    17 17   <div class="container-fluid text-sm p-2 p-lg-3">
    18 18   <div class="row">
    19 19   <div class="col-12 col-lg-7">
    20  - <table class="table">
     20 + <table class="table table-responsive">
    21 21   <thead>
    22 22   <tr>
    23  - <th scope="col">#</th>
    24  - <th scope="col">Challenge &nbsp;&nbsp;&nbsp;&nbsp;</th>
    25  - <th scope="col" th:text="'Required environments (current: '+${environment}+')'"></th>
     23 + <th scope="col" class="d-none d-xl-table-cell">#</th>
     24 + <th scope="col">&nbsp;Challenge&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th>
     25 + <th scope="col">Focus&nbsp;&nbsp;&nbsp;</th>
     26 + <th scope="col" class="d-sm-none"
     27 + th:text="'Runs on environment (current: '+${#strings.replace(environment,'_',' _')}+')'"></th>
     28 + <th scope="col" class="d-none d-md-table-cell">Difficulty&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th>
     29 + <th scope="col" class="d-none d-sm-table-cell"
     30 + th:text="'Runs on environment (current: '+${environment}+')'"></th>
    26 31   </tr>
    27 32   </thead>
    28 33   <tbody>
    29 34   <tr th:each="challenge: ${challenges}">
    30  - <td th:text="${challenge.link}"></td>
    31  - <td><a th:href="@{/challenge} + '/' + ${challenge.link}"
    32  - th:class="${challenge.isChallengeEnabled} ? '' : 'disabled'"><span
     35 + <th scope="row" class="d-none d-xl-table-cell" th:text="${challenge.link}"></th>
     36 + <td>&nbsp;<a th:href="@{/challenge} + '/' + ${challenge.link}"
     37 + th:class="${challenge.isChallengeEnabled} ? '' : 'disabled'"><span
    33 38   th:text="${challenge.name}"
    34 39   th:remove="tag"></span></a></td>
     40 + <td th:text="${challenge.tech}"></td>
     41 + <td class="d-none d-md-table-cell">
     42 + <th:span th:each="i: ${#numbers.sequence(1, challenge.difficulty)}"><span>★ </span></th:span>
     43 + <th:span th:if="${challenge.difficulty<5}"
     44 + th:each="i: ${#numbers.sequence(challenge.difficulty+1, 5)}"><span>☆</span>
     45 + </th:span>
     46 + </td>
    35 47   <th:block th:if="${challenge.requiredEnv} == 'DOCKER'">
    36 48   <td>Docker</td>
    37 49   </th:block>
    38 50   <th:block th:if="${challenge.requiredEnv} == 'K8S'">
    39  - <td>Kubernetes or Minikube</td>
     51 + <td>K8s or Minikube</td>
    40 52   </th:block>
    41 53   <th:block th:if="${challenge.requiredEnv} == 'VAULT'">
    42  - <td>Kubernetes or Minikube with Vault</td>
     54 + <td>K8s or Minikube with Vault</td>
    43 55   </th:block>
    44 56   <th:block
    45  - th:if="${challenge.requiredEnv} == 'AWS' or ${challenge.requiredEnv} == 'GCP'or ${challenge.requiredEnv} == 'AZURE'">
     57 + th:if="${challenge.requiredEnv} == 'AWS' or ${challenge.requiredEnv} == 'GCP' or ${challenge.requiredEnv} == 'AZURE'">
    46 58   <td>AWS, GCP, Azure</td>
    47 59   </th:block>
     60 + 
    48 61   </tr>
    49 62   </tbody>
    50 63   </table>
    skipped 35 lines
    86 99   <li><a href="https://github.com/RubenAtBinx">Ruben Kruiver @RubenAtBinx</a></li>
    87 100   <li><a href="https://github.com/alex-bender">Alex Bender @alex-bender</a></li>
    88 101   <li><a href="https://github.com/f3rn0s">Finn @f3rn0s</a></li>
     102 + <li><a href="https://github.com/kingthorin">Rick M @kingthorin</a></li>
    89 103   </ul>
    90 104   Testers:
    91 105   <ul>
    skipped 21 lines
    113 127   <li><a
    114 128   href="https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Secrets_Management_CheatSheet.md">OWASP
    115 129   Secretsmanagement Cheatsheet</a></li>
    116  - <li><a href="https://www.opencre.org/cre/223-780?register=true&type=tool&tool_type=training&tags=secrets,training&description=With%20this%20app%2C%20we%20have%20packed%20various%20ways%20of%20how%20to%20not%20store%20your%20secrets.%20These%20can%20help%20you%20to%20realize%20whether%20your%20secret%20management%20is%20ok.%20The%20challenge%20is%20to%20find%20all%20the%20different%20secrets%20by%20means%20of%20various%20tools%20and%20techniques.%20Can%20you%20solve%20all%20the%2014%20challenges%3F&trk=flagship-messaging-web&messageThreadUrn=urn:li:messagingThread:2-YmRkNjRkZTMtNjRlYS00OWNiLWI2YmUtMDYwNzY3ZjI1MDcyXzAxMg==&lipi=urn:li:page:d_flagship3_feed;J58Sgd80TdanpKWFMH6z+w==">Open CRE on Secrets Management</a></li>
     130 + <li><a
     131 + href="https://www.opencre.org/cre/223-780?register=true&type=tool&tool_type=training&tags=secrets,training&description=With%20this%20app%2C%20we%20have%20packed%20various%20ways%20of%20how%20to%20not%20store%20your%20secrets.%20These%20can%20help%20you%20to%20realize%20whether%20your%20secret%20management%20is%20ok.%20The%20challenge%20is%20to%20find%20all%20the%20different%20secrets%20by%20means%20of%20various%20tools%20and%20techniques.%20Can%20you%20solve%20all%20the%2014%20challenges%3F&trk=flagship-messaging-web&messageThreadUrn=urn:li:messagingThread:2-YmRkNjRkZTMtNjRlYS00OWNiLWI2YmUtMDYwNzY3ZjI1MDcyXzAxMg==&lipi=urn:li:page:d_flagship3_feed;J58Sgd80TdanpKWFMH6z+w==">Open
     132 + CRE on Secrets Management</a></li>
    117 133   </ul>
    118 134   </div>
    119 135   </div>
    skipped 17 lines
    137 153   </div>
    138 154   <div class="col-12 col-lg-7">
    139 155   <div class="border border-dark thank-you">
    140  - Want to see if your tool of choice detects all the secrets available in this project? <a href="https://github.com/commjoen/wrongsecrets/#use-owasp-wrongsecrets-as-a-secret-detection-benchmark">Check the instructions in the README</a>.
     156 + Want to see if your tool of choice detects all the secrets available in this project? <a
     157 + href="https://github.com/commjoen/wrongsecrets/#use-owasp-wrongsecrets-as-a-secret-detection-benchmark">Check
     158 + the instructions in the README</a>.
    141 159   </div>
    142 160   </div>
    143 161   </div>
    skipped 5 lines
  • ■ ■ ■ ■ ■ ■
    src/test/java/org/owasp/wrongsecrets/ChallengeAPiControllerTest.java
     1 +package org.owasp.wrongsecrets;
     2 + 
     3 +import org.junit.jupiter.api.Test;
     4 +import org.owasp.wrongsecrets.canaries.AdditionalCanaryData;
     5 +import org.owasp.wrongsecrets.canaries.CanaryToken;
     6 +import org.springframework.beans.factory.annotation.Autowired;
     7 +import org.springframework.boot.test.context.SpringBootTest;
     8 +import org.springframework.boot.web.client.RestTemplateBuilder;
     9 +import org.springframework.boot.web.server.LocalServerPort;
     10 +import org.springframework.http.HttpStatus;
     11 +import org.springframework.web.client.RestClientResponseException;
     12 + 
     13 +import static org.assertj.core.api.Assertions.assertThat;
     14 +import static org.junit.jupiter.api.Assertions.fail;
     15 + 
     16 +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
     17 +public class ChallengeAPiControllerTest {
     18 + @LocalServerPort
     19 + private int port;
     20 + 
     21 + @Autowired
     22 + private RestTemplateBuilder builder;
     23 + 
     24 + public ChallengeAPiControllerTest() {
     25 + }
     26 + 
     27 + @Test
     28 + void shouldGetListOfChallenges() {
     29 + var restTemplate = builder.build();
     30 + 
     31 + var callbackAdress = "http://localhost:"+port+"/api/Challenges";
     32 + 
     33 + try {
     34 + var response = restTemplate.getForEntity(callbackAdress, String.class);
     35 + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
     36 + assertThat(response.getBody()).contains("hint");
     37 + } catch (RestClientResponseException e) {
     38 + fail(e);
     39 + }
     40 + }
     41 +}
     42 + 
     43 +/*
     44 +"manageUrl" : "url", "memo" : "memo", "channel" : "channel", "time" : "time", "additionalData" : { "srcIp" : "soruce", "useragent" : "agent", "referer" : "referer", "location" : "locatoin"}}
     45 + */
     46 + 
  • ■ ■ ■ ■ ■ ■
    src/test/java/org/owasp/wrongsecrets/ChallengesControllerCTFModeTest.java
     1 +package org.owasp.wrongsecrets;
     2 + 
     3 +import org.junit.jupiter.api.Test;
     4 +import org.junit.jupiter.api.extension.ExtendWith;
     5 +import org.owasp.wrongsecrets.challenges.docker.Challenge1;
     6 +import org.springframework.beans.factory.annotation.Autowired;
     7 +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
     8 +import org.springframework.boot.test.context.SpringBootTest;
     9 +import org.springframework.http.MediaType;
     10 +import org.springframework.test.context.junit.jupiter.SpringExtension;
     11 +import org.springframework.test.web.servlet.MockMvc;
     12 + 
     13 +import static org.hamcrest.Matchers.containsString;
     14 +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
     15 +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
     16 +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
     17 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
     18 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
     19 + 
     20 +@ExtendWith(SpringExtension.class)
     21 +@SpringBootTest(
     22 + properties = {"ctf_enabled=true", "ctf_key=randomtextforkey"},
     23 + classes = WrongSecretsApplication.class
     24 +)
     25 +@AutoConfigureMockMvc
     26 +class ChallengesControllerCTFModeTest {
     27 + 
     28 + @Autowired
     29 + private MockMvc mvc;
     30 + 
     31 + 
     32 + @Test
     33 + void shouldNotSpoilWhenInCTFMode() throws Exception {
     34 + mvc.perform(get("/spoil-1"))
     35 + .andExpect(status().isOk())
     36 + .andExpect(content().string(containsString("Spoils are disabled in CTF mode")));
     37 + 
     38 + }
     39 + 
     40 + @Test
     41 + void shouldNotSpoilWhenInCTFModeEvenWhenChallengeUnsupported() throws Exception {
     42 + mvc.perform(get("/spoil-5"))
     43 + .andExpect(status().isOk())
     44 + .andExpect(content().string(containsString("Spoils are disabled in CTF mode")));
     45 + 
     46 + }
     47 + 
     48 + @Test
     49 + void shouldShowFlagWhenRespondingWithSuccessInCTFMode() throws Exception {
     50 + var spoil = new Challenge1(new InMemoryScoreCard(1)).spoiler().solution();
     51 + mvc.perform(post("/challenge/1")
     52 + .contentType(MediaType.APPLICATION_FORM_URLENCODED)
     53 + .param("solution", spoil)
     54 + .param("action", "submit")
     55 + .with(csrf()))
     56 + .andExpect(status().isOk())
     57 + .andExpect(content().string(containsString("ba9a72ac7057576344856")));
     58 + 
     59 + }
     60 + 
     61 + 
     62 + @Test
     63 + void shouldEnableK8sExercises() throws Exception{
     64 + mvc.perform(get("/"))
     65 + .andExpect(status().isOk())
     66 + .andExpect(content().string(containsString("class=\"disabled\">Challenge 5</a></td>")))
     67 + .andExpect(content().string(containsString("class=\"disabled\">Challenge 6</a></td>")))
     68 + .andExpect(content().string(containsString("class=\"disabled\">Challenge 7</a></td>")));
     69 + }
     70 + 
     71 + @Test
     72 + void shouldStillDissableTestsIfNotPreconfigured() throws Exception {
     73 + testK8sChallenge("/challenge/5");
     74 + testK8sChallenge("/challenge/6");
     75 + testK8sChallenge("/challenge/7");
     76 + testForCloudCluster("/challenge/9");
     77 + testForCloudCluster("/challenge/10");
     78 + testForCloudCluster("/challenge/11");
     79 + }
     80 + 
     81 + private void testK8sChallenge(String url) throws Exception {
     82 + mvc.perform(get(url)
     83 + .contentType(MediaType.APPLICATION_FORM_URLENCODED)
     84 + .with(csrf()))
     85 + .andExpect(status().isOk())
     86 + .andExpect(content().string(containsString("We are running outside a K8s cluster")));
     87 + }
     88 + 
     89 + private void testForCloudCluster(String url) throws Exception {
     90 + mvc.perform(get(url)
     91 + .contentType(MediaType.APPLICATION_FORM_URLENCODED)
     92 + .with(csrf()))
     93 + .andExpect(status().isOk())
     94 + .andExpect(content().string(containsString("We are running outside a properly configured Cloud environment.")));
     95 + }
     96 +}
     97 + 
  • ■ ■ ■ ■ ■ ■
    src/test/java/org/owasp/wrongsecrets/ChallengesControllerCTFModeWithPresetCloudValuesTest.java
     1 +package org.owasp.wrongsecrets;
     2 + 
     3 +import org.junit.jupiter.api.Test;
     4 +import org.junit.jupiter.api.extension.ExtendWith;
     5 +import org.owasp.wrongsecrets.challenges.cloud.Challenge10;
     6 +import org.owasp.wrongsecrets.challenges.cloud.Challenge11;
     7 +import org.owasp.wrongsecrets.challenges.cloud.Challenge9;
     8 +import org.springframework.beans.factory.annotation.Autowired;
     9 +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
     10 +import org.springframework.boot.test.context.SpringBootTest;
     11 +import org.springframework.http.MediaType;
     12 +import org.springframework.test.context.junit.jupiter.SpringExtension;
     13 +import org.springframework.test.web.servlet.MockMvc;
     14 + 
     15 +import static org.hamcrest.Matchers.containsString;
     16 +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
     17 +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
     18 +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
     19 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
     20 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
     21 + 
     22 +@ExtendWith(SpringExtension.class)
     23 +@SpringBootTest(
     24 + properties = {"ctf_enabled=true", "ctf_key=randomtextforkey",
     25 + "SPECIAL_K8S_SECRET=test5", "SPECIAL_SPECIAL_K8S_SECRET=test6", "vaultpassword=test7",
     26 + "secretmountpath=nothere", "default_aws_value_challenge_9=ACTUAL_ANSWER_CHALLENGE9",
     27 + "default_aws_value_challenge_10=ACTUAL_ANSWER_CHALLENGE10", "default_aws_value_challenge_11=ACTUAL_ANSWER_CHALLENGE_11"},
     28 + classes = WrongSecretsApplication.class
     29 +)
     30 +@AutoConfigureMockMvc
     31 +class ChallengesControllerCTFModeWithPresetCloudValuesTest {
     32 + 
     33 + @Autowired
     34 + private MockMvc mvc;
     35 + 
     36 + 
     37 + @Test
     38 + void shouldNotSpoilWhenInCTFMode() throws Exception {
     39 + mvc.perform(get("/spoil-9"))
     40 + .andExpect(status().isOk())
     41 + .andExpect(content().string(containsString("Spoils are disabled in CTF mode")));
     42 + 
     43 + }
     44 + 
     45 + @Test
     46 + void shouldShowFlagWhenRespondingWithSuccessInCTFModeChallenge9() throws Exception {
     47 + var spoil = new Challenge9(new InMemoryScoreCard(1), null, "ACTUAL_ANSWER_CHALLENGE9", new RuntimeEnvironment(RuntimeEnvironment.Environment.HEROKU_DOCKER)).spoiler().solution();
     48 + mvc.perform(post("/challenge/9")
     49 + .contentType(MediaType.APPLICATION_FORM_URLENCODED)
     50 + .param("solution", spoil)
     51 + .param("action", "submit")
     52 + .with(csrf()))
     53 + .andExpect(status().isOk())
     54 + .andExpect(content().string(containsString("70d75bf845890b2419bd8795c")));
     55 + }
     56 + 
     57 + @Test
     58 + void shouldShowFlagWhenRespondingWithSuccessInCTFModeChallenge10() throws Exception {
     59 + var spoil = new Challenge10(new InMemoryScoreCard(1), null, "ACTUAL_ANSWER_CHALLENGE10", new RuntimeEnvironment(RuntimeEnvironment.Environment.HEROKU_DOCKER)).spoiler().solution();
     60 + mvc.perform(post("/challenge/10")
     61 + .contentType(MediaType.APPLICATION_FORM_URLENCODED)
     62 + .param("solution", spoil)
     63 + .param("action", "submit")
     64 + .with(csrf()))
     65 + .andExpect(status().isOk())
     66 + .andExpect(content().string(containsString("176e937a2cafea3b0da3")));
     67 + }
     68 + 
     69 + @Test
     70 + void shouldShowFlagWhenRespondingWithSuccessInCTFModeChallenge11() throws Exception {
     71 + var spoil = new Challenge11(new InMemoryScoreCard(1),
     72 + "awsRoleArn", "tokenFileLocation",
     73 + "awsRegion", "gcpDefualtValue", "awsDefaultValue",
     74 + "azureDefaultValue", "azureVaultUri", "azureWrongSecret3",
     75 + "projectId", "ACTUAL_ANSWER_CHALLENGE_11", true,
     76 + new RuntimeEnvironment(RuntimeEnvironment.Environment.HEROKU_DOCKER)).spoiler().solution();
     77 + 
     78 + mvc.perform(post("/challenge/11")
     79 + .contentType(MediaType.APPLICATION_FORM_URLENCODED)
     80 + .param("solution", spoil)
     81 + .param("action", "submit")
     82 + .with(csrf()))
     83 + .andExpect(status().isOk())
     84 + .andExpect(content().string(containsString("89aeb4b29d4a0bc13bd")));
     85 + }
     86 + 
     87 + @Test
     88 + void shouldEnableCloudExercises() throws Exception {
     89 + mvc.perform(get("/"))
     90 + .andExpect(status().isOk())
     91 + .andExpect(content().string(containsString("<td>&nbsp;<a href=\"/challenge/9\">Challenge 9</a></td>")))
     92 + .andExpect(content().string(containsString("<td>&nbsp;<a href=\"/challenge/10\">Challenge 10</a></td>")))
     93 + .andExpect(content().string(containsString("<td>&nbsp;<a href=\"/challenge/11\">Challenge 11</a></td>")));
     94 + }
     95 + 
     96 + @Test
     97 + void shouldEnableK8sExercises() throws Exception{
     98 + mvc.perform(get("/"))
     99 + .andExpect(status().isOk())
     100 + .andExpect(content().string(containsString("<td>&nbsp;<a href=\"/challenge/5\">Challenge 5</a></td>")))
     101 + .andExpect(content().string(containsString("<td>&nbsp;<a href=\"/challenge/6\">Challenge 6</a></td>")))
     102 + .andExpect(content().string(containsString("<td>&nbsp;<a href=\"/challenge/7\">Challenge 7</a></td>")));
     103 + }
     104 + 
     105 +}
     106 + 
  • ■ ■ ■ ■ ■ ■
    src/test/java/org/owasp/wrongsecrets/ChallengesControllerCTFModeWithPresetK8sValuesTest.java
     1 +package org.owasp.wrongsecrets;
     2 + 
     3 +import org.junit.jupiter.api.Test;
     4 +import org.junit.jupiter.api.extension.ExtendWith;
     5 +import org.owasp.wrongsecrets.challenges.kubernetes.Challenge5;
     6 +import org.owasp.wrongsecrets.challenges.kubernetes.Challenge6;
     7 +import org.owasp.wrongsecrets.challenges.kubernetes.Challenge7;
     8 +import org.springframework.beans.factory.annotation.Autowired;
     9 +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
     10 +import org.springframework.boot.test.context.SpringBootTest;
     11 +import org.springframework.http.MediaType;
     12 +import org.springframework.test.context.junit.jupiter.SpringExtension;
     13 +import org.springframework.test.web.servlet.MockMvc;
     14 + 
     15 +import static org.hamcrest.Matchers.containsString;
     16 +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
     17 +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
     18 +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
     19 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
     20 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
     21 + 
     22 +@ExtendWith(SpringExtension.class)
     23 +@SpringBootTest(
     24 + properties = {"ctf_enabled=true", "ctf_key=randomtextforkey", "SPECIAL_K8S_SECRET=test5", "SPECIAL_SPECIAL_K8S_SECRET=test6", "vaultpassword=test7"},
     25 + classes = WrongSecretsApplication.class
     26 +)
     27 +@AutoConfigureMockMvc
     28 +class ChallengesControllerCTFModeWithPresetK8sValuesTest {
     29 + 
     30 + @Autowired
     31 + private MockMvc mvc;
     32 + 
     33 + 
     34 + @Test
     35 + void shouldNotSpoilWhenInCTFMode() throws Exception {
     36 + mvc.perform(get("/spoil-5"))
     37 + .andExpect(status().isOk())
     38 + .andExpect(content().string(containsString("Spoils are disabled in CTF mode")));
     39 + 
     40 + }
     41 + 
     42 + @Test
     43 + void shouldShowFlagWhenRespondingWithSuccessInCTFModeChallenge5() throws Exception {
     44 + var spoil = new Challenge5(new InMemoryScoreCard(1), "test5").spoiler().solution();
     45 + mvc.perform(post("/challenge/5")
     46 + .contentType(MediaType.APPLICATION_FORM_URLENCODED)
     47 + .param("solution", spoil)
     48 + .param("action", "submit")
     49 + .with(csrf()))
     50 + .andExpect(status().isOk())
     51 + .andExpect(content().string(containsString("26d5e409100ca8dc3bd2dba115b81f5b7889fbbd")));
     52 + }
     53 + 
     54 + @Test
     55 + void shouldShowFlagWhenRespondingWithSuccessInCTFModeChallenge6() throws Exception {
     56 + var spoil = new Challenge6(new InMemoryScoreCard(1), "test6").spoiler().solution();
     57 + mvc.perform(post("/challenge/6")
     58 + .contentType(MediaType.APPLICATION_FORM_URLENCODED)
     59 + .param("solution", spoil)
     60 + .param("action", "submit")
     61 + .with(csrf()))
     62 + .andExpect(status().isOk())
     63 + .andExpect(content().string(containsString("18af49a1b18359e0bf9b9a0")));
     64 + }
     65 + 
     66 + @Test
     67 + void shouldShowFlagWhenRespondingWithSuccessInCTFModeChallenge7() throws Exception {
     68 + var spoil = new Challenge7(new InMemoryScoreCard(1), null, "test7").spoiler().solution();
     69 + mvc.perform(post("/challenge/7")
     70 + .contentType(MediaType.APPLICATION_FORM_URLENCODED)
     71 + .param("solution", spoil)
     72 + .param("action", "submit")
     73 + .with(csrf()))
     74 + .andExpect(status().isOk())
     75 + .andExpect(content().string(containsString("881951b59ea4818c2")));
     76 + }
     77 + 
     78 + @Test
     79 + void shouldEnableK8sExercises() throws Exception{
     80 + mvc.perform(get("/"))
     81 + .andExpect(status().isOk())
     82 + .andExpect(content().string(containsString("<td>&nbsp;<a href=\"/challenge/5\">Challenge 5</a></td>")))
     83 + .andExpect(content().string(containsString("<td>&nbsp;<a href=\"/challenge/6\">Challenge 6</a></td>")))
     84 + .andExpect(content().string(containsString("<td>&nbsp;<a href=\"/challenge/7\">Challenge 7</a></td>")));
     85 + }
     86 + 
     87 +}
     88 + 
  • ■ ■ ■ ■ ■ ■
    src/test/java/org/owasp/wrongsecrets/ChallengesControllerTest.java
    skipped 42 lines
    43 43   when(challenge.solved(anyString())).thenReturn(false);
    44 44   
    45 45   this.mvc.perform(post("/challenge/1")
    46  - .param("solution", "wrong")
    47  - .param("action", "submit"))
    48  - .andExpect(status().isOk())
    49  - .andExpect(model().attributeDoesNotExist("answerCorrect"))
    50  - .andExpect(model().attributeExists("answerIncorrect"));
     46 + .param("solution", "wrong")
     47 + .param("action", "submit"))
     48 + .andExpect(status().isOk())
     49 + .andExpect(model().attributeDoesNotExist("answerCorrect"))
     50 + .andExpect(model().attributeExists("answerIncorrect"));
    51 51   this.mvc.perform(get("/challenge/1"));
    52 52   }
    53 53   
    skipped 1 lines
    55 55   void shouldReturnSpoiler() throws Exception {
    56 56   when(challenge.spoiler()).thenReturn(new Spoiler("solution"));
    57 57   this.mvc.perform(get("/spoil-1"))
    58  - .andExpect(status().isOk())
    59  - .andExpect(model().attribute("spoiler", new Spoiler("solution")));
     58 + .andExpect(status().isOk())
     59 + .andExpect(model().attribute("spoiler", new Spoiler("solution")));
    60 60   }
    61 61   
    62 62   @Test
    skipped 1 lines
    64 64   when(challenge.solved(anyString())).thenReturn(false);
    65 65   
    66 66   this.mvc.perform(post("/challenge/1")
    67  - .param("solution", "wrong")
    68  - .param("action", "submit"))
    69  - .andExpect(status().isOk())
    70  - .andExpect(model().attributeDoesNotExist("answerCorrect"))
    71  - .andExpect(model().attributeExists("answerIncorrect"));
     67 + .param("solution", "wrong")
     68 + .param("action", "submit"))
     69 + .andExpect(status().isOk())
     70 + .andExpect(model().attributeDoesNotExist("answerCorrect"))
     71 + .andExpect(model().attributeExists("answerIncorrect"));
    72 72   }
    73 73   
    74 74   @Test
    skipped 1 lines
    76 76   when(challenge.solved(anyString())).thenReturn(true);
    77 77   
    78 78   this.mvc.perform(post("/challenge/1")
    79  - .param("solution", "wrong")
    80  - .param("action", "submit"))
    81  - .andExpect(status().isOk())
    82  - .andExpect(model().attributeExists("answerCorrect"))
    83  - .andExpect(model().attributeDoesNotExist("answerIncorrect"));
     79 + .param("solution", "wrong")
     80 + .param("action", "submit"))
     81 + .andExpect(status().isOk())
     82 + .andExpect(model().attributeExists("answerCorrect"))
     83 + .andExpect(model().attributeDoesNotExist("answerIncorrect"));
    84 84   }
    85 85   
    86 86   @Test
    87  - void shouldReturnCompleteWhenAllItemsDone() throws Exception{
     87 + void shouldReturnCompleteWhenAllItemsDone() throws Exception {
    88 88   when(challenge.solved(anyString())).thenReturn(true);
    89 89   this.mvc.perform(post("/challenge/1")
    90 90   .param("solution", "wrong")
    skipped 2 lines
    93 93   .andExpect(model().attributeExists("answerCorrect"))
    94 94   .andExpect(model().attributeExists("allCompleted"));
    95 95   }
     96 + 
    96 97  }
    97 98   
  • ■ ■ ■ ■ ■
    src/test/java/org/owasp/wrongsecrets/InMemoryScoreCardTest.java
    skipped 6 lines
    7 7  import org.mockito.junit.jupiter.MockitoExtension;
    8 8  import org.owasp.wrongsecrets.challenges.Challenge;
    9 9   
     10 +import static org.mockito.ArgumentMatchers.anyString;
     11 +import static org.mockito.Mockito.when;
     12 + 
    10 13  @ExtendWith(MockitoExtension.class)
    11 14  class InMemoryScoreCardTest {
    12 15   
    skipped 5 lines
    18 21   
    19 22   @Test
    20 23   void whenOneChallengeSolvedPointsShouldBeCalculatedCorrectly() {
     24 + when(challenge1.difficulty()).thenReturn(2);
    21 25   var scoring = new InMemoryScoreCard(2);
    22 26   scoring.completeChallenge(challenge1);
    23 27   
    24  - Assertions.assertThat(scoring.getTotalReceivedPoints()).isEqualTo(50);
     28 + Assertions.assertThat(scoring.getTotalReceivedPoints()).isEqualTo(250);
    25 29   }
    26 30   
    27 31   @Test
    28 32   void solvingAllChallengesShouldCalculateMaxPoints() {
     33 + when(challenge1.difficulty()).thenReturn(1);
     34 + when(challenge2.difficulty()).thenReturn(3);
    29 35   var scoring = new InMemoryScoreCard(2);
    30 36   scoring.completeChallenge(challenge1);
    31 37   scoring.completeChallenge(challenge2);
    32 38   
    33  - Assertions.assertThat(scoring.getTotalReceivedPoints()).isEqualTo(100);
     39 + Assertions.assertThat(scoring.getTotalReceivedPoints()).isEqualTo(550);
    34 40   }
    35 41   
    36 42  }
    skipped 1 lines
  • ■ ■ ■ ■ ■ ■
    src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge22Test.java
     1 +package org.owasp.wrongsecrets.challenges.docker;
     2 + 
     3 +import org.assertj.core.api.Assertions;
     4 +import org.junit.jupiter.api.Test;
     5 +import org.junit.jupiter.api.extension.ExtendWith;
     6 +import org.mockito.Mock;
     7 +import org.mockito.junit.jupiter.MockitoExtension;
     8 +import org.owasp.wrongsecrets.ScoreCard;
     9 +import org.owasp.wrongsecrets.challenges.Spoiler;
     10 + 
     11 +@ExtendWith(MockitoExtension.class)
     12 +class Challenge22Test {
     13 + 
     14 + @Mock
     15 + private ScoreCard scoreCard;
     16 + 
     17 + @Test
     18 + void spoilerShouldNotCrash() {
     19 + var challenge = new Challenge22(scoreCard);
     20 + 
     21 + Assertions.assertThat(challenge.spoiler()).isNotEqualTo(new Spoiler(BinaryExecutionHelper.ERROR_EXECUTION));
     22 + Assertions.assertThat(challenge.answerCorrect(challenge.spoiler().solution())).isTrue();
     23 + }
     24 + 
     25 +}
     26 + 
  • ■ ■ ■ ■ ■ ■
    src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge23Test.java
     1 +package org.owasp.wrongsecrets.challenges.docker;
     2 + 
     3 +import org.assertj.core.api.Assertions;
     4 +import org.junit.jupiter.api.Test;
     5 +import org.junit.jupiter.api.extension.ExtendWith;
     6 +import org.mockito.Mock;
     7 +import org.mockito.Mockito;
     8 +import org.mockito.junit.jupiter.MockitoExtension;
     9 +import org.owasp.wrongsecrets.ScoreCard;
     10 +import org.owasp.wrongsecrets.challenges.Spoiler;
     11 + 
     12 +@ExtendWith(MockitoExtension.class)
     13 +class Challenge23Test {
     14 + 
     15 + @Mock
     16 + private ScoreCard scoreCard;
     17 + 
     18 + 
     19 + @Test
     20 + void rightAnswerShouldSolveChallenge() {
     21 + var challenge = new Challenge23(scoreCard);
     22 + 
     23 + Assertions.assertThat(challenge.solved(challenge.spoiler().solution())).isTrue();
     24 + Mockito.verify(scoreCard).completeChallenge(challenge);
     25 + }
     26 + 
     27 + 
     28 + 
     29 +}
     30 + 
  • ■ ■ ■ ■ ■ ■
    src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge24Test.java
    1  -package org.owasp.wrongsecrets.challenges.docker;
    2  - 
    3  -import org.assertj.core.api.Assertions;
    4  -import org.junit.jupiter.api.Test;
    5  -import org.junit.jupiter.api.extension.ExtendWith;
    6  -import org.mockito.Mock;
    7  -import org.mockito.Mockito;
    8  -import org.mockito.junit.jupiter.MockitoExtension;
    9  -import org.owasp.wrongsecrets.ScoreCard;
    10  -import org.owasp.wrongsecrets.challenges.Spoiler;
    11  - 
    12  -@ExtendWith(MockitoExtension.class)
    13  -class Challenge24Test {
    14  - 
    15  - @Mock
    16  - private ScoreCard scoreCard;
    17  - 
    18  - @Test
    19  - void spoilerShouldRevealAnswer() {
    20  - var challenge = new Challenge4(scoreCard, "test");
    21  - 
    22  - Assertions.assertThat(challenge.spoiler()).isEqualTo(new Spoiler("test"));
    23  - }
    24  - 
    25  - @Test
    26  - void rightAnswerShouldSolveChallenge() {
    27  - var challenge = new Challenge4(scoreCard, "test");
    28  - 
    29  - Assertions.assertThat(challenge.solved("test")).isTrue();
    30  - Mockito.verify(scoreCard).completeChallenge(challenge);
    31  - }
    32  - 
    33  - @Test
    34  - void incorrectAnswerShouldNotSolveChallenge() {
    35  - var challenge = new Challenge4(scoreCard, "test");
    36  - 
    37  - Assertions.assertThat(challenge.solved("wrong answer")).isFalse();
    38  - Mockito.verifyNoInteractions(scoreCard);
    39  - }
    40  - 
    41  -}
    42  - 
Please wait...
Page is in error, reload to recover