diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/Flag.java b/src/main/java/org/owasp/webgoat/lessons/challenges/Flag.java index d78186585..483b738fa 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/Flag.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/Flag.java @@ -1,89 +1,13 @@ -/* - * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ - * - * Copyright (c) 2002 - 2019 Bruce Mayhew - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if - * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Getting Source ============== - * - * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. - */ - package org.owasp.webgoat.lessons.challenges; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.stream.IntStream; -import javax.annotation.PostConstruct; -import lombok.AllArgsConstructor; -import lombok.Getter; -import org.owasp.webgoat.container.assignments.AssignmentEndpoint; -import org.owasp.webgoat.container.assignments.AttackResult; -import org.owasp.webgoat.container.session.WebSession; -import org.owasp.webgoat.container.users.UserTracker; -import org.owasp.webgoat.container.users.UserTrackerRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; +public record Flag(int number, String answer) { -/** - * @author nbaars - * @since 3/23/17. - */ -@RestController -public class Flag extends AssignmentEndpoint { - - public static final Map FLAGS = new HashMap<>(); - @Autowired private UserTrackerRepository userTrackerRepository; - @Autowired private WebSession webSession; - - @AllArgsConstructor - private class FlagPosted { - @Getter private boolean lessonCompleted; + public boolean isCorrect(String flag) { + return answer.equals(flag); } - @PostConstruct - public void initFlags() { - IntStream.range(1, 10).forEach(i -> FLAGS.put(i, UUID.randomUUID().toString())); - } - - @RequestMapping( - path = "/challenge/flag", - method = RequestMethod.POST, - produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody - public AttackResult postFlag(@RequestParam String flag) { - UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); - String currentChallenge = webSession.getCurrentLesson().getName(); - int challengeNumber = - Integer.valueOf( - currentChallenge.substring(currentChallenge.length() - 1, currentChallenge.length())); - String expectedFlag = FLAGS.get(challengeNumber); - final AttackResult attackResult; - if (expectedFlag.equals(flag)) { - userTracker.assignmentSolved(webSession.getCurrentLesson(), "Assignment" + challengeNumber); - attackResult = success(this).feedback("challenge.flag.correct").build(); - } else { - userTracker.assignmentFailed(webSession.getCurrentLesson()); - attackResult = failed(this).feedback("challenge.flag.incorrect").build(); - } - userTrackerRepository.save(userTracker); - return attackResult; + @Override + public String toString() { + return answer; } } diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/FlagController.java b/src/main/java/org/owasp/webgoat/lessons/challenges/FlagController.java new file mode 100644 index 000000000..1b2c497bd --- /dev/null +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/FlagController.java @@ -0,0 +1,62 @@ +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.lessons.challenges; + +import lombok.AllArgsConstructor; +import org.owasp.webgoat.container.assignments.AssignmentEndpoint; +import org.owasp.webgoat.container.assignments.AttackResult; +import org.owasp.webgoat.container.session.WebSession; +import org.owasp.webgoat.container.users.UserTracker; +import org.owasp.webgoat.container.users.UserTrackerRepository; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@AllArgsConstructor +public class FlagController extends AssignmentEndpoint { + + private final UserTrackerRepository userTrackerRepository; + private final WebSession webSession; + private final Flags flags; + + @PostMapping(path = "/challenge/flag", produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public AttackResult postFlag(@RequestParam String flag) { + UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); + Flag expectedFlag = flags.getFlag(webSession.getCurrentLesson()); + final AttackResult attackResult; + if (expectedFlag.isCorrect(flag)) { + userTracker.assignmentSolved( + webSession.getCurrentLesson(), "Assignment" + expectedFlag.number()); + attackResult = success(this).feedback("challenge.flag.correct").build(); + } else { + userTracker.assignmentFailed(webSession.getCurrentLesson()); + attackResult = failed(this).feedback("challenge.flag.incorrect").build(); + } + userTrackerRepository.save(userTracker); + return attackResult; + } +} diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/Flags.java b/src/main/java/org/owasp/webgoat/lessons/challenges/Flags.java new file mode 100644 index 000000000..d3b92b149 --- /dev/null +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/Flags.java @@ -0,0 +1,27 @@ +package org.owasp.webgoat.lessons.challenges; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.stream.IntStream; +import org.owasp.webgoat.container.lessons.Lesson; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class Flags { + private final Map FLAGS = new HashMap<>(); + + public Flags() { + IntStream.range(1, 10).forEach(i -> FLAGS.put(i, new Flag(i, UUID.randomUUID().toString()))); + } + + public Flag getFlag(Lesson forLesson) { + String lessonName = forLesson.getName(); + int challengeNumber = Integer.valueOf(lessonName.substring(lessonName.length() - 1)); + return FLAGS.get(challengeNumber); + } + + public Flag getFlag(int flagNumber) { + return FLAGS.get(flagNumber); + } +} diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/Assignment1.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/Assignment1.java index 0d07c7427..de99c4470 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/Assignment1.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/Assignment1.java @@ -2,11 +2,10 @@ package org.owasp.webgoat.lessons.challenges.challenge1; import static org.owasp.webgoat.lessons.challenges.SolutionConstants.PASSWORD; -import javax.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; -import org.owasp.webgoat.lessons.challenges.Flag; -import org.springframework.util.StringUtils; +import org.owasp.webgoat.lessons.challenges.Flags; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @@ -43,12 +42,14 @@ import org.springframework.web.bind.annotation.RestController; * @since August 11, 2016 */ @RestController +@RequiredArgsConstructor public class Assignment1 extends AssignmentEndpoint { + private final Flags flags; + @PostMapping("/challenge/1") @ResponseBody - public AttackResult completed( - @RequestParam String username, @RequestParam String password, HttpServletRequest request) { + public AttackResult completed(@RequestParam String username, @RequestParam String password) { boolean ipAddressKnown = true; boolean passwordCorrect = "admin".equals(username) @@ -56,14 +57,10 @@ public class Assignment1 extends AssignmentEndpoint { .replace("1234", String.format("%04d", ImageServlet.PINCODE)) .equals(password); if (passwordCorrect && ipAddressKnown) { - return success(this).feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(1)).build(); + return success(this).feedback("challenge.solved").feedbackArgs(flags.getFlag(1)).build(); } else if (passwordCorrect) { return failed(this).feedback("ip.address.unknown").build(); } return failed(this).build(); } - - public static boolean containsHeader(HttpServletRequest request) { - return StringUtils.hasText(request.getHeader("X-Forwarded-For")); - } } diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/ImageServlet.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/ImageServlet.java index 1de00e012..6ae34384c 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/ImageServlet.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/ImageServlet.java @@ -4,8 +4,7 @@ import static org.springframework.web.bind.annotation.RequestMethod.GET; import static org.springframework.web.bind.annotation.RequestMethod.POST; import java.io.IOException; -import java.security.SecureRandom; -import javax.servlet.http.HttpServlet; +import java.util.Random; import org.springframework.core.io.ClassPathResource; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestMapping; @@ -13,10 +12,9 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; @RestController -public class ImageServlet extends HttpServlet { +public class ImageServlet { - private static final long serialVersionUID = 9132775506936676850L; - public static final int PINCODE = new SecureRandom().nextInt(10000); + public static final int PINCODE = new Random().nextInt(10000); @RequestMapping( method = {GET, POST}, diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Assignment5.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Assignment5.java index d6b8dcceb..c8b3f3d10 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Assignment5.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Assignment5.java @@ -24,11 +24,12 @@ package org.owasp.webgoat.lessons.challenges.challenge5; import java.sql.PreparedStatement; import java.sql.ResultSet; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; -import org.owasp.webgoat.lessons.challenges.Flag; +import org.owasp.webgoat.lessons.challenges.Flags; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -37,13 +38,11 @@ import org.springframework.web.bind.annotation.RestController; @RestController @Slf4j +@RequiredArgsConstructor public class Assignment5 extends AssignmentEndpoint { private final LessonDataSource dataSource; - - public Assignment5(LessonDataSource dataSource) { - this.dataSource = dataSource; - } + private final Flags flags; @PostMapping("/challenge/5") @ResponseBody @@ -66,7 +65,7 @@ public class Assignment5 extends AssignmentEndpoint { ResultSet resultSet = statement.executeQuery(); if (resultSet.next()) { - return success(this).feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(5)).build(); + return success(this).feedback("challenge.solved").feedbackArgs(flags.getFlag(5)).build(); } else { return failed(this).feedback("challenge.close").build(); } diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/Assignment7.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/Assignment7.java index 30e17288c..475e59b37 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/Assignment7.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/Assignment7.java @@ -8,9 +8,8 @@ import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; import org.owasp.webgoat.lessons.challenges.Email; -import org.owasp.webgoat.lessons.challenges.Flag; +import org.owasp.webgoat.lessons.challenges.Flags; import org.owasp.webgoat.lessons.challenges.SolutionConstants; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; import org.springframework.http.HttpStatus; @@ -44,10 +43,16 @@ public class Assignment7 extends AssignmentEndpoint { + "Kind regards, \n" + "Team WebGoat"; - @Autowired private RestTemplate restTemplate; + private final Flags flags; + private final RestTemplate restTemplate; + private final String webWolfMailURL; - @Value("${webwolf.mail.url}") - private String webWolfMailURL; + public Assignment7( + Flags flags, RestTemplate restTemplate, @Value("${webwolf.mail.url}") String webWolfMailURL) { + this.flags = flags; + this.restTemplate = restTemplate; + this.webWolfMailURL = webWolfMailURL; + } @GetMapping("/challenge/7/reset-password/{link}") public ResponseEntity resetPassword(@PathVariable(value = "link") String link) { @@ -58,7 +63,7 @@ public class Assignment7 extends AssignmentEndpoint { + "" + "

Here is your flag: " + "" - + Flag.FLAGS.get(7) + + flags.getFlag(7) + ""); } return ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT) diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge8/Assignment8.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge8/Assignment8.java index 535b92f18..507b7b4bd 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge8/Assignment8.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge8/Assignment8.java @@ -4,10 +4,11 @@ import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; -import org.owasp.webgoat.lessons.challenges.Flag; +import org.owasp.webgoat.lessons.challenges.Flags; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -15,12 +16,9 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -/** - * @author nbaars - * @since 4/8/17. - */ @RestController @Slf4j +@RequiredArgsConstructor public class Assignment8 extends AssignmentEndpoint { private static final Map votes = new HashMap<>(); @@ -33,6 +31,8 @@ public class Assignment8 extends AssignmentEndpoint { votes.put(5, 300); } + private final Flags flags; + @GetMapping(value = "/challenge/8/vote/{stars}", produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public ResponseEntity vote( @@ -47,7 +47,7 @@ public class Assignment8 extends AssignmentEndpoint { Integer allVotesForStar = votes.getOrDefault(nrOfStars, 0); votes.put(nrOfStars, allVotesForStar + 1); return ResponseEntity.ok() - .header("X-Flag", "Thanks for voting, your flag is: " + Flag.FLAGS.get(8)) + .header("X-FlagController", "Thanks for voting, your flag is: " + flags.getFlag(8)) .build(); } diff --git a/src/test/java/org/owasp/webgoat/lessons/challenges/Assignment1Test.java b/src/test/java/org/owasp/webgoat/lessons/challenges/Assignment1Test.java index 3628cb904..3d360edfe 100644 --- a/src/test/java/org/owasp/webgoat/lessons/challenges/Assignment1Test.java +++ b/src/test/java/org/owasp/webgoat/lessons/challenges/Assignment1Test.java @@ -37,20 +37,17 @@ import org.owasp.webgoat.lessons.challenges.challenge1.ImageServlet; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -/** - * @author nbaars - * @since 5/2/17. - */ @ExtendWith(MockitoExtension.class) class Assignment1Test extends AssignmentEndpointTest { private MockMvc mockMvc; + private Flags flags; @BeforeEach void setup() { - Assignment1 assignment1 = new Assignment1(); + flags = new Flags(); + Assignment1 assignment1 = new Assignment1(flags); init(assignment1); - new Flag().initFlags(); this.mockMvc = standaloneSetup(assignment1).build(); } @@ -67,8 +64,7 @@ class Assignment1Test extends AssignmentEndpointTest { "password", SolutionConstants.PASSWORD.replace( "1234", String.format("%04d", ImageServlet.PINCODE)))) - .andExpect( - jsonPath("$.feedback", CoreMatchers.containsString("flag: " + Flag.FLAGS.get(1)))) + .andExpect(jsonPath("$.feedback", CoreMatchers.containsString("flag: " + flags.getFlag(1)))) .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); } @@ -83,26 +79,4 @@ class Assignment1Test extends AssignmentEndpointTest { jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.not.solved")))) .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); } - - // @Test - // public void correctPasswordXForwardHeaderMissing() throws Exception { - // mockMvc.perform(MockMvcRequestBuilders.post("/challenge/1") - // .param("username", "admin") - // .param("password", SolutionConstants.PASSWORD)) - // .andExpect(jsonPath("$.feedback", - // CoreMatchers.is(messages.getMessage("ip.address.unknown")))) - // .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - // } - - // @Test - // public void correctPasswordXForwardHeaderWrong() throws Exception { - // mockMvc.perform(MockMvcRequestBuilders.post("/challenge/1") - // .header("X-Forwarded-For", "127.0.1.2") - // .param("username", "admin") - // .param("password", SolutionConstants.PASSWORD)) - // .andExpect(jsonPath("$.feedback", - // CoreMatchers.is(messages.getMessage("ip.address.unknown")))) - // .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - // } - }