Added Assignment for Security Questions.

This commit is contained in:
Tobias-Melzer 2018-12-11 12:52:57 +01:00 committed by Nanne Baars
parent 8b61811278
commit bbb0b607b2
12 changed files with 209 additions and 73 deletions

View File

@ -6,6 +6,10 @@ import org.owasp.webgoat.lessons.NewLesson;
import java.util.List; import java.util.List;
/**
* @author TMelzer
* @since 30.11.18
*/
public class ChromeDevTools extends NewLesson { public class ChromeDevTools extends NewLesson {
@Override @Override

View File

@ -10,6 +10,11 @@ import org.springframework.web.bind.annotation.ResponseBody;
import java.io.IOException; import java.io.IOException;
/**
* This is just a class used to make the the HTTP request.
* @author TMelzer
* @since 30.11.18
*/
@AssignmentPath("/ChromeDevTools/dummy") @AssignmentPath("/ChromeDevTools/dummy")
public class NetworkDummy extends AssignmentEndpoint { public class NetworkDummy extends AssignmentEndpoint {

View File

@ -11,6 +11,12 @@ import org.springframework.web.bind.annotation.ResponseBody;
import java.io.IOException; import java.io.IOException;
/**
* 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
*/
@AssignmentPath("/ChromeDevTools/network") @AssignmentPath("/ChromeDevTools/network")
@AssignmentHints({"networkHint1", "networkHint2"}) @AssignmentHints({"networkHint1", "networkHint2"})
public class NetworkLesson extends AssignmentEndpoint { public class NetworkLesson extends AssignmentEndpoint {

View File

@ -2,6 +2,7 @@ package org.owasp.webgoat.plugin;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.owasp.webgoat.assignments.AssignmentEndpoint; import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath; import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult; import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.plugin.PasswordResetEmail; import org.owasp.webgoat.plugin.PasswordResetEmail;

View File

@ -6,23 +6,12 @@ import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints; import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath; import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult; import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.plugin.PasswordResetEmail;
import org.owasp.webgoat.plugin.resetlink.PasswordChangeForm; import org.owasp.webgoat.plugin.resetlink.PasswordChangeForm;
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.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
/** /**
* @author nbaars * @author nbaars
@ -32,13 +21,13 @@ import static org.springframework.web.bind.annotation.RequestMethod.POST;
@AssignmentHints({"password-reset-hint1", "password-reset-hint2", "password-reset-hint3", "password-reset-hint4", "password-reset-hint5", "password-reset-hint6"}) @AssignmentHints({"password-reset-hint1", "password-reset-hint2", "password-reset-hint3", "password-reset-hint4", "password-reset-hint5", "password-reset-hint6"})
public class ResetLinkAssignment extends AssignmentEndpoint { public class ResetLinkAssignment extends AssignmentEndpoint {
private static final String PASSWORD_TOM_9 = "somethingVeryRandomWhichNoOneWillEverTypeInAsPasswordForTom"; static final String PASSWORD_TOM_9 = "somethingVeryRandomWhichNoOneWillEverTypeInAsPasswordForTom";
private static final String TOM_EMAIL = "tom@webgoat-cloud.org"; static final String TOM_EMAIL = "tom@webgoat-cloud.org";
private static Map<String, String> userToTomResetLink = Maps.newHashMap(); static Map<String, String> userToTomResetLink = Maps.newHashMap();
private static Map<String, String> usersToTomPassword = Maps.newHashMap(); static Map<String, String> usersToTomPassword = Maps.newHashMap();
private static EvictingQueue resetLinks = EvictingQueue.create(1000); static EvictingQueue resetLinks = EvictingQueue.create(1000);
private static final String TEMPLATE = "Hi, you requested a password reset link, please use this " + 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." + "<a target='_blank' href='http://%s/WebGoat/PasswordReset/reset/reset-password/%s'>link</a> to reset your password." +
"\n \n\n" + "\n \n\n" +
"If you did not request this password change you can ignore this message." + "If you did not request this password change you can ignore this message." +
@ -47,57 +36,6 @@ public class ResetLinkAssignment extends AssignmentEndpoint {
"\n\n" + "\n\n" +
"Kind regards, \nTeam WebGoat"; "Kind regards, \nTeam WebGoat";
private final RestTemplate restTemplate;
private final String webWolfMailURL;
public ResetLinkAssignment(RestTemplate restTemplate, @Value("${webwolf.url.mail}") String webWolfMailURL) {
this.restTemplate = restTemplate;
this.webWolfMailURL = webWolfMailURL;
}
@RequestMapping(method = POST, value = "/create-password-reset-link")
@ResponseBody
public AttackResult sendPasswordResetLink(@RequestParam String email, HttpServletRequest request, @CookieValue("JSESSIONID") String cookie) {
String resetLink = UUID.randomUUID().toString();
resetLinks.add(resetLink);
String host = request.getHeader("host");
if (org.springframework.util.StringUtils.hasText(email)) {
if (email.equals(TOM_EMAIL) && host.contains("9090")) { //User indeed changed the host header.
userToTomResetLink.put(getWebSession().getUserName(), resetLink);
fakeClickingLinkEmail(host, resetLink);
} else {
sendMailToUser(email, host, resetLink);
}
}
return success().feedback("email.send").feedbackArgs(email).build();
}
private void sendMailToUser(@RequestParam 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(TEMPLATE, host, resetLink))
.sender("password-reset@webgoat-cloud.net")
.recipient(username)
.time(LocalDateTime.now()).build();
restTemplate.postForEntity(webWolfMailURL, mail, Object.class);
}
/**
* We need to add the current cookie of the user otherwise we cannot distinguish in WebWolf for
* which user we need to trace the incoming request. In normal situation this HOST will be in your
* full control so every incoming request would be valid.
*/
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
}
}
@PostMapping("/login") @PostMapping("/login")
@ResponseBody @ResponseBody

View File

@ -0,0 +1,85 @@
package org.owasp.webgoat.plugin;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.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.CookieValue;
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.client.RestTemplate;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.UUID;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
/**
* Part of the password reset assignment. Used to send the e-mail.
* @author nbaars
* @since 8/20/17.
*/
@AssignmentPath("/PasswordReset/ForgotPassword")
public class ResetLinkAssignmentForgotPassword extends AssignmentEndpoint {
private final RestTemplate restTemplate;
private final String webWolfMailURL;
public ResetLinkAssignmentForgotPassword(RestTemplate restTemplate,
@Value("${webwolf.url.mail}") String webWolfMailURL) {
this.restTemplate = restTemplate;
this.webWolfMailURL = webWolfMailURL;
}
@RequestMapping(method = POST, value = "/create-password-reset-link")
@ResponseBody
public AttackResult sendPasswordResetLink(@RequestParam String email, HttpServletRequest request, @CookieValue("JSESSIONID") String cookie) {
String resetLink = UUID.randomUUID().toString();
ResetLinkAssignment.resetLinks.add(resetLink);
String host = request.getHeader("host");
if (org.springframework.util.StringUtils.hasText(email)) {
if (email.equals(ResetLinkAssignment.TOM_EMAIL) && host.contains("9090")) { //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().output("E-mail can't be send. please try again.").build(); }
}
}
return success().feedback("email.send").feedbackArgs(email).build();
}
private void sendMailToUser(@RequestParam 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)
.time(LocalDateTime.now()).build();
this.restTemplate.postForEntity(webWolfMailURL, mail, Object.class);
}
/**
* We need to add the current cookie of the user otherwise we cannot distinguish in WebWolf for
* which user we need to trace the incoming request. In normal situation this HOST will be in your
* full control so every incoming request would be valid.
*/
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
}
}
}

View File

@ -0,0 +1,49 @@
package org.owasp.webgoat.plugin;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
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 java.util.HashMap;
import java.util.Map;
@AssignmentPath("/PasswordReset/SecurityQuestions")
@AssignmentHints("security-questions-hint1")
public class SecurityQuestionAssignemnt extends AssignmentEndpoint {
private static Map<String, String> questions;
static {
questions = new HashMap<>();
questions.put("What is your favorite animal?", "Bad: Can easily be guessed and can most likely be figured out through social media.");
questions.put("In what year was your mother born?", "Bad: Can be easily guessed.");
questions.put("What was the time you were born?", "Good: If you know the time you were born it is really good, because " +
"it is hard to figure out through social media and the answer is not subject to change.");
questions.put("What is the name of the person you first kissed?", "Fair: it is not a bad question, but friends and family may know and someone might figure it out through social media.");
questions.put("What was the house number and street name you lived in as a child?", "Good: hard to guess and even close friends might not know the answer.");
questions.put("In what town or city was your first full time job?", "Fair / Good: Might be easy to figure out if someone is on LinkedIn or posts a lot on social media");
questions.put("In what city were you born?", "Fair: Might be hard to figure out for a person who does not know you, but not for a person that knows, did know you.");
questions.put("What was the last name of your favorite teacher in grade three?", "Good/Fair: Most people would probably not know the answer to that, but if someone does its quite a good question.");
questions.put("What is the name of a college/job you applied to but didn't attend?", "Good: Most people will probably no an answer to that and it is really hard to figure out, even for people close to you.");
questions.put("What are the last 5 digits of your drivers license?", "Bad: 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?", "Fair: if someone had a nickname they probably remember it, but not all people had one.");
questions.put("Who was your childhood hero?", "Fair: If your childhood hero, was someone not obvious it can be quite good, but not everyone really had one and can remember it easily.");
questions.put("On which wrist do you were your watch?", "Awful: Easy to guess.");
questions.put("What is your favorite color?", "Bad: Can easily be guessed.");
}
@RequestMapping(method = RequestMethod.POST)
public
@ResponseBody
AttackResult completed(@RequestParam String question) {
System.out.println("moin");
String answer = questions.get(question);
if(answer.startsWith("Good"))
return success().output(answer).build();
return failed().output(answer).build();
}
}

View File

@ -236,5 +236,35 @@
<div class="adoc-content" th:replace="doc:PasswordReset_mitigation.adoc"></div> <div class="adoc-content" th:replace="doc:PasswordReset_mitigation.adoc"></div>
</div> </div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:PasswordReset_SecurityQuestions.adoc"></div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
action="/WebGoat/PasswordReset/SecurityQuestions"
enctype="application/json;charset=UTF-8">
<select name="question">
<option>What is your favorite animal?</option>
<option>In what year was your mother born?</option>
<option>What was the time you were born?</option>
<option>What is the name of the person you first kissed?</option>
<option>What was the house number and street name you lived in as a child?</option>
<option>In what town or city was your first full time job?</option>
<option>In what city were you born?</option>
<option>On which wrist do you were your watch?</option>
<option>What was the last name of your favorite teacher in grade three?</option>
<option>What is the name of a college/job you applied to but didn't attend?</option>
<option>What are the last 5 digits of your drivers license?</option>
<option>What was your childhood nickname?</option>
<option>Who was your childhood hero?</option>
<option>What is your favorite color?</option>
</select>
<input name="Check Question" value="check" type="SUBMIT"/>
</form>
<br/>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
</html> </html>

View File

@ -13,7 +13,7 @@ password-reset-solved=Congratulations you solved the assignment, please type in
password-reset-not-solved=Sorry but you did not redirect the reset link to WebWolf password-reset-not-solved=Sorry but you did not redirect the reset link to WebWolf
password-reset-hint1=Try to send a password reset link to your own account at {user}@webgoat.org, you can read this e-mail in WebWolf. password-reset-hint1=Try to send a password reset link to your own account at {user}@webgoat.org, you can read this e-mail in WebWolf.
password-reset-hint2=Look at the link, can you think of how the server creates this link? password-reset-hint2=Look at the link, can you think how the server creates this link?
password-reset-hint3=Tom clicks all the links he receives in his mailbox, you can use the landing page in WebWolf to get the reset link... password-reset-hint3=Tom clicks all the links he receives in his mailbox, you can use the landing page in WebWolf to get the reset link...
password-reset-hint4=The link points to localhost:8080/PasswordReset/.... can you change the host to localhost:9090? password-reset-hint4=The link points to localhost:8080/PasswordReset/.... can you change the host to localhost:9090?
password-reset-hint5=Intercept the request and change the host header. password-reset-hint5=Intercept the request and change the host header.

View File

@ -0,0 +1,17 @@
== Choosing a Security Question
We have already talked about Security questions a bit. A good security question should meet the following criteria:
- Safe: The answer should not be easy to research or guess.
- Stable: The answer should be stable, meaning that it is not subject to change.
- Memorable: The answer should be easy to remember.
- Simple: The question should be: precise, easy and consistent.
- Many: The question should have many possible answers.
== Try It! Choosing a good security question.
In this assignment your goal is to good security question from the dropdown list below.
The Assignment is complete when you picked a security question which is considered good.
Note: Some may say that one question is better than another, so this list is a bit subjective.
But you should not be having any problem differencing between the good and bad.

View File

@ -4,10 +4,10 @@ When creating a password reset link you need to make sure:
- It is a unique link with a random token - It is a unique link with a random token
- It can only be used once - It can only be used once
- The link is only valid for one hour - The link is only valid for a limited amount of time.
Send a link with a random token means an attacker cannot start a simple DOS attack to your website by starting to 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. block users. The link should not be used more than 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. The time out is necessary to restrict the attack window, having a link opens up a lot of possibilities for the attacker.
== Assignment == Assignment
@ -16,3 +16,4 @@ Try to reset the password of Tom (tom@webgoat-cloud.org) to your own choice and
that password. Note: it is not possible to use OWASP ZAP for this lesson. that password. Note: it is not possible to use OWASP ZAP for this lesson.
Tom always resets his password immediately after receiving the email with the link. Tom always resets his password immediately after receiving the email with the link.

View File

@ -17,7 +17,7 @@ resets, a good resource for security questions is: http://goodsecurityquestions.
Users can retrieve their password if they can answer the secret question properly. There is no lock-out mechanism on 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 this 'Forgot Password' page. Your username is 'webgoat' and your favorite color is 'red'. The goal is to retrieve the
password of another user. password of another user. Users you could try are: "tom", "admin" and "larry".