New lesson working
This commit is contained in:
@ -15,6 +15,4 @@ public interface SolutionConstants {
|
||||
String PASSWORD_LARRY = "larryknows";
|
||||
String JWT_PASSWORD = "victory";
|
||||
String ADMIN_PASSWORD_LINK = "375afe1104f4a487a73823c50a9292a2";
|
||||
String PASSWORD_TOM_9 = "somethingVeryRandomWhichNoOneWillEverTypeInAsPasswordForTom";
|
||||
String TOM_EMAIL = "tom@webgoat-cloud.org";
|
||||
}
|
||||
|
@ -1,161 +0,0 @@
|
||||
package org.owasp.webgoat.plugin.challenge9;
|
||||
|
||||
import com.beust.jcommander.internal.Lists;
|
||||
import com.beust.jcommander.internal.Maps;
|
||||
import com.google.common.collect.EvictingQueue;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.plugin.Email;
|
||||
import org.owasp.webgoat.users.UserRepository;
|
||||
import org.owasp.webgoat.users.WebGoatUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.util.StringUtils;
|
||||
import org.springframework.validation.BindingResult;
|
||||
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.UUID;
|
||||
|
||||
import static org.owasp.webgoat.plugin.Flag.FLAGS;
|
||||
import static org.owasp.webgoat.plugin.SolutionConstants.PASSWORD_TOM_9;
|
||||
import static org.owasp.webgoat.plugin.SolutionConstants.TOM_EMAIL;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/8/17.
|
||||
*/
|
||||
@AssignmentPath("/challenge/9")
|
||||
@Slf4j
|
||||
public class Assignment9 extends AssignmentEndpoint {
|
||||
|
||||
private static Map<String, String> userToTomResetLink = Maps.newHashMap();
|
||||
private static Map<String, String> usersToTomPassword = Maps.newHashMap();
|
||||
private static EvictingQueue resetLinks = EvictingQueue.create(1000);
|
||||
|
||||
private static final String TEMPLATE = "Hi, you requested a password reset link, please use this " +
|
||||
"<a target='_blank' href='http://%s/WebGoat/challenge/9/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;
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
@Value("${webwolf.url}")
|
||||
private String webWolfURL;
|
||||
|
||||
@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 (StringUtils.hasText(email)) {
|
||||
if (email.equals(TOM_EMAIL) && host.contains("8081")) { //User indeed changed the host header.
|
||||
userToTomResetLink.put(getWebSession().getUserName(), resetLink);
|
||||
fakeClickingLinkEmail(cookie, 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) {
|
||||
String username;
|
||||
WebGoatUser webGoatUser = userRepository.findByUsername(email.substring(0, email.indexOf("@")));
|
||||
if (webGoatUser != null) {
|
||||
username = webGoatUser.getUsername();
|
||||
Email mail = Email.builder()
|
||||
.title("Your password reset link for challenge 9")
|
||||
.contents(String.format(TEMPLATE, host, resetLink))
|
||||
.sender("password-reset@webgoat-cloud.net")
|
||||
.recipient(username)
|
||||
.time(LocalDateTime.now()).build();
|
||||
restTemplate.postForEntity(webWolfURL + "/WebWolf/mail", 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 cookie, String host, String resetLink) {
|
||||
try {
|
||||
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.put(HttpHeaders.COOKIE, Lists.newArrayList("JSESSIONID=" + cookie));
|
||||
HttpEntity httpEntity = new HttpEntity(httpHeaders);
|
||||
new RestTemplate().exchange(String.format("http://%s/challenge/9/reset-password/%s", host, resetLink), HttpMethod.GET, httpEntity, Void.class);
|
||||
} catch (Exception e) {
|
||||
//don't care
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/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().feedback("login_failed").build();
|
||||
} else if (passwordTom.equals(password)) {
|
||||
return success().feedback("challenge.solved").feedbackArgs(FLAGS.get(9)).build();
|
||||
}
|
||||
}
|
||||
return failed().feedback("login_failed.tom").build();
|
||||
}
|
||||
|
||||
@GetMapping("/reset-password/{link}")
|
||||
public String resetPassword(@PathVariable(value = "link") String link, Model model) {
|
||||
if (this.resetLinks.contains(link)) {
|
||||
PasswordChangeForm form = new PasswordChangeForm();
|
||||
form.setResetLink(link);
|
||||
model.addAttribute("form", form);
|
||||
return "password_reset"; //Display html page for changing password
|
||||
} else {
|
||||
return "password_link_not_found";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/change-password")
|
||||
public String changePassword(@ModelAttribute("form") PasswordChangeForm form, BindingResult bindingResult) {
|
||||
if (!StringUtils.hasText(form.getPassword())) {
|
||||
bindingResult.rejectValue("password", "not.empty");
|
||||
}
|
||||
if (bindingResult.hasErrors()) {
|
||||
return "password_reset";
|
||||
}
|
||||
if (!resetLinks.contains(form.getResetLink())) {
|
||||
return "password_link_not_found";
|
||||
}
|
||||
if (checkIfLinkIsFromTom(form.getResetLink())) {
|
||||
usersToTomPassword.put(getWebSession().getUserName(), form.getPassword());
|
||||
}
|
||||
return "success";
|
||||
}
|
||||
|
||||
private boolean checkIfLinkIsFromTom(String resetLinkFromForm) {
|
||||
String resetLink = userToTomResetLink.getOrDefault(getWebSession().getUserName(), "unknown");
|
||||
return resetLink.equals(resetLinkFromForm);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
package org.owasp.webgoat.plugin.challenge9;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.owasp.webgoat.lessons.Category;
|
||||
import org.owasp.webgoat.lessons.NewLesson;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/21/17.
|
||||
*/
|
||||
public class Challenge9 extends NewLesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.CHALLENGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHints() {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getDefaultRanking() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "challenge9.title";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "Challenge9";
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package org.owasp.webgoat.plugin.challenge9;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 8/18/17.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class PasswordChangeForm {
|
||||
|
||||
@NotNull
|
||||
@Size(min=6, max=10)
|
||||
private String password;
|
||||
private String resetLink;
|
||||
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:Challenge_9.adoc"></div>
|
||||
<script th:src="@{/lesson_js/challenge9.js}" language="JavaScript"></script>
|
||||
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h4 style="border-bottom: 1px solid #c5c5c5;">
|
||||
<i class="glyphicon glyphicon-user"></i>
|
||||
Account Access
|
||||
</h4>
|
||||
<div style="padding: 20px;" id="form-login">
|
||||
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
action="/WebGoat/challenge/9/login"
|
||||
enctype="application/json;charset=UTF-8" role="form">
|
||||
<fieldset>
|
||||
<div class="form-group input-group">
|
||||
<span class="input-group-addon"> @ </span>
|
||||
<input class="form-control" placeholder="Email" name="email" type="email"
|
||||
required="" autofocus=""/>
|
||||
</div>
|
||||
<div class="form-group input-group">
|
||||
<span class="input-group-addon">
|
||||
<i class="glyphicon glyphicon-lock">
|
||||
</i>
|
||||
</span>
|
||||
<input class="form-control" placeholder="Password" name="password" type="password"
|
||||
value="" required=""/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary btn-block">
|
||||
Access
|
||||
</button>
|
||||
<p class="help-block">
|
||||
<a class="pull-right text-muted" href="#" id="login">
|
||||
<small>Forgot your password?</small>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
<div style="display: none;" id="form-login">
|
||||
<h4 class="">
|
||||
Forgot your password?
|
||||
</h4>
|
||||
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
action="/WebGoat/challenge/9/create-password-reset-link"
|
||||
enctype="application/json;charset=UTF-8" role="form">
|
||||
<fieldset>
|
||||
<span class="help-block">
|
||||
Email address you use to log in to your account
|
||||
<br/>
|
||||
We'll send you an email with instructions to choose a new password.
|
||||
</span>
|
||||
<div class="form-group input-group">
|
||||
<span class="input-group-addon">
|
||||
@
|
||||
</span>
|
||||
<input class="form-control" placeholder="Email" name="email" type="email"
|
||||
required=""/>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-block" id="btn-login">
|
||||
Continue
|
||||
</button>
|
||||
<p class="help-block">
|
||||
<a class="text-muted" href="#" id="forgot">
|
||||
<small>Account Access</small>
|
||||
</a>
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<form class="attack-form" method="POST" name="form" action="/WebGoat/challenge/flag">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
||||
style="font-size:20px"></i></div>
|
||||
<input type="text" class="form-control" id="flag" name="flag"
|
||||
placeholder="a7179f89-906b-4fec-9d99-f15b796e7208"/>
|
||||
</div>
|
||||
<div class="input-group" style="margin-top: 10px">
|
||||
<button type="submit" class="btn btn-primary">Submit flag</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<br/>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</html>
|
@ -1,10 +0,0 @@
|
||||
$(document).ready(function() {
|
||||
$('#login').click(function(e) {
|
||||
e.preventDefault();
|
||||
$('div#form-login').toggle('500');
|
||||
});
|
||||
$('#forgot').click(function(e) {
|
||||
e.preventDefault();
|
||||
$('div#form-login').toggle('500');
|
||||
});
|
||||
});
|
@ -1,3 +0,0 @@
|
||||
Tom always resets his password immediately after receiving the email with the link.
|
||||
Try to reset the password of Tom (tom@webgoat-cloud.org) to your own choice and login as Tom with
|
||||
that password.
|
@ -1,19 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/plugins/bootstrap/css/bootstrap.min.css}"/>
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/css/font-awesome.min.css}"/>
|
||||
<script th:src="@{/plugins/bootstrap/js/bootstrap.min.js}"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="alert alert-danger">
|
||||
<h4>Password reset link is not valid please try again.</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,48 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/plugins/bootstrap/css/bootstrap.min.css}"/>
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/css/font-awesome.min.css}"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-8 col-md-6 col-sm-offset-2 col-md-offset-3">
|
||||
<form role="form" method="POST" action="/WebGoat/challenge/9/change-password" th:object="${form}">
|
||||
<h2 class="sign_up_title">Reset your password</h2>
|
||||
<!--<div class="form-group" th:classappend="${#fields.hasErrors('email')}? 'has-error'">-->
|
||||
<!--<div class="form-group">-->
|
||||
<!--<label for="email" class="control-label">Email</label>-->
|
||||
<!--<input autofocus="dummy_for_thymeleaf_parser" type="text" class="form-control"-->
|
||||
<!--th:field="*{email}"-->
|
||||
<!--id="email" placeholder="email" name='email'/>-->
|
||||
<!--<span th:if="${#fields.hasErrors('email')}" th:errors="*{email}">Email error</span>-->
|
||||
<!--</div>-->
|
||||
<div class="form-group" th:classappend="${#fields.hasErrors('password')}? 'has-error'">
|
||||
<input type="hidden" name="resetLink" th:field="*{resetLink}" />
|
||||
<label for="password" class="control-label" th:text="#{password}">Password</label>
|
||||
<input type="password" class="form-control" id="password" placeholder="Password"
|
||||
name='password' th:value="*{password}"/>
|
||||
<span th:if="${#fields.hasErrors('password')}" th:errors="*{password}">Password error</span>
|
||||
</div>
|
||||
|
||||
<!---->
|
||||
<!--<div class="form-group">-->
|
||||
<!--<input type="email" required="" autofocus="" name="email" id="email" class="form-control input-lg" placeholder="Email"-->
|
||||
<!--tabindex="4"/>-->
|
||||
<!--<input type="newPassword" required="" autofocus="" name="newPassword" id="newPassword" class="form-control input-lg" placeholder="New password"-->
|
||||
<!--tabindex="4"/>-->
|
||||
<!--</div>-->
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-md-12">
|
||||
<button type="submit" class="btn btn-success btn-block btn-lg">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,19 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/plugins/bootstrap/css/bootstrap.min.css}"/>
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/css/font-awesome.min.css}"/>
|
||||
<script th:src="@{/plugins/bootstrap/js/bootstrap.min.js}"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="alert alert-success">
|
||||
<h4>Password changed successfully, please login again with your new password</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
Reference in New Issue
Block a user