Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#684): add DAST with ZAP #705

Merged
merged 11 commits into from
Mar 15, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/dast-zap-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: DAST with ZAP

on:
pull_request:
branches: [master]
workflow_dispatch:

permissions:
contents: read

jobs:
test-dast:
name: DAST test with ZAP
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 19
uses: actions/setup-java@v3
with:
java-version: "19"
distribution: "temurin"
- name: Clean install
run: ./mvnw clean install
- name: Start wrongsecrets
run: nohup ./mvnw spring-boot:run -Dspring-boot.run.profiles=without-vault &
- name: ZAP Scan
uses: zaproxy/[email protected]
with:
allow_issue_writing: false
docker_name: "owasp/zap2docker-stable"
target: "http://localhost:8080"
rules_file_name: .zap/rule-config.tsv
fail_action: true
11 changes: 11 additions & 0 deletions .zap/rule-config.tsv
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
10027 IGNORE (Information Disclosure - Suspicious Comments)
10031 IGNORE (Informational User Controllable HTML Element Attribute (Potential XSS))
10049 IGNORE (Non-Storable Content)
10054 IGNORE (Cookie without SameSite Attribute)
10055 IGNORE (CSP: Wildcard Directive)
10055 IGNORE (CSP: script-src unsafe-inline)
10055 IGNORE (CSP: style-src unsafe-inline)
10063 IGNORE (Permissions Policy Header Not Set)
10109 IGNORE (Modern Web Application)
10110 IGNORE (Dangerous JS Functions)
90033 IGNORE (Loosely Scoped Cookie)
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Welcome to the OWASP WrongSecrets p0wnable app. With this app, we have packed va
secrets. These can help you to realize whether your secret management is ok. The challenge is to find all the different
secrets by means of various tools and techniques.

Can you solve all the 27 challenges?
Can you solve all the 28 challenges?
![screenshotOfChallenge1](/images/screenshot.png)

<a href="https://github.com/vshymanskyy/StandWithUkraine/blob/main/README.md"><img src="https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-no-action.svg" /></a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static void main(String[] args) {
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public InMemoryScoreCard scoreCard() {
return new InMemoryScoreCard(27);
return new InMemoryScoreCard(28);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
import org.owasp.wrongsecrets.challenges.docker.Challenge0;
import org.owasp.wrongsecrets.challenges.docker.Challenge8;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.security.crypto.codec.Hex;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.server.ResponseStatusException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
Expand Down Expand Up @@ -53,6 +55,14 @@ public ChallengesController(ScoreCard scoreCard, List<ChallengeUI> challenges, R
this.runtimeEnvironment = runtimeEnvironment;
}

private boolean checkId(int id) {
// If the id is either negative or larger than the amount of challenges, return false.
if (id < 0 || id >= challenges.size()) {
return false;
}
return true;
}

@GetMapping
public String explanation(@PathVariable Integer id) {
return challenges.get(id).getExplanation();
Expand All @@ -71,6 +81,11 @@ public String spoiler(Model model, @PathVariable Integer id) {

@GetMapping("/challenge/{id}")
public String challenge(Model model, @PathVariable Integer id) {
if (!checkId(id)) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "challenge not found"
);
}
var challenge = challenges.get(id);

model.addAttribute("challengeForm", new ChallengeForm(""));
Expand Down Expand Up @@ -98,6 +113,11 @@ public String challenge(Model model, @PathVariable Integer id) {

@PostMapping(value = "/challenge/{id}", params = "action=reset")
public String reset(@ModelAttribute ChallengeForm challengeForm, @PathVariable Integer id, Model model) {
if (!checkId(id)) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "challenge not found"
);
}
var challenge = challenges.get(id);
scoreCard.reset(challenge.getChallenge());

Expand All @@ -110,6 +130,11 @@ public String reset(@ModelAttribute ChallengeForm challengeForm, @PathVariable I

@PostMapping(value = "/challenge/{id}", params = "action=submit")
public String postController(@ModelAttribute ChallengeForm challengeForm, Model model, @PathVariable Integer id) {
if (!checkId(id)) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "challenge not found"
);
}
var challenge = challenges.get(id);

if (!challenge.isChallengeEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,5 @@ void shouldGetListOfChallenges() {
}

/*
"manageUrl" : "url", "memo" : "memo", "channel" : "channel", "time" : "time", "additionalData" : { "srcIp" : "soruce", "useragent" : "agent", "referer" : "referer", "location" : "locatoin"}}
"manageUrl" : "url", "memo" : "memo", "channel" : "channel", "time" : "time", "additionalData" : { "srcIp" : "source", "useragent" : "agent", "referer" : "referer", "location" : "location"}}
*/
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ void shouldReturnSpoiler() throws Exception {
.andExpect(model().attribute("spoiler", new Spoiler("solution")));
}

@Test
void shouldReturnNotFound() throws Exception {
// when(challenge.solved(anyString())).thenReturn(false);
// when(challenge.supportedRuntimeEnvironments()).thenReturn(List.of(Environment.DOCKER));
this.mvc.perform(get("/challenge/-1"))
.andExpect(status().isNotFound());
this.mvc.perform(get("/challenge/99999999"))
.andExpect(status().isNotFound());
}

@Test
void shouldReturnIncorrectAnswerMessageWhenChallengeIsNotSolved() throws Exception {
when(challenge.solved(anyString())).thenReturn(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class CanaryCallbackTest {
@Test
void shouldAcceptPostOfMessage() {
var restTemplate = builder.build();
var additonalCanaryData = new AdditionalCanaryData("soruce", "agent", "referer", "locatoin");
var additonalCanaryData = new AdditionalCanaryData("source", "agent", "referer", "location");
CanaryToken token = new CanaryToken("url", "memo", "channel", "time", additonalCanaryData);

var callbackAdress = "http://localhost:" + port + "/canaries/tokencallback";
Expand All @@ -37,5 +37,5 @@ void shouldAcceptPostOfMessage() {
}

/*
"manageUrl" : "url", "memo" : "memo", "channel" : "channel", "time" : "time", "additionalData" : { "srcIp" : "soruce", "useragent" : "agent", "referer" : "referer", "location" : "locatoin"}}
"manageUrl" : "url", "memo" : "memo", "channel" : "channel", "time" : "time", "additionalData" : { "srcIp" : "source", "useragent" : "agent", "referer" : "referer", "location" : "location"}}
*/