Skip to content
  •  
  •  
  •  
37 changes: 37 additions & 0 deletions src/main/java/org/owasp/wrongsecrets/MvcConfiguration.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.owasp.wrongsecrets;

import java.util.List;
import java.util.Locale;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import nz.net.ultraq.thymeleaf.layoutdialect.LayoutDialect;
Expand All @@ -12,7 +14,11 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.thymeleaf.extras.springsecurity6.dialect.SpringSecurityDialect;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver;
Expand All @@ -26,8 +32,39 @@
@Slf4j
public class MvcConfiguration implements WebMvcConfigurer {

/** Supported locales for the language toggle. */
public static final List<Locale> SUPPORTED_LOCALES =
List.of(
Locale.ENGLISH,
Locale.of("nl"),
Locale.GERMAN,
Locale.of("es"),
Locale.FRENCH,
Locale.of("uk"));

private static final String UTF8 = "UTF-8";

/** Session-based locale resolver so the selected language persists across requests. */
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
sessionLocaleResolver.setDefaultLocale(Locale.ENGLISH);
return sessionLocaleResolver;
}

/** Interceptor that reads the {@code lang} request parameter and updates the session locale. */
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}

@Bean
public ITemplateResolver springThymeleafTemplateResolver(ApplicationContext applicationContext) {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
httpServletResponse.setHeader(
"Content-Security-Policy",
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self'"
+ " 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'self'; object-src"
+ " 'none'; base-uri 'self'");
+ " 'unsafe-inline'; img-src 'self' data:; connect-src https://api.github.com;"
+ " frame-ancestors 'self'; object-src 'none'; base-uri 'self'");
}
chain.doFilter(request, response);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,28 @@
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.Getter;
import org.apache.commons.io.FilenameUtils;
import org.owasp.wrongsecrets.RuntimeEnvironment;
import org.owasp.wrongsecrets.ScoreCard;
import org.owasp.wrongsecrets.definitions.ChallengeDefinition;
import org.owasp.wrongsecrets.definitions.Difficulty;
import org.owasp.wrongsecrets.definitions.Environment;
import org.owasp.wrongsecrets.definitions.Navigator;
import org.owasp.wrongsecrets.definitions.Sources.ChallengeSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.io.ClassPathResource;

/** Wrapper class to move logic from Thymeleaf to keep logic in code instead of the html file. */
@Getter
public class ChallengeUI {

/**
* Cache of classpath file existence results so that we only hit the filesystem once per unique
* locale-specific filename across all requests.
*/
private static final ConcurrentHashMap<String, Boolean> LOCALIZED_FILE_EXISTS_CACHE =
new ConcurrentHashMap<>();

private static final Map<DifficultyKey, DifficultyUI> DIFFICULTY_UI_CACHE =
new ConcurrentHashMap<>();

Expand Down Expand Up @@ -142,30 +152,62 @@ private String documentation(Function<ChallengeSource, String> extractor) {
}

/**
* Returns filename of the explanation of the challenge.
* Resolves a locale-specific filename if available, falling back to the default (English) file.
* Checks both the raw .adoc source (used in dev mode) and the pre-compiled .html (used in
* production). If neither locale-specific file exists, the original filename is returned so the
* English content is shown. Results are cached to avoid repeated classpath lookups. Must be
* called at render time as {@link ChallengeUI} instances are cached across requests.
*
* @param defaultFileName the default (English) file path, e.g. "explanations/challenge1.adoc"
* @return locale-specific filename if it exists, otherwise the default filename
*/
private String localizeFileName(String defaultFileName) {
if (defaultFileName == null || defaultFileName.isEmpty()) {
return defaultFileName;
}
var locale = LocaleContextHolder.getLocale();
if (locale.getLanguage().isEmpty() || "en".equals(locale.getLanguage())) {
return defaultFileName;
}
String ext = FilenameUtils.getExtension(defaultFileName);
String base = FilenameUtils.removeExtension(defaultFileName);
String suffix = "_" + locale.getLanguage();
String localizedAdoc = base + suffix + (ext.isEmpty() ? "" : "." + ext);
String localizedHtml = base + suffix + ".html";
boolean exists =
LOCALIZED_FILE_EXISTS_CACHE.computeIfAbsent(
localizedAdoc,
key ->
new ClassPathResource(key).exists()
|| new ClassPathResource(localizedHtml).exists());
return exists ? localizedAdoc : defaultFileName;
}

/**
* Returns filename of the explanation of the challenge, locale-aware with English fallback.
*
* @return String with filename.
*/
public String getExplanation() {
return documentation(s -> s.explanation().fileName());
return localizeFileName(documentation(s -> s.explanation().fileName()));
}

/**
* Returns filename of the hints for the challenge.
* Returns filename of the hints for the challenge, locale-aware with English fallback.
*
* @return String with filename.
*/
public String getHint() {
return documentation(s -> s.hint().fileName());
return localizeFileName(documentation(s -> s.hint().fileName()));
}

/**
* Returns filename of the reasons of the challenge.
* Returns filename of the reasons of the challenge, locale-aware with English fallback.
*
* @return String with filename.
*/
public String getReason() {
return documentation(s -> s.reason().fileName());
return localizeFileName(documentation(s -> s.reason().fileName()));
}

/**
Expand Down
22 changes: 22 additions & 0 deletions src/main/resources/explanations/challenge0_de.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
=== Eröffnungsherausforderung

Willkommen bei OWASP WrongSecrets – der ersten Herausforderung!

In dieser Challenge erklären wir euch alles, was ihr zum Spielen von OWASP WrongSecrets wissen müsst.

Bei jeder Challenge geht es darum, ein Geheimnis zu finden, das nicht gut versteckt und/oder konfiguriert wurde in unserem https://github.com/OWASP/wrongsecrets[Anwendungscode], https://hub.docker.com/r/jeroenwillemsen/wrongsecrets[Docker-Container] oder in einem der zugehörigen Teile des https://github.com/OWASP/wrongsecrets#table-of-contents[System].

Sobald du das Geheimnis gefunden hast, kannst du es in das Feld unten eingeben und auf „Absenden“ klicken. Mit dem Button „Löschen“ wird das Eingabefeld geleert.
Möchtest du die Herausforderung erneut spielen? Drücke die „Zurücksetzen“-Taste.

Die richtige Antwort unten lautet `The first answer`. Kopiere sie in das Feld und klicke auf „Absenden“.

Viel Spaß bei den schwierigeren Herausforderungen ;-).

Hinweis: Für einige der folgenden Herausforderungen brauchst du zusätzliche Tools. Dafür brauchst du einen Computer, auf dem alle Tools installiert sind. Du möchtest diese nicht selbst installieren? Dann kannst du einen Container verwenden, um alle Tools gleichzeitig nutzen zu können.

[source, shell]
docker run -p 3000:3000 -v /var/run/docker.sock:/var/run/docker.sock jeroenwillemsen/wrongsecrets-desktop:latest


Rufe anschließend in deinem Browser http://localhost:3000 auf, um ein Webtop mit allen benötigten Tools zu finden.
22 changes: 22 additions & 0 deletions src/main/resources/explanations/challenge0_es.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
=== Desafío de apertura

¡Bienvenidos a OWASP WrongSecrets y a su primer desafío!

En este desafío, te explicamos todo lo que necesitas saber para jugar a OWASP WrongSecrets.

Cada desafío consiste en encontrar un secreto que no haya sido bien oculto y/o configurado dentro de nuestro https://github.com/OWASP/wrongsecrets[código de la aplicación], https://hub.docker.com/r/jeroenwillemsen/wrongsecrets[contenedor Docker] o en una de las partes relacionadas de https://github.com/OWASP/wrongsecrets#table-of-contents[sistema].

Una vez que encuentres el secreto, puedes escribirlo en el recuadro de abajo y pulsar "Enviar". El botón "Borrar" borrará el contenido del cuadro.
¿Quieres volver a jugar el desafío? Pulsa el botón "Reiniciar".

La respuesta correcta que aparece a continuación es `The first answer`. Cópiela en el recuadro y pulse «Enviar».

¡Diviértete mucho con los desafíos más difíciles ;-)!

Nota: algunos de los desafíos que se avecinan requerirán que utilice herramientas adicionales para llegar a la solución. Para ello, necesita un ordenador con todas las herramientas instaladas. ¿No quiere instalarlas usted mismo? Puede utilizar un contenedor para tenerlas todas disponibles a la vez mediante el uso de

[source, shell]
docker run -p 3000:3000 -v /var/run/docker.sock:/var/run/docker.sock jeroenwillemsen/wrongsecrets-desktop:latest


Luego, en su navegador vaya a http://localhost:3000[http://localhost:3000] para encontrar un escritorio web esperándolo con todas las herramientas necesarias.
22 changes: 22 additions & 0 deletions src/main/resources/explanations/challenge0_fr.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
=== Défi d'ouverture

Bienvenue dans OWASP WrongSecrets, son défi d'ouverture !

Dans ce défi, nous vous expliquons tout ce que vous devez savoir pour jouer à OWASP WrongSecrets.

Chaque défi consiste à trouver un secret qui n'a pas été bien caché et/ou configuré dans notre https://github.com/OWASP/wrongsecrets[code d'application], https://hub.docker.com/r/jeroenwillemsen/wrongsecrets[conteneur Docker], ou dans l'une des parties connexes du https://github.com/OWASP/wrongsecrets#table-of-contents[système].

Une fois le secret trouvé, saisissez-le dans la case ci-dessous et appuyez sur « Envoyer ». Le bouton « Effacer » videra le champ de saisie.
Envie de retenter le défi ? Appuyez sur le bouton « Réinitialiser ».

La bonne réponse ci-dessous est `The first answer`. Copiez-la dans la case et appuyez sur « Soumettre ».

Amuse-toi bien avec les défis les plus difficiles ;-).

Remarque : certains des défis à venir nécessiteront l’utilisation d’outils supplémentaires pour trouver la solution. Pour cela, vous aurez besoin d’un ordinateur sur lequel tous les outils sont installés. Vous ne souhaitez pas les installer vous-même ? Vous pouvez utiliser un conteneur pour les avoir tous à disposition simultanément.

[source, shell]
docker run -p 3000:3000 -v /var/run/docker.sock:/var/run/docker.sock jeroenwillemsen/wrongsecrets-desktop:latest


Ensuite, dans votre navigateur, rendez-vous sur http://localhost:3000[http://localhost:3000] pour trouver un espace web qui vous attend avec tous les outils nécessaires.
1 change: 1 addition & 0 deletions src/main/resources/explanations/challenge0_hint_de.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Wenn du auf die Schaltfläche „Hinweise anzeigen“ klickst, geben wir dir Hinweise, wie du diese spezifische Herausforderung lösen kannst.
1 change: 1 addition & 0 deletions src/main/resources/explanations/challenge0_hint_es.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Al pulsar el botón "Mostrar pistas", te daremos pistas sobre cómo resolver ese desafío específico.
1 change: 1 addition & 0 deletions src/main/resources/explanations/challenge0_hint_fr.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Lorsque vous cliquez sur le bouton « Afficher les indices », nous vous expliquerons comment résoudre ce défi spécifique.
1 change: 1 addition & 0 deletions src/main/resources/explanations/challenge0_hint_nl.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Wanneer je op de knop ‘Hints weergeven’ drukt, geven we je hints over hoe je die specifieke uitdaging kunt oplossen.
1 change: 1 addition & 0 deletions src/main/resources/explanations/challenge0_hint_uk.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Коли ви натиснете кнопку «Показати підказки», ми надамо вам підказки щодо вирішення цього конкретного завдання.
22 changes: 22 additions & 0 deletions src/main/resources/explanations/challenge0_nl.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
=== Eerste uitdaging

Welkom bij OWASP WrongSecrets, de eerste uitdaging!

In deze uitdaging leggen we je alles uit wat je moet weten om OWASP WrongSecrets te spelen.

Elke uitdaging gaat over het vinden van een geheim dat niet goed verborgen en/of geconfigureerd is in onze https://github.com/OWASP/wrongsecrets[applicatiecode], https://hub.docker.com/r/jeroenwillemsen/wrongsecrets[Docker-container] of in een van de gerelateerde delen van de https://github.com/OWASP/wrongsecrets#table-of-contents[systeem].

Zodra je het geheim hebt gevonden, kun je het in het onderstaande vak plaatsen en op "Antwoord verzenden" klikken. Met de knop "Wissen" wordt het invoervak opgeschoond.
Wil je de uitdaging nog een keer spelen? Druk op "Uitdaging resetten".

Het juiste antwoord hieronder is `The first answer` . Kopieer het in het vak en druk op "Antwoord verzenden".

Veel plezier met de moeilijkere uitdagingen ;-).

Let op: voor sommige uitdagingen die voor ons liggen, heb je extra hulpmiddelen nodig om tot de oplossing te komen. Hiervoor heb je een computer nodig waarop alle tools zijn geïnstalleerd. Wil je ze niet zelf installeren? Je kunt een container gebruiken om ze allemaal tegelijk tot je beschikking te hebben

[source, shell]
docker run -p 3000:3000 -v /var/run/docker.sock:/var/run/docker.sock jeroenwillemsen/wrongsecrets-desktop:latest


Ga vervolgens in je browser naar http://localhost:3000[http://localhost:3000] om een webtop te vinden die op je wacht met alle benodigde tools.
5 changes: 5 additions & 0 deletions src/main/resources/explanations/challenge0_reason_de.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*Warum tun wir das?*

Wir hoffen, dass dir dieses Projekt Spaß bei der Suche nach Geheimnissen bereitet. Gleichzeitig möchten wir dir zeigen, welche Fehler andere im Umgang mit Geheimnissen gemacht haben, damit du diese nicht wiederholst.

Wusstest du, dass wir all diese Herausforderungen in freier Wildbahn entdeckt haben? Sie können daher eine große Hilfe sein, wenn du mehr Kopfgeldjagden betreiben möchtest.
5 changes: 5 additions & 0 deletions src/main/resources/explanations/challenge0_reason_es.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*¿Por qué estamos haciendo esto?*

Con este proyecto, esperamos que te diviertas buscando secretos. Al mismo tiempo, esperamos que aprendas de los errores que otros han cometido al gestionar secretos, para que no los repitas.

¿Sabías que hemos detectado todos estos desafíos en la práctica? Por lo tanto, pueden ser de gran ayuda si quieres dedicarte a la caza de recompensas.
5 changes: 5 additions & 0 deletions src/main/resources/explanations/challenge0_reason_fr.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*Pourquoi faisons-nous cela ?*

Avec ce projet, nous espérons que vous prendrez plaisir à partir à la recherche de secrets. Parallèlement, nous espérons que vous tirerez des leçons des erreurs commises par d'autres en matière de gestion des secrets, afin de ne pas les reproduire.

Saviez-vous que nous avons repéré tous ces défis en situation réelle ? Ils peuvent donc vous être d’une grande aide si vous souhaitez vous adonner davantage à la chasse aux primes.
5 changes: 5 additions & 0 deletions src/main/resources/explanations/challenge0_reason_nl.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
=== Waarom?

Wist je dat iedere uitdaging in deze app een voorbeeld uit de praktijk is? Ze kunnen daarom een grote hulp zijn als je meer aan bug bounty wilt doen.

In de praktijk zien we vaak dat organisaties per ongeluk geheimen vastleggen in code repositories of Docker containers. Deze uitdaging helpt je begrijpen hoe je dergelijke fouten kunt opsporen en voorkomen.
5 changes: 5 additions & 0 deletions src/main/resources/explanations/challenge0_reason_uk.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*Чому ми це робимо?*

Сподіваємося, що завдяки цьому проєкту ви отримаєте задоволення від пошуку секретів. Водночас, ми сподіваємося, що ви дізнаєтеся про помилки інших людей в управлінні секретами, щоб не робити таких самих помилок.

Чи знаєте ви, що ми помітили всі ці виклики в дикій природі? Тому вони можуть бути дуже корисними, якщо ви хочете більше полювати за головами.
22 changes: 22 additions & 0 deletions src/main/resources/explanations/challenge0_uk.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
=== Відкриття змагання

Ласкаво просимо до вступного випробування OWASP WrongSecrets!

У цьому челенджі ми пояснимо вам усе, що потрібно знати, щоб грати в OWASP WrongSecrets.

Кожен виклик полягає у пошуку секрету, який не був добре прихований та/або налаштований всередині нашого https://github.com/OWASP/wrongsecrets[код програми], https://hub.docker.com/r/jeroenwillemsen/wrongsecrets[контейнер Docker] або в одній із пов'язаних частин https://github.com/OWASP/wrongsecrets#table-of-contents[системи].

Щойно ви знайдете секретний код, ви можете ввести його в поле нижче та натиснути «Надіслати». Кнопка «Очистити» очистить поле введення.
Хочете зіграти в челендж ще раз? Натисніть кнопку «Скинути».

Правильна відповідь нижче — `The first answer`. Скопіюйте її в поле та натисніть «Надіслати».

Отримайте масу задоволення від складніших завдань ;-).

Примітка: деякі з майбутніх завдань вимагатимуть використання додаткових інструментів для пошуку рішення. Для цього вам знадобиться комп’ютер з усіма встановленими інструментами. Не хочете встановлювати їх самостійно? Ви можете скористатися контейнером, щоб мати їх усі доступними одночасно, за допомогою

[source, shell]
docker run -p 3000:3000 -v /var/run/docker.sock:/var/run/docker.sock jeroenwillemsen/wrongsecrets-desktop:latest


Потім у вашому браузері перейдіть за адресою http://localhost:3000[http://localhost:3000], щоб знайти веб-сторінку з усіма необхідними інструментами, яка чекає на вас.
3 changes: 3 additions & 0 deletions src/main/resources/explanations/challenge10-azure_de.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
=== Azure Key Vault Teil 2

Das Geheimnis ist nun randomisiert und wird direkt im Azure Key Vault gespeichert. Wir binden es aber weiterhin über den CSI-Treiber https://secrets-store-csi-driver.sigs.k8s.io für https://azure.github.io/secrets-store-csi-driver-provider-azure/ in den K8s-Pod ein. Kannst du darauf zugreifen?
3 changes: 3 additions & 0 deletions src/main/resources/explanations/challenge10-azure_es.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
=== Azure Key Vault parte 2

El secreto ahora está aleatorizado y almacenado directamente en Azure Key Vault. Sin embargo, seguimos montándolo en el pod de K8s a través del controlador CSI https://secrets-store-csi-driver.sigs.k8s.io para https://azure.github.io/secrets-store-csi-driver-provider-azure/... ¿Puedes acceder a él?
3 changes: 3 additions & 0 deletions src/main/resources/explanations/challenge10-azure_fr.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
=== Azure Key Vault partie 2

Le secret est désormais aléatoire et stocké directement dans Azure Key Vault. Nous le montons toujours sur le pod Kubernetes via le pilote CSI (https://secrets-store-csi-driver.sigs.k8s.io) pour Azure (https://azure.github.io/secrets-store-csi-driver-provider-azure/). Pouvez-vous y accéder ?
3 changes: 3 additions & 0 deletions src/main/resources/explanations/challenge10-azure_nl.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
=== Azure Key Vault deel 2

Het geheim is nu gerandomiseerd en direct opgeslagen in de Azure Key Vault. We koppelen het nog steeds aan de K8s-pod via de https://secrets-store-csi-driver.sigs.k8s.io[CSI-driver] voor https://azure.github.io/secrets-store-csi-driver-provider-azure/[Azure]... Kun je er toegang toe krijgen?
Loading
Loading