diff --git a/webgoat-lessons/http-proxies/src/main/java/org/owasp/webgoat/plugin/HttpBasicsInterceptRequest.java b/webgoat-lessons/http-proxies/src/main/java/org/owasp/webgoat/plugin/HttpBasicsInterceptRequest.java index e39670e57..3c7d42f44 100644 --- a/webgoat-lessons/http-proxies/src/main/java/org/owasp/webgoat/plugin/HttpBasicsInterceptRequest.java +++ b/webgoat-lessons/http-proxies/src/main/java/org/owasp/webgoat/plugin/HttpBasicsInterceptRequest.java @@ -48,7 +48,7 @@ public class HttpBasicsInterceptRequest extends AssignmentEndpoint { @RequestMapping(method = RequestMethod.GET) public @ResponseBody - AttackResult completed(HttpServletRequest request) throws IOException { + AttackResult completed(HttpServletRequest request) { String header = null; String param = null; if (request != null && (header = request.getHeader("x-request-intercepted")) != null diff --git a/webgoat-lessons/password-reset/pom.xml b/webgoat-lessons/password-reset/pom.xml new file mode 100644 index 000000000..d87ebc728 --- /dev/null +++ b/webgoat-lessons/password-reset/pom.xml @@ -0,0 +1,21 @@ + + 4.0.0 + password-reset + jar + + org.owasp.webgoat.lesson + webgoat-lessons-parent + v8.0.0.M14 + + + + + org.springframework.security + spring-security-test + 4.1.3.RELEASE + test + + + + diff --git a/webgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/plugin/PasswordReset.java b/webgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/plugin/PasswordReset.java new file mode 100644 index 000000000..9e4f3143e --- /dev/null +++ b/webgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/plugin/PasswordReset.java @@ -0,0 +1,34 @@ +package org.owasp.webgoat.plugin; + +import org.owasp.webgoat.lessons.Category; +import org.owasp.webgoat.lessons.NewLesson; + +import java.util.ArrayList; +import java.util.List; + +public class PasswordReset extends NewLesson { + @Override + public Category getDefaultCategory() { + return Category.AUTHENTICATION; + } + + @Override + public List getHints() { + return new ArrayList(); + } + + @Override + public Integer getDefaultRanking() { + return 10; + } + + @Override + public String getTitle() { + return "password-reset.title"; + } + + @Override + public String getId() { + return "PasswordReset"; + } +} diff --git a/webgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/plugin/PasswordResetEmail.java b/webgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/plugin/PasswordResetEmail.java new file mode 100644 index 000000000..deec7e5f8 --- /dev/null +++ b/webgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/plugin/PasswordResetEmail.java @@ -0,0 +1,18 @@ +package org.owasp.webgoat.plugin; + +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; +} \ No newline at end of file diff --git a/webgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/plugin/questions/QuestionsAssignment.java b/webgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/plugin/questions/QuestionsAssignment.java new file mode 100644 index 000000000..e90f5cb2a --- /dev/null +++ b/webgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/plugin/questions/QuestionsAssignment.java @@ -0,0 +1,55 @@ +package org.owasp.webgoat.plugin.questions; + +import org.apache.commons.lang3.StringUtils; +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentPath; +import org.owasp.webgoat.assignments.AttackResult; +import org.owasp.webgoat.plugin.PasswordResetEmail; +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.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * @author nbaars + * @since 8/20/17. + */ +@AssignmentPath("/PasswordReset/questions") +public class QuestionsAssignment extends AssignmentEndpoint { + + private final static Map 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(consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + @ResponseBody + public AttackResult passwordReset(@RequestParam Map json) { + String securityQuestion = (String) json.getOrDefault("securityQuestion", ""); + String username = (String) json.getOrDefault("username", ""); + + if ("webgoat".equalsIgnoreCase(username.toLowerCase())) { + return trackProgress(failed().feedback("password-questions-wrong-user").build()); + } + + String validAnswer = COLORS.get(username.toLowerCase()); + if (validAnswer == null) { + return trackProgress(failed().feedback("password-questions-unknown-user").feedbackArgs(username).build()); + } else if (validAnswer.equals(securityQuestion)) { + return trackProgress(success().build()); + } + return trackProgress(failed().build()); + } +} diff --git a/webgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/plugin/simple/SimpleMailAssignment.java b/webgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/plugin/simple/SimpleMailAssignment.java new file mode 100644 index 000000000..e608742dd --- /dev/null +++ b/webgoat-lessons/password-reset/src/main/java/org/owasp/webgoat/plugin/simple/SimpleMailAssignment.java @@ -0,0 +1,82 @@ +package org.owasp.webgoat.plugin.simple; + +import org.apache.commons.lang3.StringUtils; +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentPath; +import org.owasp.webgoat.assignments.AttackResult; +import org.owasp.webgoat.plugin.PasswordResetEmail; +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.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +import java.time.LocalDateTime; +import java.util.Map; +import java.util.Optional; + +import static java.util.Optional.ofNullable; + +/** + * @author nbaars + * @since 8/20/17. + */ +@AssignmentPath("/PasswordReset/simple-mail") +public class SimpleMailAssignment extends AssignmentEndpoint { + + private final String webWolfURL; + private RestTemplate restTemplate; + + public SimpleMailAssignment(RestTemplate restTemplate, @Value("${webwolf.url.mail}") String webWolfURL) { + this.restTemplate = restTemplate; + this.webWolfURL = webWolfURL; + } + + @PostMapping(consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + @ResponseBody + public AttackResult sendEmail(@RequestParam Map json) { + String email = (String) json.get("emailReset"); + if (StringUtils.isEmpty(email)) { + email = (String) json.getOrDefault("email", "unknown@webgoat.org"); + } + String password = (String) json.getOrDefault("password", ""); + int index = email.indexOf("@"); + String username = email.substring(0, index == -1 ? email.length() : index); + + if (StringUtils.isEmpty(password)) { + return sendEmail(username, email); + } else { + return checkPassword(password, username); + } + } + + private AttackResult checkPassword(String password, String username) { + if (username.equals(getWebSession().getUserName()) && StringUtils.reverse(username).equals(password)) { + return trackProgress(success().build()); + } else { + return trackProgress(failed().feedbackArgs("password-reset-simple.password_incorrect").build()); + } + } + + 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 your 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().feedback("password-reset-simple.email_failed").output(e.getMessage()).build(); + } + return informationMessage().feedback("password-reset-simple.email_send").feedbackArgs(email).build(); + } else { + return informationMessage().feedback("password-reset-simple.email_mismatch").feedbackArgs(username).build(); + } + } +} diff --git a/webgoat-lessons/password-reset/src/main/resources/css/password.css b/webgoat-lessons/password-reset/src/main/resources/css/password.css new file mode 100644 index 000000000..e69de29bb diff --git a/webgoat-lessons/password-reset/src/main/resources/html/PasswordReset.html b/webgoat-lessons/password-reset/src/main/resources/html/PasswordReset.html new file mode 100644 index 000000000..4b5373a0f --- /dev/null +++ b/webgoat-lessons/password-reset/src/main/resources/html/PasswordReset.html @@ -0,0 +1,134 @@ + + + + +
+
+
+
+
+ + + + +
+ +
+
+
+ +
+ +
+

Account + Access

+
+
+
+ @ + +
+
+ + +
+
+ +

+ + Forgot your password? + +

+
+
+ +
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+ +
+
+ + + + +
+
+
+
+
+
+ Sign up + Login +

WebGoat Password Recovery

+ +
+ + +
+
+ + +
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+
+ + + \ No newline at end of file diff --git a/webgoat-lessons/password-reset/src/main/resources/i18n/WebGoatLabels.properties b/webgoat-lessons/password-reset/src/main/resources/i18n/WebGoatLabels.properties new file mode 100644 index 000000000..cb073b35a --- /dev/null +++ b/webgoat-lessons/password-reset/src/main/resources/i18n/WebGoatLabels.properties @@ -0,0 +1,9 @@ +password-reset.title=Password reset + +password-reset-simple.email_send=An email has been send to {0} please check your inbox. +password-reset-simple.password_incorrect=Not the correct password please try again. +password-reset-simple.email_failed=There was an error while sending the e-mail. Is WebWolf running? +password-reset-simple.email_mismatch=Of course you can send mail to user {0} however you will not be able to read this e-mail in WebWolf, please use your own username. + +password-questions-wrong-user=You need to find a different user you are logging in with 'webgoat'. +password-questions-unknown-user=User {0} is not a valid user. diff --git a/webgoat-lessons/password-reset/src/main/resources/images/reset1.png b/webgoat-lessons/password-reset/src/main/resources/images/reset1.png new file mode 100644 index 000000000..36793a8b5 Binary files /dev/null and b/webgoat-lessons/password-reset/src/main/resources/images/reset1.png differ diff --git a/webgoat-lessons/password-reset/src/main/resources/images/reset2.png b/webgoat-lessons/password-reset/src/main/resources/images/reset2.png new file mode 100644 index 000000000..3c94b01b5 Binary files /dev/null and b/webgoat-lessons/password-reset/src/main/resources/images/reset2.png differ diff --git a/webgoat-lessons/password-reset/src/main/resources/images/slack1.png b/webgoat-lessons/password-reset/src/main/resources/images/slack1.png new file mode 100644 index 000000000..34114af25 Binary files /dev/null and b/webgoat-lessons/password-reset/src/main/resources/images/slack1.png differ diff --git a/webgoat-lessons/password-reset/src/main/resources/images/slack2.png b/webgoat-lessons/password-reset/src/main/resources/images/slack2.png new file mode 100644 index 000000000..1102b4211 Binary files /dev/null and b/webgoat-lessons/password-reset/src/main/resources/images/slack2.png differ diff --git a/webgoat-lessons/password-reset/src/main/resources/js/password-reset-simple.js b/webgoat-lessons/password-reset/src/main/resources/js/password-reset-simple.js new file mode 100644 index 000000000..0073c693b --- /dev/null +++ b/webgoat-lessons/password-reset/src/main/resources/js/password-reset-simple.js @@ -0,0 +1,10 @@ +$(document).ready(function() { + $('#olvidado').click(function(e) { + e.preventDefault(); + $('div#form-olvidado').toggle('500'); + }); + $('#acceso').click(function(e) { + e.preventDefault(); + $('div#form-olvidado').toggle('500'); + }); +}); \ No newline at end of file diff --git a/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_host_header.adoc b/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_host_header.adoc new file mode 100644 index 000000000..46c8666ee --- /dev/null +++ b/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_host_header.adoc @@ -0,0 +1,17 @@ +== Creating the password reset link + +When creating a password reset link you need to make sure: + +- It is a unique link with a random token +- It can only be used once +- The link is only valid for one hour + +Send a link with a random token means an attacker cannot start a simple DOS attack to your website by starting to +block users. The link should not be used more then once which makes it impossible to change the password again. +The time out is necessary to restrict the attack window, having a link opens up a lot of possibilities for the attacker. + +== Assignment + +In this assignment Tom uses the password reset functionality, can you try to find a way to e-mail the password +reset link to your own inbox at user@webwolf.org. Use WebWolf to read the email and paste the token in the box +below. diff --git a/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_known_questions.adoc b/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_known_questions.adoc new file mode 100644 index 000000000..04d4690c9 --- /dev/null +++ b/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_known_questions.adoc @@ -0,0 +1,23 @@ +== Security questions + +This has been an issue and still is for a lot of websites, when you lost your password the website will ask you +for a security question which you answered during the sign up process. Most of the time this list contains a fixed +number of question and which sometimes even have a limited set of answers. In order to use this functionality +a user should be able to select a question by itself and type in the answer as well. This way users will not share +the question which makes it more difficult for an attacker. + +One important thing to remember the answers to these security question(s) should be treated with the same level of +security which is applied for storing a password in a database. If the database leaks an attacker should not be able +to perform password reset based on the answer of the security question. + +Users share so much information on social media these days it becomes difficult to use security questions for password +resets, a good resource for security questions is: http://goodsecurityquestions.com/ + +== Assignment + +Users can retrieve their password if they can answer the secret question properly. There is no lock-out mechanism on +this 'Forgot Password' page. Your username is 'webgoat' and your favorite color is 'red'. The goal is to retrieve the +password of another user. + + + diff --git a/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_password_reset_link.adoc b/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_password_reset_link.adoc new file mode 100644 index 000000000..c7ba7dd90 --- /dev/null +++ b/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_password_reset_link.adoc @@ -0,0 +1,3 @@ +== Password reset link + +Should be unique, do diff --git a/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_plan.adoc b/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_plan.adoc new file mode 100644 index 000000000..fac4211c0 --- /dev/null +++ b/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_plan.adoc @@ -0,0 +1,22 @@ += Password reset + +== Concept + +This lesson teaches about password reset functionality which most of the time is an overlooked part of the application +leading to all kind of interesting logic flaws. + +== Goals + +Teach how to securely implement password reset functionality within your application. + +== Introduction + +Each and every one of us will have used the password reset functionality on websites before. Each website implements +this functionality in a different manner. On some site you have to answer some question on other sites an e-mail +with an activation link will be send to you. In this lesson we will go through some of the most common password +reset functionalities and show where it can go wrong. + +Still there are companies which will send the password in plaintext to a user in an e-mail. For a couple of examples +you can take a look at http://plaintextoffenders.com/ Here you will find website which still send you the plaintext +password in an e-mail. Not only this should make you question the security of the site but this also mean they store +your password in plaintext! \ No newline at end of file diff --git a/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_simple.adoc b/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_simple.adoc new file mode 100644 index 000000000..c3e051b13 --- /dev/null +++ b/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_simple.adoc @@ -0,0 +1,6 @@ +== Email functionality with WebWolf + +Let's first do a simple assignment to make sure you are able to read e-mails with WebWolf, first start WebWolf (see http://) +In the reset page below send an e-mail to `username@webgoat.org` (part behind the @ is not important) +Open WebWolf and read the e-mail and login with your username and the password provided in the e-mail. + diff --git a/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_wrong_message.adoc b/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_wrong_message.adoc new file mode 100644 index 000000000..772eeb677 --- /dev/null +++ b/webgoat-lessons/password-reset/src/main/resources/lessonPlans/en/PasswordReset_wrong_message.adoc @@ -0,0 +1,21 @@ +:half-size: width='20%' + +== Find out if account exists + +As stated before during a password reset often you will find a different message depending on whether an e-mail +address exists or not. By itself this might not look like a big deal but it can give an attacker information which +can be used in a phishing attack. If the attacker knows you have a registered account at a site, the attacker can +for example create a phishing mail and send it to the user. The user might be more tempted to click the e-mail because +the user has a valid account at the website. On the other hand for some websites this is not really important but +some website users would like some more privacy. + +The screenshots below are taken from a real website: + +image:images/reset2.png[align="top", {half-size}] +image:images/reset1.png[align="top", {half-size}] + +Below you see how Slack implemented the same two pages, no matter what e-mail address you enter the message will +be exactly the same: + +image:images/slack1.png[{half-size}] +image:images/slack2.png[{half-size}] diff --git a/webgoat-lessons/pom.xml b/webgoat-lessons/pom.xml index 63dca5f48..04ec10fda 100644 --- a/webgoat-lessons/pom.xml +++ b/webgoat-lessons/pom.xml @@ -33,6 +33,7 @@ auth-bypass missing-function-ac csrf + password-reset diff --git a/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_challenge.adoc b/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_challenge.adoc index 0fdb4f2d3..8a8a7ce78 100644 --- a/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_challenge.adoc +++ b/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_challenge.adoc @@ -1,4 +1,6 @@ We now explained the basic steps involved in an SQL injection. In this assignment you will need to combine all the things we explained in the SQL lessons. +Goal: Can you login as Tom? + Have fun! \ No newline at end of file diff --git a/webgoat-server/pom.xml b/webgoat-server/pom.xml index 5bd46135d..1f44f04cd 100644 --- a/webgoat-server/pom.xml +++ b/webgoat-server/pom.xml @@ -190,6 +190,11 @@ missing-function-ac ${project.version} + + org.owasp.webgoat.lesson + password-reset + ${project.version} +