Refactoring (#1201)
* Some initial refactoring * Make it one application * Got it working * Fix problem on Windows * Move WebWolf * Move first lesson * Moved all lessons * Fix pom.xml * Fix tests * Add option to initialize a lesson This way we can create content for each user inside a lesson. The initialize method will be called when a new user is created or when a lesson reset happens * Clean up pom.xml files * Remove fetching labels based on language. We only support English at the moment, all the lesson explanations are written in English which makes it very difficult to translate. If we only had labels it would make sense to support multiple languages * Fix SonarLint issues * And move it all to the main project * Fix for documentation paths * Fix pom warnings * Remove PMD as it does not work * Update release notes about refactoring Update release notes about refactoring Update release notes about refactoring * Fix lesson template * Update release notes * Keep it in the same repo in Dockerhub * Update documentation to show how the connection is obtained. Resolves: #1180 * Rename all integration tests * Remove command from Dockerfile * Simplify GitHub actions Currently, we use a separate actions for pull-requests and branch build. This is now consolidated in one action. The PR action triggers always, it now only trigger when the PR is opened and not in draft. Running all platforms on a branch build is a bit too much, it is better to only run all platforms when someone opens a PR. * Remove duplicate entry from release notes * Add explicit registry for base image * Lesson scanner not working when fat jar When running the fat jar we have to take into account we are reading from the jar file and not the filesystem. In this case you cannot use `getFile` for example. * added info in README and fixed release docker * changed base image and added ignore file Co-authored-by: Zubcevic.com <rene@zubcevic.com>
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.auth_bypass;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by appsec on 7/18/17.
|
||||
*/
|
||||
public class AccountVerificationHelper {
|
||||
|
||||
//simulating database storage of verification credentials
|
||||
private static final Integer verifyUserId = 1223445;
|
||||
private static final Map<String, String> userSecQuestions = new HashMap<>();
|
||||
|
||||
static {
|
||||
userSecQuestions.put("secQuestion0", "Dr. Watson");
|
||||
userSecQuestions.put("secQuestion1", "Baker Street");
|
||||
}
|
||||
|
||||
private static final Map<Integer, Map> secQuestionStore = new HashMap<>();
|
||||
|
||||
static {
|
||||
secQuestionStore.put(verifyUserId, userSecQuestions);
|
||||
}
|
||||
// end 'data store set up'
|
||||
|
||||
// this is to aid feedback in the attack process and is not intended to be part of the 'vulnerable' code
|
||||
public boolean didUserLikelylCheat(HashMap<String, String> submittedAnswers) {
|
||||
boolean likely = false;
|
||||
|
||||
if (submittedAnswers.size() == secQuestionStore.get(verifyUserId).size()) {
|
||||
likely = true;
|
||||
}
|
||||
|
||||
if ((submittedAnswers.containsKey("secQuestion0") && submittedAnswers.get("secQuestion0").equals(secQuestionStore.get(verifyUserId).get("secQuestion0")))
|
||||
&& (submittedAnswers.containsKey("secQuestion1") && submittedAnswers.get("secQuestion1").equals(secQuestionStore.get(verifyUserId).get("secQuestion1")))) {
|
||||
likely = true;
|
||||
} else {
|
||||
likely = false;
|
||||
}
|
||||
|
||||
return likely;
|
||||
|
||||
}
|
||||
//end of cheating check ... the method below is the one of real interest. Can you find the flaw?
|
||||
|
||||
public boolean verifyAccount(Integer userId, HashMap<String, String> submittedQuestions) {
|
||||
//short circuit if no questions are submitted
|
||||
if (submittedQuestions.entrySet().size() != secQuestionStore.get(verifyUserId).size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (submittedQuestions.containsKey("secQuestion0") && !submittedQuestions.get("secQuestion0").equals(secQuestionStore.get(verifyUserId).get("secQuestion0"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (submittedQuestions.containsKey("secQuestion1") && !submittedQuestions.get("secQuestion1").equals(secQuestionStore.get(verifyUserId).get("secQuestion1"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// else
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.auth_bypass;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class AuthBypass extends Lesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.AUTHENTICATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "auth-bypass.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.auth_bypass;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by jason on 1/5/17.
|
||||
*/
|
||||
@RestController
|
||||
@AssignmentHints({"auth-bypass.hints.verify.1", "auth-bypass.hints.verify.2", "auth-bypass.hints.verify.3", "auth-bypass.hints.verify.4"})
|
||||
public class VerifyAccount extends AssignmentEndpoint {
|
||||
|
||||
@Autowired
|
||||
private WebSession webSession;
|
||||
|
||||
@Autowired
|
||||
UserSessionData userSessionData;
|
||||
|
||||
@PostMapping(path = "/auth-bypass/verify-account", produces = {"application/json"})
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String userId, @RequestParam String verifyMethod, HttpServletRequest req) throws ServletException, IOException {
|
||||
AccountVerificationHelper verificationHelper = new AccountVerificationHelper();
|
||||
Map<String, String> submittedAnswers = parseSecQuestions(req);
|
||||
if (verificationHelper.didUserLikelylCheat((HashMap) submittedAnswers)) {
|
||||
return failed(this)
|
||||
.feedback("verify-account.cheated")
|
||||
.output("Yes, you guessed correctly, but see the feedback message")
|
||||
.build();
|
||||
}
|
||||
|
||||
// else
|
||||
if (verificationHelper.verifyAccount(Integer.valueOf(userId), (HashMap) submittedAnswers)) {
|
||||
userSessionData.setValue("account-verified-id", userId);
|
||||
return success(this)
|
||||
.feedback("verify-account.success")
|
||||
.build();
|
||||
} else {
|
||||
return failed(this)
|
||||
.feedback("verify-account.failed")
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private HashMap<String, String> parseSecQuestions(HttpServletRequest req) {
|
||||
Map<String, String> userAnswers = new HashMap<>();
|
||||
List<String> paramNames = Collections.list(req.getParameterNames());
|
||||
for (String paramName : paramNames) {
|
||||
//String paramName = req.getParameterNames().nextElement();
|
||||
if (paramName.contains("secQuestion")) {
|
||||
userAnswers.put(paramName, req.getParameter(paramName));
|
||||
}
|
||||
}
|
||||
return (HashMap) userAnswers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.bypass_restrictions;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class BypassRestrictions extends Lesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.CLIENT_SIDE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "bypass-restrictions.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.bypass_restrictions;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
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
|
||||
public class BypassRestrictionsFieldRestrictions extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping("/BypassRestrictions/FieldRestrictions")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String select, @RequestParam String radio, @RequestParam String checkbox, @RequestParam String shortInput, @RequestParam String readOnlyInput) {
|
||||
if (select.equals("option1") || select.equals("option2")) {
|
||||
return failed(this).build();
|
||||
}
|
||||
if (radio.equals("option1") || radio.equals("option2")) {
|
||||
return failed(this).build();
|
||||
}
|
||||
if (checkbox.equals("on") || checkbox.equals("off")) {
|
||||
return failed(this).build();
|
||||
}
|
||||
if (shortInput.length() <= 5) {
|
||||
return failed(this).build();
|
||||
}
|
||||
if ("change".equals(readOnlyInput)) {
|
||||
return failed(this).build();
|
||||
}
|
||||
return success(this).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.bypass_restrictions;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
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
|
||||
public class BypassRestrictionsFrontendValidation extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping("/BypassRestrictions/frontendValidation")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String field1, @RequestParam String field2, @RequestParam String field3, @RequestParam String field4, @RequestParam String field5, @RequestParam String field6, @RequestParam String field7, @RequestParam Integer error) {
|
||||
final String regex1 = "^[a-z]{3}$";
|
||||
final String regex2 = "^[0-9]{3}$";
|
||||
final String regex3 = "^[a-zA-Z0-9 ]*$";
|
||||
final String regex4 = "^(one|two|three|four|five|six|seven|eight|nine)$";
|
||||
final String regex5 = "^\\d{5}$";
|
||||
final String regex6 = "^\\d{5}(-\\d{4})?$";
|
||||
final String regex7 = "^[2-9]\\d{2}-?\\d{3}-?\\d{4}$";
|
||||
if (error > 0) {
|
||||
return failed(this).build();
|
||||
}
|
||||
if (field1.matches(regex1)) {
|
||||
return failed(this).build();
|
||||
}
|
||||
if (field2.matches(regex2)) {
|
||||
return failed(this).build();
|
||||
}
|
||||
if (field3.matches(regex3)) {
|
||||
return failed(this).build();
|
||||
}
|
||||
if (field4.matches(regex4)) {
|
||||
return failed(this).build();
|
||||
}
|
||||
if (field5.matches(regex5)) {
|
||||
return failed(this).build();
|
||||
}
|
||||
if (field6.matches(regex6)) {
|
||||
return failed(this).build();
|
||||
}
|
||||
if (field7.matches(regex7)) {
|
||||
return failed(this).build();
|
||||
}
|
||||
return success(this).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.owasp.webgoat.lessons.challenges;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/21/17.
|
||||
*/
|
||||
public class ChallengeIntro extends Lesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.CHALLENGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "challenge0.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 8/20/17.
|
||||
*/
|
||||
@Builder
|
||||
@Data
|
||||
public class Email implements Serializable {
|
||||
|
||||
private LocalDateTime time;
|
||||
private String contents;
|
||||
private String sender;
|
||||
private String title;
|
||||
private String recipient;
|
||||
}
|
||||
88
src/main/java/org/owasp/webgoat/lessons/challenges/Flag.java
Normal file
88
src/main/java/org/owasp/webgoat/lessons/challenges/Flag.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 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;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/23/17.
|
||||
*/
|
||||
@RestController
|
||||
public class Flag extends AssignmentEndpoint {
|
||||
|
||||
public static final Map<Integer, String> FLAGS = new HashMap<>();
|
||||
@Autowired
|
||||
private UserTrackerRepository userTrackerRepository;
|
||||
@Autowired
|
||||
private WebSession webSession;
|
||||
|
||||
@AllArgsConstructor
|
||||
private class FlagPosted {
|
||||
@Getter
|
||||
private boolean lessonCompleted;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Interface with constants so we can easily change the flags
|
||||
*
|
||||
* @author nbaars
|
||||
* @since 3/23/17.
|
||||
*/
|
||||
public interface SolutionConstants {
|
||||
|
||||
//TODO should be random generated when starting the server
|
||||
String PASSWORD = "!!webgoat_admin_1234!!";
|
||||
String PASSWORD_TOM = "thisisasecretfortomonly";
|
||||
String ADMIN_PASSWORD_LINK = "375afe1104f4a487a73823c50a9292a2";
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package org.owasp.webgoat.lessons.challenges.challenge1;
|
||||
|
||||
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.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;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import static org.owasp.webgoat.lessons.challenges.SolutionConstants.PASSWORD;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 2014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*
|
||||
* @author WebGoat
|
||||
* @version $Id: $Id
|
||||
* @since August 11, 2016
|
||||
*/
|
||||
@RestController
|
||||
public class Assignment1 extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping("/challenge/1")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String username, @RequestParam String password, HttpServletRequest request) {
|
||||
boolean ipAddressKnown = true;
|
||||
boolean passwordCorrect = "admin".equals(username) && PASSWORD.replace("1234", String.format("%04d",ImageServlet.PINCODE)).equals(password);
|
||||
if (passwordCorrect && ipAddressKnown) {
|
||||
return success(this).feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(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"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.owasp.webgoat.lessons.challenges.challenge1;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/21/17.
|
||||
*/
|
||||
@Component
|
||||
public class Challenge1 extends Lesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.CHALLENGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "challenge1.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.owasp.webgoat.lessons.challenges.challenge1;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import java.io.IOException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
@RestController
|
||||
public class ImageServlet extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 9132775506936676850L;
|
||||
static final public int PINCODE = new SecureRandom().nextInt(10000);
|
||||
|
||||
@RequestMapping(method = {GET, POST}, value = "/challenge/logo", produces = MediaType.IMAGE_PNG_VALUE)
|
||||
@ResponseBody
|
||||
public byte[] logo() throws IOException {
|
||||
byte[] in = new ClassPathResource("lessons/challenges/images/webgoat2.png").getInputStream().readAllBytes();
|
||||
|
||||
String pincode = String.format("%04d", PINCODE);
|
||||
|
||||
in[81216]=(byte) pincode.charAt(0);
|
||||
in[81217]=(byte) pincode.charAt(1);
|
||||
in[81218]=(byte) pincode.charAt(2);
|
||||
in[81219]=(byte) pincode.charAt(3);
|
||||
|
||||
return in;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.challenge5;
|
||||
|
||||
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.springframework.util.StringUtils;
|
||||
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;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
|
||||
@RestController
|
||||
@Slf4j
|
||||
public class Assignment5 extends AssignmentEndpoint {
|
||||
|
||||
private final LessonDataSource dataSource;
|
||||
|
||||
public Assignment5(LessonDataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
@PostMapping("/challenge/5")
|
||||
@ResponseBody
|
||||
public AttackResult login(@RequestParam String username_login, @RequestParam String password_login) throws Exception {
|
||||
if (!StringUtils.hasText(username_login) || !StringUtils.hasText(password_login)) {
|
||||
return failed(this).feedback("required4").build();
|
||||
}
|
||||
if (!"Larry".equals(username_login)) {
|
||||
return failed(this).feedback("user.not.larry").feedbackArgs(username_login).build();
|
||||
}
|
||||
try (var connection = dataSource.getConnection()) {
|
||||
PreparedStatement statement = connection.prepareStatement("select password from challenge_users where userid = '" + username_login + "' and password = '" + password_login + "'");
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
|
||||
if (resultSet.next()) {
|
||||
return success(this).feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(5)).build();
|
||||
} else {
|
||||
return failed(this).feedback("challenge.close").build();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.challenge5;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/21/17.
|
||||
*/
|
||||
@Component
|
||||
public class Challenge5 extends Lesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.CHALLENGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "challenge5.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.owasp.webgoat.lessons.challenges.challenge7;
|
||||
|
||||
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.SolutionConstants;
|
||||
import org.owasp.webgoat.lessons.challenges.Flag;
|
||||
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;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
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;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/8/17.
|
||||
*/
|
||||
@RestController
|
||||
@Slf4j
|
||||
public class Assignment7 extends AssignmentEndpoint {
|
||||
|
||||
private static final String TEMPLATE = "Hi, you requested a password reset link, please use this "
|
||||
+ "<a target='_blank' href='%s:8080/WebGoat/challenge/7/reset-password/%s'>link</a> to reset your password."
|
||||
+ "\n \n\n"
|
||||
+ "If you did not request this password change you can ignore this message."
|
||||
+ "\n"
|
||||
+ "If you have any comments or questions, please do not hesitate to reach us at support@webgoat-cloud.org"
|
||||
+ "\n\n"
|
||||
+ "Kind regards, \nTeam WebGoat";
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
@Value("${webwolf.mail.url}")
|
||||
private String webWolfMailURL;
|
||||
|
||||
@GetMapping("/challenge/7/reset-password/{link}")
|
||||
public ResponseEntity<String> resetPassword(@PathVariable(value = "link") String link) {
|
||||
if (link.equals(SolutionConstants.ADMIN_PASSWORD_LINK)) {
|
||||
return ResponseEntity.accepted().body("<h1>Success!!</h1>"
|
||||
+ "<img src='/WebGoat/images/hi-five-cat.jpg'>"
|
||||
+ "<br/><br/>Here is your flag: " + "<b>" + Flag.FLAGS.get(7) + "</b>");
|
||||
}
|
||||
return ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT).body("That is not the reset link for admin");
|
||||
}
|
||||
|
||||
@PostMapping("/challenge/7")
|
||||
@ResponseBody
|
||||
public AttackResult sendPasswordResetLink(@RequestParam String email, HttpServletRequest request) throws URISyntaxException {
|
||||
if (StringUtils.hasText(email)) {
|
||||
String username = email.substring(0, email.indexOf("@"));
|
||||
if (StringUtils.hasText(username)) {
|
||||
URI uri = new URI(request.getRequestURL().toString());
|
||||
Email mail = Email.builder()
|
||||
.title("Your password reset link for challenge 7")
|
||||
.contents(String.format(TEMPLATE, uri.getScheme() + "://" + uri.getHost(), new PasswordResetLink().createPasswordReset(username, "webgoat")))
|
||||
.sender("password-reset@webgoat-cloud.net")
|
||||
.recipient(username)
|
||||
.time(LocalDateTime.now()).build();
|
||||
restTemplate.postForEntity(webWolfMailURL, mail, Object.class);
|
||||
}
|
||||
}
|
||||
return success(this).feedback("email.send").feedbackArgs(email).build();
|
||||
}
|
||||
|
||||
@GetMapping(value = "/challenge/7/.git", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||
@ResponseBody
|
||||
public ClassPathResource git() {
|
||||
return new ClassPathResource("challenge7/git.zip");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.owasp.webgoat.lessons.challenges.challenge7;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/21/17.
|
||||
*/
|
||||
@Component
|
||||
public class Challenge7 extends Lesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.CHALLENGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "challenge7.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,688 @@
|
||||
package org.owasp.webgoat.lessons.challenges.challenge7;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* MD5 hash generator.
|
||||
* More information about this class is available from <a target="_top" href=
|
||||
* "http://ostermiller.org/utils/MD5.html">ostermiller.org</a>.
|
||||
* <p>
|
||||
* This class takes as input a message of arbitrary length and produces
|
||||
* as output a 128-bit "fingerprint" or "message digest" of the input.
|
||||
* It is conjectured that it is computationally infeasible to produce
|
||||
* two messages having the same message digest, or to produce any
|
||||
* message having a given pre-specified target message digest. The MD5
|
||||
* algorithm is intended for digital signature applications, where a
|
||||
* large file must be "compressed" in a secure manner before being
|
||||
* encrypted with a private (secret) key under a public-key cryptosystem
|
||||
* such as RSA.
|
||||
* <p>
|
||||
* For more information see RFC1321.
|
||||
*
|
||||
* @author Santeri Paavolainen http://santtu.iki.fi/md5/
|
||||
* @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public class MD5 {
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public MD5() {
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Command line program that will take files as arguments
|
||||
* and output the MD5 sum for each file.
|
||||
*
|
||||
* @param args command line arguments
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
if (args.length == 0) {
|
||||
System.err.println("Please specify a file.");
|
||||
} else {
|
||||
for (String element : args) {
|
||||
try {
|
||||
System.out.println(MD5.getHashString(new File(element)) + " " + element);
|
||||
} catch (IOException x) {
|
||||
System.err.println(x.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this hash sum as an array of 16 bytes.
|
||||
*
|
||||
* @return Array of 16 bytes, the hash of all updated bytes.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public byte[] getHash() {
|
||||
if (!finalState.valid) {
|
||||
finalState.copy(workingState);
|
||||
long bitCount = finalState.bitCount;
|
||||
// Compute the number of left over bits
|
||||
int leftOver = (int) (((bitCount >>> 3)) & 0x3f);
|
||||
// Compute the amount of padding to add based on number of left over bits.
|
||||
int padlen = (leftOver < 56) ? (56 - leftOver) : (120 - leftOver);
|
||||
// add the padding
|
||||
update(finalState, padding, 0, padlen);
|
||||
// add the length (computed before padding was added)
|
||||
update(finalState, encode(bitCount), 0, 8);
|
||||
finalState.valid = true;
|
||||
}
|
||||
// make a copy of the hash before returning it.
|
||||
return encode(finalState.state, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 32-character hex representation of this hash.
|
||||
*
|
||||
* @return String representation of this object's hash.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public String getHashString() {
|
||||
return toHex(this.getHash());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MD5 hash of the given byte array.
|
||||
*
|
||||
* @param b byte array for which an MD5 hash is desired.
|
||||
* @return Array of 16 bytes, the hash of all updated bytes.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public static byte[] getHash(byte[] b) {
|
||||
MD5 md5 = new MD5();
|
||||
md5.update(b);
|
||||
return md5.getHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MD5 hash of the given byte array.
|
||||
*
|
||||
* @param b byte array for which an MD5 hash is desired.
|
||||
* @return 32-character hex representation the data's MD5 hash.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public static String getHashString(byte[] b) {
|
||||
MD5 md5 = new MD5();
|
||||
md5.update(b);
|
||||
return md5.getHashString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MD5 hash the data on the given InputStream.
|
||||
*
|
||||
* @param in byte array for which an MD5 hash is desired.
|
||||
* @return Array of 16 bytes, the hash of all updated bytes.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public static byte[] getHash(InputStream in) throws IOException {
|
||||
MD5 md5 = new MD5();
|
||||
byte[] buffer = new byte[1024];
|
||||
int read;
|
||||
while ((read = in.read(buffer)) != -1) {
|
||||
md5.update(buffer, read);
|
||||
}
|
||||
return md5.getHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MD5 hash the data on the given InputStream.
|
||||
*
|
||||
* @param in byte array for which an MD5 hash is desired.
|
||||
* @return 32-character hex representation the data's MD5 hash.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public static String getHashString(InputStream in) throws IOException {
|
||||
MD5 md5 = new MD5();
|
||||
byte[] buffer = new byte[1024];
|
||||
int read;
|
||||
while ((read = in.read(buffer)) != -1) {
|
||||
md5.update(buffer, read);
|
||||
}
|
||||
return md5.getHashString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MD5 hash of the given file.
|
||||
*
|
||||
* @param f file for which an MD5 hash is desired.
|
||||
* @return Array of 16 bytes, the hash of all updated bytes.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public static byte[] getHash(File f) throws IOException {
|
||||
InputStream is = new FileInputStream(f);
|
||||
byte[] hash = getHash(is);
|
||||
is.close();
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MD5 hash of the given file.
|
||||
*
|
||||
* @param f file array for which an MD5 hash is desired.
|
||||
* @return 32-character hex representation the data's MD5 hash.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public static String getHashString(File f) throws IOException {
|
||||
InputStream is = new FileInputStream(f);
|
||||
String hash = getHashString(is);
|
||||
is.close();
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MD5 hash of the given String.
|
||||
* The string is converted to bytes using the current
|
||||
* platform's default character encoding.
|
||||
*
|
||||
* @param s String for which an MD5 hash is desired.
|
||||
* @return Array of 16 bytes, the hash of all updated bytes.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public static byte[] getHash(String s) {
|
||||
MD5 md5 = new MD5();
|
||||
md5.update(s);
|
||||
return md5.getHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MD5 hash of the given String.
|
||||
* The string is converted to bytes using the current
|
||||
* platform's default character encoding.
|
||||
*
|
||||
* @param s String for which an MD5 hash is desired.
|
||||
* @return 32-character hex representation the data's MD5 hash.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public static String getHashString(String s) {
|
||||
MD5 md5 = new MD5();
|
||||
md5.update(s);
|
||||
return md5.getHashString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the MD5 hash of the given String.
|
||||
*
|
||||
* @param s String for which an MD5 hash is desired.
|
||||
* @param enc The name of a supported character encoding.
|
||||
* @return Array of 16 bytes, the hash of all updated bytes.
|
||||
* @throws UnsupportedEncodingException If the named encoding is not supported.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public static byte[] getHash(String s, String enc) throws UnsupportedEncodingException {
|
||||
MD5 md5 = new MD5();
|
||||
md5.update(s, enc);
|
||||
return md5.getHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MD5 hash of the given String.
|
||||
*
|
||||
* @param s String for which an MD5 hash is desired.
|
||||
* @param enc The name of a supported character encoding.
|
||||
* @return 32-character hex representation the data's MD5 hash.
|
||||
* @throws UnsupportedEncodingException If the named encoding is not supported.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public static String getHashString(String s, String enc) throws UnsupportedEncodingException {
|
||||
MD5 md5 = new MD5();
|
||||
md5.update(s, enc);
|
||||
return md5.getHashString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reset the MD5 sum to its initial state.
|
||||
*
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public void reset() {
|
||||
workingState.reset();
|
||||
finalState.valid = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 32-character hex representation of this hash.
|
||||
*
|
||||
* @return String representation of this object's hash.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getHashString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this hash with the given data.
|
||||
* <p>
|
||||
* A state may be passed into this method so that we can add padding
|
||||
* and finalize a md5 hash without limiting our ability to update
|
||||
* more data later.
|
||||
* <p>
|
||||
* If length bytes are not available to be hashed, as many bytes as
|
||||
* possible will be hashed.
|
||||
*
|
||||
* @param state Which state is updated.
|
||||
* @param buffer Array of bytes to be hashed.
|
||||
* @param offset Offset to buffer array.
|
||||
* @param length number of bytes to hash.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
private void update(MD5State state, byte buffer[], int offset, int length) {
|
||||
|
||||
finalState.valid = false;
|
||||
|
||||
// if length goes beyond the end of the buffer, cut it short.
|
||||
if ((length + offset) > buffer.length) {
|
||||
length = buffer.length - offset;
|
||||
}
|
||||
|
||||
// compute number of bytes mod 64
|
||||
// this is what we have sitting in a buffer
|
||||
// that have not been hashed yet
|
||||
int index = (int) (state.bitCount >>> 3) & 0x3f;
|
||||
|
||||
// add the length to the count (translate bytes to bits)
|
||||
state.bitCount += length << 3;
|
||||
|
||||
int partlen = 64 - index;
|
||||
|
||||
int i = 0;
|
||||
if (length >= partlen) {
|
||||
System.arraycopy(buffer, offset, state.buffer, index, partlen);
|
||||
transform(state, decode(state.buffer, 64, 0));
|
||||
for (i = partlen; (i + 63) < length; i += 64) {
|
||||
transform(state, decode(buffer, 64, i));
|
||||
}
|
||||
index = 0;
|
||||
}
|
||||
|
||||
// buffer remaining input
|
||||
if (i < length) {
|
||||
for (int start = i; i < length; i++) {
|
||||
state.buffer[index + i - start] = buffer[i + offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this hash with the given data.
|
||||
* <p>
|
||||
* If length bytes are not available to be hashed, as many bytes as
|
||||
* possible will be hashed.
|
||||
*
|
||||
* @param buffer Array of bytes to be hashed.
|
||||
* @param offset Offset to buffer array.
|
||||
* @param length number of bytes to hash.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public void update(byte buffer[], int offset, int length) {
|
||||
update(workingState, buffer, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this hash with the given data.
|
||||
* <p>
|
||||
* If length bytes are not available to be hashed, as many bytes as
|
||||
* possible will be hashed.
|
||||
*
|
||||
* @param buffer Array of bytes to be hashed.
|
||||
* @param length number of bytes to hash.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public void update(byte buffer[], int length) {
|
||||
update(buffer, 0, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this hash with the given data.
|
||||
*
|
||||
* @param buffer Array of bytes to be hashed.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public void update(byte buffer[]) {
|
||||
update(buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this hash with a single byte.
|
||||
*
|
||||
* @param b byte to be hashed.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public void update(byte b) {
|
||||
byte buffer[] = new byte[1];
|
||||
buffer[0] = b;
|
||||
update(buffer, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this hash with a String.
|
||||
* The string is converted to bytes using the current
|
||||
* platform's default character encoding.
|
||||
*
|
||||
* @param s String to be hashed.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public void update(String s) {
|
||||
update(s.getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this hash with a String.
|
||||
*
|
||||
* @param s String to be hashed.
|
||||
* @param enc The name of a supported character encoding.
|
||||
* @throws UnsupportedEncodingException If the named encoding is not supported.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
public void update(String s, String enc) throws UnsupportedEncodingException {
|
||||
update(s.getBytes(enc));
|
||||
}
|
||||
|
||||
/**
|
||||
* The current state from which the hash sum
|
||||
* can be computed or updated.
|
||||
*
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
private MD5State workingState = new MD5State();
|
||||
|
||||
/**
|
||||
* Cached copy of the final MD5 hash sum. This is created when
|
||||
* the hash is requested and it is invalidated when the hash
|
||||
* is updated.
|
||||
*
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
private MD5State finalState = new MD5State();
|
||||
|
||||
/**
|
||||
* Temporary buffer cached here for performance reasons.
|
||||
*
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
private int[] decodeBuffer = new int[16];
|
||||
|
||||
/**
|
||||
* 64 bytes of padding that can be added if the length
|
||||
* is not divisible by 64.
|
||||
*
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
private static final byte padding[] = {
|
||||
(byte) 0x80, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains internal state of the MD5 class.
|
||||
* Passes MD5 test suite as defined in RFC1321.
|
||||
*
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
private class MD5State {
|
||||
|
||||
/**
|
||||
* True if this state is valid.
|
||||
*
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
private boolean valid = true;
|
||||
|
||||
/**
|
||||
* Reset to initial state.
|
||||
*
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
private void reset() {
|
||||
state[0] = 0x67452301;
|
||||
state[1] = 0xefcdab89;
|
||||
state[2] = 0x98badcfe;
|
||||
state[3] = 0x10325476;
|
||||
|
||||
bitCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 128-byte state
|
||||
*
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
private int state[] = new int[4];
|
||||
|
||||
/**
|
||||
* 64-bit count of the number of bits that have been hashed.
|
||||
*
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
private long bitCount;
|
||||
|
||||
/**
|
||||
* 64-byte buffer (512 bits) for storing to-be-hashed characters
|
||||
*
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
private byte buffer[] = new byte[64];
|
||||
|
||||
private MD5State() {
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this state to be exactly the same as some other.
|
||||
*
|
||||
* @param from state to copy from.
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
private void copy(MD5State from) {
|
||||
System.arraycopy(from.buffer, 0, this.buffer, 0, this.buffer.length);
|
||||
System.arraycopy(from.state, 0, this.state, 0, this.state.length);
|
||||
this.valid = from.valid;
|
||||
this.bitCount = from.bitCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Turns array of bytes into string representing each byte as
|
||||
* a two digit unsigned hex number.
|
||||
*
|
||||
* @param hash Array of bytes to convert to hex-string
|
||||
* @return Generated hex string
|
||||
* @since ostermillerutils 1.00.00
|
||||
*/
|
||||
private static String toHex(byte hash[]) {
|
||||
StringBuffer buf = new StringBuffer(hash.length * 2);
|
||||
for (byte element : hash) {
|
||||
int intVal = element & 0xff;
|
||||
if (intVal < 0x10) {
|
||||
// append a zero before a one digit hex
|
||||
// number to make it two digits.
|
||||
buf.append("0");
|
||||
}
|
||||
buf.append(Integer.toHexString(intVal));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static int FF(int a, int b, int c, int d, int x, int s, int ac) {
|
||||
a += ((b & c) | (~b & d));
|
||||
a += x;
|
||||
a += ac;
|
||||
//return rotateLeft(a, s) + b;
|
||||
a = (a << s) | (a >>> (32 - s));
|
||||
return a + b;
|
||||
}
|
||||
|
||||
private static int GG(int a, int b, int c, int d, int x, int s, int ac) {
|
||||
a += ((b & d) | (c & ~d));
|
||||
a += x;
|
||||
a += ac;
|
||||
//return rotateLeft(a, s) + b;
|
||||
a = (a << s) | (a >>> (32 - s));
|
||||
return a + b;
|
||||
}
|
||||
|
||||
private static int HH(int a, int b, int c, int d, int x, int s, int ac) {
|
||||
a += (b ^ c ^ d);
|
||||
a += x;
|
||||
a += ac;
|
||||
//return rotateLeft(a, s) + b;
|
||||
a = (a << s) | (a >>> (32 - s));
|
||||
return a + b;
|
||||
}
|
||||
|
||||
private static int II(int a, int b, int c, int d, int x, int s, int ac) {
|
||||
a += (c ^ (b | ~d));
|
||||
a += x;
|
||||
a += ac;
|
||||
//return rotateLeft(a, s) + b;
|
||||
a = (a << s) | (a >>> (32 - s));
|
||||
return a + b;
|
||||
}
|
||||
|
||||
private static byte[] encode(long l) {
|
||||
byte[] out = new byte[8];
|
||||
out[0] = (byte) (l & 0xff);
|
||||
out[1] = (byte) ((l >>> 8) & 0xff);
|
||||
out[2] = (byte) ((l >>> 16) & 0xff);
|
||||
out[3] = (byte) ((l >>> 24) & 0xff);
|
||||
out[4] = (byte) ((l >>> 32) & 0xff);
|
||||
out[5] = (byte) ((l >>> 40) & 0xff);
|
||||
out[6] = (byte) ((l >>> 48) & 0xff);
|
||||
out[7] = (byte) ((l >>> 56) & 0xff);
|
||||
return out;
|
||||
}
|
||||
|
||||
private static byte[] encode(int input[], int len) {
|
||||
byte[] out = new byte[len];
|
||||
int i, j;
|
||||
for (i = j = 0; j < len; i++, j += 4) {
|
||||
out[j] = (byte) (input[i] & 0xff);
|
||||
out[j + 1] = (byte) ((input[i] >>> 8) & 0xff);
|
||||
out[j + 2] = (byte) ((input[i] >>> 16) & 0xff);
|
||||
out[j + 3] = (byte) ((input[i] >>> 24) & 0xff);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private int[] decode(byte buffer[], int len, int offset) {
|
||||
int i, j;
|
||||
for (i = j = 0; j < len; i++, j += 4) {
|
||||
decodeBuffer[i] = (
|
||||
(buffer[j + offset] & 0xff)) |
|
||||
(((buffer[j + 1 + offset] & 0xff)) << 8) |
|
||||
(((buffer[j + 2 + offset] & 0xff)) << 16) |
|
||||
(((buffer[j + 3 + offset] & 0xff)) << 24
|
||||
);
|
||||
}
|
||||
return decodeBuffer;
|
||||
}
|
||||
|
||||
private static void transform(MD5State state, int[] x) {
|
||||
int a = state.state[0];
|
||||
int b = state.state[1];
|
||||
int c = state.state[2];
|
||||
int d = state.state[3];
|
||||
|
||||
/* Round 1 */
|
||||
a = FF(a, b, c, d, x[0], 7, 0xd76aa478); /* 1 */
|
||||
d = FF(d, a, b, c, x[1], 12, 0xe8c7b756); /* 2 */
|
||||
c = FF(c, d, a, b, x[2], 17, 0x242070db); /* 3 */
|
||||
b = FF(b, c, d, a, x[3], 22, 0xc1bdceee); /* 4 */
|
||||
a = FF(a, b, c, d, x[4], 7, 0xf57c0faf); /* 5 */
|
||||
d = FF(d, a, b, c, x[5], 12, 0x4787c62a); /* 6 */
|
||||
c = FF(c, d, a, b, x[6], 17, 0xa8304613); /* 7 */
|
||||
b = FF(b, c, d, a, x[7], 22, 0xfd469501); /* 8 */
|
||||
a = FF(a, b, c, d, x[8], 7, 0x698098d8); /* 9 */
|
||||
d = FF(d, a, b, c, x[9], 12, 0x8b44f7af); /* 10 */
|
||||
c = FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
|
||||
b = FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
|
||||
a = FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
|
||||
d = FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
|
||||
c = FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
|
||||
b = FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
a = GG(a, b, c, d, x[1], 5, 0xf61e2562); /* 17 */
|
||||
d = GG(d, a, b, c, x[6], 9, 0xc040b340); /* 18 */
|
||||
c = GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
|
||||
b = GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); /* 20 */
|
||||
a = GG(a, b, c, d, x[5], 5, 0xd62f105d); /* 21 */
|
||||
d = GG(d, a, b, c, x[10], 9, 0x02441453); /* 22 */
|
||||
c = GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
|
||||
b = GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); /* 24 */
|
||||
a = GG(a, b, c, d, x[9], 5, 0x21e1cde6); /* 25 */
|
||||
d = GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
|
||||
c = GG(c, d, a, b, x[3], 14, 0xf4d50d87); /* 27 */
|
||||
b = GG(b, c, d, a, x[8], 20, 0x455a14ed); /* 28 */
|
||||
a = GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
|
||||
d = GG(d, a, b, c, x[2], 9, 0xfcefa3f8); /* 30 */
|
||||
c = GG(c, d, a, b, x[7], 14, 0x676f02d9); /* 31 */
|
||||
b = GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
a = HH(a, b, c, d, x[5], 4, 0xfffa3942); /* 33 */
|
||||
d = HH(d, a, b, c, x[8], 11, 0x8771f681); /* 34 */
|
||||
c = HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
|
||||
b = HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
|
||||
a = HH(a, b, c, d, x[1], 4, 0xa4beea44); /* 37 */
|
||||
d = HH(d, a, b, c, x[4], 11, 0x4bdecfa9); /* 38 */
|
||||
c = HH(c, d, a, b, x[7], 16, 0xf6bb4b60); /* 39 */
|
||||
b = HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
|
||||
a = HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
|
||||
d = HH(d, a, b, c, x[0], 11, 0xeaa127fa); /* 42 */
|
||||
c = HH(c, d, a, b, x[3], 16, 0xd4ef3085); /* 43 */
|
||||
b = HH(b, c, d, a, x[6], 23, 0x04881d05); /* 44 */
|
||||
a = HH(a, b, c, d, x[9], 4, 0xd9d4d039); /* 45 */
|
||||
d = HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
|
||||
c = HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
|
||||
b = HH(b, c, d, a, x[2], 23, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
a = II(a, b, c, d, x[0], 6, 0xf4292244); /* 49 */
|
||||
d = II(d, a, b, c, x[7], 10, 0x432aff97); /* 50 */
|
||||
c = II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
|
||||
b = II(b, c, d, a, x[5], 21, 0xfc93a039); /* 52 */
|
||||
a = II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
|
||||
d = II(d, a, b, c, x[3], 10, 0x8f0ccc92); /* 54 */
|
||||
c = II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
|
||||
b = II(b, c, d, a, x[1], 21, 0x85845dd1); /* 56 */
|
||||
a = II(a, b, c, d, x[8], 6, 0x6fa87e4f); /* 57 */
|
||||
d = II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
|
||||
c = II(c, d, a, b, x[6], 15, 0xa3014314); /* 59 */
|
||||
b = II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
|
||||
a = II(a, b, c, d, x[4], 6, 0xf7537e82); /* 61 */
|
||||
d = II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
|
||||
c = II(c, d, a, b, x[2], 15, 0x2ad7d2bb); /* 63 */
|
||||
b = II(b, c, d, a, x[9], 21, 0xeb86d391); /* 64 */
|
||||
|
||||
state.state[0] += a;
|
||||
state.state[1] += b;
|
||||
state.state[2] += c;
|
||||
state.state[3] += d;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.owasp.webgoat.lessons.challenges.challenge7;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* WARNING: DO NOT CHANGE FILE WITHOUT CHANGING .git contents
|
||||
*
|
||||
* @author nbaars
|
||||
* @since 8/17/17.
|
||||
*/
|
||||
public class PasswordResetLink {
|
||||
|
||||
public String createPasswordReset(String username, String key) {
|
||||
Random random = new Random();
|
||||
if (username.equalsIgnoreCase("admin")) {
|
||||
//Admin has a fix reset link
|
||||
random.setSeed(key.length());
|
||||
}
|
||||
return scramble(random, scramble(random, scramble(random, MD5.getHashString(username))));
|
||||
}
|
||||
|
||||
public static String scramble(Random random, String inputString) {
|
||||
char[] a = inputString.toCharArray();
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
int j = random.nextInt(a.length);
|
||||
char temp = a[i];
|
||||
a[i] = a[j];
|
||||
a[j] = temp;
|
||||
}
|
||||
return new String(a);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (args == null || args.length != 2) {
|
||||
System.out.println("Need a username and key");
|
||||
System.exit(1);
|
||||
}
|
||||
String username = args[0];
|
||||
String key = args[1];
|
||||
System.out.println("Generation password reset link for " + username);
|
||||
System.out.println("Created password reset link: " + new PasswordResetLink().createPasswordReset(username, key));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package org.owasp.webgoat.lessons.challenges.challenge8;
|
||||
|
||||
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.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/8/17.
|
||||
*/
|
||||
@RestController
|
||||
@Slf4j
|
||||
public class Assignment8 extends AssignmentEndpoint {
|
||||
|
||||
private static final Map<Integer, Integer> votes = new HashMap<>();
|
||||
|
||||
static {
|
||||
votes.put(1, 400);
|
||||
votes.put(2, 120);
|
||||
votes.put(3, 140);
|
||||
votes.put(4, 150);
|
||||
votes.put(5, 300);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/challenge/8/vote/{stars}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public ResponseEntity<?> vote(@PathVariable(value = "stars") int nrOfStars, HttpServletRequest request) {
|
||||
//Simple implementation of VERB Based Authentication
|
||||
String msg = "";
|
||||
if (request.getMethod().equals("GET")) {
|
||||
var json = Map.of("error", true, "message", "Sorry but you need to login first in order to vote");
|
||||
return ResponseEntity.status(200).body(json);
|
||||
}
|
||||
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)).build();
|
||||
}
|
||||
|
||||
@GetMapping("/challenge/8/votes/")
|
||||
public ResponseEntity<?> getVotes() {
|
||||
return ResponseEntity.ok(votes.entrySet().stream().collect(Collectors.toMap(e -> "" + e.getKey(), e -> e.getValue())));
|
||||
}
|
||||
|
||||
@GetMapping("/challenge/8/votes/average")
|
||||
public ResponseEntity<Map<String, Integer>> average() {
|
||||
int totalNumberOfVotes = votes.values().stream().mapToInt(i -> i.intValue()).sum();
|
||||
int categories = votes.entrySet().stream().mapToInt(e -> e.getKey() * e.getValue()).reduce(0, (a, b) -> a + b);
|
||||
var json = Map.of("average", (int) Math.ceil((double) categories / totalNumberOfVotes));
|
||||
return ResponseEntity.ok(json);
|
||||
}
|
||||
|
||||
@GetMapping("/challenge/8/notUsed")
|
||||
public AttackResult notUsed() {
|
||||
throw new IllegalStateException("Should never be called, challenge specific method");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.owasp.webgoat.lessons.challenges.challenge8;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/21/17.
|
||||
*/
|
||||
@Component
|
||||
public class Challenge8 extends Lesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.CHALLENGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "challenge8.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.chrome_dev_tools;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author TMelzer
|
||||
* @since 30.11.18
|
||||
*/
|
||||
@Component
|
||||
public class ChromeDevTools extends Lesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.GENERAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "3.chrome-dev-tools.title";//3rd lesson in General
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.chrome_dev_tools;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
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;
|
||||
|
||||
/**
|
||||
* This is just a class used to make the the HTTP request.
|
||||
*
|
||||
* @author TMelzer
|
||||
* @since 30.11.18
|
||||
*/
|
||||
@RestController
|
||||
public class NetworkDummy extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping("/ChromeDevTools/dummy")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String successMessage) {
|
||||
UserSessionData userSessionData = getUserSessionData();
|
||||
String answer = (String) userSessionData.getValue("randValue");
|
||||
|
||||
if (successMessage != null && successMessage.equals(answer)) {
|
||||
return success(this).feedback("xss-dom-message-success").build();
|
||||
} else {
|
||||
return failed(this).feedback("xss-dom-message-failure").build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.chrome_dev_tools;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Assignment where the user has to look through an HTTP Request
|
||||
* using the Developer Tools and find a specific number.
|
||||
*
|
||||
* @author TMelzer
|
||||
* @since 30.11.18
|
||||
*/
|
||||
@RestController
|
||||
@AssignmentHints({"networkHint1", "networkHint2"})
|
||||
public class NetworkLesson extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping(value = "/ChromeDevTools/network", params = {"network_num", "number"})
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String network_num, @RequestParam String number) {
|
||||
if (network_num.equals(number)) {
|
||||
return success(this).feedback("network.success").output("").build();
|
||||
} else {
|
||||
return failed(this).feedback("network.failed").build();
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(path = "/ChromeDevTools/network", params = "networkNum")
|
||||
@ResponseBody
|
||||
public ResponseEntity<?> ok(@RequestParam String networkNum) {
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
}
|
||||
23
src/main/java/org/owasp/webgoat/lessons/cia/CIA.java
Normal file
23
src/main/java/org/owasp/webgoat/lessons/cia/CIA.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package org.owasp.webgoat.lessons.cia;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author BenediktStuhrmann
|
||||
* @since 11/2/18.
|
||||
*/
|
||||
@Component
|
||||
public class CIA extends Lesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.GENERAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "4.cia.title";//4th lesson in general
|
||||
}
|
||||
}
|
||||
48
src/main/java/org/owasp/webgoat/lessons/cia/CIAQuiz.java
Normal file
48
src/main/java/org/owasp/webgoat/lessons/cia/CIAQuiz.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package org.owasp.webgoat.lessons.cia;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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
|
||||
public class CIAQuiz extends AssignmentEndpoint {
|
||||
|
||||
String[] solutions = {"Solution 3", "Solution 1", "Solution 4", "Solution 2"};
|
||||
boolean[] guesses = new boolean[solutions.length];
|
||||
|
||||
@PostMapping("/cia/quiz")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String[] question_0_solution, @RequestParam String[] question_1_solution, @RequestParam String[] question_2_solution, @RequestParam String[] question_3_solution) {
|
||||
int correctAnswers = 0;
|
||||
|
||||
String[] givenAnswers = {question_0_solution[0], question_1_solution[0], question_2_solution[0], question_3_solution[0]};
|
||||
|
||||
for (int i = 0; i < solutions.length; i++) {
|
||||
if (givenAnswers[i].contains(solutions[i])) {
|
||||
// answer correct
|
||||
correctAnswers++;
|
||||
guesses[i] = true;
|
||||
} else {
|
||||
// answer incorrect
|
||||
guesses[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (correctAnswers == solutions.length) {
|
||||
return success(this).build();
|
||||
} else {
|
||||
return failed(this).build();
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/cia/quiz")
|
||||
@ResponseBody
|
||||
public boolean[] getResults() {
|
||||
return this.guesses;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.owasp.webgoat.lessons.client_side_filtering;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 2014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*
|
||||
* @author WebGoat
|
||||
* @version $Id: $Id
|
||||
* @since October 12, 2016
|
||||
*/
|
||||
@Component
|
||||
public class ClientSideFiltering extends Lesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.CLIENT_SIDE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "client.side.filtering.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.client_side_filtering;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
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
|
||||
@AssignmentHints({"ClientSideFilteringHint1", "ClientSideFilteringHint2", "ClientSideFilteringHint3", "ClientSideFilteringHint4"})
|
||||
public class ClientSideFilteringAssignment extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping("/clientSideFiltering/attack1")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String answer) {
|
||||
return "450000".equals(answer)
|
||||
? success(this).feedback("assignment.solved").build() :
|
||||
failed(this).feedback("ClientSideFiltering.incorrect").build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.client_side_filtering;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/6/17.
|
||||
*/
|
||||
@RestController
|
||||
@AssignmentHints({"client.side.filtering.free.hint1", "client.side.filtering.free.hint2", "client.side.filtering.free.hint3"})
|
||||
public class ClientSideFilteringFreeAssignment extends AssignmentEndpoint {
|
||||
|
||||
public static final String SUPER_COUPON_CODE = "get_it_for_free";
|
||||
|
||||
@PostMapping("/clientSideFiltering/getItForFree")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String checkoutCode) {
|
||||
if (SUPER_COUPON_CODE.equals(checkoutCode)) {
|
||||
return success(this).build();
|
||||
}
|
||||
return failed(this).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.client_side_filtering;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@Slf4j
|
||||
public class Salaries {
|
||||
|
||||
@Value("${webgoat.user.directory}")
|
||||
private String webGoatHomeDirectory;
|
||||
|
||||
@PostConstruct
|
||||
public void copyFiles() {
|
||||
ClassPathResource classPathResource = new ClassPathResource("lessons/employees.xml");
|
||||
File targetDirectory = new File(webGoatHomeDirectory, "/ClientSideFiltering");
|
||||
if (!targetDirectory.exists()) {
|
||||
targetDirectory.mkdir();
|
||||
}
|
||||
try {
|
||||
FileCopyUtils.copy(classPathResource.getInputStream(), new FileOutputStream(new File(targetDirectory, "employees.xml")));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("clientSideFiltering/salaries")
|
||||
@ResponseBody
|
||||
public List<Map<String, Object>> invoke() {
|
||||
NodeList nodes = null;
|
||||
File d = new File(webGoatHomeDirectory, "ClientSideFiltering/employees.xml");
|
||||
XPathFactory factory = XPathFactory.newInstance();
|
||||
XPath path = factory.newXPath();
|
||||
try (InputStream is = new FileInputStream(d)) {
|
||||
InputSource inputSource = new InputSource(is);
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
sb.append("/Employees/Employee/UserID | ");
|
||||
sb.append("/Employees/Employee/FirstName | ");
|
||||
sb.append("/Employees/Employee/LastName | ");
|
||||
sb.append("/Employees/Employee/SSN | ");
|
||||
sb.append("/Employees/Employee/Salary ");
|
||||
|
||||
String expression = sb.toString();
|
||||
nodes = (NodeList) path.evaluate(expression, inputSource, XPathConstants.NODESET);
|
||||
} catch (XPathExpressionException e) {
|
||||
log.error("Unable to parse xml", e);
|
||||
} catch (IOException e) {
|
||||
log.error("Unable to read employees.xml at location: '{}'", d);
|
||||
}
|
||||
int columns = 5;
|
||||
List json = new ArrayList();
|
||||
java.util.Map<String, Object> employeeJson = new HashMap<>();
|
||||
for (int i = 0; i < nodes.getLength(); i++) {
|
||||
if (i % columns == 0) {
|
||||
employeeJson = new HashMap<>();
|
||||
json.add(employeeJson);
|
||||
}
|
||||
Node node = nodes.item(i);
|
||||
employeeJson.put(node.getNodeName(), node.getTextContent());
|
||||
}
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.client_side_filtering;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/6/17.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/clientSideFiltering/challenge-store")
|
||||
public class ShopEndpoint {
|
||||
|
||||
@AllArgsConstructor
|
||||
private class CheckoutCodes {
|
||||
|
||||
@Getter
|
||||
private List<CheckoutCode> codes;
|
||||
|
||||
public Optional<CheckoutCode> get(String code) {
|
||||
return codes.stream().filter(c -> c.getCode().equals(code)).findFirst();
|
||||
}
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
private class CheckoutCode {
|
||||
private String code;
|
||||
private int discount;
|
||||
}
|
||||
|
||||
private CheckoutCodes checkoutCodes;
|
||||
|
||||
public ShopEndpoint() {
|
||||
List<CheckoutCode> codes = Lists.newArrayList();
|
||||
codes.add(new CheckoutCode("webgoat", 25));
|
||||
codes.add(new CheckoutCode("owasp", 25));
|
||||
codes.add(new CheckoutCode("owasp-webgoat", 50));
|
||||
this.checkoutCodes = new CheckoutCodes(codes);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/coupons/{code}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public CheckoutCode getDiscountCode(@PathVariable String code) {
|
||||
if (ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE.equals(code)) {
|
||||
return new CheckoutCode(ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE, 100);
|
||||
}
|
||||
return checkoutCodes.get(code).orElse(new CheckoutCode("no", 0));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/coupons", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public CheckoutCodes all() {
|
||||
List<CheckoutCode> all = Lists.newArrayList();
|
||||
all.addAll(this.checkoutCodes.getCodes());
|
||||
all.add(new CheckoutCode(ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE, 100));
|
||||
return new CheckoutCodes(all);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package org.owasp.webgoat.lessons.cryptography;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Signature;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.RSAKeyGenParameterSpec;
|
||||
import java.util.Base64;
|
||||
|
||||
@Slf4j
|
||||
public class CryptoUtil {
|
||||
|
||||
private static final BigInteger[] FERMAT_PRIMES =
|
||||
{ BigInteger.valueOf(3),
|
||||
BigInteger.valueOf(5),
|
||||
BigInteger.valueOf(17),
|
||||
BigInteger.valueOf(257),
|
||||
BigInteger.valueOf(65537) };
|
||||
|
||||
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||
RSAKeyGenParameterSpec kpgSpec = new RSAKeyGenParameterSpec(2048, FERMAT_PRIMES[new SecureRandom().nextInt(FERMAT_PRIMES.length)]);
|
||||
keyPairGenerator.initialize(kpgSpec);
|
||||
//keyPairGenerator.initialize(2048);
|
||||
return keyPairGenerator.generateKeyPair();
|
||||
}
|
||||
|
||||
public static String getPrivateKeyInPEM(KeyPair keyPair) {
|
||||
String encodedString = "-----BEGIN PRIVATE KEY-----\n";
|
||||
encodedString = encodedString+new String(Base64.getEncoder().encode(keyPair.getPrivate().getEncoded()),Charset.forName("UTF-8"))+"\n";
|
||||
encodedString = encodedString+"-----END PRIVATE KEY-----\n";
|
||||
return encodedString;
|
||||
}
|
||||
|
||||
public static String signMessage(String message, PrivateKey privateKey) {
|
||||
|
||||
log.debug("start signMessage");
|
||||
String signature = null;
|
||||
|
||||
try {
|
||||
//Initiate signature verification
|
||||
Signature instance = Signature.getInstance("SHA256withRSA");
|
||||
instance.initSign(privateKey);
|
||||
instance.update(message.getBytes("UTF-8"));
|
||||
|
||||
//actual verification against signature
|
||||
signature = new String(Base64.getEncoder().encode(instance.sign()), Charset.forName("UTF-8"));
|
||||
|
||||
log.info("signe the signature with result: {}", signature);
|
||||
} catch (Exception e) {
|
||||
log.error("Signature signing failed", e);
|
||||
}
|
||||
|
||||
log.debug("end signMessage");
|
||||
return signature;
|
||||
}
|
||||
|
||||
public static boolean verifyMessage(String message, String base64EncSignature,
|
||||
PublicKey publicKey) {
|
||||
|
||||
log.debug("start verifyMessage");
|
||||
boolean result = false;
|
||||
|
||||
try {
|
||||
|
||||
base64EncSignature = base64EncSignature.replace("\r", "").replace("\n", "")
|
||||
.replace(" ", "");
|
||||
//get raw signature from base64 encrypted string in header
|
||||
byte[] decodedSignature = Base64.getDecoder().decode(base64EncSignature);
|
||||
|
||||
//Initiate signature verification
|
||||
Signature instance = Signature.getInstance("SHA256withRSA");
|
||||
instance.initVerify(publicKey);
|
||||
instance.update(message.getBytes("UTF-8"));
|
||||
|
||||
//actual verification against signature
|
||||
result = instance.verify(decodedSignature);
|
||||
|
||||
log.info("Verified the signature with result: {}", result);
|
||||
} catch (Exception e) {
|
||||
log.error("Signature verification failed", e);
|
||||
}
|
||||
|
||||
log.debug("end verifyMessage");
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean verifyAssignment(String modulus, String signature, PublicKey publicKey) {
|
||||
|
||||
/* first check if the signature is correct, i.e. right private key and right hash */
|
||||
boolean result = false;
|
||||
|
||||
if (modulus != null && signature != null) {
|
||||
result = verifyMessage(modulus, signature, publicKey);
|
||||
|
||||
/*
|
||||
* next check if the submitted modulus is the correct modulus of the public key
|
||||
*/
|
||||
RSAPublicKey rsaPubKey = (RSAPublicKey) publicKey;
|
||||
if (modulus.length()==512) {
|
||||
modulus = "00".concat(modulus);
|
||||
}
|
||||
result = result && (DatatypeConverter.printHexBinary(rsaPubKey.getModulus().toByteArray()).equals(modulus.toUpperCase()));
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
public static PrivateKey getPrivateKeyFromPEM(String privateKeyPem) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
privateKeyPem = privateKeyPem.replace("-----BEGIN PRIVATE KEY-----", "");
|
||||
privateKeyPem = privateKeyPem.replace("-----END PRIVATE KEY-----", "");
|
||||
privateKeyPem = privateKeyPem.replace("\n", "").replace("\r", "");
|
||||
|
||||
|
||||
byte [] decoded = Base64.getDecoder().decode(privateKeyPem);
|
||||
|
||||
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);
|
||||
KeyFactory kf = KeyFactory.getInstance("RSA");
|
||||
return kf.generatePrivate(spec);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.cryptography;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class Cryptography extends Lesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.GENERAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "6.crypto.title";//first lesson in general
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.cryptography;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Base64;
|
||||
import java.util.Random;
|
||||
|
||||
@RestController
|
||||
public class EncodingAssignment extends AssignmentEndpoint {
|
||||
|
||||
public static String getBasicAuth(String username, String password) {
|
||||
return Base64.getEncoder().encodeToString(username.concat(":").concat(password).getBytes());
|
||||
}
|
||||
|
||||
@GetMapping(path="/crypto/encoding/basic",produces=MediaType.TEXT_HTML_VALUE)
|
||||
@ResponseBody
|
||||
public String getBasicAuth(HttpServletRequest request) {
|
||||
|
||||
String basicAuth = (String) request.getSession().getAttribute("basicAuth");
|
||||
String username = request.getUserPrincipal().getName();
|
||||
if (basicAuth == null) {
|
||||
String password = HashingAssignment.SECRETS[new Random().nextInt(HashingAssignment.SECRETS.length)];
|
||||
basicAuth = getBasicAuth(username, password);
|
||||
request.getSession().setAttribute("basicAuth", basicAuth);
|
||||
}
|
||||
return "Authorization: Basic ".concat(basicAuth);
|
||||
}
|
||||
|
||||
@PostMapping("/crypto/encoding/basic-auth")
|
||||
@ResponseBody
|
||||
public AttackResult completed(HttpServletRequest request, @RequestParam String answer_user, @RequestParam String answer_pwd) {
|
||||
String basicAuth = (String) request.getSession().getAttribute("basicAuth");
|
||||
if (basicAuth !=null && answer_user!=null && answer_pwd !=null
|
||||
&& basicAuth.equals(getBasicAuth(answer_user,answer_pwd)))
|
||||
{
|
||||
return success(this)
|
||||
.feedback("crypto-encoding.success")
|
||||
.build();
|
||||
} else {
|
||||
return failed(this).feedback("crypto-encoding.empty").build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.cryptography;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Random;
|
||||
|
||||
@RestController
|
||||
@AssignmentHints({"crypto-hashing.hints.1","crypto-hashing.hints.2"})
|
||||
public class HashingAssignment extends AssignmentEndpoint {
|
||||
|
||||
public static final String[] SECRETS = {"secret","admin","password", "123456", "passw0rd"};
|
||||
|
||||
@RequestMapping(path="/crypto/hashing/md5",produces=MediaType.TEXT_HTML_VALUE)
|
||||
@ResponseBody
|
||||
public String getMd5(HttpServletRequest request) throws NoSuchAlgorithmException {
|
||||
|
||||
String md5Hash = (String) request.getSession().getAttribute("md5Hash");
|
||||
if (md5Hash == null) {
|
||||
|
||||
String secret = SECRETS[new Random().nextInt(SECRETS.length)];
|
||||
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
md.update(secret.getBytes());
|
||||
byte[] digest = md.digest();
|
||||
md5Hash = DatatypeConverter
|
||||
.printHexBinary(digest).toUpperCase();
|
||||
request.getSession().setAttribute("md5Hash", md5Hash);
|
||||
request.getSession().setAttribute("md5Secret", secret);
|
||||
}
|
||||
return md5Hash;
|
||||
}
|
||||
|
||||
@RequestMapping(path="/crypto/hashing/sha256",produces=MediaType.TEXT_HTML_VALUE)
|
||||
@ResponseBody
|
||||
public String getSha256(HttpServletRequest request) throws NoSuchAlgorithmException {
|
||||
|
||||
String sha256 = (String) request.getSession().getAttribute("sha256");
|
||||
if (sha256 == null) {
|
||||
String secret = SECRETS[new Random().nextInt(SECRETS.length)];
|
||||
sha256 = getHash(secret, "SHA-256");
|
||||
request.getSession().setAttribute("sha256Hash", sha256);
|
||||
request.getSession().setAttribute("sha256Secret", secret);
|
||||
}
|
||||
return sha256;
|
||||
}
|
||||
|
||||
@PostMapping("/crypto/hashing")
|
||||
@ResponseBody
|
||||
public AttackResult completed(HttpServletRequest request, @RequestParam String answer_pwd1, @RequestParam String answer_pwd2) {
|
||||
|
||||
String md5Secret = (String) request.getSession().getAttribute("md5Secret");
|
||||
String sha256Secret = (String) request.getSession().getAttribute("sha256Secret");
|
||||
|
||||
if (answer_pwd1!=null && answer_pwd2 !=null) {
|
||||
if (answer_pwd1.equals(md5Secret)
|
||||
&& answer_pwd2.equals(sha256Secret)) {
|
||||
return success(this)
|
||||
.feedback("crypto-hashing.success")
|
||||
.build();
|
||||
} else if (answer_pwd1.equals(md5Secret)
|
||||
|| answer_pwd2.equals(sha256Secret)) {
|
||||
return failed(this).feedback("crypto-hashing.oneok").build();
|
||||
}
|
||||
}
|
||||
return failed(this).feedback("crypto-hashing.empty").build();
|
||||
}
|
||||
|
||||
public static String getHash(String secret, String algorithm) throws NoSuchAlgorithmException {
|
||||
MessageDigest md = MessageDigest.getInstance(algorithm);
|
||||
md.update(secret.getBytes());
|
||||
byte[] digest = md.digest();
|
||||
return DatatypeConverter
|
||||
.printHexBinary(digest).toUpperCase();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.cryptography;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
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;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
@RestController
|
||||
@AssignmentHints({"crypto-secure-defaults.hints.1", "crypto-secure-defaults.hints.2", "crypto-secure-defaults.hints.3"})
|
||||
public class SecureDefaultsAssignment extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping("/crypto/secure/defaults")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String secretFileName, @RequestParam String secretText) throws NoSuchAlgorithmException {
|
||||
if (secretFileName!=null && secretFileName.equals("default_secret")) {
|
||||
if (secretText!=null && HashingAssignment.getHash(secretText, "SHA-256").equalsIgnoreCase("34de66e5caf2cb69ff2bebdc1f3091ecf6296852446c718e38ebfa60e4aa75d2")) {
|
||||
return success(this)
|
||||
.feedback("crypto-secure-defaults.success")
|
||||
.build();
|
||||
} else {
|
||||
return failed(this).feedback("crypto-secure-defaults.messagenotok").build();
|
||||
}
|
||||
}
|
||||
return failed(this).feedback("crypto-secure-defaults.notok").build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.cryptography;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
|
||||
@RestController
|
||||
@AssignmentHints({"crypto-signing.hints.1","crypto-signing.hints.2", "crypto-signing.hints.3", "crypto-signing.hints.4"})
|
||||
@Slf4j
|
||||
public class SigningAssignment extends AssignmentEndpoint {
|
||||
|
||||
@RequestMapping(path="/crypto/signing/getprivate",produces=MediaType.TEXT_HTML_VALUE)
|
||||
@ResponseBody
|
||||
public String getPrivateKey(HttpServletRequest request) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
|
||||
|
||||
String privateKey = (String) request.getSession().getAttribute("privateKeyString");
|
||||
if (privateKey == null) {
|
||||
KeyPair keyPair = CryptoUtil.generateKeyPair();
|
||||
privateKey = CryptoUtil.getPrivateKeyInPEM(keyPair);
|
||||
request.getSession().setAttribute("privateKeyString", privateKey);
|
||||
request.getSession().setAttribute("keyPair", keyPair);
|
||||
}
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
@PostMapping("/crypto/signing/verify")
|
||||
@ResponseBody
|
||||
public AttackResult completed(HttpServletRequest request, @RequestParam String modulus, @RequestParam String signature) {
|
||||
|
||||
String tempModulus = modulus;/* used to validate the modulus of the public key but might need to be corrected */
|
||||
KeyPair keyPair = (KeyPair) request.getSession().getAttribute("keyPair");
|
||||
RSAPublicKey rsaPubKey = (RSAPublicKey) keyPair.getPublic();
|
||||
if (tempModulus.length() == 512) {
|
||||
tempModulus = "00".concat(tempModulus);
|
||||
}
|
||||
if (!DatatypeConverter.printHexBinary(rsaPubKey.getModulus().toByteArray()).equals(tempModulus.toUpperCase())) {
|
||||
log.warn("modulus {} incorrect", modulus);
|
||||
return failed(this).feedback("crypto-signing.modulusnotok").build();
|
||||
}
|
||||
/* orginal modulus must be used otherwise the signature would be invalid */
|
||||
if (CryptoUtil.verifyMessage(modulus, signature, keyPair.getPublic())) {
|
||||
return success(this).feedback("crypto-signing.success").build();
|
||||
} else {
|
||||
log.warn("signature incorrect");
|
||||
return failed(this).feedback("crypto-signing.notok").build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.cryptography;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
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
|
||||
@AssignmentHints({"crypto-encoding-xor.hints.1"})
|
||||
public class XOREncodingAssignment extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping("/crypto/encoding/xor")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String answer_pwd1) {
|
||||
if (answer_pwd1!=null && answer_pwd1.equals("databasepassword")) {
|
||||
return success(this)
|
||||
.feedback("crypto-encoding-xor.success")
|
||||
.build();
|
||||
}
|
||||
return failed(this).feedback("crypto-encoding-xor.empty").build();
|
||||
}
|
||||
}
|
||||
41
src/main/java/org/owasp/webgoat/lessons/csrf/CSRF.java
Normal file
41
src/main/java/org/owasp/webgoat/lessons/csrf/CSRF.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.csrf;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Created by jason on 9/29/17.
|
||||
*/
|
||||
@Component
|
||||
public class CSRF extends Lesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.REQUEST_FORGERIES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() { return "csrf.title"; }
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.csrf;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* Created by jason on 9/29/17.
|
||||
*/
|
||||
|
||||
@RestController
|
||||
@AssignmentHints({"csrf-get.hint1", "csrf-get.hint2", "csrf-get.hint3", "csrf-get.hint4"})
|
||||
public class CSRFConfirmFlag1 extends AssignmentEndpoint {
|
||||
|
||||
@Autowired
|
||||
UserSessionData userSessionData;
|
||||
|
||||
@PostMapping(path = "/csrf/confirm-flag-1", produces = {"application/json"})
|
||||
@ResponseBody
|
||||
public AttackResult completed(String confirmFlagVal) {
|
||||
Object userSessionDataStr = userSessionData.getValue("csrf-get-success");
|
||||
if (userSessionDataStr != null && confirmFlagVal.equals(userSessionDataStr.toString())) {
|
||||
return success(this)
|
||||
.feedback("csrf-get-null-referer.success")
|
||||
.output("Correct, the flag was " + userSessionData.getValue("csrf-get-success"))
|
||||
.build();
|
||||
}
|
||||
|
||||
return failed(this).build();
|
||||
}
|
||||
}
|
||||
120
src/main/java/org/owasp/webgoat/lessons/csrf/CSRFFeedback.java
Normal file
120
src/main/java/org/owasp/webgoat/lessons/csrf/CSRFFeedback.java
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.csrf;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 11/17/17.
|
||||
*/
|
||||
@RestController
|
||||
@AssignmentHints({"csrf-feedback-hint1", "csrf-feedback-hint2", "csrf-feedback-hint3"})
|
||||
public class CSRFFeedback extends AssignmentEndpoint {
|
||||
|
||||
@Autowired
|
||||
private UserSessionData userSessionData;
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@PostMapping(value = "/csrf/feedback/message", produces = {"application/json"})
|
||||
@ResponseBody
|
||||
public AttackResult completed(HttpServletRequest request, @RequestBody String feedback) {
|
||||
try {
|
||||
objectMapper.enable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES);
|
||||
objectMapper.enable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);
|
||||
objectMapper.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS);
|
||||
objectMapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY);
|
||||
objectMapper.enable(DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES);
|
||||
objectMapper.enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS);
|
||||
objectMapper.readValue(feedback.getBytes(), Map.class);
|
||||
} catch (IOException e) {
|
||||
return failed(this).feedback(ExceptionUtils.getStackTrace(e)).build();
|
||||
}
|
||||
boolean correctCSRF = requestContainsWebGoatCookie(request.getCookies()) && request.getContentType().contains(MediaType.TEXT_PLAIN_VALUE);
|
||||
correctCSRF &= hostOrRefererDifferentHost(request);
|
||||
if (correctCSRF) {
|
||||
String flag = UUID.randomUUID().toString();
|
||||
userSessionData.setValue("csrf-feedback", flag);
|
||||
return success(this).feedback("csrf-feedback-success").feedbackArgs(flag).build();
|
||||
}
|
||||
return failed(this).build();
|
||||
}
|
||||
|
||||
@PostMapping(path = "/csrf/feedback", produces = "application/json")
|
||||
@ResponseBody
|
||||
public AttackResult flag(@RequestParam("confirmFlagVal") String flag) {
|
||||
if (flag.equals(userSessionData.getValue("csrf-feedback"))) {
|
||||
return success(this).build();
|
||||
} else {
|
||||
return failed(this).build();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hostOrRefererDifferentHost(HttpServletRequest request) {
|
||||
String referer = request.getHeader("Referer");
|
||||
String host = request.getHeader("Host");
|
||||
if (referer != null) {
|
||||
return !referer.contains(host);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean requestContainsWebGoatCookie(Cookie[] cookies) {
|
||||
if (cookies != null) {
|
||||
for (Cookie c : cookies) {
|
||||
if (c.getName().equals("JSESSIONID")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Solution
|
||||
<form name="attack" enctype="text/plain" action="http://localhost:8080/WebGoat/csrf/feedback/message" METHOD="POST">
|
||||
<input type="hidden" name='{"name": "Test", "email": "test1233@dfssdf.de", "subject": "service", "message":"dsaffd"}'>
|
||||
</form>
|
||||
<script>document.attack.submit();</script>
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.csrf;
|
||||
|
||||
import org.owasp.webgoat.container.i18n.PluginMessages;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by jason on 9/30/17.
|
||||
*/
|
||||
@RestController
|
||||
public class CSRFGetFlag {
|
||||
|
||||
@Autowired
|
||||
UserSessionData userSessionData;
|
||||
@Autowired
|
||||
private PluginMessages pluginMessages;
|
||||
|
||||
@RequestMapping(path = "/csrf/basic-get-flag", produces = {"application/json"}, method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Map<String, Object> invoke(HttpServletRequest req) {
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
|
||||
String host = (req.getHeader("host") == null) ? "NULL" : req.getHeader("host");
|
||||
String referer = (req.getHeader("referer") == null) ? "NULL" : req.getHeader("referer");
|
||||
String[] refererArr = referer.split("/");
|
||||
|
||||
|
||||
if (referer.equals("NULL")) {
|
||||
if ("true".equals(req.getParameter("csrf"))) {
|
||||
Random random = new Random();
|
||||
userSessionData.setValue("csrf-get-success", random.nextInt(65536));
|
||||
response.put("success", true);
|
||||
response.put("message", pluginMessages.getMessage("csrf-get-null-referer.success"));
|
||||
response.put("flag", userSessionData.getValue("csrf-get-success"));
|
||||
} else {
|
||||
Random random = new Random();
|
||||
userSessionData.setValue("csrf-get-success", random.nextInt(65536));
|
||||
response.put("success", true);
|
||||
response.put("message", pluginMessages.getMessage("csrf-get-other-referer.success"));
|
||||
response.put("flag", userSessionData.getValue("csrf-get-success"));
|
||||
}
|
||||
} else if (refererArr[2].equals(host)) {
|
||||
response.put("success", false);
|
||||
response.put("message", "Appears the request came from the original host");
|
||||
response.put("flag", null);
|
||||
} else {
|
||||
Random random = new Random();
|
||||
userSessionData.setValue("csrf-get-success", random.nextInt(65536));
|
||||
response.put("success", true);
|
||||
response.put("message", pluginMessages.getMessage("csrf-get-other-referer.success"));
|
||||
response.put("flag", userSessionData.getValue("csrf-get-success"));
|
||||
}
|
||||
|
||||
return response;
|
||||
|
||||
}
|
||||
}
|
||||
66
src/main/java/org/owasp/webgoat/lessons/csrf/CSRFLogin.java
Normal file
66
src/main/java/org/owasp/webgoat/lessons/csrf/CSRFLogin.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.csrf;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.users.UserTracker;
|
||||
import org.owasp.webgoat.container.users.UserTrackerRepository;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 11/17/17.
|
||||
*/
|
||||
@RestController
|
||||
@AssignmentHints({"csrf-login-hint1", "csrf-login-hint2", "csrf-login-hint3"})
|
||||
public class CSRFLogin extends AssignmentEndpoint {
|
||||
|
||||
private final UserTrackerRepository userTrackerRepository;
|
||||
|
||||
public CSRFLogin(UserTrackerRepository userTrackerRepository) {
|
||||
this.userTrackerRepository = userTrackerRepository;
|
||||
}
|
||||
|
||||
@PostMapping(path = "/csrf/login", produces = {"application/json"})
|
||||
@ResponseBody
|
||||
public AttackResult completed(HttpServletRequest request) {
|
||||
String userName = request.getUserPrincipal().getName();
|
||||
if (userName.startsWith("csrf")) {
|
||||
markAssignmentSolvedWithRealUser(userName.substring("csrf-".length()));
|
||||
return success(this).feedback("csrf-login-success").build();
|
||||
}
|
||||
return failed(this).feedback("csrf-login-failed").feedbackArgs(userName).build();
|
||||
}
|
||||
|
||||
private void markAssignmentSolvedWithRealUser(String username) {
|
||||
UserTracker userTracker = userTrackerRepository.findByUser(username);
|
||||
userTracker.assignmentSolved(getWebSession().getCurrentLesson(), this.getClass().getSimpleName());
|
||||
userTrackerRepository.save(userTracker);
|
||||
}
|
||||
}
|
||||
114
src/main/java/org/owasp/webgoat/lessons/csrf/ForgedReviews.java
Normal file
114
src/main/java/org/owasp/webgoat/lessons/csrf/ForgedReviews.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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.csrf;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.springframework.http.MediaType.ALL_VALUE;
|
||||
|
||||
@RestController
|
||||
@AssignmentHints({"csrf-review-hint1", "csrf-review-hint2", "csrf-review-hint3"})
|
||||
public class ForgedReviews extends AssignmentEndpoint {
|
||||
|
||||
@Autowired
|
||||
private WebSession webSession;
|
||||
private static DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd, HH:mm:ss");
|
||||
|
||||
private static final Map<String, List<Review>> userReviews = new HashMap<>();
|
||||
private static final List<Review> REVIEWS = new ArrayList<>();
|
||||
private static final String weakAntiCSRF = "2aa14227b9a13d0bede0388a7fba9aa9";
|
||||
|
||||
|
||||
static {
|
||||
REVIEWS.add(new Review("secUriTy", DateTime.now().toString(fmt), "This is like swiss cheese", 0));
|
||||
REVIEWS.add(new Review("webgoat", DateTime.now().toString(fmt), "It works, sorta", 2));
|
||||
REVIEWS.add(new Review("guest", DateTime.now().toString(fmt), "Best, App, Ever", 5));
|
||||
REVIEWS.add(new Review("guest", DateTime.now().toString(fmt), "This app is so insecure, I didn't even post this review, can you pull that off too?", 1));
|
||||
}
|
||||
|
||||
@GetMapping(path = "/csrf/review", produces = MediaType.APPLICATION_JSON_VALUE, consumes = ALL_VALUE)
|
||||
@ResponseBody
|
||||
public Collection<Review> retrieveReviews() {
|
||||
Collection<Review> allReviews = Lists.newArrayList();
|
||||
Collection<Review> newReviews = userReviews.get(webSession.getUserName());
|
||||
if (newReviews != null) {
|
||||
allReviews.addAll(newReviews);
|
||||
}
|
||||
|
||||
allReviews.addAll(REVIEWS);
|
||||
|
||||
return allReviews;
|
||||
}
|
||||
|
||||
@PostMapping("/csrf/review")
|
||||
@ResponseBody
|
||||
public AttackResult createNewReview(String reviewText, Integer stars, String validateReq, HttpServletRequest request) {
|
||||
final String host = (request.getHeader("host") == null) ? "NULL" : request.getHeader("host");
|
||||
final String referer = (request.getHeader("referer") == null) ? "NULL" : request.getHeader("referer");
|
||||
final String[] refererArr = referer.split("/");
|
||||
|
||||
Review review = new Review();
|
||||
review.setText(reviewText);
|
||||
review.setDateTime(DateTime.now().toString(fmt));
|
||||
review.setUser(webSession.getUserName());
|
||||
review.setStars(stars);
|
||||
var reviews = userReviews.getOrDefault(webSession.getUserName(), new ArrayList<>());
|
||||
reviews.add(review);
|
||||
userReviews.put(webSession.getUserName(), reviews);
|
||||
//short-circuit
|
||||
if (validateReq == null || !validateReq.equals(weakAntiCSRF)) {
|
||||
return failed(this).feedback("csrf-you-forgot-something").build();
|
||||
}
|
||||
//we have the spoofed files
|
||||
if (referer != "NULL" && refererArr[2].equals(host)) {
|
||||
return failed(this).feedback("csrf-same-host").build();
|
||||
} else {
|
||||
return success(this).feedback("csrf-review.success").build(); //feedback("xss-stored-comment-failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
47
src/main/java/org/owasp/webgoat/lessons/csrf/Review.java
Normal file
47
src/main/java/org/owasp/webgoat/lessons/csrf/Review.java
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.csrf;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/8/17.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@XmlRootElement
|
||||
public class Review {
|
||||
private String user;
|
||||
private String dateTime;
|
||||
private String text;
|
||||
private Integer stars;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.owasp.webgoat.lessons.deserialization;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 2014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*
|
||||
* @author WebGoat
|
||||
* @version $Id: $Id
|
||||
* @since October 12, 2016
|
||||
*/
|
||||
@Component
|
||||
public class InsecureDeserialization extends Lesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.INSECURE_DESERIALIZATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "insecure-deserialization.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.deserialization;
|
||||
|
||||
import org.dummy.insecure.framework.VulnerableTaskHolder;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
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;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidClassException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.Base64;
|
||||
|
||||
@RestController
|
||||
@AssignmentHints({"insecure-deserialization.hints.1", "insecure-deserialization.hints.2", "insecure-deserialization.hints.3"})
|
||||
public class InsecureDeserializationTask extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping("/InsecureDeserialization/task")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String token) throws IOException {
|
||||
String b64token;
|
||||
long before;
|
||||
long after;
|
||||
int delay;
|
||||
|
||||
b64token = token.replace('-', '+').replace('_', '/');
|
||||
|
||||
try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(b64token)))) {
|
||||
before = System.currentTimeMillis();
|
||||
Object o = ois.readObject();
|
||||
if (!(o instanceof VulnerableTaskHolder)) {
|
||||
if (o instanceof String) {
|
||||
return failed(this).feedback("insecure-deserialization.stringobject").build();
|
||||
}
|
||||
return failed(this).feedback("insecure-deserialization.wrongobject").build();
|
||||
}
|
||||
after = System.currentTimeMillis();
|
||||
} catch (InvalidClassException e) {
|
||||
return failed(this).feedback("insecure-deserialization.invalidversion").build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return failed(this).feedback("insecure-deserialization.expired").build();
|
||||
} catch (Exception e) {
|
||||
return failed(this).feedback("insecure-deserialization.invalidversion").build();
|
||||
}
|
||||
|
||||
delay = (int) (after - before);
|
||||
if (delay > 7000) {
|
||||
return failed(this).build();
|
||||
}
|
||||
if (delay < 3000) {
|
||||
return failed(this).build();
|
||||
}
|
||||
return success(this).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.owasp.webgoat.lessons.deserialization;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.Base64;
|
||||
|
||||
public class SerializationHelper {
|
||||
|
||||
private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
|
||||
|
||||
public static Object fromString(String s) throws IOException,
|
||||
ClassNotFoundException {
|
||||
byte[] data = Base64.getDecoder().decode(s);
|
||||
ObjectInputStream ois = new ObjectInputStream(
|
||||
new ByteArrayInputStream(data));
|
||||
Object o = ois.readObject();
|
||||
ois.close();
|
||||
return o;
|
||||
}
|
||||
|
||||
public static String toString(Serializable o) throws IOException {
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(o);
|
||||
oos.close();
|
||||
return Base64.getEncoder().encodeToString(baos.toByteArray());
|
||||
}
|
||||
|
||||
public static String show() throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(baos);
|
||||
dos.writeLong(-8699352886133051976L);
|
||||
dos.close();
|
||||
byte[] longBytes = baos.toByteArray();
|
||||
return bytesToHex(longBytes);
|
||||
}
|
||||
|
||||
public static String bytesToHex(byte[] bytes) {
|
||||
char[] hexChars = new char[bytes.length * 2];
|
||||
for (int j = 0; j < bytes.length; j++) {
|
||||
int v = bytes[j] & 0xFF;
|
||||
hexChars[j * 2] = hexArray[v >>> 4];
|
||||
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
|
||||
}
|
||||
return new String(hexChars);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 2021 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.hijacksession;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/***
|
||||
*
|
||||
* @author Angel Olle Blazquez
|
||||
*
|
||||
*/
|
||||
|
||||
@Component
|
||||
public class HijackSession extends Lesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.SESSION_MANAGEMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "hijacksession.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 2021 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.hijacksession;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.lessons.hijacksession.cas.Authentication;
|
||||
import org.owasp.webgoat.lessons.hijacksession.cas.HijackSessionAuthenticationProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.CookieValue;
|
||||
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;
|
||||
|
||||
/***
|
||||
*
|
||||
* @author Angel Olle Blazquez
|
||||
*
|
||||
*/
|
||||
|
||||
@RestController
|
||||
@AssignmentHints({
|
||||
"hijacksession.hints.1",
|
||||
"hijacksession.hints.2",
|
||||
"hijacksession.hints.3",
|
||||
"hijacksession.hints.4",
|
||||
"hijacksession.hints.5"
|
||||
})
|
||||
public class HijackSessionAssignment extends AssignmentEndpoint {
|
||||
|
||||
private static final String COOKIE_NAME = "hijack_cookie";
|
||||
|
||||
@Autowired
|
||||
HijackSessionAuthenticationProvider provider;
|
||||
|
||||
@PostMapping(path = "/HijackSession/login")
|
||||
@ResponseBody
|
||||
public AttackResult login(
|
||||
@RequestParam String username,
|
||||
@RequestParam String password,
|
||||
@CookieValue(value = COOKIE_NAME, required = false) String cookieValue,
|
||||
HttpServletResponse response) {
|
||||
|
||||
Authentication authentication;
|
||||
if (StringUtils.isEmpty(cookieValue)) {
|
||||
authentication = provider.authenticate(Authentication.builder().name(username).credentials(password).build());
|
||||
setCookie(response, authentication.getId());
|
||||
} else {
|
||||
authentication = provider.authenticate(Authentication.builder().id(cookieValue).build());
|
||||
}
|
||||
|
||||
if (authentication.isAuthenticated()) {
|
||||
return success(this).build();
|
||||
}
|
||||
|
||||
return failed(this).build();
|
||||
}
|
||||
|
||||
private void setCookie(HttpServletResponse response, String cookieValue) {
|
||||
Cookie cookie = new Cookie(COOKIE_NAME, cookieValue);
|
||||
cookie.setPath("/WebGoat");
|
||||
cookie.setSecure(true);
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 2021 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.hijacksession.cas;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Angel Olle Blazquez
|
||||
*
|
||||
*/
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
public class Authentication implements Principal {
|
||||
|
||||
private boolean authenticated = false;
|
||||
private String name;
|
||||
private Object credentials;
|
||||
private String id;
|
||||
|
||||
@Builder
|
||||
public Authentication(String name, Object credentials, String id) {
|
||||
this.name = name;
|
||||
this.credentials = credentials;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
protected void setAuthenticated(boolean authenticated) {
|
||||
this.authenticated = authenticated;
|
||||
}
|
||||
|
||||
protected void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 2021 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.hijacksession.cas;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Angel Olle Blazquez
|
||||
*
|
||||
*/
|
||||
|
||||
@FunctionalInterface
|
||||
public interface AuthenticationProvider<T extends Principal> {
|
||||
|
||||
T authenticate(T t);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 2021 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.hijacksession.cas;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.function.DoublePredicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.annotation.ApplicationScope;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Angel Olle Blazquez
|
||||
*
|
||||
*/
|
||||
|
||||
// weak id value and mechanism
|
||||
|
||||
@ApplicationScope
|
||||
@Component
|
||||
public class HijackSessionAuthenticationProvider implements AuthenticationProvider<Authentication> {
|
||||
|
||||
private Queue<String> sessions = new LinkedList<>();
|
||||
private static long id = new Random().nextLong() & Long.MAX_VALUE;
|
||||
protected static final int MAX_SESSIONS = 50;
|
||||
|
||||
private static final DoublePredicate PROBABILITY_DOUBLE_PREDICATE = pr -> pr < 0.75;
|
||||
private static final Supplier<String> GENERATE_SESSION_ID = () -> ++id + "-" + Instant.now().toEpochMilli();
|
||||
public static final Supplier<Authentication> AUTHENTICATION_SUPPLIER = () -> Authentication
|
||||
.builder()
|
||||
.id(GENERATE_SESSION_ID.get())
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) {
|
||||
if (authentication == null) {
|
||||
return AUTHENTICATION_SUPPLIER.get();
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(authentication.getId()) && sessions.contains(authentication.getId())) {
|
||||
authentication.setAuthenticated(true);
|
||||
return authentication;
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(authentication.getId())) {
|
||||
authentication.setId(GENERATE_SESSION_ID.get());
|
||||
}
|
||||
|
||||
authorizedUserAutoLogin();
|
||||
|
||||
return authentication;
|
||||
}
|
||||
|
||||
protected void authorizedUserAutoLogin() {
|
||||
if (!PROBABILITY_DOUBLE_PREDICATE.test(ThreadLocalRandom.current().nextDouble())) {
|
||||
Authentication authentication = AUTHENTICATION_SUPPLIER.get();
|
||||
authentication.setAuthenticated(true);
|
||||
addSession(authentication.getId());
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean addSession(String sessionId) {
|
||||
if (sessions.size() >= MAX_SESSIONS) {
|
||||
sessions.remove();
|
||||
}
|
||||
return sessions.add(sessionId);
|
||||
}
|
||||
|
||||
protected int getSessionsSize() {
|
||||
return sessions.size();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.owasp.webgoat.lessons.html_tampering;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 2014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*
|
||||
* @author WebGoat
|
||||
* @version $Id: $Id
|
||||
* @since October 12, 2016
|
||||
*/
|
||||
@Component
|
||||
public class HtmlTampering extends Lesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.CLIENT_SIDE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "html-tampering.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.html_tampering;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
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
|
||||
@AssignmentHints({"hint1", "hint2", "hint3"})
|
||||
public class HtmlTamperingTask extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping("/HtmlTampering/task")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String QTY, @RequestParam String Total) {
|
||||
if (Float.parseFloat(QTY) * 2999.99 > Float.parseFloat(Total) + 1) {
|
||||
return success(this).feedback("html-tampering.tamper.success").build();
|
||||
}
|
||||
return failed(this).feedback("html-tampering.tamper.failure").build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.http_basics;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class HttpBasics extends Lesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.GENERAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "1.http-basics.title";//first lesson in general
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.http_basics;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
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
|
||||
@AssignmentHints({"http-basics.hints.http_basics_lesson.1"})
|
||||
public class HttpBasicsLesson extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping("/HttpBasics/attack1")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String person) {
|
||||
if (!person.isBlank()) {
|
||||
return success(this)
|
||||
.feedback("http-basics.reversed")
|
||||
.feedbackArgs(new StringBuilder(person).reverse().toString())
|
||||
.build();
|
||||
} else {
|
||||
return failed(this).feedback("http-basics.empty").build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.http_basics;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
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
|
||||
@AssignmentHints({"http-basics.hints.http_basic_quiz.1", "http-basics.hints.http_basic_quiz.2"})
|
||||
@AssignmentPath("HttpBasics/attack2")
|
||||
public class HttpBasicsQuiz extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping("/HttpBasics/attack2")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String answer, @RequestParam String magic_answer, @RequestParam String magic_num) {
|
||||
if ("POST".equalsIgnoreCase(answer) && magic_answer.equals(magic_num)) {
|
||||
return success(this).build();
|
||||
} else {
|
||||
if (!"POST".equalsIgnoreCase(answer)) {
|
||||
return failed(this).feedback("http-basics.incorrect").build();
|
||||
}
|
||||
if (!magic_answer.equals(magic_num)) {
|
||||
return failed(this).feedback("http-basics.magic").build();
|
||||
}
|
||||
}
|
||||
return failed(this).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.http_proxies;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
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;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@RestController
|
||||
public class HttpBasicsInterceptRequest extends AssignmentEndpoint {
|
||||
|
||||
@RequestMapping(path = "/HttpProxies/intercept-request", method = {RequestMethod.POST, RequestMethod.GET})
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestHeader(value = "x-request-intercepted", required = false) Boolean headerValue,
|
||||
@RequestParam(value = "changeMe", required = false) String paramValue, HttpServletRequest request) {
|
||||
if (HttpMethod.POST.matches(request.getMethod())) {
|
||||
return failed(this).feedback("http-proxies.intercept.failure").build();
|
||||
}
|
||||
if (headerValue != null && paramValue != null && headerValue && "Requests are tampered easily".equalsIgnoreCase(paramValue)) {
|
||||
return success(this).feedback("http-proxies.intercept.success").build();
|
||||
} else {
|
||||
return failed(this).feedback("http-proxies.intercept.failure").build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.owasp.webgoat.lessons.http_proxies;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 2014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*
|
||||
* @author WebGoat
|
||||
* @version $Id: $Id
|
||||
* @since October 12, 2016
|
||||
*/
|
||||
@Component
|
||||
public class HttpProxies extends Lesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.GENERAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "2.http-proxies.title";//second lesson in GENERAL
|
||||
}
|
||||
}
|
||||
48
src/main/java/org/owasp/webgoat/lessons/idor/IDOR.java
Normal file
48
src/main/java/org/owasp/webgoat/lessons/idor/IDOR.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package org.owasp.webgoat.lessons.idor;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 2014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*
|
||||
* @author misfir3
|
||||
* @version $Id: $Id
|
||||
* @since January 3, 2017
|
||||
*/
|
||||
@Component
|
||||
public class IDOR extends Lesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.ACCESS_CONTROL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "idor.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.idor;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
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
|
||||
@AssignmentHints({"idor.hints.idorDiffAttributes1", "idor.hints.idorDiffAttributes2", "idor.hints.idorDiffAttributes3"})
|
||||
public class IDORDiffAttributes extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping("/IDOR/diff-attributes")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String attributes) {
|
||||
attributes = attributes.trim();
|
||||
String[] diffAttribs = attributes.split(",");
|
||||
if (diffAttribs.length < 2) {
|
||||
return failed(this).feedback("idor.diff.attributes.missing").build();
|
||||
}
|
||||
if (diffAttribs[0].toLowerCase().trim().equals("userid") && diffAttribs[1].toLowerCase().trim().equals("role")
|
||||
|| diffAttribs[1].toLowerCase().trim().equals("userid") && diffAttribs[0].toLowerCase().trim().equals("role")) {
|
||||
return success(this).feedback("idor.diff.success").build();
|
||||
} else {
|
||||
return failed(this).feedback("idor.diff.failure").build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.idor;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@AssignmentHints({"idor.hints.otherProfile1", "idor.hints.otherProfile2", "idor.hints.otherProfile3", "idor.hints.otherProfile4", "idor.hints.otherProfile5", "idor.hints.otherProfile6", "idor.hints.otherProfile7", "idor.hints.otherProfile8", "idor.hints.otherProfile9"})
|
||||
public class IDOREditOtherProfiile extends AssignmentEndpoint {
|
||||
|
||||
@Autowired
|
||||
private UserSessionData userSessionData;
|
||||
|
||||
@PutMapping(path = "/IDOR/profile/{userId}", consumes = "application/json")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@PathVariable("userId") String userId, @RequestBody UserProfile userSubmittedProfile) {
|
||||
|
||||
String authUserId = (String) userSessionData.getValue("idor-authenticated-user-id");
|
||||
// this is where it starts ... accepting the user submitted ID and assuming it will be the same as the logged in userId and not checking for proper authorization
|
||||
// Certain roles can sometimes edit others' profiles, but we shouldn't just assume that and let everyone, right?
|
||||
// Except that this is a vulnerable app ... so we will
|
||||
UserProfile currentUserProfile = new UserProfile(userId);
|
||||
if (userSubmittedProfile.getUserId() != null && !userSubmittedProfile.getUserId().equals(authUserId)) {
|
||||
// let's get this started ...
|
||||
currentUserProfile.setColor(userSubmittedProfile.getColor());
|
||||
currentUserProfile.setRole(userSubmittedProfile.getRole());
|
||||
// we will persist in the session object for now in case we want to refer back or use it later
|
||||
userSessionData.setValue("idor-updated-other-profile", currentUserProfile);
|
||||
if (currentUserProfile.getRole() <= 1 && currentUserProfile.getColor().toLowerCase().equals("red")) {
|
||||
return success(this)
|
||||
.feedback("idor.edit.profile.success1")
|
||||
.output(currentUserProfile.profileToMap().toString())
|
||||
.build();
|
||||
}
|
||||
|
||||
if (currentUserProfile.getRole() > 1 && currentUserProfile.getColor().toLowerCase().equals("red")) {
|
||||
return success(this)
|
||||
.feedback("idor.edit.profile.failure1")
|
||||
.output(currentUserProfile.profileToMap().toString())
|
||||
.build();
|
||||
}
|
||||
|
||||
if (currentUserProfile.getRole() <= 1 && !currentUserProfile.getColor().toLowerCase().equals("red")) {
|
||||
return success(this)
|
||||
.feedback("idor.edit.profile.failure2")
|
||||
.output(currentUserProfile.profileToMap().toString())
|
||||
.build();
|
||||
}
|
||||
|
||||
// else
|
||||
return failed(this)
|
||||
.feedback("idor.edit.profile.failure3")
|
||||
.output(currentUserProfile.profileToMap().toString())
|
||||
.build();
|
||||
} else if (userSubmittedProfile.getUserId().equals(authUserId)) {
|
||||
return failed(this).feedback("idor.edit.profile.failure4").build();
|
||||
}
|
||||
|
||||
if (currentUserProfile.getColor().equals("black") && currentUserProfile.getRole() <= 1) {
|
||||
return success(this)
|
||||
.feedback("idor.edit.profile.success2")
|
||||
.output(userSessionData.getValue("idor-updated-own-profile").toString())
|
||||
.build();
|
||||
} else {
|
||||
return failed(this).feedback("idor.edit.profile.failure3").build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
77
src/main/java/org/owasp/webgoat/lessons/idor/IDORLogin.java
Normal file
77
src/main/java/org/owasp/webgoat/lessons/idor/IDORLogin.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.idor;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@AssignmentHints({"idor.hints.idor_login"})
|
||||
public class IDORLogin extends AssignmentEndpoint {
|
||||
|
||||
private Map<String, Map<String, String>> idorUserInfo = new HashMap<>();
|
||||
|
||||
public void initIDORInfo() {
|
||||
|
||||
idorUserInfo.put("tom", new HashMap<String, String>());
|
||||
idorUserInfo.get("tom").put("password", "cat");
|
||||
idorUserInfo.get("tom").put("id", "2342384");
|
||||
idorUserInfo.get("tom").put("color", "yellow");
|
||||
idorUserInfo.get("tom").put("size", "small");
|
||||
|
||||
idorUserInfo.put("bill", new HashMap<String, String>());
|
||||
idorUserInfo.get("bill").put("password", "buffalo");
|
||||
idorUserInfo.get("bill").put("id", "2342388");
|
||||
idorUserInfo.get("bill").put("color", "brown");
|
||||
idorUserInfo.get("bill").put("size", "large");
|
||||
|
||||
}
|
||||
|
||||
@PostMapping("/IDOR/login")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String username, @RequestParam String password) {
|
||||
initIDORInfo();
|
||||
UserSessionData userSessionData = getUserSessionData();
|
||||
|
||||
if (idorUserInfo.containsKey(username)) {
|
||||
if ("tom".equals(username) && idorUserInfo.get("tom").get("password").equals(password)) {
|
||||
userSessionData.setValue("idor-authenticated-as", username);
|
||||
userSessionData.setValue("idor-authenticated-user-id", idorUserInfo.get(username).get("id"));
|
||||
return success(this).feedback("idor.login.success").feedbackArgs(username).build();
|
||||
} else {
|
||||
return failed(this).feedback("idor.login.failure").build();
|
||||
}
|
||||
} else {
|
||||
return failed(this).feedback("idor.login.failure").build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.idor;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@AssignmentHints({"idor.hints.otherProfile1", "idor.hints.otherProfile2", "idor.hints.otherProfile3", "idor.hints.otherProfile4", "idor.hints.otherProfile5", "idor.hints.otherProfile6", "idor.hints.otherProfile7", "idor.hints.otherProfile8", "idor.hints.otherProfile9"})
|
||||
public class IDORViewOtherProfile extends AssignmentEndpoint {
|
||||
|
||||
@Autowired
|
||||
UserSessionData userSessionData;
|
||||
|
||||
@GetMapping(path = "/IDOR/profile/{userId}", produces = {"application/json"})
|
||||
@ResponseBody
|
||||
public AttackResult completed(@PathVariable("userId") String userId, HttpServletResponse resp) {
|
||||
Map<String, Object> details = new HashMap<>();
|
||||
|
||||
if (userSessionData.getValue("idor-authenticated-as").equals("tom")) {
|
||||
//going to use session auth to view this one
|
||||
String authUserId = (String) userSessionData.getValue("idor-authenticated-user-id");
|
||||
if (userId != null && !userId.equals(authUserId)) {
|
||||
//on the right track
|
||||
UserProfile requestedProfile = new UserProfile(userId);
|
||||
// secure code would ensure there was a horizontal access control check prior to dishing up the requested profile
|
||||
if (requestedProfile.getUserId().equals("2342388")) {
|
||||
return success(this).feedback("idor.view.profile.success").output(requestedProfile.profileToMap().toString()).build();
|
||||
} else {
|
||||
return failed(this).feedback("idor.view.profile.close1").build();
|
||||
}
|
||||
} else {
|
||||
return failed(this).feedback("idor.view.profile.close2").build();
|
||||
}
|
||||
}
|
||||
return failed(this).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.idor;
|
||||
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@Slf4j
|
||||
public class IDORViewOwnProfile {
|
||||
|
||||
@Autowired
|
||||
UserSessionData userSessionData;
|
||||
|
||||
@GetMapping(path = {"/IDOR/own", "/IDOR/profile"}, produces = {"application/json"})
|
||||
@ResponseBody
|
||||
public Map<String, Object> invoke() {
|
||||
Map<String,Object> details = new HashMap<>();
|
||||
try {
|
||||
if (userSessionData.getValue("idor-authenticated-as").equals("tom")) {
|
||||
//going to use session auth to view this one
|
||||
String authUserId = (String)userSessionData.getValue("idor-authenticated-user-id");
|
||||
UserProfile userProfile = new UserProfile(authUserId);
|
||||
details.put("userId",userProfile.getUserId());
|
||||
details.put("name",userProfile.getName());
|
||||
details.put("color",userProfile.getColor());
|
||||
details.put("size",userProfile.getSize());
|
||||
details.put("role",userProfile.getRole());
|
||||
} else {
|
||||
details.put("error","You do not have privileges to view the profile. Authenticate as tom first please.");
|
||||
}
|
||||
}catch (Exception ex) {
|
||||
log.error("something went wrong", ex.getMessage());
|
||||
}
|
||||
return details;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.idor;
|
||||
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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
|
||||
@AssignmentHints({"idor.hints.ownProfileAltUrl1", "idor.hints.ownProfileAltUrl2", "idor.hints.ownProfileAltUrl3"})
|
||||
public class IDORViewOwnProfileAltUrl extends AssignmentEndpoint {
|
||||
|
||||
@Autowired
|
||||
UserSessionData userSessionData;
|
||||
|
||||
@PostMapping("/IDOR/profile/alt-path")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String url) {
|
||||
try {
|
||||
if (userSessionData.getValue("idor-authenticated-as").equals("tom")) {
|
||||
//going to use session auth to view this one
|
||||
String authUserId = (String) userSessionData.getValue("idor-authenticated-user-id");
|
||||
//don't care about http://localhost:8080 ... just want WebGoat/
|
||||
String[] urlParts = url.split("/");
|
||||
if (urlParts[0].equals("WebGoat") && urlParts[1].equals("IDOR") && urlParts[2].equals("profile") && urlParts[3].equals(authUserId)) {
|
||||
UserProfile userProfile = new UserProfile(authUserId);
|
||||
return success(this).feedback("idor.view.own.profile.success").output(userProfile.profileToMap().toString()).build();
|
||||
} else {
|
||||
return failed(this).feedback("idor.view.own.profile.failure1").build();
|
||||
}
|
||||
|
||||
} else {
|
||||
return failed(this).feedback("idor.view.own.profile.failure2").build();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
return failed(this).feedback("an error occurred with your request").build();
|
||||
}
|
||||
}
|
||||
}
|
||||
136
src/main/java/org/owasp/webgoat/lessons/idor/UserProfile.java
Normal file
136
src/main/java/org/owasp/webgoat/lessons/idor/UserProfile.java
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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.idor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by jason on 1/5/17.
|
||||
*/
|
||||
public class UserProfile {
|
||||
private String userId;
|
||||
private String name;
|
||||
private String color;
|
||||
private String size;
|
||||
private boolean isAdmin;
|
||||
private int role;
|
||||
|
||||
public UserProfile() {}
|
||||
|
||||
public UserProfile(String id) {
|
||||
setProfileFromId(id);
|
||||
}
|
||||
|
||||
//
|
||||
private void setProfileFromId(String id) {
|
||||
// emulate look up from database
|
||||
if (id.equals("2342384")) {
|
||||
this.userId = id;
|
||||
this.color = "yellow";
|
||||
this.name = "Tom Cat";
|
||||
this.size = "small";
|
||||
this.isAdmin = false;
|
||||
this.role = 3;
|
||||
} else if (id.equals("2342388")) {
|
||||
this.userId = id;
|
||||
this.color = "brown";
|
||||
this.name = "Buffalo Bill";
|
||||
this.size = "large";
|
||||
this.isAdmin = false;
|
||||
this.role = 3;
|
||||
} else {
|
||||
//not found
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Map <String,Object> profileToMap () {
|
||||
Map<String,Object> profileMap = new HashMap<>();
|
||||
profileMap.put("userId", this.userId);
|
||||
profileMap.put("name", this.name);
|
||||
profileMap.put("color", this.color);
|
||||
profileMap.put("size", this.size);
|
||||
profileMap.put("role", this.role);
|
||||
return profileMap;
|
||||
}
|
||||
|
||||
public String toHTMLString() {
|
||||
String htmlBreak = "<br/>";
|
||||
return "userId" + this.userId + htmlBreak +
|
||||
"name" + this.name + htmlBreak +
|
||||
"size" + this.size + htmlBreak +
|
||||
"role" + this.role + htmlBreak +
|
||||
"isAdmin" + this.isAdmin;
|
||||
}
|
||||
|
||||
//
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(String color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public String getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(String size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public boolean isAdmin() {
|
||||
return isAdmin;
|
||||
}
|
||||
|
||||
public void setAdmin(boolean admin) {
|
||||
isAdmin = admin;
|
||||
}
|
||||
|
||||
public int getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public void setRole(int role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.owasp.webgoat.lessons.insecure_login;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 2014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*
|
||||
* @author WebGoat
|
||||
* @version $Id: $Id
|
||||
* @since October 12, 2016
|
||||
*/
|
||||
@Component
|
||||
public class InsecureLogin extends Lesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.INSECURE_COMMUNICATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "insecure-login.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.insecure_login;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
public class InsecureLoginTask extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping("/InsecureLogin/task")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String username, @RequestParam String password) {
|
||||
if ("CaptainJack".equals(username) && "BlackPearl".equals(password)) {
|
||||
return success(this).build();
|
||||
}
|
||||
return failed(this).build();
|
||||
}
|
||||
|
||||
@PostMapping("/InsecureLogin/login")
|
||||
@ResponseStatus(HttpStatus.ACCEPTED)
|
||||
public void login() {
|
||||
//only need to exists as the JS needs to call an existing endpoint
|
||||
}
|
||||
}
|
||||
45
src/main/java/org/owasp/webgoat/lessons/jwt/JWT.java
Normal file
45
src/main/java/org/owasp/webgoat/lessons/jwt/JWT.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.jwt;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/22/17.
|
||||
*/
|
||||
@Component
|
||||
public class JWT extends Lesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.AUTHENTICATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "jwt.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.owasp.webgoat.lessons.jwt;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
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
|
||||
public class JWTDecodeEndpoint extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping("/JWT/decode")
|
||||
@ResponseBody
|
||||
public AttackResult decode(@RequestParam("jwt-encode-user") String user) {
|
||||
if ("user".equals(user)) {
|
||||
return success(this).build();
|
||||
} else {
|
||||
return failed(this).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.jwt;
|
||||
|
||||
import io.jsonwebtoken.*;
|
||||
import io.jsonwebtoken.impl.TextCodec;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.owasp.webgoat.container.LessonDataSource;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* {
|
||||
* "typ": "JWT",
|
||||
* "kid": "webgoat_key",
|
||||
* "alg": "HS256"
|
||||
* }
|
||||
* {
|
||||
* "iss": "WebGoat Token Builder",
|
||||
* "iat": 1524210904,
|
||||
* "exp": 1618905304,
|
||||
* "aud": "webgoat.org",
|
||||
* "sub": "jerry@webgoat.com",
|
||||
* "username": "Jerry",
|
||||
* "Email": "jerry@webgoat.com",
|
||||
* "Role": [
|
||||
* "Cat"
|
||||
* ]
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author nbaars
|
||||
* @since 4/23/17.
|
||||
*/
|
||||
@RestController
|
||||
@AssignmentHints({"jwt-final-hint1", "jwt-final-hint2", "jwt-final-hint3", "jwt-final-hint4", "jwt-final-hint5", "jwt-final-hint6"})
|
||||
public class JWTFinalEndpoint extends AssignmentEndpoint {
|
||||
|
||||
private final LessonDataSource dataSource;
|
||||
|
||||
private JWTFinalEndpoint(LessonDataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
@PostMapping("/JWT/final/follow/{user}")
|
||||
public @ResponseBody
|
||||
String follow(@PathVariable("user") String user) {
|
||||
if ("Jerry".equals(user)) {
|
||||
return "Following yourself seems redundant";
|
||||
} else {
|
||||
return "You are now following Tom";
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/JWT/final/delete")
|
||||
public @ResponseBody
|
||||
AttackResult resetVotes(@RequestParam("token") String token) {
|
||||
if (StringUtils.isEmpty(token)) {
|
||||
return failed(this).feedback("jwt-invalid-token").build();
|
||||
} else {
|
||||
try {
|
||||
final String[] errorMessage = {null};
|
||||
Jwt jwt = Jwts.parser().setSigningKeyResolver(new SigningKeyResolverAdapter() {
|
||||
@Override
|
||||
public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
|
||||
final String kid = (String) header.get("kid");
|
||||
try (var connection = dataSource.getConnection()) {
|
||||
ResultSet rs = connection.createStatement().executeQuery("SELECT key FROM jwt_keys WHERE id = '" + kid + "'");
|
||||
while (rs.next()) {
|
||||
return TextCodec.BASE64.decode(rs.getString(1));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
errorMessage[0] = e.getMessage();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}).parseClaimsJws(token);
|
||||
if (errorMessage[0] != null) {
|
||||
return failed(this).output(errorMessage[0]).build();
|
||||
}
|
||||
Claims claims = (Claims) jwt.getBody();
|
||||
String username = (String) claims.get("username");
|
||||
if ("Jerry".equals(username)) {
|
||||
return failed(this).feedback("jwt-final-jerry-account").build();
|
||||
}
|
||||
if ("Tom".equals(username)) {
|
||||
return success(this).build();
|
||||
} else {
|
||||
return failed(this).feedback("jwt-final-not-tom").build();
|
||||
}
|
||||
} catch (JwtException e) {
|
||||
return failed(this).feedback("jwt-invalid-token").output(e.toString()).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
49
src/main/java/org/owasp/webgoat/lessons/jwt/JWTQuiz.java
Normal file
49
src/main/java/org/owasp/webgoat/lessons/jwt/JWTQuiz.java
Normal file
@@ -0,0 +1,49 @@
|
||||
package org.owasp.webgoat.lessons.jwt;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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
|
||||
public class JWTQuiz extends AssignmentEndpoint {
|
||||
|
||||
private final String[] solutions = {"Solution 1", "Solution 2"};
|
||||
private final boolean[] guesses = new boolean[solutions.length];
|
||||
|
||||
@PostMapping("/JWT/quiz")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String[] question_0_solution, @RequestParam String[] question_1_solution) {
|
||||
int correctAnswers = 0;
|
||||
|
||||
String[] givenAnswers = {question_0_solution[0], question_1_solution[0]};
|
||||
|
||||
for (int i = 0; i < solutions.length; i++) {
|
||||
if (givenAnswers[i].contains(solutions[i])) {
|
||||
// answer correct
|
||||
correctAnswers++;
|
||||
guesses[i] = true;
|
||||
} else {
|
||||
// answer incorrect
|
||||
guesses[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (correctAnswers == solutions.length) {
|
||||
return success(this).build();
|
||||
} else {
|
||||
return failed(this).build();
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/JWT/quiz")
|
||||
@ResponseBody
|
||||
public boolean[] getResults() {
|
||||
return this.guesses;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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.jwt;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import io.jsonwebtoken.Header;
|
||||
import io.jsonwebtoken.Jwt;
|
||||
import io.jsonwebtoken.JwtException;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.springframework.http.ResponseEntity.ok;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/23/17.
|
||||
*/
|
||||
@RestController
|
||||
@AssignmentHints({"jwt-refresh-hint1", "jwt-refresh-hint2", "jwt-refresh-hint3", "jwt-refresh-hint4"})
|
||||
public class JWTRefreshEndpoint extends AssignmentEndpoint {
|
||||
|
||||
public static final String PASSWORD = "bm5nhSkxCXZkKRy4";
|
||||
private static final String JWT_PASSWORD = "bm5n3SkxCX4kKRy4";
|
||||
private static final List<String> validRefreshTokens = new ArrayList<>();
|
||||
|
||||
@PostMapping(value = "/JWT/refresh/login", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public ResponseEntity follow(@RequestBody(required = false) Map<String, Object> json) {
|
||||
if (json == null) {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
}
|
||||
String user = (String) json.get("user");
|
||||
String password = (String) json.get("password");
|
||||
|
||||
if ("Jerry".equalsIgnoreCase(user) && PASSWORD.equals(password)) {
|
||||
return ok(createNewTokens(user));
|
||||
}
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
}
|
||||
|
||||
private Map<String, Object> createNewTokens(String user) {
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put("admin", "false");
|
||||
claims.put("user", user);
|
||||
String token = Jwts.builder()
|
||||
.setIssuedAt(new Date(System.currentTimeMillis() + TimeUnit.DAYS.toDays(10)))
|
||||
.setClaims(claims)
|
||||
.signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD)
|
||||
.compact();
|
||||
Map<String, Object> tokenJson = new HashMap<>();
|
||||
String refreshToken = RandomStringUtils.randomAlphabetic(20);
|
||||
validRefreshTokens.add(refreshToken);
|
||||
tokenJson.put("access_token", token);
|
||||
tokenJson.put("refresh_token", refreshToken);
|
||||
return tokenJson;
|
||||
}
|
||||
|
||||
@PostMapping("/JWT/refresh/checkout")
|
||||
@ResponseBody
|
||||
public ResponseEntity<AttackResult> checkout(@RequestHeader(value = "Authorization", required = false) String token) {
|
||||
if (token == null) {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
}
|
||||
try {
|
||||
Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(token.replace("Bearer ", ""));
|
||||
Claims claims = (Claims) jwt.getBody();
|
||||
String user = (String) claims.get("user");
|
||||
if ("Tom".equals(user)) {
|
||||
return ok(success(this).build());
|
||||
}
|
||||
return ok(failed(this).feedback("jwt-refresh-not-tom").feedbackArgs(user).build());
|
||||
} catch (ExpiredJwtException e) {
|
||||
return ok(failed(this).output(e.getMessage()).build());
|
||||
} catch (JwtException e) {
|
||||
return ok(failed(this).feedback("jwt-invalid-token").build());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/JWT/refresh/newToken")
|
||||
@ResponseBody
|
||||
public ResponseEntity newToken(@RequestHeader(value = "Authorization", required = false) String token,
|
||||
@RequestBody(required = false) Map<String, Object> json) {
|
||||
if (token == null || json == null) {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
}
|
||||
|
||||
String user;
|
||||
String refreshToken;
|
||||
try {
|
||||
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(token.replace("Bearer ", ""));
|
||||
user = (String) jwt.getBody().get("user");
|
||||
refreshToken = (String) json.get("refresh_token");
|
||||
} catch (ExpiredJwtException e) {
|
||||
user = (String) e.getClaims().get("user");
|
||||
refreshToken = (String) json.get("refresh_token");
|
||||
}
|
||||
|
||||
if (user == null || refreshToken == null) {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
} else if (validRefreshTokens.contains(refreshToken)) {
|
||||
validRefreshTokens.remove(refreshToken);
|
||||
return ok(createNewTokens(user));
|
||||
} else {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.jwt;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwt;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.impl.TextCodec;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/23/17.
|
||||
*/
|
||||
@RestController
|
||||
@AssignmentHints({"jwt-secret-hint1", "jwt-secret-hint2", "jwt-secret-hint3"})
|
||||
public class JWTSecretKeyEndpoint extends AssignmentEndpoint {
|
||||
|
||||
public static final String[] SECRETS = {"victory", "business", "available", "shipping", "washington"};
|
||||
public static final String JWT_SECRET = TextCodec.BASE64.encode(SECRETS[new Random().nextInt(SECRETS.length)]);
|
||||
private static final String WEBGOAT_USER = "WebGoat";
|
||||
private static final List<String> expectedClaims = List.of("iss", "iat", "exp", "aud", "sub", "username", "Email", "Role");
|
||||
|
||||
@RequestMapping(path = "/JWT/secret/gettoken", produces = MediaType.TEXT_HTML_VALUE)
|
||||
@ResponseBody
|
||||
public String getSecretToken() {
|
||||
return Jwts.builder()
|
||||
.setIssuer("WebGoat Token Builder")
|
||||
.setAudience("webgoat.org")
|
||||
.setIssuedAt(Calendar.getInstance().getTime())
|
||||
.setExpiration(Date.from(Instant.now().plusSeconds(60)))
|
||||
.setSubject("tom@webgoat.org")
|
||||
.claim("username", "Tom")
|
||||
.claim("Email", "tom@webgoat.org")
|
||||
.claim("Role", new String[]{"Manager", "Project Administrator"})
|
||||
.signWith(SignatureAlgorithm.HS256, JWT_SECRET).compact();
|
||||
}
|
||||
|
||||
@PostMapping("/JWT/secret")
|
||||
@ResponseBody
|
||||
public AttackResult login(@RequestParam String token) {
|
||||
try {
|
||||
Jwt jwt = Jwts.parser().setSigningKey(JWT_SECRET).parseClaimsJws(token);
|
||||
Claims claims = (Claims) jwt.getBody();
|
||||
if (!claims.keySet().containsAll(expectedClaims)) {
|
||||
return failed(this).feedback("jwt-secret-claims-missing").build();
|
||||
} else {
|
||||
String user = (String) claims.get("username");
|
||||
|
||||
if (WEBGOAT_USER.equalsIgnoreCase(user)) {
|
||||
return success(this).build();
|
||||
} else {
|
||||
return failed(this).feedback("jwt-secret-incorrect-user").feedbackArgs(user).build();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return failed(this).feedback("jwt-invalid-token").output(e.getMessage()).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* 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.jwt;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwt;
|
||||
import io.jsonwebtoken.JwtException;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.impl.TextCodec;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.lessons.jwt.votes.Views;
|
||||
import org.owasp.webgoat.lessons.jwt.votes.Vote;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.converter.json.MappingJacksonValue;
|
||||
import org.springframework.web.bind.annotation.CookieValue;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
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.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Comparator.comparingLong;
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/23/17.
|
||||
*/
|
||||
@RestController
|
||||
@AssignmentHints({"jwt-change-token-hint1", "jwt-change-token-hint2", "jwt-change-token-hint3", "jwt-change-token-hint4", "jwt-change-token-hint5"})
|
||||
public class JWTVotesEndpoint extends AssignmentEndpoint {
|
||||
|
||||
public static final String JWT_PASSWORD = TextCodec.BASE64.encode("victory");
|
||||
private static String validUsers = "TomJerrySylvester";
|
||||
|
||||
private static int totalVotes = 38929;
|
||||
private Map<String, Vote> votes = new HashMap<>();
|
||||
|
||||
@PostConstruct
|
||||
public void initVotes() {
|
||||
votes.put("Admin lost password", new Vote("Admin lost password",
|
||||
"In this challenge you will need to help the admin and find the password in order to login",
|
||||
"challenge1-small.png", "challenge1.png", 36000, totalVotes));
|
||||
votes.put("Vote for your favourite",
|
||||
new Vote("Vote for your favourite",
|
||||
"In this challenge ...",
|
||||
"challenge5-small.png", "challenge5.png", 30000, totalVotes));
|
||||
votes.put("Get it for free",
|
||||
new Vote("Get it for free",
|
||||
"The objective for this challenge is to buy a Samsung phone for free.",
|
||||
"challenge2-small.png", "challenge2.png", 20000, totalVotes));
|
||||
votes.put("Photo comments",
|
||||
new Vote("Photo comments",
|
||||
"n this challenge you can comment on the photo you will need to find the flag somewhere.",
|
||||
"challenge3-small.png", "challenge3.png", 10000, totalVotes));
|
||||
}
|
||||
|
||||
@GetMapping("/JWT/votings/login")
|
||||
public void login(@RequestParam("user") String user, HttpServletResponse response) {
|
||||
if (validUsers.contains(user)) {
|
||||
Claims claims = Jwts.claims().setIssuedAt(Date.from(Instant.now().plus(Duration.ofDays(10))));
|
||||
claims.put("admin", "false");
|
||||
claims.put("user", user);
|
||||
String token = Jwts.builder()
|
||||
.setClaims(claims)
|
||||
.signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD)
|
||||
.compact();
|
||||
Cookie cookie = new Cookie("access_token", token);
|
||||
response.addCookie(cookie);
|
||||
response.setStatus(HttpStatus.OK.value());
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
} else {
|
||||
Cookie cookie = new Cookie("access_token", "");
|
||||
response.addCookie(cookie);
|
||||
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/JWT/votings")
|
||||
@ResponseBody
|
||||
public MappingJacksonValue getVotes(@CookieValue(value = "access_token", required = false) String accessToken) {
|
||||
MappingJacksonValue value = new MappingJacksonValue(votes.values().stream().sorted(comparingLong(Vote::getAverage).reversed()).collect(toList()));
|
||||
if (StringUtils.isEmpty(accessToken)) {
|
||||
value.setSerializationView(Views.GuestView.class);
|
||||
} else {
|
||||
try {
|
||||
Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken);
|
||||
Claims claims = (Claims) jwt.getBody();
|
||||
String user = (String) claims.get("user");
|
||||
if ("Guest".equals(user) || !validUsers.contains(user)) {
|
||||
value.setSerializationView(Views.GuestView.class);
|
||||
} else {
|
||||
value.setSerializationView(Views.UserView.class);
|
||||
}
|
||||
} catch (JwtException e) {
|
||||
value.setSerializationView(Views.GuestView.class);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@PostMapping(value = "/JWT/votings/{title}")
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.ACCEPTED)
|
||||
public ResponseEntity<?> vote(@PathVariable String title, @CookieValue(value = "access_token", required = false) String accessToken) {
|
||||
if (StringUtils.isEmpty(accessToken)) {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
} else {
|
||||
try {
|
||||
Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken);
|
||||
Claims claims = (Claims) jwt.getBody();
|
||||
String user = (String) claims.get("user");
|
||||
if (!validUsers.contains(user)) {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
} else {
|
||||
ofNullable(votes.get(title)).ifPresent(v -> v.incrementNumberOfVotes(totalVotes));
|
||||
return ResponseEntity.accepted().build();
|
||||
}
|
||||
} catch (JwtException e) {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/JWT/votings")
|
||||
@ResponseBody
|
||||
public AttackResult resetVotes(@CookieValue(value = "access_token", required = false) String accessToken) {
|
||||
if (StringUtils.isEmpty(accessToken)) {
|
||||
return failed(this).feedback("jwt-invalid-token").build();
|
||||
} else {
|
||||
try {
|
||||
Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken);
|
||||
Claims claims = (Claims) jwt.getBody();
|
||||
boolean isAdmin = Boolean.valueOf((String) claims.get("admin"));
|
||||
if (!isAdmin) {
|
||||
return failed(this).feedback("jwt-only-admin").build();
|
||||
} else {
|
||||
votes.values().forEach(vote -> vote.reset());
|
||||
return success(this).build();
|
||||
}
|
||||
} catch (JwtException e) {
|
||||
return failed(this).feedback("jwt-invalid-token").output(e.toString()).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/main/java/org/owasp/webgoat/lessons/jwt/votes/Views.java
Normal file
13
src/main/java/org/owasp/webgoat/lessons/jwt/votes/Views.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package org.owasp.webgoat.lessons.jwt.votes;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/30/17.
|
||||
*/
|
||||
public class Views {
|
||||
public interface GuestView {
|
||||
}
|
||||
|
||||
public interface UserView extends GuestView {
|
||||
}
|
||||
}
|
||||
72
src/main/java/org/owasp/webgoat/lessons/jwt/votes/Vote.java
Normal file
72
src/main/java/org/owasp/webgoat/lessons/jwt/votes/Vote.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.jwt.votes;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 5/2/17.
|
||||
*/
|
||||
@Getter
|
||||
public class Vote {
|
||||
@JsonView(Views.GuestView.class)
|
||||
private final String title;
|
||||
@JsonView(Views.GuestView.class)
|
||||
private final String information;
|
||||
@JsonView(Views.GuestView.class)
|
||||
private final String imageSmall;
|
||||
@JsonView(Views.GuestView.class)
|
||||
private final String imageBig;
|
||||
@JsonView(Views.UserView.class)
|
||||
private int numberOfVotes;
|
||||
@JsonView(Views.UserView.class)
|
||||
private boolean votingAllowed = true;
|
||||
@JsonView(Views.UserView.class)
|
||||
private long average = 0;
|
||||
|
||||
|
||||
public Vote(String title, String information, String imageSmall, String imageBig, int numberOfVotes, int totalVotes) {
|
||||
this.title = title;
|
||||
this.information = information;
|
||||
this.imageSmall = imageSmall;
|
||||
this.imageBig = imageBig;
|
||||
this.numberOfVotes = numberOfVotes;
|
||||
this.average = calculateStars(totalVotes);
|
||||
}
|
||||
|
||||
public void incrementNumberOfVotes(int totalVotes) {
|
||||
this.numberOfVotes = this.numberOfVotes + 1;
|
||||
this.average = calculateStars(totalVotes);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
this.numberOfVotes = 1;
|
||||
this.average = 1;
|
||||
}
|
||||
|
||||
private long calculateStars(int totalVotes) {
|
||||
return Math.round(((double) numberOfVotes / (double) totalVotes) * 4);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.lesson_template;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class LessonTemplate extends Lesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.GENERAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "lesson-template.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.lesson_template;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by jason on 1/5/17.
|
||||
*/
|
||||
|
||||
@RestController
|
||||
@AssignmentHints({"lesson-template.hints.1", "lesson-template.hints.2", "lesson-template.hints.3"})
|
||||
public class SampleAttack extends AssignmentEndpoint {
|
||||
|
||||
String secretValue = "secr37Value";
|
||||
|
||||
//UserSessionData is bound to session and can be used to persist data across multiple assignments
|
||||
@Autowired
|
||||
UserSessionData userSessionData;
|
||||
|
||||
@PostMapping("/lesson-template/sample-attack")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam("param1") String param1, @RequestParam("param2") String param2) {
|
||||
if (userSessionData.getValue("some-value") != null) {
|
||||
// do any session updating you want here ... or not, just comment/example here
|
||||
//return failed().feedback("lesson-template.sample-attack.failure-2").build());
|
||||
}
|
||||
|
||||
//overly simple example for success. See other existing lesssons for ways to detect 'success' or 'failure'
|
||||
if (secretValue.equals(param1)) {
|
||||
return success(this)
|
||||
.output("Custom Output ...if you want, for success")
|
||||
.feedback("lesson-template.sample-attack.success")
|
||||
.build();
|
||||
//lesson-template.sample-attack.success is defined in src/main/resources/i18n/WebGoatLabels.properties
|
||||
}
|
||||
|
||||
// else
|
||||
return failed(this)
|
||||
.feedback("lesson-template.sample-attack.failure-2")
|
||||
.output("Custom output for this failure scenario, usually html that will get rendered directly ... yes, you can self-xss if you want")
|
||||
.build();
|
||||
}
|
||||
|
||||
@GetMapping("lesson-template/shop/{user}")
|
||||
@ResponseBody
|
||||
public List<Item> getItemsInBasket(@PathVariable("user") String user) {
|
||||
return List.of(new Item("WG-1", "WebGoat promo", 12.0), new Item("WG-2", "WebGoat sticker", 0.00));
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
private class Item {
|
||||
private String number;
|
||||
private String description;
|
||||
private double price;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.logging;
|
||||
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.Base64;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
public class LogBleedingTask extends AssignmentEndpoint {
|
||||
|
||||
Logger log = LoggerFactory.getLogger(this.getClass().getName());
|
||||
private String password;
|
||||
|
||||
@PostConstruct
|
||||
public void generatePassword(){
|
||||
password = UUID.randomUUID().toString();
|
||||
log.info("Password for admin: {}", Base64.getEncoder().encodeToString(password.getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
|
||||
@PostMapping("/LogSpoofing/log-bleeding")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String username, @RequestParam String password) {
|
||||
if (Strings.isEmpty(username) || Strings.isEmpty(password)) {
|
||||
return failed(this).output("Please provide username (Admin) and password").build();
|
||||
}
|
||||
|
||||
if (username.equals("Admin") && password.equals(this.password)) {
|
||||
return success(this).build();
|
||||
}
|
||||
|
||||
return failed(this).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.owasp.webgoat.lessons.logging;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 2014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*
|
||||
* @author WebGoat
|
||||
* @version $Id: $Id
|
||||
* @since October 12, 2016
|
||||
*/
|
||||
@Component
|
||||
public class LogSpoofing extends Lesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.INSECURE_CONFIGURATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "logging.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.logging;
|
||||
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
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
|
||||
public class LogSpoofingTask extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping("/LogSpoofing/log-spoofing")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String username, @RequestParam String password) {
|
||||
if (Strings.isEmpty(username)) {
|
||||
return failed(this).output(username).build();
|
||||
}
|
||||
username = username.replace("\n", "<br/>");
|
||||
if (username.contains("<p>") || username.contains("<div>")) {
|
||||
return failed(this).output("Try to think of something simple ").build();
|
||||
}
|
||||
if (username.indexOf("<br/>") < username.indexOf("admin")) {
|
||||
return success(this).output(username).build();
|
||||
}
|
||||
return failed(this).output(username).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package org.owasp.webgoat.lessons.missing_ac;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 2014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*/
|
||||
@Getter
|
||||
public class DisplayUser {
|
||||
//intended to provide a display version of WebGoatUser for admins to view user attributes
|
||||
|
||||
private String username;
|
||||
private boolean admin;
|
||||
private String userHash;
|
||||
|
||||
public DisplayUser(User user, String passwordSalt) {
|
||||
this.username = user.getUsername();
|
||||
this.admin = user.isAdmin();
|
||||
|
||||
try {
|
||||
this.userHash = genUserHash(user.getUsername(), user.getPassword(), passwordSalt);
|
||||
} catch (Exception ex) {
|
||||
this.userHash = "Error generating user hash";
|
||||
}
|
||||
}
|
||||
|
||||
protected String genUserHash(String username, String password, String passwordSalt) throws Exception {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
// salting is good, but static & too predictable ... short too for a salt
|
||||
String salted = password + passwordSalt + username;
|
||||
//md.update(salted.getBytes("UTF-8")); // Change this to "UTF-16" if needed
|
||||
byte[] hash = md.digest(salted.getBytes(StandardCharsets.UTF_8));
|
||||
return Base64.getEncoder().encodeToString(hash);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.owasp.webgoat.lessons.missing_ac;
|
||||
|
||||
import org.owasp.webgoat.container.LessonDataSource;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class MissingAccessControlUserRepository {
|
||||
|
||||
private final NamedParameterJdbcTemplate jdbcTemplate;
|
||||
private final RowMapper<User> mapper = (rs, rowNum) -> new User(rs.getString("username"), rs.getString("password"), rs.getBoolean("admin"));
|
||||
|
||||
public MissingAccessControlUserRepository(LessonDataSource lessonDataSource) {
|
||||
this.jdbcTemplate = new NamedParameterJdbcTemplate(lessonDataSource);
|
||||
}
|
||||
|
||||
public List<User> findAllUsers() {
|
||||
return jdbcTemplate.query("select username, password, admin from access_control_users", mapper);
|
||||
}
|
||||
|
||||
public User findByUsername(String username) {
|
||||
var users = jdbcTemplate.query("select username, password, admin from access_control_users where username=:username",
|
||||
new MapSqlParameterSource().addValue("username", username),
|
||||
mapper);
|
||||
if (CollectionUtils.isEmpty(users)) {
|
||||
return null;
|
||||
}
|
||||
return users.get(0);
|
||||
}
|
||||
|
||||
public User save(User user) {
|
||||
jdbcTemplate.update("INSERT INTO access_control_users(username, password, admin) VALUES(:username,:password,:admin)",
|
||||
new MapSqlParameterSource()
|
||||
.addValue("username", user.getUsername())
|
||||
.addValue("password", user.getPassword())
|
||||
.addValue("admin", user.isAdmin()));
|
||||
return user;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.missing_ac;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class MissingFunctionAC extends Lesson {
|
||||
|
||||
public static final String PASSWORD_SALT_SIMPLE = "DeliberatelyInsecure1234";
|
||||
public static final String PASSWORD_SALT_ADMIN = "DeliberatelyInsecure1235";
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.ACCESS_CONTROL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "missing-function-access-control.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.missing_ac;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* Created by jason on 1/5/17.
|
||||
*/
|
||||
@RestController
|
||||
@AssignmentHints({"access-control.hidden-menus.hint1","access-control.hidden-menus.hint2","access-control.hidden-menus.hint3"})
|
||||
public class MissingFunctionACHiddenMenus extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping(path = "/access-control/hidden-menu", produces = {"application/json"})
|
||||
@ResponseBody
|
||||
public AttackResult completed(String hiddenMenu1, String hiddenMenu2) {
|
||||
if (hiddenMenu1.equals("Users") && hiddenMenu2.equals("Config")) {
|
||||
return success(this)
|
||||
.output("")
|
||||
.feedback("access-control.hidden-menus.success")
|
||||
.build();
|
||||
}
|
||||
|
||||
if (hiddenMenu1.equals("Config") && hiddenMenu2.equals("Users")) {
|
||||
return failed(this)
|
||||
.output("")
|
||||
.feedback("access-control.hidden-menus.close")
|
||||
.build();
|
||||
}
|
||||
|
||||
return failed(this)
|
||||
.feedback("access-control.hidden-menus.failure")
|
||||
.output("")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.missing_ac;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.owasp.webgoat.lessons.missing_ac.MissingFunctionAC.PASSWORD_SALT_ADMIN;
|
||||
import static org.owasp.webgoat.lessons.missing_ac.MissingFunctionAC.PASSWORD_SALT_SIMPLE;
|
||||
|
||||
/**
|
||||
* Created by jason on 1/5/17.
|
||||
*/
|
||||
@Controller
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
public class MissingFunctionACUsers {
|
||||
|
||||
private final MissingAccessControlUserRepository userRepository;
|
||||
private final WebSession webSession;
|
||||
|
||||
@GetMapping(path = {"access-control/users"})
|
||||
public ModelAndView listUsers() {
|
||||
|
||||
ModelAndView model = new ModelAndView();
|
||||
model.setViewName("list_users");
|
||||
List<User> allUsers = userRepository.findAllUsers();
|
||||
model.addObject("numUsers", allUsers.size());
|
||||
//add display user objects in place of direct users
|
||||
List<DisplayUser> displayUsers = new ArrayList<>();
|
||||
for (User user : allUsers) {
|
||||
displayUsers.add(new DisplayUser(user, PASSWORD_SALT_SIMPLE));
|
||||
}
|
||||
model.addObject("allUsers", displayUsers);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
@GetMapping(path = {"access-control/users"}, consumes = "application/json")
|
||||
@ResponseBody
|
||||
public ResponseEntity<List<DisplayUser>> usersService() {
|
||||
return ResponseEntity.ok(userRepository.findAllUsers().stream().map(user -> new DisplayUser(user, PASSWORD_SALT_SIMPLE)).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@GetMapping(path = {"access-control/users-admin-fix"}, consumes = "application/json")
|
||||
@ResponseBody
|
||||
public ResponseEntity<List<DisplayUser>> usersFixed() {
|
||||
var currentUser = userRepository.findByUsername(webSession.getUserName());
|
||||
if (currentUser != null && currentUser.isAdmin()) {
|
||||
return ResponseEntity.ok(userRepository.findAllUsers().stream().map(user -> new DisplayUser(user, PASSWORD_SALT_ADMIN)).collect(Collectors.toList()));
|
||||
}
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
|
||||
}
|
||||
|
||||
@PostMapping(path = {"access-control/users", "access-control/users-admin-fix"}, consumes = "application/json", produces = "application/json")
|
||||
@ResponseBody
|
||||
public User addUser(@RequestBody User newUser) {
|
||||
try {
|
||||
userRepository.save(newUser);
|
||||
return newUser;
|
||||
} catch (Exception ex) {
|
||||
log.error("Error creating new User", ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
//@RequestMapping(path = {"user/{username}","/"}, method = RequestMethod.DELETE, consumes = "application/json", produces = "application/json")
|
||||
//TODO implement delete method with id param and authorization
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.missing_ac;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.owasp.webgoat.lessons.missing_ac.MissingFunctionAC.PASSWORD_SALT_SIMPLE;
|
||||
|
||||
@RestController
|
||||
@AssignmentHints({"access-control.hash.hint1", "access-control.hash.hint2", "access-control.hash.hint3", "access-control.hash.hint4", "access-control.hash.hint5"})
|
||||
@RequiredArgsConstructor
|
||||
public class MissingFunctionACYourHash extends AssignmentEndpoint {
|
||||
|
||||
private final MissingAccessControlUserRepository userRepository;
|
||||
|
||||
|
||||
@PostMapping(path = "/access-control/user-hash", produces = {"application/json"})
|
||||
@ResponseBody
|
||||
public AttackResult simple(String userHash) {
|
||||
User user = userRepository.findByUsername("Jerry");
|
||||
DisplayUser displayUser = new DisplayUser(user, PASSWORD_SALT_SIMPLE);
|
||||
if (userHash.equals(displayUser.getUserHash())) {
|
||||
return success(this).feedback("access-control.hash.success").build();
|
||||
} else {
|
||||
return failed(this).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.missing_ac;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.owasp.webgoat.lessons.missing_ac.MissingFunctionAC.PASSWORD_SALT_ADMIN;
|
||||
|
||||
@RestController
|
||||
@AssignmentHints({"access-control.hash.hint6", "access-control.hash.hint7",
|
||||
"access-control.hash.hint8", "access-control.hash.hint9", "access-control.hash.hint10", "access-control.hash.hint11", "access-control.hash.hint12"})
|
||||
public class MissingFunctionACYourHashAdmin extends AssignmentEndpoint {
|
||||
|
||||
private final MissingAccessControlUserRepository userRepository;
|
||||
|
||||
public MissingFunctionACYourHashAdmin(MissingAccessControlUserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@PostMapping(path = "/access-control/user-hash-fix", produces = {"application/json"})
|
||||
@ResponseBody
|
||||
public AttackResult admin(String userHash) {
|
||||
//current user should be in the DB
|
||||
//if not admin then return 403
|
||||
|
||||
var user = userRepository.findByUsername("Jerry");
|
||||
var displayUser = new DisplayUser(user, PASSWORD_SALT_ADMIN);
|
||||
if (userHash.equals(displayUser.getUserHash())) {
|
||||
return success(this).feedback("access-control.hash.success").build();
|
||||
} else {
|
||||
return failed(this).feedback("access-control.hash.close").build();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
15
src/main/java/org/owasp/webgoat/lessons/missing_ac/User.java
Normal file
15
src/main/java/org/owasp/webgoat/lessons/missing_ac/User.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package org.owasp.webgoat.lessons.missing_ac;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class User {
|
||||
|
||||
private String username;
|
||||
private String password;
|
||||
private boolean admin;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.password_reset;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class PasswordReset extends Lesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.AUTHENTICATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "password-reset.title";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.password_reset;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
public class PasswordResetEmail implements Serializable {
|
||||
|
||||
private LocalDateTime time;
|
||||
private String contents;
|
||||
private String sender;
|
||||
private String title;
|
||||
private String recipient;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.password_reset;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 8/20/17.
|
||||
*/
|
||||
@RestController
|
||||
public class QuestionsAssignment extends AssignmentEndpoint {
|
||||
|
||||
private static final Map<String, String> COLORS = new HashMap<>();
|
||||
|
||||
static {
|
||||
COLORS.put("admin", "green");
|
||||
COLORS.put("jerry", "orange");
|
||||
COLORS.put("tom", "purple");
|
||||
COLORS.put("larry", "yellow");
|
||||
COLORS.put("webgoat", "red");
|
||||
}
|
||||
|
||||
@PostMapping(path = "/PasswordReset/questions", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
@ResponseBody
|
||||
public AttackResult passwordReset(@RequestParam Map<String, Object> json) {
|
||||
String securityQuestion = (String) json.getOrDefault("securityQuestion", "");
|
||||
String username = (String) json.getOrDefault("username", "");
|
||||
|
||||
if ("webgoat".equalsIgnoreCase(username.toLowerCase())) {
|
||||
return failed(this).feedback("password-questions-wrong-user").build();
|
||||
}
|
||||
|
||||
String validAnswer = COLORS.get(username.toLowerCase());
|
||||
if (validAnswer == null) {
|
||||
return failed(this).feedback("password-questions-unknown-user").feedbackArgs(username).build();
|
||||
} else if (validAnswer.equals(securityQuestion)) {
|
||||
return success(this).build();
|
||||
}
|
||||
return failed(this).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.password_reset;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.lessons.password_reset.resetlink.PasswordChangeForm;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
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.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 8/20/17.
|
||||
*/
|
||||
@RestController
|
||||
@AssignmentHints({"password-reset-hint1", "password-reset-hint2", "password-reset-hint3", "password-reset-hint4", "password-reset-hint5", "password-reset-hint6"})
|
||||
public class ResetLinkAssignment extends AssignmentEndpoint {
|
||||
|
||||
static final String PASSWORD_TOM_9 = "somethingVeryRandomWhichNoOneWillEverTypeInAsPasswordForTom";
|
||||
static final String TOM_EMAIL = "tom@webgoat-cloud.org";
|
||||
static Map<String, String> userToTomResetLink = new HashMap<>();
|
||||
static Map<String, String> usersToTomPassword = Maps.newHashMap();
|
||||
static List<String> resetLinks = new ArrayList<>();
|
||||
|
||||
static final String TEMPLATE = "Hi, you requested a password reset link, please use this "
|
||||
+ "<a target='_blank' href='http://%s/WebGoat/PasswordReset/reset/reset-password/%s'>link</a> to reset your password."
|
||||
+ "\n \n\n"
|
||||
+ "If you did not request this password change you can ignore this message."
|
||||
+ "\n"
|
||||
+ "If you have any comments or questions, please do not hesitate to reach us at support@webgoat-cloud.org"
|
||||
+ "\n\n"
|
||||
+ "Kind regards, \nTeam WebGoat";
|
||||
|
||||
|
||||
@PostMapping("/PasswordReset/reset/login")
|
||||
@ResponseBody
|
||||
public AttackResult login(@RequestParam String password, @RequestParam String email) {
|
||||
if (TOM_EMAIL.equals(email)) {
|
||||
String passwordTom = usersToTomPassword.getOrDefault(getWebSession().getUserName(), PASSWORD_TOM_9);
|
||||
if (passwordTom.equals(PASSWORD_TOM_9)) {
|
||||
return failed(this).feedback("login_failed").build();
|
||||
} else if (passwordTom.equals(password)) {
|
||||
return success(this).build();
|
||||
}
|
||||
}
|
||||
return failed(this).feedback("login_failed.tom").build();
|
||||
}
|
||||
|
||||
@GetMapping("/PasswordReset/reset/reset-password/{link}")
|
||||
public ModelAndView resetPassword(@PathVariable(value = "link") String link, Model model) {
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
if (ResetLinkAssignment.resetLinks.contains(link)) {
|
||||
PasswordChangeForm form = new PasswordChangeForm();
|
||||
form.setResetLink(link);
|
||||
model.addAttribute("form", form);
|
||||
modelAndView.addObject("form", form);
|
||||
modelAndView.setViewName("password_reset"); //Display html page for changing password
|
||||
} else {
|
||||
modelAndView.setViewName("password_link_not_found");
|
||||
}
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@GetMapping("/PasswordReset/reset/change-password")
|
||||
public ModelAndView illegalCall() {
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
modelAndView.setViewName("password_link_not_found");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@PostMapping("/PasswordReset/reset/change-password")
|
||||
public ModelAndView changePassword(@ModelAttribute("form") PasswordChangeForm form, BindingResult bindingResult) {
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
if (!org.springframework.util.StringUtils.hasText(form.getPassword())) {
|
||||
bindingResult.rejectValue("password", "not.empty");
|
||||
}
|
||||
if (bindingResult.hasErrors()) {
|
||||
modelAndView.setViewName("password_reset");
|
||||
return modelAndView;
|
||||
}
|
||||
if (!resetLinks.contains(form.getResetLink())) {
|
||||
modelAndView.setViewName("password_link_not_found");
|
||||
return modelAndView;
|
||||
}
|
||||
if (checkIfLinkIsFromTom(form.getResetLink())) {
|
||||
usersToTomPassword.put(getWebSession().getUserName(), form.getPassword());
|
||||
}
|
||||
modelAndView.setViewName("lessons/password_reset/templates/success.html");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
private boolean checkIfLinkIsFromTom(String resetLinkFromForm) {
|
||||
String resetLink = userToTomResetLink.getOrDefault(getWebSession().getUserName(), "unknown");
|
||||
return resetLink.equals(resetLinkFromForm);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.password_reset;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
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;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Part of the password reset assignment. Used to send the e-mail.
|
||||
*
|
||||
* @author nbaars
|
||||
* @since 8/20/17.
|
||||
*/
|
||||
@RestController
|
||||
public class ResetLinkAssignmentForgotPassword extends AssignmentEndpoint {
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
private String webWolfHost;
|
||||
private String webWolfPort;
|
||||
private final String webWolfMailURL;
|
||||
|
||||
public ResetLinkAssignmentForgotPassword(RestTemplate restTemplate,
|
||||
@Value("${webwolf.host}") String webWolfHost,
|
||||
@Value("${webwolf.port}") String webWolfPort,
|
||||
@Value("${webwolf.mail.url}") String webWolfMailURL) {
|
||||
this.restTemplate = restTemplate;
|
||||
this.webWolfHost = webWolfHost;
|
||||
this.webWolfPort = webWolfPort;
|
||||
this.webWolfMailURL = webWolfMailURL;
|
||||
}
|
||||
|
||||
@PostMapping("/PasswordReset/ForgotPassword/create-password-reset-link")
|
||||
@ResponseBody
|
||||
public AttackResult sendPasswordResetLink(@RequestParam String email, HttpServletRequest request) {
|
||||
String resetLink = UUID.randomUUID().toString();
|
||||
ResetLinkAssignment.resetLinks.add(resetLink);
|
||||
String host = request.getHeader("host");
|
||||
if (ResetLinkAssignment.TOM_EMAIL.equals(email) && (host.contains(webWolfPort) || host.contains(webWolfHost))) { //User indeed changed the host header.
|
||||
ResetLinkAssignment.userToTomResetLink.put(getWebSession().getUserName(), resetLink);
|
||||
fakeClickingLinkEmail(host, resetLink);
|
||||
} else {
|
||||
try {
|
||||
sendMailToUser(email, host, resetLink);
|
||||
} catch (Exception e) {
|
||||
return failed(this).output("E-mail can't be send. please try again.").build();
|
||||
}
|
||||
}
|
||||
|
||||
return success(this).feedback("email.send").feedbackArgs(email).build();
|
||||
}
|
||||
|
||||
private void sendMailToUser(String email, String host, String resetLink) {
|
||||
int index = email.indexOf("@");
|
||||
String username = email.substring(0, index == -1 ? email.length() : index);
|
||||
PasswordResetEmail mail = PasswordResetEmail.builder()
|
||||
.title("Your password reset link")
|
||||
.contents(String.format(ResetLinkAssignment.TEMPLATE, host, resetLink))
|
||||
.sender("password-reset@webgoat-cloud.net")
|
||||
.recipient(username).build();
|
||||
this.restTemplate.postForEntity(webWolfMailURL, mail, Object.class);
|
||||
}
|
||||
|
||||
private void fakeClickingLinkEmail(String host, String resetLink) {
|
||||
try {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
HttpEntity httpEntity = new HttpEntity(httpHeaders);
|
||||
new RestTemplate().exchange(String.format("http://%s/PasswordReset/reset/reset-password/%s", host, resetLink), HttpMethod.GET, httpEntity, Void.class);
|
||||
} catch (Exception e) {
|
||||
//don't care
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.password_reset;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Optional.of;
|
||||
|
||||
/**
|
||||
* Assignment for picking a good security question.
|
||||
*
|
||||
* @author Tobias Melzer
|
||||
* @since 11.12.18
|
||||
*/
|
||||
@RestController
|
||||
public class SecurityQuestionAssignment extends AssignmentEndpoint {
|
||||
|
||||
@Autowired
|
||||
private TriedQuestions triedQuestions;
|
||||
|
||||
private static Map<String, String> questions;
|
||||
|
||||
static {
|
||||
questions = new HashMap<>();
|
||||
questions.put("What is your favorite animal?", "The answer can easily be guessed and figured out through social media.");
|
||||
questions.put("In what year was your mother born?", "Can be easily guessed.");
|
||||
questions.put("What was the time you were born?", "This may first seem like a good question, but you most likely dont know the exact time, so it might be hard to remember.");
|
||||
questions.put("What is the name of the person you first kissed?", "Can be figured out through social media, or even guessed by trying the most common names.");
|
||||
questions.put("What was the house number and street name you lived in as a child?", "Answer can be figured out through social media, or worse it might be your current address.");
|
||||
questions.put("In what town or city was your first full time job?", "In times of LinkedIn and Facebook, the answer can be figured out quite easily.");
|
||||
questions.put("In what city were you born?", "Easy to figure out through social media.");
|
||||
questions.put("What was the last name of your favorite teacher in grade three?", "Most people would probably not know the answer to that.");
|
||||
questions.put("What is the name of a college/job you applied to but didn't attend?", "It might not be easy to remember and an hacker could just try some company's/colleges in your area.");
|
||||
questions.put("What are the last 5 digits of your drivers license?", "Is subject to change, and the last digit of your driver license might follow a specific pattern. (For example your birthday).");
|
||||
questions.put("What was your childhood nickname?", "Not all people had a nickname.");
|
||||
questions.put("Who was your childhood hero?", "Most Heroes we had as a child where quite obvious ones, like Superman for example.");
|
||||
questions.put("On which wrist do you were your watch?", "There are only to possible real answers, so really easy to guess.");
|
||||
questions.put("What is your favorite color?", "Can easily be guessed.");
|
||||
}
|
||||
|
||||
@PostMapping("/PasswordReset/SecurityQuestions")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String question) {
|
||||
var answer = of(questions.get(question));
|
||||
if (answer.isPresent()) {
|
||||
triedQuestions.incr(question);
|
||||
if (triedQuestions.isComplete()) {
|
||||
return success(this).output("<b>" + answer + "</b>").build();
|
||||
}
|
||||
}
|
||||
return informationMessage(this)
|
||||
.feedback("password-questions-one-successful")
|
||||
.output(answer.orElse("Unknown question, please try again..."))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.password_reset;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
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;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static java.util.Optional.ofNullable;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 8/20/17.
|
||||
*/
|
||||
@RestController
|
||||
public class SimpleMailAssignment extends AssignmentEndpoint {
|
||||
|
||||
private final String webWolfURL;
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
public SimpleMailAssignment(RestTemplate restTemplate, @Value("${webwolf.mail.url}") String webWolfURL) {
|
||||
this.restTemplate = restTemplate;
|
||||
this.webWolfURL = webWolfURL;
|
||||
}
|
||||
|
||||
@PostMapping(path = "/PasswordReset/simple-mail", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
@ResponseBody
|
||||
public AttackResult login(@RequestParam String email, @RequestParam String password) {
|
||||
String emailAddress = ofNullable(email).orElse("unknown@webgoat.org");
|
||||
String username = extractUsername(emailAddress);
|
||||
|
||||
if (username.equals(getWebSession().getUserName()) && StringUtils.reverse(username).equals(password)) {
|
||||
return success(this).build();
|
||||
} else {
|
||||
return failed(this).feedbackArgs("password-reset-simple.password_incorrect").build();
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, value = "/PasswordReset/simple-mail/reset")
|
||||
@ResponseBody
|
||||
public AttackResult resetPassword(@RequestParam String emailReset) {
|
||||
String email = ofNullable(emailReset).orElse("unknown@webgoat.org");
|
||||
return sendEmail(extractUsername(email), email);
|
||||
}
|
||||
|
||||
private String extractUsername(String email) {
|
||||
int index = email.indexOf("@");
|
||||
return email.substring(0, index == -1 ? email.length() : index);
|
||||
}
|
||||
|
||||
private AttackResult sendEmail(String username, String email) {
|
||||
if (username.equals(getWebSession().getUserName())) {
|
||||
PasswordResetEmail mailEvent = PasswordResetEmail.builder()
|
||||
.recipient(username)
|
||||
.title("Simple e-mail assignment")
|
||||
.time(LocalDateTime.now())
|
||||
.contents("Thanks for resetting your password, your new password is: " + StringUtils.reverse(username))
|
||||
.sender("webgoat@owasp.org")
|
||||
.build();
|
||||
try {
|
||||
restTemplate.postForEntity(webWolfURL, mailEvent, Object.class);
|
||||
} catch (RestClientException e) {
|
||||
return informationMessage(this).feedback("password-reset-simple.email_failed").output(e.getMessage()).build();
|
||||
}
|
||||
return informationMessage(this).feedback("password-reset-simple.email_send").feedbackArgs(email).build();
|
||||
} else {
|
||||
return informationMessage(this).feedback("password-reset-simple.email_mismatch").feedbackArgs(username).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.password_reset;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.annotation.SessionScope;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@Component
|
||||
@SessionScope
|
||||
public class TriedQuestions {
|
||||
|
||||
private Set<String> answeredQuestions = new HashSet<>();
|
||||
|
||||
public void incr(String question) {
|
||||
answeredQuestions.add(question);
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
return answeredQuestions.size() > 1;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user