diff --git a/src/main/java/org/owasp/wrongsecrets/AuditConfiguration.java b/src/main/java/org/owasp/wrongsecrets/AuditConfiguration.java new file mode 100644 index 000000000..577ac450e --- /dev/null +++ b/src/main/java/org/owasp/wrongsecrets/AuditConfiguration.java @@ -0,0 +1,27 @@ +package org.owasp.wrongsecrets; + +import groovy.util.logging.Slf4j; +import java.util.Map; +import java.util.UUID; +import lombok.Getter; +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.boot.actuate.audit.InMemoryAuditEventRepository; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Getter +@Configuration +@Slf4j +public class AuditConfiguration { + + private final String apiKey = UUID.randomUUID().toString(); + + @Bean + public InMemoryAuditEventRepository inMemoryAuditEventRepository() { + InMemoryAuditEventRepository repository = new InMemoryAuditEventRepository(); + AuditEvent auditEvent = + new AuditEvent("john.doe", "API_KEY_RECEIVED", Map.of("apiKey", apiKey)); + repository.add(auditEvent); + return repository; + } +} diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge42.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge42.java new file mode 100644 index 000000000..7c17dc8bb --- /dev/null +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge42.java @@ -0,0 +1,27 @@ +package org.owasp.wrongsecrets.challenges.docker; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.owasp.wrongsecrets.AuditConfiguration; +import org.owasp.wrongsecrets.challenges.Challenge; +import org.owasp.wrongsecrets.challenges.Spoiler; +import org.springframework.stereotype.Component; + +/** This is a challenge based on finding API Key in Spring Boot Actuator audit events */ +@Slf4j +@Component +@RequiredArgsConstructor +public class Challenge42 implements Challenge { + + private final AuditConfiguration auditConfiguration; + + @Override + public Spoiler spoiler() { + return new Spoiler(auditConfiguration.getApiKey()); + } + + @Override + public boolean answerCorrect(String answer) { + return auditConfiguration.getApiKey().equals(answer); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 90e2a7f58..a8aea1427 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -65,6 +65,7 @@ challenge41password=UEBzc3dvcmQxMjM= management.endpoint.health.probes.enabled=true management.health.livenessState.enabled=true management.health.readinessState.enabled=true +management.endpoints.web.exposure.include=auditevents #--- spring.config.activate.on-profile=kubernetes-vault wrongsecretvalue=wrongsecret diff --git a/src/main/resources/explanations/challenge42.adoc b/src/main/resources/explanations/challenge42.adoc new file mode 100644 index 000000000..63075e92f --- /dev/null +++ b/src/main/resources/explanations/challenge42.adoc @@ -0,0 +1,12 @@ +=== Spring Boot Actuator Audit Event + +The developers decided to leverage the power of Spring Boot Actuator +to monitor and audit their application. The project involved interfacing with various external APIs, +each requiring a unique key for authentication. The audit events, detailed and informative, seemed like +the perfect solution for monitoring the inner workings of their system. + +The team implemented a logging mechanism that included detailed audit events. +Unbeknownst to them, these logs contained traces of the sacred API key hidden within +the audit events. + +Can you find this API key? diff --git a/src/main/resources/explanations/challenge42_hint.adoc b/src/main/resources/explanations/challenge42_hint.adoc new file mode 100644 index 000000000..b0ba93e34 --- /dev/null +++ b/src/main/resources/explanations/challenge42_hint.adoc @@ -0,0 +1,7 @@ +This challenge can be solved using the following steps: + +1. Check available Actuator endpoints at "/actuator" + +2. Check audit events exposed at the "/actuator/auditevents" endpoint + +3. Find API_KEY_RECEIVED event with exposed secret diff --git a/src/main/resources/explanations/challenge42_reason.adoc b/src/main/resources/explanations/challenge42_reason.adoc new file mode 100644 index 000000000..c7b03d9a8 --- /dev/null +++ b/src/main/resources/explanations/challenge42_reason.adoc @@ -0,0 +1,6 @@ +*Why hiding API key in the audit events is not a good idea?* + +In a secure and well-architected system, protecting sensitive information such as API keys is crucial. +Audit events are significant in tracking and monitoring activities within an application. + +Ensure that API keys are not visible in plain text in the (audit) logs or any other output. diff --git a/src/main/resources/wrong-secrets-configuration.yaml b/src/main/resources/wrong-secrets-configuration.yaml index 428914147..f0fc7a417 100644 --- a/src/main/resources/wrong-secrets-configuration.yaml +++ b/src/main/resources/wrong-secrets-configuration.yaml @@ -676,3 +676,16 @@ configurations: category: *crypto ctf: enabled: true + + - name: Challenge 42 + short-name: "challenge-42" + sources: + - class-name: "org.owasp.wrongsecrets.challenges.docker.Challenge42" + explanation: "explanations/challenge42.adoc" + hint: "explanations/challenge42_hint.adoc" + reason: "explanations/challenge42_reason.adoc" + environments: *docker_envs + difficulty: *normal + category: *logging + ctf: + enabled: true diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge42Test.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge42Test.java new file mode 100644 index 000000000..161a9561c --- /dev/null +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge42Test.java @@ -0,0 +1,41 @@ +package org.owasp.wrongsecrets.challenges.docker; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.owasp.wrongsecrets.AuditConfiguration; + +@ExtendWith(MockitoExtension.class) +public class Challenge42Test { + + @Mock private AuditConfiguration auditConfiguration; + + @BeforeEach + void init() { + when(auditConfiguration.getApiKey()).thenReturn("qemGhPXJjmipa9O7cYBJnuO79BQg"); + } + + @Test + void spoilerShouldGiveAnswer() { + var challenge = new Challenge42(auditConfiguration); + var solution = challenge.spoiler().solution(); + assertEquals("qemGhPXJjmipa9O7cYBJnuO79BQg", solution); + } + + @Test + void rightAnswerShouldSolveChallenge() { + var challenge = new Challenge42(auditConfiguration); + assertTrue(challenge.answerCorrect("qemGhPXJjmipa9O7cYBJnuO79BQg")); + } + + @Test + void incorrectAnswerShouldNotSolveChallenge() { + var challenge = new Challenge42(auditConfiguration); + assertFalse(challenge.answerCorrect("wrong answer")); + } +}