From 46c536554c93308cb037d45f52eaf1a91394c109 Mon Sep 17 00:00:00 2001 From: Nanne Baars Date: Sun, 13 Aug 2017 11:22:52 +0200 Subject: [PATCH] - Added new challenges - Added new webapplication called WebWolf to make attacks more realistic - Added WebWolf lesson to explain the concepts behind this new application --- pom.xml | 2 + webgoat-commons/pom.xml | 37 + .../org/owasp/webgoat/login/LoginEvent.java | 15 + .../org/owasp/webgoat/login/LogoutEvent.java | 14 + .../owasp/webgoat/mail/IncomingMailEvent.java | 21 + webgoat-container/pom.xml | 47 +- .../java/org/owasp/webgoat/HammerHead.java | 42 +- .../java/org/owasp/webgoat/JmsConfig.java | 35 + .../org/owasp/webgoat/MvcConfiguration.java | 8 +- .../main/java/org/owasp/webgoat/WebGoat.java | 14 +- .../org/owasp/webgoat/WebSecurityConfig.java | 6 +- .../assignments/AssignmentEndpoint.java | 4 + .../owasp/webgoat/login/LogoutHandler.java | 47 ++ .../owasp/webgoat/plugins/PluginsLoader.java | 1 + .../webgoat/users/RegistrationController.java | 23 +- .../org/owasp/webgoat/users/Scoreboard.java | 3 +- .../org/owasp/webgoat/users/UserSession.java | 21 + .../src/main/resources/application.properties | 5 + .../main/resources/i18n/messages.properties | 2 +- .../resources/static/css/img/owasp_logo.jpg | Bin 0 -> 57346 bytes .../src/main/resources/static/css/main.css | 2 +- .../js/goatApp/templates/scoreboard.html | 4 +- .../owasp/webgoat/plugins/JmsTestConfig.java | 19 + .../org/owasp/webgoat/plugins/LessonTest.java | 2 + .../java/org/owasp/webgoat/plugin/Flag.java | 2 +- .../webgoat/plugin/SolutionConstants.java | 4 +- .../plugin/challenge3/Assignment3.java | 12 +- .../challenge5/challenge6/Assignment5.java | 8 + .../plugin/challenge7/Assignment7.java | 84 +++ .../webgoat/plugin/challenge7/Challenge7.java | 39 + .../owasp/webgoat/plugin/challenge7/MD5.java | 689 ++++++++++++++++++ .../plugin/challenge7/PasswordResetLink.java | 43 ++ .../plugin/challenge8/Assignment8.java | 68 ++ .../webgoat/plugin/challenge8/Challenge8.java | 39 + .../plugin/challenge9/Assignment9.java | 159 ++++ .../webgoat/plugin/challenge9/Challenge9.java | 39 + .../plugin/challenge9/PasswordChangeForm.java | 22 + .../src/main/resources/challenge7/git.zip | Bin 0 -> 28890 bytes .../src/main/resources/css/challenge8.css | 43 ++ .../src/main/resources/html/Challenge7.html | 82 +++ .../src/main/resources/html/Challenge8.html | 255 +++++++ .../src/main/resources/html/Challenge9.html | 109 +++ .../resources/i18n/WebGoatLabels.properties | 15 +- .../src/main/resources/images/hi-five-cat.jpg | Bin 0 -> 40693 bytes .../src/main/resources/images/user1.png | Bin 0 -> 1580 bytes .../src/main/resources/images/user2.png | Bin 0 -> 1771 bytes .../src/main/resources/images/user3.png | Bin 0 -> 2077 bytes .../src/main/resources/js/challenge8.js | 57 ++ .../src/main/resources/js/challenge9.js | 10 + .../resources/lessonPlans/en/Challenge_7.adoc | 1 + .../resources/lessonPlans/en/Challenge_8.adoc | 1 + .../resources/lessonPlans/en/Challenge_9.adoc | 3 + .../templates/password_link_not_found.html | 19 + .../resources/templates/password_reset.html | 48 ++ .../src/main/resources/templates/success.html | 19 + webgoat-lessons/pom.xml | 1 + .../resources/html/SqlInjectionAdvanced.html | 4 +- webgoat-lessons/webwolf-introduction/pom.xml | 11 + .../webgoat/plugin/LandingAssignment.java | 48 ++ .../owasp/webgoat/plugin/MailAssignment.java | 55 ++ .../webgoat/plugin/WebWolfIntroduction.java | 63 ++ .../resources/html/WebWolfIntroduction.html | 99 +++ .../resources/i18n/WebGoatLabels.properties | 9 + .../src/main/resources/images/files.png | Bin 0 -> 26417 bytes .../src/main/resources/images/mailbox.png | Bin 0 -> 55853 bytes .../src/main/resources/images/requests.png | Bin 0 -> 58485 bytes .../lessonPlans/en/Introduction.adoc | 21 + .../lessonPlans/en/Landing_page.adoc | 25 + .../lessonPlans/en/Receiving_mail.adoc | 18 + .../lessonPlans/en/Uploading_files.adoc | 12 + .../templates/webwolfPasswordReset.html | 34 + webgoat-server/pom.xml | 27 +- .../java/org/owasp/webgoat/StartWebGoat.java | 6 +- webwolf/README.md | 46 ++ webwolf/pom.xml | 111 +++ .../java/org/owasp/webwolf/FileServer.java | 89 +++ .../org/owasp/webwolf/MvcConfiguration.java | 43 ++ .../org/owasp/webwolf/WebSecurityConfig.java | 84 +++ .../main/java/org/owasp/webwolf/WebWolf.java | 59 ++ .../java/org/owasp/webwolf/mailbox/Email.java | 42 ++ .../webwolf/mailbox/MailboxController.java | 35 + .../webwolf/mailbox/MailboxListener.java | 37 + .../webwolf/mailbox/MailboxRepository.java | 16 + .../org/owasp/webwolf/requests/Requests.java | 69 ++ .../requests/WebWolfTraceRepository.java | 105 +++ .../org/owasp/webwolf/user/LoginListener.java | 33 + .../owasp/webwolf/user/UserRepository.java | 12 + .../org/owasp/webwolf/user/UserService.java | 30 + .../org/owasp/webwolf/user/WebGoatUser.java | 69 ++ .../owasp/webwolf/user/WebGoatUserCookie.java | 22 + .../user/WebGoatUserToCookieRepository.java | 14 + .../src/main/resources/application.properties | 41 ++ .../src/main/resources/static/css/main.css | 87 +++ .../src/main/resources/static/images/wolf.png | Bin 0 -> 5953 bytes .../src/main/resources/static/images/wolf.svg | 80 ++ .../main/resources/static/js/fileUpload.js | 15 + webwolf/src/main/resources/static/js/mail.js | 10 + .../src/main/resources/templates/files.html | 72 ++ .../resources/templates/fragments/footer.html | 19 + .../resources/templates/fragments/header.html | 51 ++ .../src/main/resources/templates/home.html | 37 + .../src/main/resources/templates/login.html | 58 ++ .../src/main/resources/templates/mailbox.html | 150 ++++ .../main/resources/templates/requests.html | 56 ++ 104 files changed, 4199 insertions(+), 70 deletions(-) create mode 100644 webgoat-commons/pom.xml create mode 100644 webgoat-commons/src/main/java/org/owasp/webgoat/login/LoginEvent.java create mode 100644 webgoat-commons/src/main/java/org/owasp/webgoat/login/LogoutEvent.java create mode 100644 webgoat-commons/src/main/java/org/owasp/webgoat/mail/IncomingMailEvent.java create mode 100644 webgoat-container/src/main/java/org/owasp/webgoat/JmsConfig.java create mode 100644 webgoat-container/src/main/java/org/owasp/webgoat/login/LogoutHandler.java create mode 100644 webgoat-container/src/main/java/org/owasp/webgoat/users/UserSession.java create mode 100644 webgoat-container/src/main/resources/static/css/img/owasp_logo.jpg create mode 100644 webgoat-container/src/test/java/org/owasp/webgoat/plugins/JmsTestConfig.java create mode 100644 webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/Assignment7.java create mode 100644 webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/Challenge7.java create mode 100644 webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/MD5.java create mode 100644 webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/PasswordResetLink.java create mode 100644 webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge8/Assignment8.java create mode 100644 webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge8/Challenge8.java create mode 100644 webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge9/Assignment9.java create mode 100644 webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge9/Challenge9.java create mode 100644 webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge9/PasswordChangeForm.java create mode 100644 webgoat-lessons/challenge/src/main/resources/challenge7/git.zip create mode 100644 webgoat-lessons/challenge/src/main/resources/css/challenge8.css create mode 100644 webgoat-lessons/challenge/src/main/resources/html/Challenge7.html create mode 100644 webgoat-lessons/challenge/src/main/resources/html/Challenge8.html create mode 100644 webgoat-lessons/challenge/src/main/resources/html/Challenge9.html create mode 100644 webgoat-lessons/challenge/src/main/resources/images/hi-five-cat.jpg create mode 100644 webgoat-lessons/challenge/src/main/resources/images/user1.png create mode 100644 webgoat-lessons/challenge/src/main/resources/images/user2.png create mode 100644 webgoat-lessons/challenge/src/main/resources/images/user3.png create mode 100644 webgoat-lessons/challenge/src/main/resources/js/challenge8.js create mode 100644 webgoat-lessons/challenge/src/main/resources/js/challenge9.js create mode 100644 webgoat-lessons/challenge/src/main/resources/lessonPlans/en/Challenge_7.adoc create mode 100644 webgoat-lessons/challenge/src/main/resources/lessonPlans/en/Challenge_8.adoc create mode 100644 webgoat-lessons/challenge/src/main/resources/lessonPlans/en/Challenge_9.adoc create mode 100644 webgoat-lessons/challenge/src/main/resources/templates/password_link_not_found.html create mode 100644 webgoat-lessons/challenge/src/main/resources/templates/password_reset.html create mode 100644 webgoat-lessons/challenge/src/main/resources/templates/success.html create mode 100644 webgoat-lessons/webwolf-introduction/pom.xml create mode 100644 webgoat-lessons/webwolf-introduction/src/main/java/org/owasp/webgoat/plugin/LandingAssignment.java create mode 100644 webgoat-lessons/webwolf-introduction/src/main/java/org/owasp/webgoat/plugin/MailAssignment.java create mode 100644 webgoat-lessons/webwolf-introduction/src/main/java/org/owasp/webgoat/plugin/WebWolfIntroduction.java create mode 100644 webgoat-lessons/webwolf-introduction/src/main/resources/html/WebWolfIntroduction.html create mode 100644 webgoat-lessons/webwolf-introduction/src/main/resources/i18n/WebGoatLabels.properties create mode 100644 webgoat-lessons/webwolf-introduction/src/main/resources/images/files.png create mode 100644 webgoat-lessons/webwolf-introduction/src/main/resources/images/mailbox.png create mode 100644 webgoat-lessons/webwolf-introduction/src/main/resources/images/requests.png create mode 100644 webgoat-lessons/webwolf-introduction/src/main/resources/lessonPlans/en/Introduction.adoc create mode 100644 webgoat-lessons/webwolf-introduction/src/main/resources/lessonPlans/en/Landing_page.adoc create mode 100644 webgoat-lessons/webwolf-introduction/src/main/resources/lessonPlans/en/Receiving_mail.adoc create mode 100644 webgoat-lessons/webwolf-introduction/src/main/resources/lessonPlans/en/Uploading_files.adoc create mode 100644 webgoat-lessons/webwolf-introduction/src/main/resources/templates/webwolfPasswordReset.html create mode 100644 webwolf/README.md create mode 100644 webwolf/pom.xml create mode 100644 webwolf/src/main/java/org/owasp/webwolf/FileServer.java create mode 100644 webwolf/src/main/java/org/owasp/webwolf/MvcConfiguration.java create mode 100644 webwolf/src/main/java/org/owasp/webwolf/WebSecurityConfig.java create mode 100644 webwolf/src/main/java/org/owasp/webwolf/WebWolf.java create mode 100644 webwolf/src/main/java/org/owasp/webwolf/mailbox/Email.java create mode 100644 webwolf/src/main/java/org/owasp/webwolf/mailbox/MailboxController.java create mode 100644 webwolf/src/main/java/org/owasp/webwolf/mailbox/MailboxListener.java create mode 100644 webwolf/src/main/java/org/owasp/webwolf/mailbox/MailboxRepository.java create mode 100644 webwolf/src/main/java/org/owasp/webwolf/requests/Requests.java create mode 100644 webwolf/src/main/java/org/owasp/webwolf/requests/WebWolfTraceRepository.java create mode 100644 webwolf/src/main/java/org/owasp/webwolf/user/LoginListener.java create mode 100644 webwolf/src/main/java/org/owasp/webwolf/user/UserRepository.java create mode 100644 webwolf/src/main/java/org/owasp/webwolf/user/UserService.java create mode 100644 webwolf/src/main/java/org/owasp/webwolf/user/WebGoatUser.java create mode 100644 webwolf/src/main/java/org/owasp/webwolf/user/WebGoatUserCookie.java create mode 100644 webwolf/src/main/java/org/owasp/webwolf/user/WebGoatUserToCookieRepository.java create mode 100644 webwolf/src/main/resources/application.properties create mode 100644 webwolf/src/main/resources/static/css/main.css create mode 100644 webwolf/src/main/resources/static/images/wolf.png create mode 100644 webwolf/src/main/resources/static/images/wolf.svg create mode 100644 webwolf/src/main/resources/static/js/fileUpload.js create mode 100644 webwolf/src/main/resources/static/js/mail.js create mode 100644 webwolf/src/main/resources/templates/files.html create mode 100644 webwolf/src/main/resources/templates/fragments/footer.html create mode 100644 webwolf/src/main/resources/templates/fragments/header.html create mode 100644 webwolf/src/main/resources/templates/home.html create mode 100644 webwolf/src/main/resources/templates/login.html create mode 100644 webwolf/src/main/resources/templates/mailbox.html create mode 100644 webwolf/src/main/resources/templates/requests.html diff --git a/pom.xml b/pom.xml index 79c12a753..1ff00fd25 100644 --- a/pom.xml +++ b/pom.xml @@ -172,9 +172,11 @@ + webgoat-commons webgoat-container webgoat-lessons webgoat-server + webwolf diff --git a/webgoat-commons/pom.xml b/webgoat-commons/pom.xml new file mode 100644 index 000000000..35dc173e9 --- /dev/null +++ b/webgoat-commons/pom.xml @@ -0,0 +1,37 @@ + + 4.0.0 + webgoat-commons + jar + + org.owasp.webgoat + webgoat-parent + 8.0-SNAPSHOT + + + + + + org.projectlombok + lombok + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 1.8 + 1.8 + ISO-8859-1 + + + + + + + diff --git a/webgoat-commons/src/main/java/org/owasp/webgoat/login/LoginEvent.java b/webgoat-commons/src/main/java/org/owasp/webgoat/login/LoginEvent.java new file mode 100644 index 000000000..42c5f384c --- /dev/null +++ b/webgoat-commons/src/main/java/org/owasp/webgoat/login/LoginEvent.java @@ -0,0 +1,15 @@ +package org.owasp.webgoat.login; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * @author nbaars + * @since 8/20/17. + */ +@Data +@AllArgsConstructor +public class LoginEvent { + private String user; + private String cookie; +} diff --git a/webgoat-commons/src/main/java/org/owasp/webgoat/login/LogoutEvent.java b/webgoat-commons/src/main/java/org/owasp/webgoat/login/LogoutEvent.java new file mode 100644 index 000000000..4e6995b08 --- /dev/null +++ b/webgoat-commons/src/main/java/org/owasp/webgoat/login/LogoutEvent.java @@ -0,0 +1,14 @@ +package org.owasp.webgoat.login; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * @author nbaars + * @since 8/20/17. + */ +@AllArgsConstructor +@Data +public class LogoutEvent { + private String user; +} \ No newline at end of file diff --git a/webgoat-commons/src/main/java/org/owasp/webgoat/mail/IncomingMailEvent.java b/webgoat-commons/src/main/java/org/owasp/webgoat/mail/IncomingMailEvent.java new file mode 100644 index 000000000..a33002839 --- /dev/null +++ b/webgoat-commons/src/main/java/org/owasp/webgoat/mail/IncomingMailEvent.java @@ -0,0 +1,21 @@ +package org.owasp.webgoat.mail; + +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * @author nbaars + * @since 8/20/17. + */ +@Builder +@Data +public class IncomingMailEvent { + + 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-container/pom.xml b/webgoat-container/pom.xml index 50950734a..ec6c79c81 100644 --- a/webgoat-container/pom.xml +++ b/webgoat-container/pom.xml @@ -34,6 +34,23 @@ + + local + + true + + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + + + + + + ctf + + @@ -132,6 +149,19 @@ + + org.owasp.webgoat + webgoat-commons + ${project.version} + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + org.projectlombok + lombok + org.projectlombok lombok @@ -144,6 +174,19 @@ org.springframework.boot spring-boot-starter-actuator + + org.springframework.boot + spring-boot-starter-cache + + + org.springframework.boot + spring-boot-starter-activemq + + + org.springframework + spring-jms + + org.asciidoctor asciidoctorj @@ -153,10 +196,6 @@ org.springframework.boot spring-boot-starter-data-mongodb - - de.flapdoodle.embed - de.flapdoodle.embed.mongo - org.apache.commons commons-lang3 diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/HammerHead.java b/webgoat-container/src/main/java/org/owasp/webgoat/HammerHead.java index e2a09ab3a..0eadd90a9 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/HammerHead.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/HammerHead.java @@ -1,11 +1,24 @@ package org.owasp.webgoat; +import lombok.AllArgsConstructor; +import org.owasp.webgoat.login.LoginEvent; import org.owasp.webgoat.session.Course; +import org.owasp.webgoat.users.WebGoatUser; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.security.core.Authentication; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Optional; + +import static java.util.Optional.empty; +import static java.util.Optional.of; + /** * ************************************************************************************************* *

@@ -41,19 +54,38 @@ import org.springframework.web.servlet.ModelAndView; * @since October 28, 2003 */ @Controller +@AllArgsConstructor public class HammerHead { private final Course course; - - public HammerHead(Course course) { - this.course = course; - } + private JmsTemplate jmsTemplate; /** * Entry point for WebGoat, redirects to the first lesson found within the course. */ @RequestMapping(path = "/attack", method = {RequestMethod.GET, RequestMethod.POST}) - public ModelAndView attack() { + public ModelAndView attack(Authentication authentication, HttpServletRequest request, HttpServletResponse response) { + sendUserLoggedInMessage(request, response, authentication); return new ModelAndView("redirect:" + "start.mvc" + course.getFirstLesson().getLink()); } + + private void sendUserLoggedInMessage(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { + WebGoatUser user = (WebGoatUser) authentication.getPrincipal(); + getWebGoatCookie(request).ifPresent(c -> { + jmsTemplate.convertAndSend("webgoat", new LoginEvent(user.getUsername(), c.getValue()), m -> { + m.setStringProperty("type", LoginEvent.class.getSimpleName()); + return m; + } + ); + }); + } + + private Optional getWebGoatCookie(HttpServletRequest request) { + for (Cookie c : request.getCookies()) { + if (c.getName().equals("JSESSIONID")) { + return of(c); + } + } + return empty(); + } } diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/JmsConfig.java b/webgoat-container/src/main/java/org/owasp/webgoat/JmsConfig.java new file mode 100644 index 000000000..9f9aa2fca --- /dev/null +++ b/webgoat-container/src/main/java/org/owasp/webgoat/JmsConfig.java @@ -0,0 +1,35 @@ +package org.owasp.webgoat; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.activemq.broker.BrokerService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jms.support.converter.MappingJackson2MessageConverter; +import org.springframework.jms.support.converter.MessageConverter; +import org.springframework.jms.support.converter.MessageType; + +/** + * @author nbaars + * @since 8/20/17. + */ +@Configuration +public class JmsConfig { + + @Bean(initMethod = "start", destroyMethod = "stop") + public BrokerService broker() throws Exception { + final BrokerService broker = new BrokerService(); + broker.addConnector("tcp://localhost:61616"); + broker.addConnector("vm://localhost"); + broker.setPersistent(false); + return broker; + } + + @Bean + public MessageConverter jacksonJmsMessageConverter(ObjectMapper objectMapper) { + MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); + converter.setTargetType(MessageType.TEXT); + converter.setObjectMapper(objectMapper); + converter.setTypeIdPropertyName("_type"); + return converter; + } +} diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/MvcConfiguration.java b/webgoat-container/src/main/java/org/owasp/webgoat/MvcConfiguration.java index bf67aff33..e52cff71a 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/MvcConfiguration.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/MvcConfiguration.java @@ -39,11 +39,9 @@ import org.owasp.webgoat.session.LabelDebugger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationContext; -import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ResourceLoader; -import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; @@ -154,13 +152,9 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter { return slr; } - @Bean - public HammerHead hammerHead(Course course) { - return new HammerHead(course); - } - @Bean public LabelDebugger labelDebugger() { return new LabelDebugger(); } + } \ No newline at end of file diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/WebGoat.java b/webgoat-container/src/main/java/org/owasp/webgoat/WebGoat.java index 58b269168..ffbf9bb6d 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/WebGoat.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/WebGoat.java @@ -30,7 +30,6 @@ */ package org.owasp.webgoat; -import com.fasterxml.jackson.annotation.JsonInclude; import lombok.extern.slf4j.Slf4j; import org.apache.catalina.Context; import org.owasp.webgoat.plugins.PluginEndpointPublisher; @@ -49,10 +48,8 @@ import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletCon import org.springframework.boot.web.support.SpringBootServletInitializer; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.ScopedProxyMode; -import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import java.io.File; import java.util.Arrays; @@ -70,15 +67,6 @@ public class WebGoat extends SpringBootServletInitializer { SpringApplication.run(WebGoat.class, args); } - @Bean - @Primary - public Jackson2ObjectMapperBuilder jacksonBuilder() { - Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); - builder.indentOutput(true); - builder.serializationInclusion(JsonInclude.Include.NON_NULL); - return builder; - } - @Bean(name = "pluginTargetDirectory") public File pluginTargetDirectory(@Value("${webgoat.user.directory}") final String webgoatHome) { return new File(webgoatHome); @@ -93,7 +81,7 @@ public class WebGoat extends SpringBootServletInitializer { @Bean @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) public UserSessionData userSessionData() { - return new UserSessionData("test","data"); + return new UserSessionData("test", "data"); } @Bean diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java b/webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java index 7bc8e7f79..ff19cf3a9 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java @@ -31,6 +31,7 @@ package org.owasp.webgoat; import lombok.AllArgsConstructor; +import org.owasp.webgoat.login.LogoutHandler; import org.owasp.webgoat.users.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -52,6 +53,7 @@ import org.springframework.security.core.userdetails.UserDetailsService; public class WebSecurityConfig extends WebSecurityConfigurerAdapter { private final UserService userDetailsService; + private final LogoutHandler logoutHandler; @Override protected void configure(HttpSecurity http) throws Exception { @@ -69,8 +71,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { .passwordParameter("password") .permitAll(); security.and() - .logout() - .permitAll(); + .logout().deleteCookies("JSESSIONID").invalidateHttpSession(true) + .permitAll().logoutSuccessHandler(logoutHandler); security.and().csrf().disable(); http.headers().cacheControl().disable(); diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/assignments/AssignmentEndpoint.java b/webgoat-container/src/main/java/org/owasp/webgoat/assignments/AssignmentEndpoint.java index 584ed7155..c4713a054 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/assignments/AssignmentEndpoint.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/assignments/AssignmentEndpoint.java @@ -108,4 +108,8 @@ public abstract class AssignmentEndpoint extends Endpoint { protected AttackResult.AttackResultBuilder failed() { return AttackResult.builder(messages).lessonCompleted(false).feedback("assignment.not.solved"); } + + protected AttackResult.AttackResultBuilder informationMessage() { + return AttackResult.builder(messages).lessonCompleted(false); + } } diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/login/LogoutHandler.java b/webgoat-container/src/main/java/org/owasp/webgoat/login/LogoutHandler.java new file mode 100644 index 000000000..ce8eebc1e --- /dev/null +++ b/webgoat-container/src/main/java/org/owasp/webgoat/login/LogoutHandler.java @@ -0,0 +1,47 @@ +package org.owasp.webgoat.login; + +import lombok.AllArgsConstructor; +import org.owasp.webgoat.users.WebGoatUser; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Optional; + +/** + * @author nbaars + * @since 8/20/17. + */ +@AllArgsConstructor +@Component +public class LogoutHandler extends SimpleUrlLogoutSuccessHandler { + + private JmsTemplate jmsTemplate; + + @Override + public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { + if (authentication != null) { + WebGoatUser user = (WebGoatUser) authentication.getPrincipal(); + jmsTemplate.convertAndSend("webgoat", new LogoutEvent(user.getUsername()), m -> { + m.setStringProperty("type", LogoutEvent.class.getSimpleName()); + return m; + }); + } + super.onLogoutSuccess(httpServletRequest, httpServletResponse, authentication); + } + + private Optional findSessionCookie(Cookie[] cookies) { + for (Cookie cookie : cookies) { + if ("JSESSIONID".equals(cookie.getName())) { + return Optional.of(cookie); + } + } + return Optional.empty(); + } +} diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginsLoader.java b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginsLoader.java index 20e193025..28437e786 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginsLoader.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginsLoader.java @@ -71,6 +71,7 @@ public class PluginsLoader { NewLesson lesson = null; try { lesson = (NewLesson) c.newInstance(); + log.trace("Lesson loaded: {}", lesson.getId()); } catch (Exception e) { log.error("Error while loading:" + c, e); } diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/users/RegistrationController.java b/webgoat-container/src/main/java/org/owasp/webgoat/users/RegistrationController.java index 5c7a4fff3..41eda0bda 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/users/RegistrationController.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/users/RegistrationController.java @@ -1,16 +1,16 @@ package org.owasp.webgoat.users; import lombok.AllArgsConstructor; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; 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.PostMapping; +import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; /** @@ -32,29 +32,16 @@ public class RegistrationController { } @PostMapping("/register.mvc") - public String registration(@ModelAttribute("userForm") @Valid UserForm userForm, BindingResult bindingResult) { + @SneakyThrows + public String registration(@ModelAttribute("userForm") @Valid UserForm userForm, BindingResult bindingResult, HttpServletRequest request) { userValidator.validate(userForm, bindingResult); if (bindingResult.hasErrors()) { return "registration"; } userService.addUser(userForm.getUsername(), userForm.getPassword()); - autologin(userForm.getUsername(), userForm.getPassword()); + request.login(userForm.getUsername(), userForm.getPassword()); return "redirect:/attack"; } - - private void autologin(String username, String password) { - WebGoatUser user = userService.loadUserByUsername(username); - UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities()); - - authenticationManager.authenticate(usernamePasswordAuthenticationToken); - - if (usernamePasswordAuthenticationToken.isAuthenticated()) { - SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); - log.debug("Login for {} successfully!", username); - } - } - - } diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/users/Scoreboard.java b/webgoat-container/src/main/java/org/owasp/webgoat/users/Scoreboard.java index 1b08e35bc..aa8416d58 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/users/Scoreboard.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/users/Scoreboard.java @@ -45,10 +45,11 @@ public class Scoreboard { } private List challengesSolved(UserTracker userTracker) { - List challenges = Lists.newArrayList("Challenge1", "Challenge2", "Challenge3", "Challenge4", "Challenge5"); + List challenges = Lists.newArrayList("Challenge1", "Challenge2", "Challenge3", "Challenge4", "Challenge5", "Challenge6", "Challenge7", "Challenge8", "Challenge9"); return challenges.stream() .map(c -> userTracker.getLessonTracker(c)) .filter(l -> l.isPresent()).map(l -> l.get()) + .filter(l -> l.isLessonSolved()) .map(l -> l.getLessonName()) .map(l -> toLessonTitle(l)) .collect(Collectors.toList()); diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/users/UserSession.java b/webgoat-container/src/main/java/org/owasp/webgoat/users/UserSession.java new file mode 100644 index 000000000..5e00333b4 --- /dev/null +++ b/webgoat-container/src/main/java/org/owasp/webgoat/users/UserSession.java @@ -0,0 +1,21 @@ +package org.owasp.webgoat.users; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.Id; + +/** + * @author nbaars + * @since 8/15/17. + */ +@Getter +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class UserSession { + + private WebGoatUser webGoatUser; + @Id + private String sessionId; +} diff --git a/webgoat-container/src/main/resources/application.properties b/webgoat-container/src/main/resources/application.properties index aa20c6c47..abcbe6e3c 100644 --- a/webgoat-container/src/main/resources/application.properties +++ b/webgoat-container/src/main/resources/application.properties @@ -29,7 +29,12 @@ webgoat.database.driver=org.hsqldb.jdbcDriver webgoat.database.connection.string=jdbc:hsqldb:mem:{USER} webgoat.default.language=en +spring.jackson.serialization.indent_output=true +spring.jackson.serialization.write-dates-as-timestamps=false +spring.activemq.brokerUrl=tcp://localhost:61616 + +spring.data.mongodb.port=27017 spring.data.mongodb.database=webgoat spring.mongodb.embedded.storage.databaseDir=${webgoat.user.directory}/mongodb/ diff --git a/webgoat-container/src/main/resources/i18n/messages.properties b/webgoat-container/src/main/resources/i18n/messages.properties index 442a4d35b..d58990c3e 100644 --- a/webgoat-container/src/main/resources/i18n/messages.properties +++ b/webgoat-container/src/main/resources/i18n/messages.properties @@ -24,7 +24,7 @@ # lesson.completed=Congratulations. You have successfully completed this lesson. -assignment.solved=Congratulations. You have successfully complete the assignment. +assignment.solved=Congratulations. You have successfully completed the assignment. assignment.not.solved=Sorry the solution is not correct, please try again. RestartLesson=Restart this Lesson SolutionVideos=Solution Videos diff --git a/webgoat-container/src/main/resources/static/css/img/owasp_logo.jpg b/webgoat-container/src/main/resources/static/css/img/owasp_logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1f98298c8b714eaa6a2fd9f3d19b68156a9fb78f GIT binary patch literal 57346 zcmd431z1&E)GoYf0cioH5u`h%yBh?gM5Mbr6cqtcxUxu=&M1 z0t6C{0$@QPY#i)tkhJqLI~yBZ+8N5}DHsPTK&Z5EadF^hWwmo=F*31#V9H`_Z_Dao z*Zvs;iY`X z*vs0O&xBS)7){WF-^13y*3`v_!o$|a&Y9msh!zIU4~#)GD=pyUWMamzE-8KP0?dSH z&$YO_yR*1+ve-MBv$FH?@v*XTuySxP10KxIo^~!q9?W*mQ~&}R1q?&d)Y;g{(!s^j z-tL0V)7ur8&W@`&-pr8;0geocVt2kK#=^5Eb+8evtn%cR@NeXjFO7cl^a7wV> z=Hio<;^gC#U}xvzl;YwOljP!%=3^6N{nyanxN>&RE=G37rT`w`&0=Y3!Y{?kCoX+k zl9NM%N1B}-0G5*CkdTt*;FjQ%7MEfdzrei|`Wx^6md@XKQ-IszWa@11>SSyxL<_1m z`K_Ak-&E65uwE+XCGG!5(v~!JvUD>wk#@4Th3RuJa&k7k*Z1 zCCCcqbg51LyLJA%aej3Tzl4*ik&C_49eaBlVKMONP^eniyVyHh*gH^2XmGQzQz#i3 zTiSsZ*q;6o@XxBwlmdqWI3BFO4iPZeWAAAP5`+0s;~u5-Kt>Dh4_#ItCUd@WR4^Ii9~= zJ)8X*`)hXk8G>^K;)*(W_tv9nQszO06>=F&PWzzAoKP@NV`>2mbH&BiBT9c)H=v4E4IV7RO^N%w1fRB z-!J?h^FOY7+7|1ZbSN<;0{JP+TNf)z5a=!S62|w3DGu!O--hMaz&V#0n-6_g&*E)8 zh+Q9h$OZCubM?}ykX+vYa&AdX)BzIIpz*ft1=jyoz^i>dE%^gryv^WscGG_=!21>@ zsAbTDHeY_z1J*AGmVvE@f)n^-Gq!mLEOw#X3H*G^!P8lXbGKYeXhu{6okRK#4GD8- z&%G2sH{`Qc_7{=FLtk>DEml(V|nyApwN+$%s zPy~{NvxoPp<%D&HX7^sLF_;nDvh*Fu51(!Edbi@k99wztg z*L`!qMc`xXZ

YBLiDhXdmVTVa`q`tGdxfXBTh7uBQe&4!y!^sZAgabB1CaqbZP) z+g`N_)Dg%i7RZPk$OzQp`)*w@K4~qvh0!z^x^;#^t`-K!g}DTPF1aRr?ABYIlKC+_ z!~Vll+rmSQi(JBbLvtQ}Yqzq_l8yjSwmRiurE@EX5xvBU1Cl2Hoirc2En$14R%?>2 zIB9{1#>&TgZ|Y~p{M?_dZRkF@sUA0B^${R~X#wQ=1+NRI-4<{@rhP6PICFRpPfu8D zL-(hT!orDl`?fP1HlqKwh``X!$Lh(sow>c*+|5Zu;sxuQo{4IY9wQ?x`neacczV}& zt#qwF)Sml9F{Yq{*WU925st!Fp>xN#jMc+|XKt_Ta@ZqktQ^nrF6hh}Ci3Vh1b^Gl zPgKK~`GIF#2Ji`qTz#`T)wXS%?4jMm5U*MhYPibSBHDz^>sKi53un%G3y;KoyiM$U zq}RXy^9rx}K*Pq?uQ2Pj30eeLm@u|jO)Qi)4hVx6JqSx(KJ-)m`Q5f_-B5dO8i{vc zM3kx6$QowAiE(G(fs^G6 z(i0Jd6%yfG$)m!mwsqec{pT_7+N8Fj9Bp^F&GYi36cMVL7JRb<2P}Mw0SBQP{RpJs zq6d4)mPJ+yT3)SAmO<_w$E+nk4?3`7-97Ko7Pluz6411SOnqx(R_#|Zqos)tbPnq| z)W&+(vTtu6Hzgog5q`_oH1~CJFprX)RaP-xoZ|h}^#c*h$?ZhinUrzu;FV2ke`_8^ zi{OSN0OM5=REZ69jyz+hfZQN`V|C6C%F!QNe*N`J zCBk}RGajK`9H!WJlW4dkr<7vff+SIj5*1DJ$GL$6CP!7pZ9k7|^qX;^Mg8464KNIy z;Fez)TqNc;S2m{o8F|_b z@m>O%SY{RCg(*su0VIWigBCtjRRGB={Z@((Kqes%m`Wuyx#N=)ACT6F01(2(l1H^= zZ9m8UNk*YinR($#SLDG&2U+gWDr}s(emF zgp;w%n+~-D*1TSn?Ax2;bagM4Hnr=PIk~!eRUCaBtnKLDthH{6pBQl735*_z3hVyd z)Bmc2ps7$0RZr+0DsFQEie75rfYB(KhMlsA3OZ5o(2|Xw^QV~N;j|AN!Qrm&m$&2H z!Z(tf91m{m>Vm5R&X2XatR6SC(ufVz7Y;b@qJY4?4b32MW8v*vHal;b6knT=>hmAl zi#T{HRd^heU@+?}_d|s$zRM4-sLIAlHuH}j`xRq;->7nOtn|3sAKOLPSjGivLdTa z1a!az{Id}U8BisPi;^?5CBWwr$f@Y_&@h1-W(BqK`C<+jP=WycvvEQ~0IYkkd^_xE^ysC2S-lsg|U*av0C{ zE&jlOZjrW*rQ#*1*kPYI&Nq02AV4F;4 zr=QGF;A$#@Vf}>O`jG+W?znx%XsMsZyrY*P=hykA)Ql!W@`?Icyw3T#UHvgKJ$dgn zk*a$Ydzhhq+A2cqJi2My)up9T(kcY3#fsvU!!0><1W@lgjQOwnBXYf8cV=XV5DsNg z8rYijMTSCrh^@A$vm+=O&6$X0n}SdI)62UKlBxop;>%@YjKB} z+C@lne|2dRO`fB5R)-@PQj#X$HVp3K9kMcLvFW>RLEQzh5>lY&|(%n6U73;;S)qSPx?bLIXgR2jTR6rF%f+lXQW)6yxVo2VJ73)U&Dq7lwJXZYK6u{TYje1| zVn|@KH>^Ng0)NSrxqXC1D34Ykw9+OtF%gD9l~3FIw_bFX4b^f3H>oyjF)*Gb--p zZ}&3(vi>a5m}1=`c*&2SVD~>t)(cW?f+8y%B!zZ(;HC+(fGC4n@sG7SxDzhiB^5E) zea%x0xc}6Mb45YXP-jkCN!J8bk2{xw`V8gqXWUJ~fzibYK#Nq0y4odhB1XaCrCdcZ zMzh3r|C{&j;{pfhCJl1@n4a^S?UbMof))9(!MHSP99y?-w=h}SI?bX#rz*rIGk<7g zf$AO>_?^_I5xNs|A{+ zx4krD2)Avi9$tIAx0d|WUCSWwT5(2!yA3_3XpR6r^?+Nb0U(t$Ix_3oN(Ik!*p$dd z+$1`u7~-~;1dfc_v;GA5NU*czsKH|(O*|m_h#EWwS19It7GLn@!EUoa-%IjySH|1R z!A=kX2E}9G2xSqgo1n=7H&J@(aIx;p{_FNS=Ld`eIGpd;#*5Amrx^D9z%MLx;9d$G zA`Ofj4kT*uI7Z6;LG?EwH%ZY(+3rQcu$YL%z>}^Bp7coI1gZny@B+#T4y-eTep+|D z>bo0m`AEL49XG2CY6*Uw)$>}*s^pkJ9vxbd%8SCdiHf`P=v`bBv(2qZTxj$2 z1J_{N3zRs=n^g|HgIU*9TC`<=VUocSSvOJfOu-#4rO_PdMz=TU8&vk598BVV`+)*D zadGjtl51%wrWi34F^Q=j#Z94=ISs9hf7DR07Lj$#Zq#OnN;(hJ17r3KK^{&CYb=wniSv zeD=L9sOQTCsq=}v4|@toM(fKBsrSi^hs{ueCzPHdV{k~qW(W;yS!vhpW1L|#$hyG7 zTV(X8!5`u_?je|=-fsA*Jk`14VgH!A#3OhCM z*zyYSOcM?XUNLWE;iq}LRPA^b-`l5i1k%-7&N@`zp0;+>q#}Dh)jM7)P7G3ZG_gi2 zPHZ7tPS7dq{ochE^03;?Sq+tzK>B?yUtYwrxT)EM$`irQ%qQDJ9g?)Si?{=HI!vBK zpvEM53L|b_DLWiA=f+N+Y94&oX-!QM^fy)z=F_eT$O?a%wcngO9_1z;BhP^k>MV}^ zZb7FNC0}Dy9z&<~9fUvNImDeqsP2IZlkgxmHQ5R$K@<&ZpnX$cgPF?24(9JP~KF5*sKGvrEs^Ru+O^_J>k zrp;Fm_=`;ufSSB%erII@LDZU-P-QYI$&o3VM)oDuDJp(CyOn^iqy&LH9}TiXdchMz z7pwoMDFpnfmj!Gxgy&K=ml+GQPrOe7`Ki9JPxmy#H2j>gIH` zvMa6f*RKU75}Dllv{M<9F^Rzo<}>)6fnfywiXJ4yH_)}R_P>6Z8qUf7^!;12ZqWok znV_B~`*#N$6K36{If)K_^71vrn)BDQw@X&c9zOJ4aYpX#VU?v#7-?ngK%-4AFS>yX41f+;oND@fV~s*LhCfH{k@!>B_aLq z?DPNZUwm$-J7=ylv>)pM6>T8pIA2oqhy8hU0vebcmcxzr+9SIz@0T963Hw{=Pi4}m zU*yJyf1Y$#nrlv3C(Dwv6?TzXw;M$= z&G*fn~CcQQ@ z3eRaN>$Ug%FiF!{s_U7;E7{&gsS#yQGciJjYqO-8ozUx|sK|!T$8*4Z{M)Ia9(2kY z-!%TL^lAzQ_2BPNXI=o*b;1k6Gp}y@l`vEu*LS_`3zal9*U^%be0fg3{fsg%&sE{f znvah+VQ{kD8X33okSiWN*T4a2*swkR;P1)f{k&w8-!3@#nRqtMxKu4vka}p90l=zN z`LSfUMJu04bnm9Fli&U3%p8Zly_LRfJ%{d8tske53?AG;x!NJcxP^s2>s*CbgX&r_ zIg7?#nXlizaN(#5+w!8{ERfZsa&eIBEEaAz%i(*w2sZ8JX zgXOrzl8O0!lUmKJQ;1C4t%H2t&?ea1fv^s1zvV}_e|W3y-e~d5Rr>MaAK%d0HB#4U z`AeS&$toz|D4RFMIi<=h40!Z@S6^H=e>JSau}@SmA5#W zu&|(Q7;y?|E`&n8P+A<{5z%H7Kd0K{OrfXiRaTHWTEU`Ud>{~IGtkT8UM-b{O5IvL ztV$7->``e0T&dx~J=9$7@kf;W(b&WE+tTWfXpVDx*Cm9JEji?{Vv=FkRP^yp$EgM2 z+Bt1F)`hBF#ej%|7v`=MlT3T_WYZXaqtGq-%1v6b)d*8_)MkQRX8;#Kc{r^sGNMe)~xR7>LFmw?3tRlL^N#X#B|u?IPx}DsH};APPlk z7IGOFVR7r110iYXKScm6i~vhBy`_KtH>S7ZiKze1K}hGZiookJ*i4<(68d z)NJirW|iu$w^m;*+Vobkz9Vsp=)EHxX`WkI(Yi4e!P4IFJu*5aT16><(uL-0u#T2+ z^2&{zK>gRvt*x!dEs(a*kP11p1j??!TS`}F;F-$_IjE64AC(otxI+^Zt_Nx16_-+E6Ke*4?u zchMKRHkYB#>W4VKm7Lnpaq7_J*usNZ`2V*A2faif3k;;KLcSk2=zce{LZ8e zMhWkML(N|RMfd3CpGnBI6MR6krI*?HvQ_bH##~J^o9D-Nf?SYWriv%lfJ9Wt%HY-Z z>5^JCUfph5TEWqJO|-laXY`ylE(YaW3nOG!$cr~HXxVfc=u0xmN3N4ZV>CBg@;&aP zRLZ0SE}(>}ysF@Q;GgH4=gXiw{mHja(`k0;;XTes$>K@!YR4bGv*dj$x}>q`QKf$c zNT+*7_jmTI=s1_+XY)RNxa#I;eUrKgk1$^rW%4;qCIm!==LG$W$I3-R>D?yYEEtJLq3&N;~D=vw2 z%s@uDb>ZZB$q730fM)~;nsBRt653!3rLz5ikoE0sX#FAA z_5-nP(1;@L7{;^SEw{;5V$5t?4!{RyJr6wh1_Cp`^+RE^EIGSpZL$Xf4l@{m8qfrs zbL)Aajpzc%17HjT^aEgU+qzf#=?UanM-n?>Q*{AIyQ+ z;H4gru?cE)?w7nc$#{k74kcF*eNfQ_ys#-#mwXZZKRc6WqO zWyaOd@a99t+>L#_eFMY84cd*$TGj}WnErjA;G=@Vw&}lk#5Je3E*{lLo@i^&Ty_=# zzRe5cK;RJI5fKnkP!JG-@A2TTCgBmVaS(AS)d?urk&thSv2k#Usu?-rUBmZJ@BSI_ zp^l16e3E)y;(-(F`#tcBB@wtMm~%_E1XNeor%HYJZ0{~})7Kl&;cY}@8n^PlW|n1J z^@DalVC%Aj76vlsl0M74?eoWK_!hWIG+aXh&2uA)UM)f0w}pk$Ba?O=FiDgCXtdgM z8vgK&IQqNbyCZ1NhZ#~ef;ZRQ7JzTj+n-v4u^)c8H`8S99AQ?#q3Zn)9tvF+;y zqgUL&G)-!oQe7;LQ7-(kcnV>tWiH9{l({2CQD1SQ%Ori{57tAyUy(GhWXKq`>tp*v zKaFN%xTL9+o`vQBf;TQDgFFMKTJ%fO7;S6_&NGjJGr@h?+qvg!>Q@C)XFx%MTCf`V zS12R27Pi?klBxCI268zMT-QCX(MhE$t?savV8%P<0#?lKsVj?#pI7~PQFuOQ)>o(K zinkV}Nxkby*(e|&kee!XjCTvek4TdqSD@EXEq&Lw7US@~NX%QCFwkOMhX`@WlPQ-0 zQ8!PtNGUc$S6j8%upNwsH~q%=t! zE-xnnVbFjD%@}mueENZn0$duod|1F^8h;qCKS8d%duzF@4h^(`6Ub27pV*Tr(^Pyw z`lSk()tUDhyk-nMvsUyWpb`&M`Kfyf4o@`2{#Fd&o-6PAG52Xeq_x%5&lNB&)PW5h ztvgprbyGHG8oh76_l-J*&_B#xO^ReUI|*44R^V@Nv(d2P66wsvL73z-m=_QkO3in? z*Szu6%L}t>$9zfOut+eS?A4Rv(VMCjXW_5W z4^u9XIzgn1=;Oaf(>gs0QxO|F>Dnw{93oQ%$K&ZR4o0KVL1(`-4@+?+hUM@<~ClG`GD1jD!k`_QcH4< z_VZ-EL;N$D*F?Sl226g203_jG-wI@5-0hmhiHr5riO5h{TKo*57|M)25Z^8<3?_k{ z3y7F>7%0~nI+F%N2+|C%X!%)geK*_17tN(GX2`B6C?T5Wk!A&4zgvTjS;x9TT%b+i ztugp8GK0m^G`dW@(%^h!@Q^>lt=mC?!P$;JLFv6onLKChVN+(x#G71-Y z514pv#b^5_zaTo|(vaD)XWk=b5;Phf@c1E`jLkJ~-9P_9Li_xk zZ-G?`n~2tdF9dYEt`iN=kCBUKH3$tG##8BokrtoUwdj*O1C)Ziw`$p@>%WlZo4>%Y zzSe0jo|&@Rb5uuEcby-GuL$7lON?diKj!}J6_&2?fDGi!!wIz3`GL?-D4XTXkIzH7 z28K@lz#J(4f?WFCoikm1>aw41BWJ?boDW!TakEzjv97z7CbDtoY48h!I!bEUq~A+} zIn?qeC9@9H{YX*z|Zb{kb|KHf=}I{C55NZvo8IW+#oFnceH z_Bi^X;TR9CoIl*_*;B}LVf{KWTK%WJ_eCfnOvtw)0y$JP+g7n_`=b3GcKys;9(rJB z^md=+%TD%uO23<)TuLtCO6nez(hePNQc0^`!9{6d4V}o z-7uAO_FZtj0wbLFO)tW0E`TA=^D*}`)jsY8xhxcU=(uGA85qC~V*mjMK>`fm(xLz| z{#$$l#(}z}fA?MOqV=11i(X~y;peNWF-+0K@u~2R2$sLia#3y{&t2EvFU{UiUeS?# z|Nelr#C6SeFFADsgF*Rg!T@h+4f?u_?!KODaAON!RYc?M#+`ezbnAAZylgHES0yH0 zzt!S9E`CXEQ5sgSuJFQ&tbbsDP|SUeVK8<}+0i|*RWmQ-nPG|y<*ap^7wzq;4pXfn zmK%PqB!LNq%=5`pYuquq&E=;1eNJR%AD`+Q%ogS95MHh250y~U`dIebIppJjdcKK1 z$I&7mhLr9`-yET5-n#**de+X2@IK9dg3!N=P|DXhZp}~{;n24EcA6XCx=kbbPl`Vr z1Uo#hlmilVtPwi{h7#YGe|ey{xyKZMz4rL3*H1~#+XY`&5JUoM3U{+e(>n*ht85V( znhlnarTF{~t*Y2jesaTg(`HF^?^;CS-*6jF5CjQdU0 z&r^tqNL(Wa*0vL=*U`s<(CY*fVuM-L%$p+kyKbv{emURnJ=yP{D6+wD{JL;l+q9Va z%$mr~wRf9P`SYXYvOzsRLy;Cahz0*5^TFmzyy{ODDXR#QYYs$IXK%FLkGjeKI-^v5 zl4p0#ppcV)Y1=UL;nwlP1-TIw;at&U;40T@x9L@v#2fgILw3wX$ktkKF8i1=DDo7t zC0HZZdwXg7*y|MHN<3|^GS_qRP>OoP(2#X*W1+a>1m`%QWH4KDol4ny`vm{m>IFrw~${2ElE*snqoo^5qo9l!vKwz%M$=nBVbX zv0WM{Gq+iVO0?r-b_0Va&7P0BDsNTTs{Q*w)$><8hLrfZw-v(~0Em=j(rdCJ-Dx90mD6|(l51(Yaw20)&7AZQpMbl-h(G6I3+U!)T2+1 zw~jU5SerX;3~nnn-o@!v*Qjvt!TC^i(Ctea-9&Zlyud&EQ{PVWAwtE@U)^WdQE0x zbPVM~#jSd^l4z~8?uh>pp>r>tC`v0@iAVzgE2EgE$*1eiYH4FAs)-?a+MjvvC697n z-n-WAD}DWMlYo_hTfi{`5CFeKt|5VUK<0d?x$+fnyUAXC=aLyk4jzZS1#RuZy%rMs zWD!=5fpalbIqMu>z^WoYLW^xNz;}SOt4;ewXTTp&5za7zIE8Wj^GV2RsLG4td=vp$ zeA}oXE@P4l3p~I}0lVyVzhIrOnV;TkbuZhO#5&JtuQ!SO3RSo2fd?2R2*((;vI=J>)-3FX;th;{_+YO8(Tt&{P)G4rbkc<92B&fQ9AhW9;{#d}9Xe@;i`lImiqU2m#C>A~+{oZL&7Ma7-V2yBj_J>E-L8=SQeX&)x4!Puet+t;qb+P!2GG z+F=sa*64PB&!fGoNb{2~#0COlHN4?@Ld+O{(%8|D`4a~eU-K?LwMM)=t ze!09CLSvx=ofl0j0kj}}wLh^`G5#JN@3qxWFFy}Gzr4?2FJ5Z)%X>k$>n5PbchRJn zKnrH=AleeNU+f&#-OKx|jq$rh1Kq%Vzl0o^QCfV_5USvU{e9_fn?^sxjz)p^R5$-a z(w{)w_V;95xAK>oy$-atr`-+Z$3KQHEy#ezj6%w#1--$DF<(Zn4S~W;Qcu#sp3q;* zK+I}Qv?~xJ1w5A#gFTl4{tg-n63XT0GL#w-h`{eGfCn=iYItm-5=M^xoMP!8y76y{ ztJh8byhg>fPW`|svIq8P1|EDg6RSFr_*~VYfH(I9wS>N`+R(WhLCzFIO&$~f%Wm$v zcz*Tb;j18Z9f>>YWtmGa*R<2M#Un(dnQDDY72|GXwl|5Zz-^mp|B zpUcO$AJ*{%@PMQg_Hwr{_TOfrpaFiT5X51a6bfs^H{Tz757)U9Q-oe*Ogk(lGhDCEp2{nFxQi+wUnEbr!U1Ye=m!umbW#JX#c$ZSfd;5nlR&85C{t}i>juT#cuHCDCPC= z#ov1`??ovdaI#%P0GehV4K3NOgphtKJ;rm>$rk85(q5i8u0=fdum5b9wn7heHh&;2 z)j9cga1vtttseQX@q>pabcjFl%=F16H_p5o_mz|6Xr5BdC9J_}rh1#w~etV^;w9nG*h$m&ddlDV8yE6p0aeS?=XGJ(5+eHumkcgGnD$%gWmO0EL zwyMJ|c>{%mhS;9++xjU44}`nw_epp5c5IY2{s_xW9D6PSdgyws;W9KoQ7NJ(k~f+E z$@6C_vR|s&4P=*$v~F+Z{=iggAa3`hc74}G7UN^odOMLXj5?GG?L$+h;dOUS5~b^# z*BGgSKIb_uXn!He2+oM#IE&QE07D1B)qJhn{p*2rQx>y=k^J8@LxmXj>MP$)S$wJW zmB){0_{Gx=^1RO_@nTdvbEngi(ftjau0v|W08=q`$C1mpT{SNhifY)hq%zNy@#SutYY&Px73mP z&13qaQ%Gmj%mEeS&5^cb8|Gv97buiB;BnmlAsX)4c;MQky1 z>F&|J%6p|@jZ0@kdwk<{CoD}?-KMGSp6xt8Rs-0u*CUraB-|^&u#mPuG5* zSj54g;R%>fbE)W5vqqh-G3*%VzAzFGxIkpsUQtS}F*3 zisnwGJjj0qhmL?Uni)`3=K6WkulfG`9M(H~lg}7q?mh$GOM?uHUZ3DjZm8|JFqfCE z&DNT5?2NnCSep(}4K*ele;v9`!|4m$)ffz3M#>IhY2{~_nXHU?7#8XB3)L^CEjMSl z?P{#+X|;}}R~3j-see_4Fn=#}A+pzK=1T@AGu~;v)xRdyu9e_Qh?uBd{!BIKrXHZA zf8po#O00eM@gq2U#xdlS#orUVq`nQz2VYf*b3N@1kdylQ(lxYs<{<<>wJR}rbEZi; zE$AQw8`WPe$H9s1SAg}L2#^2=1PxmF7jwF{`X(9#?;d_U>N7~I|3PpR+8nArH8#Oq|k4A*Q55Y zxp}M{cdRdksXt|cAJ{nJ_Y;$Eo|rm?a2?io(Cv8S2TGh6&1|VW=E0Z}!Siug>X$Zl z7%R=U;rEf5&h#(BepqikvT3-G;rcOu9fiE{dIn_F=fptdHL;+{L%pP>!Pln{#X4)u zAe#^So}S0!eioA5)|kneXgUy}IT(O@S~&7x zY8Bvjm*TOa#N%0+fQ9)vAz+!MQ*TB9+vhBH8lM|9cmtgRSU!mF0)5elM(`SYzAR=R z?OICG@_QNc@T2#il8z20z9$v)m9IV-#7fw=wtsEIYIj}t`}RiJ{IgbxyMmST;)FxH zERgq9le@;=daH^rJN=)eA5YYYm{$2$uQyG@mCe4mRYr}jPrMIj-z|aACRU~@9J?Pf z{}gf3=;-dz+QC~Q2^*<*sY$Qkh=ePSguwSW3_Dd2cMds3;offoMTbMYEqQ1#_FaN-Cs zpgfUivAS@)Gl=4nJ`I0CA8i2eGh7Z_41K_=%%4hM8PnuE!>bsvL1YVH@b8>e|P8U>xX|1!9d}V8t|X0(#0X(SjHf zwHkl1dKT{3_7w=gG62`YU^sux;9Fn%1WbeLZ-MQJE<+zqIkWzk5E zM9n4^FeW|tm1FrTxEUl};AZ@m3fm0KW7rm5veMKJ0hK0%M#h(r)QEar^qJfF zab$7N)X(+vzo>#N0>9&q=1Cmm&|X%MK~E{n*fdUWUm8djn~8aUbolQn$R;#pO4K-io4sb7OpFTJ3s64t4#WaQ|>IV{TEzY%ex< zlDK@{UE*Tv^qxX`&L5jY)rDmE#vNb!&FU`J2<`N(;PmNaomGOkJ z)J$6&F^uQ8)1XA=z0OG$D&R?`-k@4^cq;xWN&PuCOEM z1Oc@`>is1w{1+M?xfPJ6n>uTCHkA&woMs68LSupdjCOIkM)PRFjo9rz(>Jt@52wy{ z5>^YCvPwtG$5=Fv!U@p==)b(vy1xzoU4^K`#T|>h@Vi@N#*Y0VOC) z?2XcPIkxGq$kG)zO62mbd|q3uQrH|xj$VgQAbn1kcVNmiYwJUQZO7b|@67kh_g**6 z!9aE^P3RPISA$aBBY22D!?kRp9G#+V`1zy|=K}MVf(LSeG!YR6>dd&-x~X)D0zt$g zIK0RZS@Zz$=pUMlJcbkoc#Rc=M!7%L6wUWfa1a*wbOk`E^e?5tYS!_QMlEkltYcPi?eou^>Gy)m z*&w24{0uzz(hTq%?OfaUxxotbaB#Qo1as%rsByVt-#Sx@3a6TRyI=lgTr;8MI^a1w z$WC1!CEGm6I80MY2r5O)J{N$GruXvB+qw;;ZeD^p{kDsgUJO$Yyxx}VP8N+=$8)$3 zc|-_6miMEzZ?k6Hx~vxc(-PYr&lNFJW0j(4)WK{Vqnnb>#lZ6aq7uJBE}s}OAX?+n+a= zLmA+0)?LIF;}GQ186BOf+8vnCqi#KZ$5{U{Af%_T&Qw6xCcm3rR|TH6fKIYvbhtT= zoxhJP%={rF<7b59{WnRXqf+88z7LCEy~pY=80e9aR}~?CtD`i6vO&3YL8iF&k=mYY z`FnMxH%UQn)sl&2#X=f?(tcDMFlbK4orS^mXOeZEz!}mL5}?VIL^ruk})*#iE-xURGl2VT>0~W8+9d5uYWXz_jLD(&tREWO>nL_ zqqPKSwcF4`kf?{{D#X*J9c(FSSP4J9GMIW*v?_%f$1@-qh{F%^9>5tgu`peWvZR?} zxMoh%gZp6J2X$tguC3y2u(Pd+LVSu<514FW?3p^JfWIW07!0CS1P|oX?YMtM+cyGh zBF9U2hprRj4Rzzx9$wqWH>RU~iZTL8I=Cc~OIp$10`o{d?_o80H-iRCBfc6;Bl<;E zV(2@DJqaC27U zIIr-V%b8x{lsR+5Az6jxYA(8OcYwf@(0D_ouT-5N`j+6$4D=^nLIgJ{uMyE9BO_Wf z2rfU_zHf0-oKznEVK#Lk9f^8NWCY1F@=Yt9ZX~9oX*h*8y3D=>e^K$2j?$0ldXeP~ zUjzDEOK&zjR`)!!f42BV*KrLRneWoxDP`WZpi+=d0sT zOXFxsI|wg*GWnurNQfO%k!i>QD)glYwH_Z38(_dbHczkwO0(eeMlHD-l2 z=R3=@kXmCIw01vk1a?^&*yTj59Q3=wWaPFHy0g*x`~zfFF&Ri8?AST%n^cT?$|6Sn zo{&J@`a!3X`yY-5{zzwXXXsb1x@>pz=E>TjH9Gy8W|Rbk@55tBO= znIxB3FOoT9Wzg>lh3Tb1C-3l$Y3ngK(JKmkTI-|IO&>Vpe^_ME@}~M;lvbV2Q~oWJ z%<-ZlmGV>;u~#+6lI5xh`4RYjcjrIBZ;0ZZLIQ485p_L}j!wNLMZ2u`VQ{MC$d{WK zDr}BQ9(xLD=rh?Y1%BUZKEb#{b`SCIKYMK+x>_CBhOOos z%9=w(Doc+kUwu1S9Naou0c;OdI$@J%-av%Dm!DhHu2%WQQir+~)wcfRB7usip8T55 z9l{o$hpU5cGZGZ^hg}!nMKt_$6DdB03_)MEiz{z-`YA4uuc&Gja)&JxS_w2uk-iG3 z)mcJEJ?|Q&0+QdxL~{gP7-D{BgaS0i`J#`kf|5 zscM5;Q-aYGQ|2XcOMV8FVzd;#|!@asIIC@s$&1{gpz4;Y&Cz*OOUH!@X< z80Id{-?3f+Vby7FfY%y8*_jsT9h~f$IQ>+VEtKaCW`RYw2r>`Csa8pj@E1O<163r~ZJeR!W?T?ZVV-1Lc z=#CQug7DQ+hP1y%-mjBdhtk|suE+whhQFf zVx5rkF}oUx#bl-xDVm1&6PqI=6;G5~pedh3rrM#x_P~4FD?#!$WCCoeM)t)PcLK2R znoLe1OqFOZTttj@ravkU>8lb>m1VH+#VWxYnwb$M~ za}FHoCLEONX}2jW$fa7Er1CSFr7U>@qWl4l0QA!ah~~|UsF(!DPr58`aBqQY-nr=w z!{d$bA+3RsR>`NeFy=`jm9|$?p53gi>J+@_%$tx5<09ibH&R!8uyaB zu==W`Gm76J%BXgZ#0>dDm++nb-kGoa_guL@Jq~XZ%*5FXraiak;bwcyc8dhz4I5YF z*&3|W1AfMb+^x+NiL&pImWKEhcVb82?$)hTFvzZX=Yus*8S5VSrR`T#$qAf73${ns zKr#oZg)@C>i+!BAGSkbR%q{2I?X=uQ%QWlEsc!cR?FtYIb~p^JDsZ#D9mTQm%LA|nn2H{ z0dH{7!8S5%(`FdKgtmK!z_H-ZUD6=Cr-i=YrtWlMtN)HGEMFv~MWe&X+MgmQAxkyP zj+H4;%-nMH^O!R&IZo1RUxwaU4+>FGqxs`aI>W9NE}v&JVj(kcq((M(XwfoeI8kaL zAF_PuQtUn(ZN7totXMKaQmRa$TI%Icq!L-j)S@ayUOMAUA05f@!%|}D#UNw+@p(~8 zO+XO?Th_iBj=iDGgZ4JgtgCByoE1X>-*gH^IEoHenl%+SAAXTm$$mMmw7o&MTR|Oj z7g7kGW7EgYHX_)Y z&c3A|K!Z~B3d^VSHX?+7BHDjZ{#S=h$4Qvz6XP@t_Ur^MUlK*}Akj#ihRxM=F7B#O z7Z`?Mn=8&Y)4vcNGsPlBoFs3P)qzVnGb9R2xQ#RFJff>g$1?FB7xLJoWo2}N`$Xha zlN0MIRYTK<1c_$18RO*KZ)bNog{9;_Vye^^U0O+|uM$Sq_ZMLx)mqJD3FzPyVoIi& z!7=q_KTp!)jgEr8vpsjgn0xpHc1qiV^VxFzHtULxSBr{~*z=XXoYKDdt|<(W;#O4y zxB)HC5BfA*lt>;$uBA%)?Z`3=?#;!kjhIF8)w9rW<*b)@G8j{hGtB&+A$v*2l+e8* z;n1mtAwr&|sndDvSWGCYNgQ-lXWF$G_{juTtO|rJuB2k~1)SW>4vITPR^;J1iP&UI z?!hgYNK_2-lpGNjwM9Xt6`lnb?d}>Vdugef<}-E@C-IYWXZtEe`G|f-T!|<6(lf)~ zo;%6ok;Gv*%79ZDdC17t69$>p?FC=;Qb%c(t$4l*lE$r7X*s=yjb$(?blNyUdZs!k zwb{Rd&08GR0>G2c{?O$-f%in>|89q6weKLd2^3uRc@g=cwap{D%k%OuB%rp$89F(! zC>|||2Ju5IWrCHA=Yt|SzpsLe^o6TUGOi@L`qAh}BxZNC<+PH&DC>f>W--5ewHB#B zo&OA;%&O(quz#sHd27C^Wnf=+jLD@#atal4j(i;_i^ zy1s%^ca0-&^{gw#ld|%FFQ8B@M=nCfxua_59#QtWy-G!nDf2Ia9dfo7?_`(TyNJ@W z4XuT{$;g3#Xsz;9@5V8zKJYQWo{dHyurrz}+h> zq`-?@;CoI~wnD@x#PrZNy~YDC7YDR3dH%aaAV0AhXn|nMZVJgE^fmzfqyxOTslG;$ z1NI<^)e-lhkiE=^%9*qcRHn!rX7bP^eoT><(w!v>`*!WmPf&T*h;nZ&qNQd8Gf-ah z*?MXIPgp~MC2wE5#gvZmnAJZ~62CzTa3#;0;?ZD~#neayb+{9@oUho6e6yH*|NU%GCO*G>z@6`H- zMYw7HG^c%lN0grzaYg&9P-tRc`Y+@^wE%PnAo)a^z9@}fr}zt!{}K#KbCAc+bI3$7 zi0oZP7Ff&10de;K_An6y^&fY=NZw`Wf!*5LPe~L4F8{{z0JOrr+ zGgHERr8h8Bf3t%meg2Q!|Ee+#bNVuDZ2gZM-~olF9Af_Z|7XyD*m@G!;zj&NY5%(j zF_B*XiyT}r|6M4re~-gR6z-)2**_ipyYl}TMMx&(a-Pyqp#QWPg>Fl-#Cm}wOOdnA`BNw^FL5wBqWQS|@& zXW<_TOvCJA1{E-cesy)I%B2;7dw)Ntkgv;s+(5n`f5(=Iw7>Cx@lyv}M`FSRW+{V( z27dl7&j762fJym6)L4bWDX=ynzxR}VdgDx4#OUvoX2O)J`+2^UI_(z`?Yaa!sl0AJ z?=7rlq|g?P<}Q^PM}!t)tJs`Mf{I7Mqk0Y44 zt3E5bH+*IMF6KE39pk7zC*lM2dwuT#{g2TKUb5+KzUkTJ0g{EJF?Rbgc%X85~~-_A^&Q;Eg*s+zY!7`CCO+_~!GEGTY{ zK9FhVug%d~_a~bOITdh!ByW+8w7pL22o#|)*6DlZiwKYHew6@akMQCzg{O1Z!l$c< zW}sWz9uvPsmcci86W`{Dbq7b*uLY!IRm~7fYM>!a!-<%EZ5HG)tx}zJa6a09i~PrC zAi^mg)R`zG9~Z*dYR2%S3d=!YDARK)Oupo-u?ZFlJC(rcMSWT2MHCJwfJOOJ&f5OU z(J$_50THXI7_Zdj+Fw-*Rtd+KLv1O~L$fOrg3gTNVh$s2a^B@bF?Td>%Le$sr)1d! z|LWlJzxoX#k)-TBl4Eaq-;%*zdXP65k_a6u@u{srkv;(1eMSgz9NI(#6RJn|152Z8cxpnCCR z&iHAAocJw8fHcT2XHjrqa}i9K;bjGL3t0 z9{6H?3dm1Z!V##yJ0s-;y#_uL;{YJS?w|A1)~I3%My!oBt#zg`F~A5US^101$tJ zEY--+K+oXv(K&0TZgMO|Q}w<*@5exstUFcaWW}h{K#3UZ+UsMR7RAR_gd>#GXL+Vv z#=0VRGh~Sa5Xn$LdUnQnH`!cJe`Bsv8kI)e$n`oA@n=ww1w_Mg1WKFe11W;5S&0k@ zfs$@uLiHM>5EF=GDP|zz(6NLhu%FJM6yf5gAuLwmU?r6oBK`(R!eW`423GK4x3MyY zH)D6Pk0ZbB&4UT*3*)Tf6r$-DMI9M4rX}>WMx_Jg71bjwGQk0#8p|LSsA#kRU@Y3M zE_Pp2(1?KSGD5KMKk!jc&X3jA$*Q{Uk2++vX^09r-1sJUBS^6g+)p|0lyIJRcXGj> zv;M08MgGF)#cvSLzM+iY1DqUNvWXRldeb2B27{-c{M-+Xe2&al=+|^;G0hG2jNuYf zgUO@AOm~^!olL++;=g}*w94+8dKm5z;Q_I^f!r!3GOSS_H zp`iTAjn^y`mN%M3U9dYhfXV>%eeh%<-qE-sesbD+)b5nwQgnm=qF?bts=jc2}0KI+zb95~;Pn^g-fLBqTde6%5a z@J8A9p97xDe1Lg-m$V;yA}wDpiy*Wz7*$axrT#^hq``C1kwxklVhps60>Az!3*8i27%RcAwrQN? zZ8;_`Fqh^94I+HzxkTg7uttk~Gty~#?8-($Pslm~CDR7c)yv>|3xeF&r-u~?#)Ec) zuhmX^gwj|eieC2kSa7;J>r=VTZFq8jt=4Se2X53e&s$}Ha+y5>4Wi$J2RI8jy-kgGt-TAPlIyDsl#bTH0*?OK9MXe3Gq=jZZv1^) zLTN}L@f>I5MB}8`V?~M?k30%sf);Nw@srr2M)(66oET)(Re$&Xo^S9fg_vJrt zVfGzYu*1|Fe$`8h(I7^5a!DM5?nt$4Q@s$=q{oudiCq z9R}xb(f>e84QEV&cC^g@&`QjQ0k<;~CrI9w<{p09)#-+=iLlG54jB`mzT>zcGe=j! zP>jJ07}rW@AoG{boX)_Y3_=DaN(C5{$69gc)ZDD8bJRA8>*`InXY6i03$=en1QLLJ z_jLkq$C4o;Dy3}WVr}F7tsZtICyD<>k`G`8j}E)Mu-w8 zLFJ90!&PDB1j&E{hGCGNQCLUDc{9jtHDP`+A|NC z!pT{i^Otwrfy#HC5^X*CoOrwTYF}>-pDh8Z!zjx@m;S4V(>N^KtIq2Fbok;~QNr); zlX2PoYblGpZ?{Cc9J35msKtp^KXWQ~TwRqtXuA$WPzX84LQL6(YbhgCfF+&@oanK) z(q4ABeBjX8r9$uuMS!)wGR667egCfIb+JplDv;gj25(1`le7mJV$xqv<$pab0iGKE z;mMwlDwb^0I@&1=3cyJ5tajYoOLsEWhdqkH_y9TuQVkQjv9I&afhyh2=Sl$KAZ41} zY+ZV{ub1)sH|Y5ju8Gs5UDD1yI2d9|B*I!>6$brXLz1(w4tsa9{2ik@GOcJE)8p=z zX&aGe)a)R-*u^jMu0s05S!l3Rcym;G>trbhT?d(E5(i54m0YZH(LJdx)^*DJIAnh~ zSCgVm6~AN|fBFTyAIk%62lDg{8C1J#*~wo-e}mNFnW=-F2{PPPuVr6;q2bdBAy~YW zPqL78uEOPujG8@awAUOhM+z?bun;Dy`VwEX=o4vQZm&D`&p6kdAc`2L1Gl|!*V0q{ z5a4lBpn8SSPrTC^fmsWaoQS7-!NgYB#JQzY13|L@}jW zF8MFSyIg>VEJ(xGmP?_Cd!@ZL9OvLQvf#Npq7}Yh1jan{uQnjmmmLt~%73WR5Ndcj z1pCoDSK{sI?x{WoA410~1cTCPvT2A1KnTAdfsHeR9CiI8!?Xu4_?^rl7gS%#8mBc; zIk3tVu1hfq;wdkE>IQkbVIHn?zS3vUv=9aqy@ z*1B4?uAX~h{11U!U+&HGWC(??`VwShLhXGd`9ID`Q68RaNPx6VF9%EGOVodZ3|`~N zgVC8N>7<^e%*IyI%5_t32v=k#Ubw2t;?wanzEUBlijs?qFq^4twDO!hc{WAK9VVxY zXJqH3YfyURqgzFwj!j0+0y2)JX)%-r z`~q(G66hxX?Q_8;^=BP71>}T>UsI0N z&f#)}f)mE5Uc~6S&@vY(oU@1wY>$&+OCnwo*}Nr|6O6s#A!n*mb2IGWXj^9YG=dHT zbO$Y>KgeAJCmp?*kP%H+R(R7o;hB@kT!7VKzuP>73bOUk9ptea9=b-3`bmmSiN)@0 z4?>TK?(9uG<5}u9zEr|FrTnE1kI~^fNTp~`CN~-&qdz`Y8-+qk-?2(W+3)qn51d1{ zj&rF@D0Fr$`|KE9E|daZiHCKe6E3lM%+(aI^5)5k(!7Y#yWgNTnO$BlL16AGz>Hww z_#ZPC=p@JfbsCg6un%fm~_s6b%Uk(qL z?jWCC2q?>h<4@13GSJA*#>l1r=L>IOO%@PBI8=!&Uhp({tw|lc13(HXbP%56Qa9YqC>6q*&wKQA@)(!{>6pA<*FgtP&bEASmH zk9G+iixcr!qr9)}VHx`SQcKkkS_QTy7so5W#b6(|_dY^gxhk-Xv3Q`WxgcL3*l-@y!C&kV#HN9XT2d|9eaY~ zAu$pNNA?z6{Y*qS==m$AN>f%2Nw9k*WR} zh^Z|TH4YpU5vw+5y*(?PM|+Y;9bK1R4l9g5)GDlwFX1>z7adw5(4uhe`ue8*MO3^6 zxZ5pDm@z(#k6u9~j)|X+vnA2yQf28RJqiWXe1x+kD@-}gt6*bljSR1*hYUCQ$_AH7 zjXOu5LGZ?keN{XR35uwyaJu+5{ql>t_4Q_OhB8`lKQt#x5(6tSdn;ohL-+`k{Wc-u znApX~U4*(kj_t6qP&)3nD~HG?lzPFseUQ=n#@4v_hfjej7zGooQi8hm)ylhrydsX4^+n9rGCde1Jywuub)_$g;zz+d-|Htl*MPW$3QvJroGxMB z`D*3lDGZp@dy8h}XqLm}BUw~46~w}hEcl-)tZxA)6Uj7DO@ayFwcRSS@UZ*E5E};A zPp5L7)yOp5GW5tW=A~`goPfV)?TO5~sHU|nK`yIdvK#ZlYYVs;dcznC`In#C2StAH zV3HB<)?LZTYs-B;Xlvig?C{vbLKt^B`{kOsCEa!s2{fesnHY0hp_+k15 zVxmihfA=Q_ZZmdZcNW=p*z^jTB5U^h*k)0^nfRr?{)NJtzy)G(zuqrHQra)YFU*u>sALPOTHCV7D|QrpA5p&8#f{`$sBpJT@fl|4R7iH`f)!hM5iSz=vWLudRFrm6k2#|b^H zxIMXfuWwnByCv53DtLpkf);5ttWZE59d?7cG4o2=&O`A6cG#}}2#`vj+*yzNu)4kh zDlp1EH;&k~LkQ%x4b;sA9arz5L1DdW@lBj@QjM@joXlRW!;DdRk$rAQr8rOU9Pm}I zdWtZn-&Y_**Nib91diO96(L$V*^dvgj(mTz0wXvr00a1%1PR!5c=&-6IY=Duxlv;2 z0b?*f+6VfeDrjG}Bc@Nx;{@_X)6kao2-viFQ2!I%~qt0$X z?++VMDL+MDdNleCDux|CuDz0%9h9SNp%(J+Y!Ty<81fh|?xk~O73GbFd;7;)9@T$Y zJ9UButo_Jze18t98S*aOUvH=}EkM-IxU%h>P(V~;&^!*&YEanAMu~Mrs*#bAb<)OF zfvEt~cNq0XEd^e`R$z8KJb6Xv)9HMciJqN{tSgexNYe$lFPtMh(8EjH#f=w%i!oQQ zKCJz~K$OHG`p%sOtAj(4B^gu;(OO}|#Cz2w%#9NDe6=LtW$WsNr6kTsjy**}fQ`sI zVbm^N`k=rgA-Syg+r6;%B0(%NOf|vK-&&1Yf+R&*Kzn|hql*&U`^G=jx6EI7isH5* zQqA@1!D2F0(?WxhNMS#UvV0xeu8XiG>)$FLE-=89Babv$_bbgrziH6jpmL!CAY#@<@r&@LM4__9Z3!?X^N8o5|7Ay0x)1=JPUvAu$@c(>6R`Bc z!aH&II>EjV)>DRmfYj!FDNvi7Sb-qK;wPPNqJef^?0Ta3nDWXf2qr&)dq$%^g-d-l zQ<6*~2*HvM2x55+2{!r@D4-(6d|qf9kx!E{DS4Oxqc?L}2$mEi@u%t(LhJ-!&xzeX zi{7sO^~Oi&y-x}|>r-(kAjR<%g_?+|(G#VjSiptq`oeK*TgZ`HyQr4%*-;d?0~iNj z&brN-AW^!L-=JT#iL$~Tzd@zXldgq-y}a_jQC0#LM&<-A#62yE4uZ^CjESxZ2gV@a zrP}-D2Jg({gI^JZhr-lW+XE9|=7>)*?G(j2^jR5!nyXi*22HiDz5E%75MC3?L>7Ut z;>gyG*128}t`d5Xk*#fdDj>wnQI$DCbpOG~woj;2jdw9!Tq)53;pJ5BqY*G z?;dzAmy6FuiEU-l&_z?AK#!fKo+w@fJ$;9dlz^KS-o32}93?AFAa|tm zfmd{5DF}y&??%PN*!<@w#mHpS`ha)g&l`89laqR{8&W9}JmIc$*0FIYAA4-0#nulM z9f)KFF`VVZ81Mtu_$HtzISj*~hc8&+Yc6U53UyHk6_zE-dGb0o7I3vo>xCP1n)>_s zlBhGgfPA^<9N9I=RuWy|L<%-ENrkPIkGm)>8>_d@N z7;ujRY5_`2UGly}m~1n4Hb8M7!!tokl3n}o?#c?y8|7ojVWvEYtuqdP$uXLf^NkBuPpgErEcIrb-?QCp7kFo9oub00jdLiCq=1Fd)(h z+5T}O)`&WkGvS3Rt4dK4Ds$w?PJrTAqO0DN?eIAXU#2V$f#|l56?@Nc*NG*(Z7ZGR zVAz*9%K8t<0EG;zB#9X{`eY}_{1BjM*^bMnOK=3SaL#=^cwXd2nHVXN@S<3Cnm#cq zxj>GFLq#Wk#I!&zPL+s0Sr$aBLW5mSUo7{$K%54z95q#rCg2i6iH9myRbfnwnyZj2 z=1}n>OY@9Db{dJL#D4$UR1=y5XQXOs!c~lqx7L#x$&}igAvA%0U`W#OC8c1-IO??o zby7J&P*0ecM?tza=6gj`O&EakUUU+m5GHssBbpk8#$h=%hZzxRJi<^Fz+)1CN>)$` zzTMz|Ky}O7%{)2Po2*IG~*`YE8qQ z_#aSQZ-lAFd?iO-C(AX`H&P@g`vUpIpyG{^gA=Dyi7+#e{KHhoHi3G>x-huR0lQDNUt6pMI#PYK#%DV z)emf|8lr)L5HyrN_;Hoy%)qOqikVsKrhYfQCA+W7rqP)rLEr7>b-g;s?b?p)xTEd3 z-yE0BJ2c6ZH>R^(jYu|U_FgTs4gr)|GyEkxjb;0&Ozog$yJTIj1|m7`JK5)nvd+tp zEo){uu%%hH0=Cbi9g2W$8Vh8bxZecX>Ni8SvQ1AElP3yurWMdav+N6OpJ&|0yDCoZam$W0GWy%Qyn>{3yU;m zp&w6R==OeRFg_-ur%4&bqNLM(=B$?<5aj%E6twAx@s@ye@XchNVhPc2VJ^Wg$*5Q!bb+(v}ZJ!w1?C2jKnYQ2gYArC~!hk4XmYh}q;G6$cj}Cou#ECy)oNH@%L)^bY zFQsDH{s!@xR3~;sAcviXMgcWJ`^U(Tu<+uK4L5mT-;eg=`5Ye8yGHIJBl8ABRqC5G zhxmQ)L3vO#h@-Xi5heeQJr$9rFr8fN=bWZ#m4C;{L$dDej7e|+a%@CJ6J_O^%mUGG zg5K=@V09b96v&2RK{QJ;)pdla+wM0BwAA~1BuddfJ7-cgBX*u) zxe^kG01=Rp(Vod?M4;C$hoG;o(`>Az$=OERgWRo|lzV#ZpGpvndOztYU&U`B0u;H4 zTe1Um6g$Vx1=Rv%2r7IJb)EBbSI=0jg%`0*oH>&U5E^^mMx6Ey|CO78yQtX7`Pw77 z-+n~^zkk+Euka;kpEBZRm)xT9MZ~Q4iQ?IzUv`>M?Va$6O?Ug9bd7h1r29UPe)okZ zQOVlomAm4{s7>Dj7q4z9ZJ^&>$w$*6{}BU*YkBoS0F|dX;?pXG{Zha4`wXA)!9Y{y zr~X`k`w7BT(qOtnci`C@LwVO-YI;5Bo_YKm6x=h$eeJI}(g_4QYQ2n`&Nx1KOgJK| z#?mi2tl51agSV*%0@*L)T`3}s?>rERI(S?h<=lLl_3i%YNhG!QV}FqVi2K=WIP$GI zkB;bqnof7K66x1Z0-rF4VJlN?s24t!x*VO3DY4J)xEwO7uZ5L7a52JCo#gneLvagw zZrXiwzP={691Wx&Z%gaL)1A2B;_<|cZu2@1Lg5YfS$20*ta6kRl(!JWQyE(4y2%nS z%)-0}x_zGAr5_9Hqj;vi2H%YnZUg&mRj~V8 z;9GN;u8A&RY9KNxVpOR>{KDon&*ei(kp2Gd1Ns-Z!?O=4 z_CXlUS7>F}gxUi?DCRgFPOKi;y=vQjIB0Hsv64L1c>E0lyDV{rIw7z1Dh<2})nS89 zWhP!g0qaXFe2rfCRTgp7fDzTQv0*5eBYESu{x->xj9|8u%B59*s%GD{+mFBJum$0` z)mRzI@VL`JpfzAX-r3;jN2utn!Os?YD}4HHf-$$XmsMAOXbMHsIVijMi%y+^`!`?# zGwr%+&O<(Na(usZA44i_No5 zx;To*3F)3i+l|E?!Bd*%p17EqH@B>3iWU&AcRAUmk$)r0aU-p(TGY(N-43!hk9@;w zRhp%1uV-kaFhVO)HCv@Sn#Sq3@rmxGtRQ%q^;HWMw=5g7hSgV=Lsq@%`@spKT@s$~ zD;RFrKiVCU4aAhOBoNoH0#|1zTHY^e*j63^t|JSS|KU32kLz+5=@a73XBL2K@Ny8f znPID^YQ18u*%+~~XA5_ZQxhvs`+eMeWKInuI@=p43*FSJwMW0%D`Ax%k9@fYXWds0(Ln%itqQS~KBr3yDQPNY8=L?7NicjS9B4Yr+B-;|7*PUVWvT$*t;E#R3&$qupE_dV;{l0!_Y`IPTvy(OZcY0k8 z=Yq9klQR!pix0L5yZ-W5-IMpZQ;+T>K%d{@Z;+Bu|J#dJpYJ?^f4}hlZlFy7FkzheHot2y4a(aoMM8fv&jR7y_)NFBYr{oLt2T#( zu#W)(`>T(XcC#y)NE#h3jy3v$;AMl-9eS&fDgDah6Y3lt8~v@@RE{<@UAMAN-^e~% zee_C9d=-7*Vc2Q7B8?N?&8H z3ci4zPnfokXe5L7-nJJa|~OchrogMk%jybu0s=BCiVOk<7g9FWydW> zBqUUUwhN>p=(X}qoRD_Z2zOp16iBOLY~EV2s7+X^#T)JNCmq5->*2j-34_=If-2h< z6TlEXU-EvCfD#6fLQ8(L#B8<%g4W{7dkuh6`ZASKz@89(XgE)oys!-FD}(zGL`pOP z{WB`oTT^A0$muzfxiS_9#{6ewJy1!m{i17KS#fH8=9o$AqpADh0&y zOB5{?%g4J9al>f_2;xT~(PDz*nA5EkZYz+zVi^5 zx6OUeWye12u@sEp3f1lEsP=U`c^`^3-{rR~TsN=Qzmh$|U-85JVKg-}UZeAE9v+kL zcQBJ?7ggQY5rPuT7|pMm%DP$gRk}T&R}&an$(Bk!%+SZE^aU+iXf+3xO?<$vb^4fS z^?f9j`psoZGXA4kw#mBn%MyvQjZQAI5?rZrT~T}gH9k{EE&_KIZ5!+8SwyMIL#8s8 zRJUkP!if)(k{z!~O0xf3RMLTfc#$?c8mr=NbQHy(W1`lPi)fZg-El1=PIVBgVw(l7 zd#%+}w`Wd&QPM1iivS1&h|;rE0Zw~~X6egXY!nn;7O4<-ybXn`o2YewQ6c4sT4UuZ z{x4OaIh%t<8g0MqlDzJ*&WEVb@@K1{;`!%utc?z{lf7stV7@p(6G4QZ?cX=9 zJqAiLkqI=7aMxzfkaxQ(iK#-}m#e{W{C6dR)AG2;+w!ICA5&lv;K}qQGCuLf6x;a? z*k;h?bwhdSTiw$(yhD=H!9q4;5iGXN~zejbd2E|^GpVldVD*Q z`$vwBmgg1oymsKRi?%^`OO`Bn>i9c1dY04zwWI@OT^5PbrUwv;1vZ$=OQ;yGJ`iiz zmp>VQOnKDV{jgrewi7!mJA4mQmrZii`lqiPiixEeA4aJ%^rAHlpMcw9S(6hDS5nOb za$^XT!EiJr;DVNx^M+q#gk#h? z_V;QNMX_Ztvn;mT{NNSZG<0&=AH$`yl`J-@5K1HWEe?gKSOWa9{%%mf(VPD`--Z^dYhRgjs(%5$vlpb=bvU`<4 z7|zZCmIO0QYLTr`#PtYg8sHE@xk&;=2DiAt%omGp@+^X=_=K|GhzbCpzty4w-j`~H zekFlo45yWeMGSxc)NdP2A4rTqt1JyGp1=qkC@=`WA+EDdv>JbLbiv#b8E11sCxHS0 zS}w%Bm|MVsae%ev8q52$2ajIZfIVV`j2MeFM2Vz zp)w4>&$yx4(O=i>a0O8g2WGfMxEqzL4&5Z@%~^eYPL+~|f2zPRF(Ho=p44%m{T1Y7 zj3qT21k|fZAE;bqjX<$Sr9Ml21{mIzNt0XL$JL;<=IgeG4n|VsM)ha`d;piFho)P} z7(#q|Z0G(08s=heSA3?`$x-Cs>%${<}QrRYAj$=_P1$CpgsciUyG!b0HZjmTy zRV^PU-hcQ~+oAOxI|dDcV$gQOKQE-|$7_xz0jpTX@DGF==|*Q0vDVskXgy_#s7T~G zXs@Dee)JzD0$#IOyw>TYLuLnD0kCSYN~uSs;=ILgF)AWsl&fFlA47M)zxX41^hp>Gz;Y_F1EHd`el&%|1==4#sV7I>^w zwcu`S`UvidiPF)A{(W9o-M(|XTYMML5wvDjc8B-p<)SxP?=s2}4HqLzW|)T9{lA*G zm*wt6eM6**;X1|^rm8}(urpHd$MUYwzp)uJl&jdb5ox0w0dOP*Ig}VXCOTWTnuxiw z<`3R?#!sxFsnHRLEazyn+0^LqSFvpg5^pKyp&GDtB`b^gG9nEdEbMS*j6qG}V#|xy z7~L|{BZtRi`HU1Xf^s1$0-*VWH)oi3@3mv-+cFp@4J{jyABbb}kbFx&36258nS`W)8G#UeF0LX^o&rTj)#9~SRpAkg$oEO$#O zif#~7*fRPGKvphMF`m=sq5^H?Q#6z}0M@bD6Z^p%_NKr`1xh$jh%gsdDrR!ab0V=0wR=>~DY5f}}U_Y#m$SZ}f~^dK*I*8(|%1d;yR^ZGwM-xN?) z3hd>g|HHHLljrCE<+%Xj83+;8F-rGu%Ru4S{vVcEG$W>6Hi5cucR~~X$Fc~-G6mfq z%LxC|@?#(angQ$$SVI^w%l`@dH$U=!gEc=$+&Ba20a%OyrC2Js_MWuE=_iLszmOan zfbsMD_xNde{IRj=4O=CQCB&PIaE24N|1`D?kFc7M!NB-Q^#GJhh(7uam{act?4yEK zEfR(Rru&SAT{-+mdNTs)SEL6-n(SZFQl1QJj?OdjAq`t>(I8Kn+L~w2~{J!eFEgl|L4pf3^4sa)Sq*I|2p&6drG0= zly6)MocaSEN_sl;2bt*~6FoV&X{Du+|FTN2PMwBlf^(&u4V_hoVW1{eq~aR=TL=4I z<3NX&%0l|wcMk9nURFPTl;etqeDKT(@4Uqt>pMFqRBd`{8&7SqdZoD+mZey;NGL1F zlS4p{{9s~!V+Vau{Rijmf-Jc-Rs{JL_vJKvw?nN~(=s`SERLcM-d4*}?0)CrHwGKa z1W6?e*k`7N)i27s%myQv_`*p+dgAzUh)Zku%E_~rs5%U!?05$28h$Ta ze09>IX~b+i)g`dA#?k;m^;X9=RrF=&%~uUHV?dA3Mlua2c&E7z&2~k1mxSpIj{Jih z%+G}rC!SwPzgn<=gT_(@bQSZ|%M9WfY)vG1{I}fKu-oAX35e~26*6eY*_q%f`2s5) zGa{xPE?K<#Jp5?jp~rp}zwH!RybaW1(MA~yX&G8MI}_%W_t<;KD5UPL92hMdyypj<2FTrT~D&hvGaQbeNRg(dlJ=>8*~jBke!(XefLiRyFT4+OqD>Vl5d>b z5{sqEOmH9NX<9x?&^Lb`c(WYR>_<@uRc>!myOvk0Z=`{o0R%jul+F>N9c89Qz%#RPtBzK-u~OGkFiAN z)_3Q>LEH;X6_&O)x0w_ME5iO)_T9A(2s@K2WX&J% zQKeZhZ#T~nc=-B9nA@IGtESnv#aDy_9y7wR+x|`-44yR@Fz8;8zW)uXPbp&~U&KUc zXoR+Ey!s9LHkv*CARrLF9&4uBm9JZE5z`;uwMIT4eKn2(TdTF!P40wgC0QCRg;&w= zATkI4k>TC8>L)zt(BM)Ij#^XagWJa*-fNx!^I9*1MRH49Yoh2Ue+nCGrGNZ1UzI1Wcgsd1Ni+qdaNO zfsEvJ-_XLgO)|$Tm1(3{!&!r2niK*Em~dCB5E9Yk-s?-VTC112kB>(<;4yS8!Plx> zaGZUmFzRH&(M*?_qz(`McTKkFkz)DMGP{!xyRC}$DanZ(!Ok`z(R`o zzd;n!&}gnvUaI@nSFhaM{a9}U-u!r{xlb|0)+1+_czx`$56rC&z6o1ZCr^#D2@4+z zdGG>hDrH zis!Q@r>}_&0w0ABg32xZtACksAFf`MdH3a!dI|TMfUiaH5Q!29B|DcSD*;=O3WM{SIACpg$qd<0P?^pyg z3rep5=h{+W^`3E;rQ+^-u;F`-Sik71#d%H9jG&vwrW1(l;FeOOJKnfq?wlbPP4I=K&bSs-xW1Qg5GWb3G0px1d+IJRdZ zptDYXaC=5$U^Vka5j#>Hu=&t7LNko>u#uQHVt&_(EWy+bx*AlhUV4S1BfK{0vJuqU zmNWUwTWo@+Fz);wD2{)NbO4HG5ifJws~;)H|EH?&42QGp+MY3b@4btJ!RR$1xvtBrOki?TugOn)?ODd}7lt!GC$E2^ zh+|36mHz-b-|Mijuc9dW?)MN7m6@!dmT_5nO^`_=m@|6>EihX@4I*E4IA|KjRva{M zMA4=zjpgnN+@dvpV*05!5m88dkM&aZbc|eOmI%9(a$rrp`?Wl(;%&1DDApqq^cQiZ zkeK^lNWlL>+T~%)?&rQ9>5+_oz^;`f|40%2jYwjD__chGLYgQ29zG`;CtUBp@PK{y z(F8;#oCgx$Km=a%U@mBpyo91>F1@8*&l)|FHHDAhUxJ{w65@cKkqX7}77?oyp%e$E zXlX10Kdg~m;l&$Ss*}*2N`ZZ5vghBgQ$+d?>29St8~?PXX58~u39b*;cwQ2=aMJF! zmV50Zjj5jO{vKjg^~=?w75%9UT@ETLF`hR|m}xPmofHG2KY_m;j&kQtb9d0n95dAb z)xRrB`R0D#{2JFJ9{Qd8adS(zc3SOa`Eu3f)7tb{q!^Y!d6ZuWe%@={{seH+vbn{2 z=LA#-lQ0#fiE@mb{g9bDK+LihR zK?BHEyl%OB{Ry=Nou!1DL2>D84Lc;B$4crO5A)FS{ws*7F7J!HV7jbd7A^Ud%h5*d zufDb98!d&jj$e81!|Nlm&en@Z;xvMZ_S@F;cjw5{XGIzgI<@8~KaGxG;YogT%h#JW z9eA-2k_BcLxFs6Df{5!9cqs8%wca6OfNI9Cq?3FT8BzR1eFn6$EFZU#32vb!7s+#4 zEeogEkB6$RLUwK5bo?A0jW?22**BUqR&4YDH~K*U;iziC6t_%Y$trIc-v?O5OVV-6 zO0-k~d_sq9TW!#!`p0ztrT`NY9+S*rzM(te@|2zXBBNs3C`=_kb#}wOMY?Q(@|~r; zu2$C0zQ^Wo#K~LQ^sZcGt@gL-{M9%r6-NERsy|WwfRarG?{3BRazn8LkB&UU@>{|d zq*wG@W4XsqyTcC_G``G`WXv%hkjGJ=l4@khrsw+Mk~htejba`)AJ&(|Hk>U6f|Rw< z{-!YLZbKW-ZEl#RcYx03eUTxRffci16#U_?dLTts}T&X<{6|nXHgP39OVe_Df zteB&s8SLpOES51eXu^KK_b2KTp~{Xvv{I1n{tt!~P}rNM?I>MHSBR-i%7m8Q<{318 zv_BUqZ|V&(T_NisaggN0BJAZLs*qt+MJ+Cnsph1pR>t$6Irg39E)~rURy?QGlJLd7 z093sacKl>52B2&XFuEwoAOosR9GV?oS+G~&`DTV}tZ4D}&ndadH%|AQ&Np?~*Lj#5 zV*$X?D_>UZABB1T#xcxP(9)lN5mA~~P!SQxZ(afA@9?Ocno<1%a&^JD2w{4J8V7Q(i)wJBZazFxwY+ZDDUuWJrfPXn)UK# zH={v;LssnhHQxBvLXD~<1{FK5xJAlgZ3bjdcu*D^=`VYaB22Y*6ikpzL$4J~nh)!Qa5Vf)G!u*H_pMYs}AFh$~(T@>zv7JE)PTBeH&38PzsmmT})b>&lac{nm8D zX#@Sqz1^?L@`={~|bOb#CuEiF|Wq)dHPxUSef&rzK z=#GM=9(Cj4_^LAXrjM-6;LJAB>2%cYc9Z4fbnC?~i)^LWHu~-Y{YW&rR4puQnp$+3 z(zs{`4(ac|_u{XK#!^5qMLw2l(WN(HZpdn~`J|FmNOOld8xh{ZMd($88QtRtp_vs# zHG3KFhk3tJ_F(WPGBt03!djwIk0KxtcGG6xd`TWvf#fIM5(o;1L?KGzrq%!OEJ9(} z*YbO?Yw}|wqKh<~QeNf&m$^dl`qWny2uwL+!fv(Me>?)!uWf|B8+wR&raqF(eMDBe z!%~v+61FmQk)yEekLOPQ*PQDesO!##sg3L;0MBKICI1WFEMC~zqlo$w(#eN%YFqwz z&H;F6s13I#dn9Ur{e*O8=%Gs6f8gRT*mTH1=)WU#UmnRlz>vY9bDdE(k}J+X+3{zi z`b&Y0{pOBTM7@6373@e3Lj+@n_kwE+Gjf9^UveWzxuTC8p33Xbwu70W>!H>cyvx5F zrnEt5P}dd4JOIy`q%AoP;|Aqy<03_AmE1pmv6^b20!U)Qv;L-OyehnbT>ckFgp3U=83)h^zjO@|c^ z(+Ucsfc*El&FTLoulj$!|4gBFH$~S&oAAGM6vzN~ikKcf9{wAeg#Ut9 z3dDp7xXh|>m7PIg9?QWeocOOAFa9HTe$Ib~>3?K?L~)gHXMGR)i0n?Nl$XgE_y3B` zyAdq!&!+!38YDlgSneVPT*lbN&NYQo)~dlC-~A2nUy1O)GaQjFZKiwQS_$<^g$mL; z#he^R`-ch=*Ck^f7 z##)kR?Aeb89(XKtQXBU$<21XKuNHEH>t7RCE%hHa<(eZU!T0q}Th}rD)h$M&cx2e| zaApZ@bOS2Y))Tv&#@aPBm+@oy6dO!19~61M05=!p4r{a0)M_oaOh3u=n#<`cUV<1x zS=^k9BUqz#hGfT+bgRRvwr{k6ZtY6u=W$< zbfrU2BrDRFt|`UFu(?wGIGcED;hZaq8_!)yYcb>sz_4Skx=sJmKdMLm?cUh@?Xwg)ledBRSiVv3 z66GNHupQ&I;aHPF3=79($M(}OqrGN~ikl5+%Wjt^i#*eqL|nD!BC#QjZ;aikKFfKt z`!;Oho@e^#vnuaup(2Z4jDcIB>lrW%+}G!Ahv?glFM$i;8rBH9IIgBj8+=I0eDA+9k&ar&XJ|FwykyvX*__4d9gxu?~O4)lNL< zH8MXt{l8?~aQiD`giOaryH{IVBX=^^+YK!aBn)tmM!Cv70T%Fvv)_B2Y<1h_;6Na% z@shRDIwLbQ2sdXF^JVe7nILL(gC+HET=3I15aV%$WGxBL|F49`-})98yTj(}C^w6v zQ$Yout|qaPD}FX9%E(gyzy<`6McGZ7W{(hQm^N*slIvYJcV@Z}$XNIt_;2bVMO3B4B^c9l1w@v{T68F3%s z{gf8d2{GpCMV`qK01qf!zqdjq6I)4Ina3!CPMhBq@pczZ8?_~6mz$;GBAKCxVw%1# zENes%*S*3DIFBxOe8Mi^hH$S!3rQJN2CK!e_R0qvAS0D$q8QT|-{~RfU7Q|GLc5>U zcFp1dNQu?Qzc}p1f&}7oM~E%&FYZ_wryCe+Q}xndNh;GwW(q`rm7H%!+pSQNH zGb^-o3Tl0a@mM4HPQgOfBH35tgOP8#Cxa+EExUL;v&9yEi1#X)7dxi=jN=I@$Ijye za*2UhwbF<9H7F-x6OriZ0K1HOr(O6(eEu=Busl{GI56K)Sz`G{&roCKUFy$NqR#u- zk~{z;bk{-UUh2rqH>MGT|fjD zSFmyYCNannRKkx$J)o*d;EBgKI5$lvGJa>gEK=YP(L^|DBRv@r#pgllKsU9AaPoLe zl#9i7gf`^317lSzAEF-XuwM#o=3-*N&fHr_sl)@wB_+@%ZNMph8#PCcqNZ;Nurp{& z=0|>F<)ZEbGAW6?5Q;L9EV?W$z4RKD3?;|==LQFPEC@kU-`z`V18cxdL)Q5tMbWayG;^K-@;iN4Su8?s|fJqkR7W-ZINQ zuxG$~nMfE++hfR4ADWg%FmF5jYPgd9gB)G)NeY1Q542MxALo>J0=4S=Ox=hq8QT2Q z%a*BxMEs9d2z34%Ls9mr;TS#^cRt1se44i@%H4gdGG(OhJOHa`ZbS9H9BLJwA;kZ%h_QK z1)fXRvx-n&%nZbH&Sa&!_~|8nvApXZ-1sG~6_d=p^%UJmz`u(jFf9cO=-_R1x14SB zp>4JKJVDO}#L1UAsDeCcOGyf@3k$(@q#7MsN>)~1vQ~2mw>^#bbjbxX-UK^tKa(%g z33|nMwyO9}Y_qu2S!!F#44;2!WU|uMj)O!93$`C-${3g?)PuY1XNFtBYT~Z$b24(R zqU-;LzMnmxfps6j6TM}-u=lY&un?>Rn_*h6X)}HKje&o?2TwvA5;cS!~|I>R&GZ>F;qH-m8WG`;IitSe) zaU?5m76vqsv|Q~$bO?@6j~Iy$B6P|-TW|Rb#r##i*)>iE*uQVsmX6KtP}tdCKysPz zfTIs$SL&)D`Ft22hDyIXUX(vV4paw*SvTRa(&H_hvdGSc$Dq*W1w_Q}{08j*<&D|y zE#tEYFnpV>wJ!Pn#I6R~8AR3-IvA~2&NRzyKZ7q?rK312Z-^(}>s>AgaT}*nY#2nu za+XL={7XDOQss)Q_gdP}$?NUHjCR)<&=ng;$H%NSL-A+ANtCFjTQa2C$nf{qxwJpg z$;1MfP1A|q&(hH^68G5kE-OC^#&Y~5clK>$OOol!MLNPj5`M`E3>_T=b7% z-kY$iuX~*4ya{Yp#fCb)_tv~K<`A8joRuAEB4Gs1qe}d(VrHG3k2mXkN#- z5ZZ;kJ|nip#^L-?Dau%T{t@(=Gh;dVcclE}@2&08GD@`tdnV6kg5 z9Xb>8p|+{8=19n?@h+-v2BQi;iIv4qBmG0hN1SOj<_EHyUzx|(H8Kd{r`AfdLgyL0 zxGsGj9+xs{1qy?3EgJ2>ufb_211!C3;1DWie_Lyd>u%jfai4?PLa{y(&4xSCH;z`p z@l#ctjX2cP^xCnxdf~+YiE;wSFDYN(>lYM6#Eh1?ttxg4@bWNFEP#+i8DK!*{JcuO z?hOh!REEnq+U7|}?UASC;oLMLA3xQ>r|HG+!aF@fH66xb!Ff;gAHX|q{ZoMgs-y6P zt3-XP6xk*1zMA2;(~bh|jJxqW*wnNnJEY(04Ec5)Sf=UiD0sj&AlG9mlE{>)h}!a^ z`ATsC-dAH=8~WjAUg1t2$;RZ-X-+t86wY=Z?RKuh-tKpfF`Fl6NTT}V`;Dq zmF|PqW~-jJBq&Aw3WcU_bnAl6b_g$(RxVce+H2??7GrYxzR8q)x>M%{jI^d zxneqC&x^ff{N7PPRI9rYrj}4$6HmZSyG*+H9)#_oO7CGfePC1^#k+%G8lgQ>#CP}c z;$q?J4yH0Aw2aq3@JbU#p5jp`3I>`4JLcaOp}5`w4@ZJiyjgtE1!cfK2=`*O=8U7d znj;qPkjae-&g2*z})mgMde0i1h<;?d&zoCdU{hlKSA8MRurD^QduOev)U#Or4ALK z4d7sM5y7aUnhm#vR9k4-E^1^j3T%8h7Hn^pL zQ8Cs?0C(T~e>CUEXx=DJ6Lo2c!B?i~Imc^zjbLus2)>_xo8N$kiD=p%?zdh)D(m>A z$O+cQqQV`sFx8DZ5&erM{XnDI2MQ}ZDN0%uy(DEVW)&9dg!;n}zBB=pJYccW+fK$f z{OW;=!x!~nPx5&2hY@HV3C`pQyD^mwfX| zvsd`qBv+KWtvAubV?Eo*?sgZ`)a_9X3-v^j!oA|Z;MlTLijVP4Qb#suyl@R;$bt80 zFKf%bxi)x<$Jjz_oEu{`NNM}VET}x)>85aos#-PJ|4VedZ9+^BHng=KgAmzEz4lbJ z0Hd|?OB-iiso!}v48<2n)8g3QDZOXZG)NjV(8t)*d@S&WQWNjtk+fqt#q(g?1wwslCf{8Nr;5tE==- z=r$Ewq)un4r_KIf&3CVEa^EGDES*pt7Mpn=x`*+5;{M{NA9FthDy5sYde8y=v^* zM6$8cvMIpcTZgNU6zg4{WYAJ4GUYD<-Op7OECrq;O;zyg5=cbq*;|~ujRXYQnNaGf zhvVxa;pxMMG+y#?IoR|u3TV&C)K7+O?`fEs-f$#2)3ZnIjG>;pwor^wYV}G#Q!(J? zFCuj+jdo{l@DdmSFrEdM;9=PDCL|2;>_>M%|BQG>o)b7-Fd001)E>`qfci0;5UT z#PGAJRhuti*vRGO3tZDy!6wSz2oU`b#v%pH`sHaRKM z=$V+q7F=dA`$E*XJZOU^_ICLP^pb}Lgq21{(t9j2%MLlC+AUed;+Q)#r*L_O#%2KOj`F~_#g%)Yja(Yq^l|%EXGwD5y80^395HIip09`i3 z#(ia;r!2S#gJ!CPLRSD~fy>CnBXhgUsK#Xr38e-rslt!;TScDO=ESM7Dk)hHV~N14 z$ZU&yiXtFAt`wOccSLZ2@iK6RngJy}Z{PK19dNU`eU791)V<$C+QZU4M&I^>!{C&i z?@i*H;a~$ZDyQc>So-eyx*1cs0xDPRj_v(_1Pf>F|But43%bo1>yNcWtOCzQ0c1P zKjVisqE($=I%gt#`%$XVZ+1^kLp9#oCWyV)_AA(++wT6RW_&B0yl^uEADe+e4kSJX z0K&THtKy0;54pr4&95KOJ()#vJI=s!nj#ZgwNuQ4i$+%e81_#8!Hb7CQMilpM4Av( zhvB5HfFIBS&_z2o>QFqZAxw_w2&*ZVzKupRzDq#;DgK)zFW$d@^ptAJrTvx%(BlBZJBo}lD~vd^J^6??yk7@* zh4b`e*OaB#KA7*ND9oixT>6FSwxo;YLRp&e%{KhKI&688FHVD#g13fdgUR*OmGXd2 z5n=8Q1Y405U7FEi=e5@_PkAAo;m!0H;Vog8kLw<{soC2v+TGYIs{kJBqitJt*a&zU zFNj$w*S{m!j3v~I4kVAI_M@WoL%+^iZDMO~;7}(Hez#0^M#wB(s3{AL;oFlGve$Pg zC^L>SY`es^GlhIRCKFfuh>!CDr&JLUf_Wj?S$fEE>1fc#PCS6c{X>y^>O~t46#*j$ z&!50YQS2d$$&*19KK$w?jDBC~`Y($bEP8v9Z}H<-b2PvtrimzvV;5#Qe?nOwy{w4n7MeoNBl>M_u?aa!_cz z)6R;woXG-&+?Tr+b4XOWBXArN+%P5<@I<+lqit?)GumxDypve^2rY~~ZTo2JqEl`; z>Yx~ZYD4B9)Oi!fVUTfgny_`y z%}*k88n$&ky{33A%t1lj4C$1_7qxN+US#|^S`d!)wQIPe{(C`aYB!gAhH3oOE)dsk z9L6ybEsVz@l;a&_{n0}+z&Wxj31NBJw3&*T*oSh^|3C(K88+u-GO^E~$wgO_zgVK- ztaWje2u;xsg?mip=)`tlr8GyqS0dbem1{5~N8DeucPW-=S+OcI#ezEVt1 zO}pd5^5##%Plj2+)j_b`XTT1ok&ccn<$?zjb$5VuhSI*S9f{%EC<4Z3KpI8*BY~Hb z3M-mMV;6sdR|M9RuDW?idc*}RXM18r5&@g{S|X8oaIC4x=B%=-(;S;iVkVrGGBiji z!D!UCxGHG)+qmtxYFrc+w)ZfO6t7r%4ax+b^YK=Hm|bcJV>HOVXRKs%H91mNw);Na zT=S@Wf$VFnH|e_VH;&&UUVtC=+-{xB@-p;-pM+k=&p9b%`@wywu( zlI}Hor6(+pz!;PI4L zP3?`woi3oZE=RNziw1&s+O7=m>Ih8#GCo4NQ`cVoO!QGyVqU&q@8uRPRekI&d+}!- zP^&i;QHu#ufwUrFeT$uXFClJ<#FtD`OrY?K3<7N>e#U1_V~8ew9Osqvm>-Fif?!km zr6@BA;_=G%`sh{1QfS;`$HHZXBy)cTxo{pa@fACDS80jq)W0pYZ+q$p3vmK1XASC2 z#CB8`xoxk+J@3>>qTkh2h}YPIh;i>RZx; z%5%nyg1TeKy$ZNl_)1K>!^dI^>-W9ehG>f>4V51b^2EY|Gqm-ReO#zThmFVi!N(xp z<^7NMB$h@14~-tYdMQSWEkpmXan|N6g8K>qF{)VsyviV(C)qBA?#gHy%404c#WG{b z&t>4gN=V`ZjutTI<%cArjzw)7VsAMMoOpoCO-Z{e8HC-W70I{Cc*kn9O&{pz>RCPA z0{>=Cr?pS{X|KP@A5z)Dzr0_Hs&YsA-@ zmOC@vu56C<4k@|O8}vt-fDUzji%XvIUnHQ>Mjf(sdJ|}Cq-rueBf>ss_mnm%SU${U zN8{<|Z)eAnb|QR-g!X3jc&=!%gP`Jav>Bqa zmdz^Anj9-VGCORwVnD?7>0a2CS~wNn7sBj_QNWt3uTW(!(#mXb- zJC**uM*!F6Y7Hs}C5H?(6|4$AD4+!_X7$*4Yi-^tr3|ORDX3ePnckcw-9z)=u zu{&=Wuh#lRABHGEq-+~5e+|KTM>=6(2ViqhUG zzAjbH$Dwgd2}}cgZCp>F@S72#ZGbr_!*^nVaXMCgi?{SQ9}wF|!*s*4p~U#6gKfRJ z^9~mqaDnP;gHnAQoO-+t2ORM45g7#21Tp4nJq55X;nQKXF5l|+$i`0g8PU%kU#Dup zZ`xJcsiRN>Ofrlw)<)20a6X-{@lle=rOIGlccL2yfMGz8iDA*HsL@neusXMT4G{#7 zS^W>TvLo`x$@`t&3%u|1(5c^N+>sBXg7=0Cd@iduEM z|184P(>#$uA5PY<4j0mOgq@G&mWMd7Xpl6nGF0g1!g-?ZNvJ<=w)*NW(0qyeKF8;U zT+&-H@o}MFdZ3dd319J#ulSyPGAPZvKpI=?<+&)BDcm?H&IKOvm-|fU3%h9<(_<3B z4ysTPr}r&eGVt`NcLcHEMDddry4(<9*he0BWUkREucH?415*D|le2Cx1r1K2Y!}dN z`4pTh;YRP!@1~Ajs#l>pp#!KaBFB4<5i;TZ`N^*rVX5Y&5XP15=aLWVY720Q_w>y1 zOZBi`mn!gtshAda>;j~J9NR%!92L{6iILfus<}x_F3{C_gc2|`oLq-6a9%o9ZH57G zo~awNdWrKvI4|-#ho7)B@Qj=}D;X^77ACSTu@xzL&8>?K*J951w>>!IQ+;0_wtm?_ zq&QHltfMJ(L{(eHWJh3@N5?y~fKpF-iN5b6+bd5Cp`As=n^O-keJ~9e|N0*BN4vTd^P3(`)YFn0b8E05e{uHjx_j$x$51&3ht9zg0lyffL53 z)34-h>nz0Ufdi*&N;?SSvT6I=6er6YkLIjQq*W{o-%+=t6lr)%D79PrS%CJlDPSo7 zX?1^*w`uy6N2ymWT0s`6FF|S<&}>IgB1tIQv&2lk^#?7L79nQtd*w>t5`Z=FA>@m0 z;wec01^>b&#ANQdow45UH}n`QVOVN5?V?;}xEZE9@mk0iXTt-vu}2mZ3m>F0&DAN# zy{VEuY&UoZpD}ioE)hAifv|O?fgwy)JWO7ufG+P^FOI!OLbgu`BRIk6lfRcrXy1L zFBg6Y4@T zVf*cMPssd-Cd@M8jwbEVU@gWUT$5ZV*0rQ{V6Z`O~k{RrVYMcwt&KFX87%jyD z>XIc$0~S6gP>##z{b21nU)S}SVIXp61L00e{pFa=d}?^7WdZ9M2`i*1HgNU{-#Msy z>(3U={b5Zk9j7t`+TuAm?#U^!U+e>o_}`MW!d*wg>Iu`?C~`{C=Yd5Z(}C9od*6ET z8rdY_4lfBFR{mbexW$)eceeUUW~B?iBA)~nS2+^|(ix3vV(NaI&} z0uS(K({#SS>OZ))pUfk-93K&c`t7P{5cofRosdxst}PI`%uN=?9T_$-$j90VFPAwQ ze$sD@wOYMO$6GAW|4oiSCV}_mCN!)Cw|9n?r-F!G5xZmgNTG=2{331R$_f4>xcGT)}3>jgQ+vTH&9aLo77KZ9Xa1 z+tv7N-|N)n>|Q*@$saovlvVK;HM!4=-}t=QJ1VcsW}_DKZ%=smNsl_?V(62y2I~yI z^n}ekYv?jNch77_rNd}q6ySxRu$W#Z0?ntzn)+SdocrgjEg%N#91m9%Vo`7P8de@j z$9ess8+%pG#Q0VN^0tY#mnHy#4pviyeYR}V0BW8>%raMyg4Ak~hZdc;0~m+BW+>0m zG>csfpr{0m2{!pzZ>!O{p&JAD(}lwYjBten{?7qVzVR*nek7EoX#3Yh=<#y zB!ohD2Waqs5r)s(uaaLx^@Z;iy?XyJ2q##G=aLpCe6@o4tY^TMkenQ zeZg6yOwqnpaysJnt3-BkG4_oChtap;r?WJ?N%=b=YF?PC9Pz0NlsQ zYe~_(8lj@H7FX~>z*?2C80bFQ!b3Q1wpN7sS|h?M7Bk#F@f1Sc{18T+hupz9@fj<=k&~ZH-J}|NgSux$e>Egsv6wJpPOu?a$R_?9!bq$cHq`Ev<_6v}-jyqZE3LThZszAAnY8*3a%3Xv^RbrGq< z-5<}0h>mp{Tr6eafKT(L%1%G@WR4`*oiIi1V`|tFhwWZym;^`X5!-b!&~LaVQL%lXlo0(J|pfzvz8l%C0Ved0`p~ zy+|pWp^TkR;?bE9iZx@hs2aO^gO{f0gr)!qfsKuQgU7=sYmTT_o1x?^hOxH}BP($0 zZ-lGJCGb-n+ApTMcx0<104a5Diu3{4F+Q#mg73!>Oo>0Om>xgFGbf>iv%XFx>Vmf^ zF3DMXVDJF?y96idGXX|Fg+aYs$QM)Pf(JhAz*6NZU4$2}*@Vy#pG9l%Nc?@ytS1AC zWlP#B`^k1{Q863(6jKRAlhBbj?Ux5_vs#&%qq@&y|JPDP)zIU|i;V z3`B020}nj$UD7I&B-9`WImrI|5;7v9970d4O+u2U);AaxgxnzvM@jFrvk#vW5g(6G#_Ddh(o*pFP5@TI>B!0r?v3&z~py~Zy(80jAFN|?Vg3Vv`ddXk-(ugfnIMP#~1 zK;-7u*b94<#~U@qZctfyOvO2Umjewca`uCVftgr~doEy;CC|5?Wi;m6nI{8ui{d7woV=J#l*jOj01Zi6s zf<34<3M-rY!nd6wwh+=TOre^xj@N%XT?lK@fBVahG|*=kP=#yTDQ3`?qa(4aHi78C zzvqP=%VR~u+q<RDLPMe-UQk!e4?ncMc}sFOp_cZd(aFff+{#t!IL*wE0DL z)kaBJSuxdAUH5G5Fii>B=vD_gR7(qkv1<=9TTWmv;z}}|=CAXJ667y~8pgOY_@7Le zxP!Ch1e-VqEqTj=u_+HSJ0S_aN@@vP_@%?0JVhr{yE7PiFXhkDN3}PDd#8Exw7B;F zi(!1kyAb)&6gK`xkNYqTV^NQy^&`-K(1ujc(!Tv7_wo2S0<MF06RKf65$^HM^}Ql+SP=Ky1*}tPi+%R%kP{GXgL%VgbLcBn!mj3@|$bZ6_yR)7G zz69;2GcO=9_cGF`p)^ne^UY}H`MHQ3rtu)v+iW>4bF8%PK zgk=+~eYr57k@8W@d5!jQXQ@{v&&~+EW~?J2fy4UTkZQtU5x?HQVwpBn# zQE13ob_zLy?6o_Zt;>!+h-#wN;RXe1W|Q^od&LpSrB_VZ>zxAg@xUXcaFuoyOS)Nq zq?pE59faq-dppXXeBb>Ik@u>Cf>`An*DB~&kQ!^5<;|hlW_g641IYci?Q&%m!AXw* zYu9LGx5Ah_rfR`@yQvBoJ4^lUDi)JVIHr7IDcc{Cu$SB_=0(ET-F1t z(yZ}y;;FgaaL+UB&an<@2M+0_ zl`r`FNS_iqaRjg-DwZ$7SL(**r39#aE5l*!PqU+AC6CyB+})Pdi(r>Hjrj)81h)0r zCM}^)BVqp|Q@3u^X!1StI`~g)KLcs~=Ph6Oym6k)E}J%VZ5l zFL2+;8nj-%5*Rt_ZmA7xJeDJFFGC+E5Pegt7TFZi@$m*~MN{7CMBVnkI_X(1ji1NG zDa~$KLqKj=Coodvv$Lm?A6gvWmvE2}D5O7YW^q2u7 z6(~r5 zE9n#mEI0{CJ=uAydo-?J(QMEq4#rCKSeJ(C5^B_b3G71}RN+w`Rbr&7#V>}P@#J|n ze4%{ta5H_)i6TN##~~R9(*|{JQ_ys5Z5yQkcqIVgExO zgFSQjPbvcQF{zujoYyxS;(wrTCYMjR8jkyIgQTToC}!yh=WaXK-wm4klJ@xR2L-|n z=Tq%=7hXi2t3*V`^>OEtoCO6u`W3-$D#N&KKO}7xdOC<}p1r%_Np+RJVcF!6^T?N9 zZaBt5PIRd3%I@Xv^2NkJmg7BLXG~Ya38EuyR5(^AKhKi68SgXWK^p3#oeixxoIbus za>jDq3Pak-WJxchUJ$F5e_3ZefY&v*jXeiW{Mb34RgTJT>$O<20LdmyypjL3Iods& zt>Itfbb9&d*CKGyn6Otn^0cfY)$!+}4$&hcytrmwGr-rFss}kAf@q%o$IBkLm;1&u zjF<5kFaOs`H@M-icXW`}pclVWkLR&81KSX!Tv%u6Vg)c7NFScnfIOiJrx z+;Zf-y zmb+H!tYTg7uFrRB=E#eqivGg%j0aoIS@!ICNkd;e=qS98+TEky8`)s^ZWRP& z*$(iRp^9^%M%{)!$VmV^B-}J{InFUOp4MFZiWmqX?Aao8-T-`>Hf!))vfngye=j<%fBVdRtY9vyL|FARY4M= zFOK902gST>sARjfE}>ItyFuPc{?JM)J8uDbxBtXab0N8>>8W|I@T>L?+2zFpQ3?eQ zOxj&l6V@RzxRUSVU`9b@x0kvnvo(0)C%&Ep>{o-TE3t7uGVB@#-y8oD5cFUJ-{Mgd`@;c}Bg2IrdNZ4_up|P1G#PVh5 zR#m&7RcP|jtLWO0^&dNk_X`o;R*VzJx9bnzwnBO+;gsNTBTz3xsc`d0KRNlRCXLxyMcz`hskbcv~6n`|Yz4#B{ k#SLp`?^(%@+bWebGoat Challenge - AppSec EU 2017 -

banner here
+
WebGoat Challenge
+
<% _.each(rankings, function(userRanking, index) { %> diff --git a/webgoat-container/src/test/java/org/owasp/webgoat/plugins/JmsTestConfig.java b/webgoat-container/src/test/java/org/owasp/webgoat/plugins/JmsTestConfig.java new file mode 100644 index 000000000..4895df60f --- /dev/null +++ b/webgoat-container/src/test/java/org/owasp/webgoat/plugins/JmsTestConfig.java @@ -0,0 +1,19 @@ +package org.owasp.webgoat.plugins; + +import org.apache.activemq.broker.BrokerService; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author nbaars + * @since 8/30/17. + */ +@Configuration +public class JmsTestConfig { + + @Bean + public BrokerService broker() throws Exception { + return Mockito.mock(BrokerService.class); + } +} diff --git a/webgoat-container/src/test/java/org/owasp/webgoat/plugins/LessonTest.java b/webgoat-container/src/test/java/org/owasp/webgoat/plugins/LessonTest.java index 3e6dffe9e..379f577f2 100644 --- a/webgoat-container/src/test/java/org/owasp/webgoat/plugins/LessonTest.java +++ b/webgoat-container/src/test/java/org/owasp/webgoat/plugins/LessonTest.java @@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.embedded.LocalServerPort; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; import org.springframework.test.context.TestPropertySource; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.context.WebApplicationContext; @@ -23,6 +24,7 @@ import static org.mockito.Mockito.when; */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @TestPropertySource(locations = "classpath:/application-test.properties") +@Import(JmsTestConfig.class) public abstract class LessonTest { @LocalServerPort diff --git a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/Flag.java b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/Flag.java index a1caa5266..fe9d66466 100644 --- a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/Flag.java +++ b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/Flag.java @@ -45,7 +45,7 @@ public class Flag extends Endpoint { @PostConstruct public void initFlags() { - IntStream.range(1, 7).forEach(i -> FLAGS.put(i, UUID.randomUUID().toString())); + IntStream.range(1, 10).forEach(i -> FLAGS.put(i, UUID.randomUUID().toString())); FLAGS.entrySet().stream().forEach(e -> log.debug("Flag {} {}", e.getKey(), e.getValue())); } diff --git a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/SolutionConstants.java b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/SolutionConstants.java index 86586d36b..886565dc8 100644 --- a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/SolutionConstants.java +++ b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/SolutionConstants.java @@ -14,5 +14,7 @@ public interface SolutionConstants { String PASSWORD_TOM = "thisisasecretfortomonly"; 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"; } diff --git a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge3/Assignment3.java b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge3/Assignment3.java index ed32e2458..2fd355bd3 100644 --- a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge3/Assignment3.java +++ b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge3/Assignment3.java @@ -6,7 +6,7 @@ import com.google.common.collect.EvictingQueue; import com.google.common.collect.Maps; import com.google.common.io.Files; import lombok.SneakyThrows; -import org.apache.commons.lang3.StringUtils; +import lombok.extern.slf4j.Slf4j; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; @@ -45,6 +45,7 @@ import static org.springframework.web.bind.annotation.RequestMethod.POST; * @since 4/8/17. */ @AssignmentPath("/challenge/3") +@Slf4j public class Assignment3 extends AssignmentEndpoint { @Value("${webgoat.server.directory}") @@ -66,10 +67,11 @@ public class Assignment3 extends AssignmentEndpoint { @PostConstruct @SneakyThrows public void copyFile() { - File targetDirectory = new File(webGoatHomeDirectory, "/challenges"); + File targetDirectory = new File(webGoatHomeDirectory); if (!targetDirectory.exists()) { targetDirectory.mkdir(); } + log.info("Copied secret.txt to: {}", targetDirectory); Files.write(secretContents, new File(targetDirectory, "secret.txt"), Charset.defaultCharset()); } @@ -106,14 +108,14 @@ public class Assignment3 extends AssignmentEndpoint { userComments.put(webSession.getUserName(), comments); } if (checkSolution(comment)) { - attackResult = success().feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(2)).build(); + attackResult = success().feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(3)).build(); } return attackResult; } private boolean checkSolution(Comment comment) { - if (StringUtils.equals(comment.getText(), secretContents)) { - comment.setText("Congratulations to " + webSession.getUserName() + " for finding the flag!!"); + if (comment.getText().contains(secretContents)) { + comment.setText("Congratulations to " + webSession.getUserName() + " for finding the flag!! Check your original response where you posted the XXE attack "); comments.add(comment); return true; } diff --git a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge5/challenge6/Assignment5.java b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge5/challenge6/Assignment5.java index 0d987e4a8..bdb663ec2 100644 --- a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge5/challenge6/Assignment5.java +++ b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge5/challenge6/Assignment5.java @@ -9,6 +9,7 @@ import org.owasp.webgoat.plugin.Flag; import org.owasp.webgoat.session.DatabaseUtilities; import org.owasp.webgoat.session.WebSession; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @@ -38,6 +39,13 @@ public class Assignment5 extends AssignmentEndpoint { Connection connection = DatabaseUtilities.getConnection(webSession); checkDatabase(connection); + if (!StringUtils.hasText(username_login) || !StringUtils.hasText(password_login)) { + return failed().feedback("required4").build(); + } + if (!"Larry".equals(username_login)) { + return failed().feedback("user.not.larry").feedbackArgs(username_login).build(); + } + PreparedStatement statement = connection.prepareStatement("select password from " + USERS_TABLE_NAME + " where userid = '" + username_login + "' and password = '" + password_login + "'"); ResultSet resultSet = statement.executeQuery(); diff --git a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/Assignment7.java b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/Assignment7.java new file mode 100644 index 000000000..bf4a0494a --- /dev/null +++ b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/Assignment7.java @@ -0,0 +1,84 @@ +package org.owasp.webgoat.plugin.challenge7; + +import lombok.SneakyThrows; +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.mail.IncomingMailEvent; +import org.owasp.webgoat.plugin.SolutionConstants; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import java.net.URI; +import java.net.URISyntaxException; +import java.time.LocalDateTime; + +import static org.owasp.webgoat.plugin.Flag.FLAGS; +import static org.springframework.web.bind.annotation.RequestMethod.GET; +import static org.springframework.web.bind.annotation.RequestMethod.POST; + +/** + * @author nbaars + * @since 4/8/17. + */ +@AssignmentPath("/challenge/7") +@Slf4j +public class Assignment7 extends AssignmentEndpoint { + + private static final String TEMPLATE = "Hi, you requested a password reset link, please use this " + + "link 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 JmsTemplate jmsTemplate; + + @GetMapping("/reset-password/{link}") + public ResponseEntity resetPassword(@PathVariable(value = "link") String link) { + if (link.equals(SolutionConstants.ADMIN_PASSWORD_LINK)) { + return ResponseEntity.accepted().body("

Success!!

" + + "" + + "

Here is your flag: " + "" + FLAGS.get(7) + ""); + } + return ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT).body("That is not the reset link for admin"); + } + + @RequestMapping(method = POST) + @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()); + IncomingMailEvent mail = IncomingMailEvent.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(); + jmsTemplate.convertAndSend("mailbox", mail); + } + } + return success().feedback("email.send").feedbackArgs(email).build(); + } + + @RequestMapping(method = GET, value = "/.git", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + @ResponseBody + @SneakyThrows + public ClassPathResource git() { + return new ClassPathResource("challenge7/git.zip"); + } +} + diff --git a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/Challenge7.java b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/Challenge7.java new file mode 100644 index 000000000..27cfad08a --- /dev/null +++ b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/Challenge7.java @@ -0,0 +1,39 @@ +package org.owasp.webgoat.plugin.challenge7; + +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 Challenge7 extends NewLesson { + + @Override + public Category getDefaultCategory() { + return Category.CHALLENGE; + } + + @Override + public List getHints() { + return Lists.newArrayList(); + } + + @Override + public Integer getDefaultRanking() { + return 10; + } + + @Override + public String getTitle() { + return "challenge7.title"; + } + + @Override + public String getId() { + return "Challenge7"; + } +} diff --git a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/MD5.java b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/MD5.java new file mode 100644 index 000000000..f4d34e0bc --- /dev/null +++ b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/MD5.java @@ -0,0 +1,689 @@ +package org.owasp.webgoat.plugin.challenge7; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; + +import java.io.*; + +/** + * MD5 hash generator. + * More information about this class is available from ostermiller.org. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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; + } +} \ No newline at end of file diff --git a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/PasswordResetLink.java b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/PasswordResetLink.java new file mode 100644 index 000000000..237b6e361 --- /dev/null +++ b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge7/PasswordResetLink.java @@ -0,0 +1,43 @@ +package org.owasp.webgoat.plugin.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)); + } +} diff --git a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge8/Assignment8.java b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge8/Assignment8.java new file mode 100644 index 000000000..5a38aaf4e --- /dev/null +++ b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge8/Assignment8.java @@ -0,0 +1,68 @@ +package org.owasp.webgoat.plugin.challenge8; + +import com.google.common.collect.Maps; +import lombok.extern.slf4j.Slf4j; +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentPath; +import org.owasp.webgoat.plugin.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 javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author nbaars + * @since 4/8/17. + */ +@AssignmentPath("/challenge/8") +@Slf4j +public class Assignment8 extends AssignmentEndpoint { + + private static final Map votes = Maps.newHashMap(); + + static { + votes.put(1, 400); + votes.put(2, 120); + votes.put(3, 140); + votes.put(4, 150); + votes.put(5, 300); + } + + @GetMapping(value = "/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")) { + HashMap json = Maps.newHashMap(); + json.put("error", true); + json.put("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("/votes/") + public ResponseEntity getVotes() { + return ResponseEntity.ok(votes.entrySet().stream().collect(Collectors.toMap(e -> "" + e.getKey(), e -> e.getValue()))); + } + + @GetMapping("/votes/average") + public ResponseEntity> 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); + Map json = Maps.newHashMap(); + json.put("average", (int) Math.ceil((double) categories / totalNumberOfVotes)); + return ResponseEntity.ok(json); + } + +} + diff --git a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge8/Challenge8.java b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge8/Challenge8.java new file mode 100644 index 000000000..b75efac43 --- /dev/null +++ b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge8/Challenge8.java @@ -0,0 +1,39 @@ +package org.owasp.webgoat.plugin.challenge8; + +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 Challenge8 extends NewLesson { + + @Override + public Category getDefaultCategory() { + return Category.CHALLENGE; + } + + @Override + public List getHints() { + return Lists.newArrayList(); + } + + @Override + public Integer getDefaultRanking() { + return 10; + } + + @Override + public String getTitle() { + return "challenge8.title"; + } + + @Override + public String getId() { + return "Challenge8"; + } +} diff --git a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge9/Assignment9.java b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge9/Assignment9.java new file mode 100644 index 000000000..661fde45b --- /dev/null +++ b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge9/Assignment9.java @@ -0,0 +1,159 @@ +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.mail.IncomingMailEvent; +import org.owasp.webgoat.users.UserRepository; +import org.owasp.webgoat.users.WebGoatUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.jms.core.JmsTemplate; +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 userToTomResetLink = Maps.newHashMap(); + private static Map 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 " + + "link 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 JmsTemplate jmsTemplate; + @Autowired + private UserRepository userRepository; + + @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(); + IncomingMailEvent mail = IncomingMailEvent.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(); + jmsTemplate.convertAndSend("mailbox", mail); + } + } + + /** + * 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); + } + +} + diff --git a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge9/Challenge9.java b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge9/Challenge9.java new file mode 100644 index 000000000..c13a6e4c8 --- /dev/null +++ b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge9/Challenge9.java @@ -0,0 +1,39 @@ +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 getHints() { + return Lists.newArrayList(); + } + + @Override + public Integer getDefaultRanking() { + return 10; + } + + @Override + public String getTitle() { + return "challenge9.title"; + } + + @Override + public String getId() { + return "Challenge9"; + } +} diff --git a/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge9/PasswordChangeForm.java b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge9/PasswordChangeForm.java new file mode 100644 index 000000000..bfe2d3625 --- /dev/null +++ b/webgoat-lessons/challenge/src/main/java/org/owasp/webgoat/plugin/challenge9/PasswordChangeForm.java @@ -0,0 +1,22 @@ +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; + +} diff --git a/webgoat-lessons/challenge/src/main/resources/challenge7/git.zip b/webgoat-lessons/challenge/src/main/resources/challenge7/git.zip new file mode 100644 index 0000000000000000000000000000000000000000..0e01d46f0d1484d939c2965727592141076e8692 GIT binary patch literal 28890 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 literal 0 HcmV?d00001 diff --git a/webgoat-lessons/challenge/src/main/resources/css/challenge8.css b/webgoat-lessons/challenge/src/main/resources/css/challenge8.css new file mode 100644 index 000000000..b3e74d70d --- /dev/null +++ b/webgoat-lessons/challenge/src/main/resources/css/challenge8.css @@ -0,0 +1,43 @@ +.btn-grey{ + background-color:#D8D8D8; + color:#FFF; +} +.rating-block{ + background-color:#FAFAFA; + border:1px solid #EFEFEF; + padding:15px 15px 20px 15px; + border-radius:3px; +} +.bold{ + font-weight:700; +} +.padding-bottom-7{ + padding-bottom:7px; +} + +.review-block{ + background-color:#FAFAFA; + border:1px solid #EFEFEF; + padding:15px; + border-radius:3px; + margin-bottom:15px; +} +.review-block-name{ + font-size:12px; + margin:10px 0; +} +.review-block-date{ + font-size:12px; +} +.review-block-rate{ + font-size:13px; + margin-bottom:15px; +} +.review-block-title{ + font-size:15px; + font-weight:700; + margin-bottom:10px; +} +.review-block-description{ + font-size:13px; +} \ No newline at end of file diff --git a/webgoat-lessons/challenge/src/main/resources/html/Challenge7.html b/webgoat-lessons/challenge/src/main/resources/html/Challenge7.html new file mode 100644 index 000000000..e69601c30 --- /dev/null +++ b/webgoat-lessons/challenge/src/main/resources/html/Challenge7.html @@ -0,0 +1,82 @@ + + + + + + +

+
+
+
+
+
+
+
+
+
+

+

Forgot Password?

+

You can reset your password here.

+
+ +
+ +
+
+ + +
+
+
+ +
+
+

(c) 2017 WebGoat Cloud Platform

+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+ + + +
+
+
+
+
+ + \ No newline at end of file diff --git a/webgoat-lessons/challenge/src/main/resources/html/Challenge8.html b/webgoat-lessons/challenge/src/main/resources/html/Challenge8.html new file mode 100644 index 000000000..efaed5c85 --- /dev/null +++ b/webgoat-lessons/challenge/src/main/resources/html/Challenge8.html @@ -0,0 +1,255 @@ + + + + +
+
+ + + +
+
+ +
+ +
+
+
+

Average user rating

+

4.3 + / 5 +

+ + + + + +
+
+
+

Rating breakdown

+
+
+
5 +
+
+
+
+
+ 5 +
+
+
+
0
+
+
+
+
4 +
+
+
+
+
+ 4 +
+
+
+
0
+
+
+
+
3 +
+
+
+
+
+ 4 +
+
+
+
0
+
+
+
+
2 +
+
+
+
+
+ 2 +
+
+
+
0
+
+
+
+
1 +
+
+ +
+
+
+ 4 +
+
+
+
0
+
+
+
+ +
+
+
+ +
+ Please login or register in order to vote (comments are disabled) +
+
+
+
+ + +
August 22, 2017
1 day ago
+
+
+
+ + + + + +
+
WebGoat rocks!
+
This is a great tool to learn about security + and have some fun with a couple challenges. +
+
+
+
+
+
+ + +
July 29, 2017
12 day ago
+
+
+
+ + + + + +
+
Nice
+
I liked it and learned a couple of things. + Still some bugs sometimes though. +
+
+
+
+
+
+ + +
January 27, 2017
100 days ago
+
+
+
+ + + + + +
+
WebGoat is great
+
WebGoat teaches you web security with some great + lessons +
+
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+
+ +
+
+ + + +
+
+
+
+
+ + \ No newline at end of file diff --git a/webgoat-lessons/challenge/src/main/resources/html/Challenge9.html b/webgoat-lessons/challenge/src/main/resources/html/Challenge9.html new file mode 100644 index 000000000..49cc34ca9 --- /dev/null +++ b/webgoat-lessons/challenge/src/main/resources/html/Challenge9.html @@ -0,0 +1,109 @@ + + + + +
+
+ + +
+
+ +
+
+
+

+ + Account Access +

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

+ + Forgot your password? + +

+
+
+ +
+ +
+
+
+ +
+
+
+
+
+ +
+
+ +
+
+ + + +
+
+
+
+
+ + \ No newline at end of file diff --git a/webgoat-lessons/challenge/src/main/resources/i18n/WebGoatLabels.properties b/webgoat-lessons/challenge/src/main/resources/i18n/WebGoatLabels.properties index 9328177ef..40f882656 100644 --- a/webgoat-lessons/challenge/src/main/resources/i18n/WebGoatLabels.properties +++ b/webgoat-lessons/challenge/src/main/resources/i18n/WebGoatLabels.properties @@ -5,8 +5,13 @@ challenge3.title=Photo comments challenge4.title=Voting challenge5.title=Without password challenge6.title=Creating a new account +challenge7.title=Admin password reset +challenge8.title=Without account +challenge9.title=Changing password challenge.solved=Congratulations, you solved the challenge. Here is your flag: {0} -challenge.close=This is not the correct password for tom, please try again. +challenge.close=This is not the correct password for Larry, please try again. + +email.send=An e-mail has been send to {0} user.exists=User {0} already exists please try to register with a different username. user.created=User {0} created, please proceed to the login page. @@ -15,4 +20,10 @@ input.invalid=Input for user, email and/or password is empty or too long, please challenge.flag.correct=Congratulations you have solved the challenge!! challenge.flag.incorrect=Sorry this is not the correct flag, please try again. -ip.address.unknown=IP address unknown, e-mail has been sent. \ No newline at end of file +ip.address.unknown=IP address unknown, e-mail has been sent. + +login_failed=Login failed +login_failed.tom=Sorry only Tom can login at the moment + +required4=Missing username or password, please specify both. +user.not.larry=Please try to log in as Larry not {0}. \ No newline at end of file diff --git a/webgoat-lessons/challenge/src/main/resources/images/hi-five-cat.jpg b/webgoat-lessons/challenge/src/main/resources/images/hi-five-cat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..be29a53129aa5433fb537193df6e3240a837652e GIT binary patch literal 40693 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�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℘s228O@-jHO#7^*9j| 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 ehvyL&;eP=WN;P)8ynVxb@iD;Q%U5s5qyj4@e~ zBsY(&85!Gw)hq&7K}1`KDA!C-0Q`YKV24TFq-wSTi=wzb45~t#9*nUr##oUo%k8F( zBv7;kSQN!vBHGP6ZFwLVV=Vx-NRo7vN1j*4GO#F${K-JCY#&_
    %clcd!A4R!=-EQ|D zB3ffdR_wN+p2{RiD&n!r1*}$PK@d854B91g{}jUC-Hh9uqA2RL);)Xk0+$PdpjKx` zhYGnkF9pT(T*#Xtp!v)IwlxNMeRA!~T)-ZWN4=`8=k;tvE*3IYx8;vPY^n*OH>jKK zoq<4LgPw0LV7J>X6VXyVW4zDxAY<*cT~)B@$jzivoH2Gnk|f8T{3KxY!Xt6m@%&Bq>WT4qad?1oo~X1CIq{EOcz99RYqcN5Csjq-p!)SdUM> z31RQa{zw>(0Kd4%g*A&Oj5Vv~|1Pi{YxwXR3;Z8^m-*gsO2>1C*Dk!a?uB<-K2A3M zk`^s?BsUX%uHTwlGcvcG7~0dvEAYmpohUBoZAW^jh*q{I?0_T(-d9i#f_7v{-tW@jO5N}8#)-q{_*FBdvBebr8)F}#MC<@e%sF?^Y0SV@)V6LvI{ z16LQQt&`2e4*d-?QTX75ghlJ~=8HIW?wTf^o|b}j&lDhg#$-d#m#_BXqeJI$GdQT} zEu1qA70YJDwV?vH{2s#g(o3VCZ>81e6SjPGGMu*oBy1nH*5k@S%jGmI$xpo{05#C} z_nnLSeZeDB@oe!!hJg3hw&C1`=oz{3rFn5@%h#;~D9jEbqyNtlA58I6Wn02O;*tY@ znqLTkM*7bgIY4UsjEx1bMmf+6^o#;lSP?znny_`Nd(vXn1?qZOp&3sCtUew+rPC$| zc)8+XQ&alGgTEpeQZ$#kvt%?dV>_v`HR+vLA9$!z*Fe1w>j0|(szs}_yB~A&GA$LY zvu$0-n&QITys62T#0cw?}pgN69>vUT?!)gYB%c82b=^*V?RI74nJ@@Ak#(*2k ziUFa?&UmfcQoK}B-^^>r81VNCUFgW}0B|p_14rc;>&A>L)9JAvM(&6@4h;c^*YSQ3 zJ?AJ0uW`l>P-)#NUU5TJI#R70m#+q}&xjMpWC<1ItvzJKzVQq*2x#=Rg2>pJ(MVK$ zvhDEJ&L+ap359bQ2G*u^W7#S|sMhr{*pIoW)=b|E?v`rvYJZj_j3qF ziI@T&g7&ol$-kS_JoWvDf%cPt62F%miAG38YVIOnB1b)B>3NwAgj4S|Dyfa! z&pCDMS;M2PuqIz66xt1fGyPkJJ_x8HZ|!GhAV=$1n$l6wjlRbLItU=!YEaSo>hmAA=PZ`gXq4fAQ|fbp$!aQL10bft#|ap zH^+fvGr%M<1O1cowBKDf+Q=>U7|oIu`P&X`C0ILj?*iNL7RR%V{{c65s9Uk;^6dZs N002ovPDHLkV1k0DP5}S_ literal 0 HcmV?d00001 diff --git a/webgoat-lessons/challenge/src/main/resources/images/user3.png b/webgoat-lessons/challenge/src/main/resources/images/user3.png new file mode 100644 index 0000000000000000000000000000000000000000..b5b18a54acdb828dd3d9526780d64abbf0a37928 GIT binary patch literal 2077 zcmV+&2;%pNP)dgU`sn%9;NM6v?y$nS}m52Ft*M(V|CO~^bef@ zI)v5&rA3`7pe?(Rw%CrHI<3UVI2LW2fKa4mHwhsR2#)}H5VCumOJGU%aql^sKpe}N z*}wMp`~H5P^E>C>^SHvttjWiWm#e`4?-jpV;lZr1@_TPUxEql>K-~g(K*pquq0|Zq zhJQYoImBxXdWF?jJY$GtE(ab0rW+^U(=%PR*Y7p<({va#VD;dnd?MK^5SD=q*NmTN zrc|{A!=Fyu-^FoIfK{3AJHStYyg^A+sS1RxM9;NKWy9e?(YzosAYiq~<0CUO0L&Q7 zq>_|jt>& zc1lGcI$wfyJ9T220hf8-1i42?_{!R-c90SYgbujH)dp5&h0DQu&P{O0{#Wedv{fQ+ ze00_+2Q6S#UNDJh)_#OhLk6T1SgAD<41aInz-8Vbh+ik>(Auajx~(bl%E2S4@^G!N zDl3={S$nQ1NNz54bfg#3rOFz>-fbXd=|wm6@_rH)JOIOU;OQsf+&M!5K+%Q@O^`~u zlQ}yAt3|%4Wa9edGtVl{W71@}{|hkn#!G*^y9RW~I{WPPxyNw+O z_bq^;6q}=$wnFv0?mCGUZ%ZI#uLcvE8}Jc?@##c#^vTPE`S-z$+rY|5ZQ9)pYgfUE z<7O$?i;>Q=dGcCg!h;|suqyY>LouM8NkW!6IWT)3+<6ydW$8gQ9)@)l5RK~D$E>0Y zB~ZH~-YGS3nfF&9j~YfvZT`7AFn2!WL&EZJ|Mo@n~1qTUBm{vbU9+Rwn+)o|vt zURp|ZNH9D?54hC(I3nxyl;fwAoBikAe^>s)(hgF$x zJMd+FWgywR)JQXRQdL_!w?;X0+i$Gi#Zu-e4vkV`E z=hm5MJSKtAMn_=fzb*%BnEpa``QzZ58q@6TXyRWpdHW~mcR!cDS183lJ?`Ki+7wvA01Kw1zhVX$)Pt%)!d`qqWuS%V>s z+9HAQ5@+BtpPk(Xtqg6WIN%>Hw=W&~x0TO7uO;W|TVD$sp4QSjZ=}>)5)99G1}^n( zKt!)3=YhWkzUyO}u2phK*VXq>9jt#!9~kw%1i~e5z&jB6qPA+1Ib6AUGappfU=L^i zk|joS*wOb;J*;1=of@cG3530Fz`GEcsjV6ZtnHVMVM9HvGXPfVqy)qLZYvYsBdXNb zU~~+7C4mngf@do9yGqd`!BD?lN)lji6ftJs8Z)oXQ+e|H*4P5PKX5unI&n{Fvuq5lo15UN)n-ms*LZoUu{C*x z7kO?WGxOg@idS+-H#PPi?wPc6kxBA$T~l)4GOxWLt~Sw&Uw9b#ni{85;kX@B{~=xO zn}On=MtNMx3b!=%?ukuW57T6OD7Mz^51h_bs1tA`0_}!p%OkQNBgMhqkrt>}X@YC7 zFN-A*u1P+mO*ale^pRy)H{P5&iSSWqJ)@Uo{z&jToRFjgERj29TV3ovyMKk3kwu&L z*C1ch%Mj`(6ySN{31@R1Xg65kMAe@e^TsQ>soB-t%INT;vWeI*OMc=}?p;Py)*%dY zQ?G71!NjFYnK=6{XVa7I5Nd@;+;MA$1-^W^#(B@&ak!DaD}KVv@fx3$D0&dSErHOp z@ku$HOBdco)OyYBAl?Q(dA5femVbj!%$@DlKXAGePG7jf9hD8Ea$J4d8ycwj*-ETa zZQSn3ceYpR7)lmOW$16o44rQt{Dl({%l>%f)>Ki>19$a~n8MP<6fQP93Ui}v+y5VS zuY8h7XD7omEp9Jx1l~)u`(CGSyIc>Ul*_#C3v4H!KeL3XOCKS7+&DKD*Z*rPw`2b< zHW%QR$%#HBFVuE93A+McbXF{+bljfeCASA`wH9hdQbDouO4gfwtKmXbM3Frsph0^a9z8dpUGWlcR+TAwP=VFLMVEx%__tdlc1Msd?-=00000NkvXX Hu0mjfDS!I{ literal 0 HcmV?d00001 diff --git a/webgoat-lessons/challenge/src/main/resources/js/challenge8.js b/webgoat-lessons/challenge/src/main/resources/js/challenge8.js new file mode 100644 index 000000000..453ea0f53 --- /dev/null +++ b/webgoat-lessons/challenge/src/main/resources/js/challenge8.js @@ -0,0 +1,57 @@ +$(document).ready(function () { + loadVotes(); + average(); +}) + +function loadVotes() { + $.get("challenge/8/votes/", function (votes) { + var totalVotes = 0; + for (var i = 1; i <= 5; i++) { + totalVotes = totalVotes + votes[i]; + } + console.log(totalVotes); + for (var i = 1; i <= 5; i++) { + var percent = votes[i] * 100 / totalVotes; + console.log(percent); + var progressBar = $('#progressBar' + i); + progressBar.width(Math.round(percent) * 2 + '%'); + $("#nrOfVotes" + i).html(votes[i]); + + } + } + ); +} + +function average() { + $.get("challenge/8/votes/average", function (average) { + for (var i = 1; i <= 5; i++) { + var number = average["average"]; + $("#star" + i).removeClass('btn-warning'); + $("#star" + i).removeClass('btn-default'); + $("#star" + i).removeClass('btn-grey'); + + if (i <= number) { + $("#star" + i).addClass('btn-warning'); + } else { + $("#star" + i).addClass('btn-grey'); + } + } + } + ); +} + + +function doVote(stars) { + $("#voteResultMsg").hide(); + $.get("challenge/8/vote/" + stars, function (result) { + if (result["error"]) { + $("#voteResultMsg").addClass('alert-danger alert-dismissable'); + } else { + $("#voteResultMsg").addClass('alert-success alert-dismissable'); + } + $("#voteResultMsg").html(result["message"]); + $("#voteResultMsg").show(); + }) + loadVotes(); + average(); +} \ No newline at end of file diff --git a/webgoat-lessons/challenge/src/main/resources/js/challenge9.js b/webgoat-lessons/challenge/src/main/resources/js/challenge9.js new file mode 100644 index 000000000..eccbd7d33 --- /dev/null +++ b/webgoat-lessons/challenge/src/main/resources/js/challenge9.js @@ -0,0 +1,10 @@ +$(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'); + }); +}); \ No newline at end of file diff --git a/webgoat-lessons/challenge/src/main/resources/lessonPlans/en/Challenge_7.adoc b/webgoat-lessons/challenge/src/main/resources/lessonPlans/en/Challenge_7.adoc new file mode 100644 index 000000000..cb66a4329 --- /dev/null +++ b/webgoat-lessons/challenge/src/main/resources/lessonPlans/en/Challenge_7.adoc @@ -0,0 +1 @@ +Try to reset the password for admin. diff --git a/webgoat-lessons/challenge/src/main/resources/lessonPlans/en/Challenge_8.adoc b/webgoat-lessons/challenge/src/main/resources/lessonPlans/en/Challenge_8.adoc new file mode 100644 index 000000000..1d51b75c0 --- /dev/null +++ b/webgoat-lessons/challenge/src/main/resources/lessonPlans/en/Challenge_8.adoc @@ -0,0 +1 @@ +Can you still vote? \ No newline at end of file diff --git a/webgoat-lessons/challenge/src/main/resources/lessonPlans/en/Challenge_9.adoc b/webgoat-lessons/challenge/src/main/resources/lessonPlans/en/Challenge_9.adoc new file mode 100644 index 000000000..f2e2c1c9b --- /dev/null +++ b/webgoat-lessons/challenge/src/main/resources/lessonPlans/en/Challenge_9.adoc @@ -0,0 +1,3 @@ +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. diff --git a/webgoat-lessons/challenge/src/main/resources/templates/password_link_not_found.html b/webgoat-lessons/challenge/src/main/resources/templates/password_link_not_found.html new file mode 100644 index 000000000..6ffe93937 --- /dev/null +++ b/webgoat-lessons/challenge/src/main/resources/templates/password_link_not_found.html @@ -0,0 +1,19 @@ + + + + + + + +
    + + +
    + + × +

    + Upload a file which you need to host as an attacker. +

    +

    + Each file will be available under the following url: + http://localhost:8081/files/{username}/{filename}. +

    +

    + You can copy and paste the location from the table below. +

    +
    + +
    +
    Upload a file + +
    +
    + + +
    +
    +
    + +
    + +
    + + +
    +
    + +
+ + + + + + + + + + + + + + +
FilenameSizeLink
filenamesizelink + +
+ + + + \ No newline at end of file diff --git a/webwolf/src/main/resources/templates/fragments/footer.html b/webwolf/src/main/resources/templates/fragments/footer.html new file mode 100644 index 000000000..971d0dffb --- /dev/null +++ b/webwolf/src/main/resources/templates/fragments/footer.html @@ -0,0 +1,19 @@ + + + + +
+ +
+ +
+ © 2017 WebGoat - Use WebWolf at your own risk + +
+
+ +
+ + \ No newline at end of file diff --git a/webwolf/src/main/resources/templates/fragments/header.html b/webwolf/src/main/resources/templates/fragments/header.html new file mode 100644 index 000000000..1cf1965dd --- /dev/null +++ b/webwolf/src/main/resources/templates/fragments/header.html @@ -0,0 +1,51 @@ + + + WebWolf +
+ + + + + +
+ + +
+ +
+ + + \ No newline at end of file diff --git a/webwolf/src/main/resources/templates/home.html b/webwolf/src/main/resources/templates/home.html new file mode 100644 index 000000000..e19d5c4d9 --- /dev/null +++ b/webwolf/src/main/resources/templates/home.html @@ -0,0 +1,37 @@ + + + +
+ + + +
+ +
+ +
+ + + +
+

WebWolf

+
+

+ Some challenges requires to have a local web server running. WebWolf is for you the attacker it + helps you while solving some of the assignments and challenges within + WebGoat. An assignment might for example require you to serve a file or connect back to your own + environment or to receive an e-mail. + In order to not let you run WebGoat open and connected to the internet we provided these tools in this + application, called WebWolf. +

+
+
+ + +
+ + +
+ + + \ No newline at end of file diff --git a/webwolf/src/main/resources/templates/login.html b/webwolf/src/main/resources/templates/login.html new file mode 100644 index 000000000..6f9a4e07c --- /dev/null +++ b/webwolf/src/main/resources/templates/login.html @@ -0,0 +1,58 @@ + + + + WebWolf +
+ + + +
+ +
+ +
+
+
+
+

Sign in

+ Use your WebGoat account. +
+
+
+ Invalid username or password. +
+
+
+
+ You have been logged out. +
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + + \ No newline at end of file diff --git a/webwolf/src/main/resources/templates/mailbox.html b/webwolf/src/main/resources/templates/mailbox.html new file mode 100644 index 000000000..8a78d9697 --- /dev/null +++ b/webwolf/src/main/resources/templates/mailbox.html @@ -0,0 +1,150 @@ + + + + WebWolf +
+ + + +
+ + + +
+ + +
+ + × +

+ The mailbox of you as an attacker, all the mail send to {user}@{random} will be send to this mailbox. +

+

+ Only the user part is important the domain can be anything +

+
+ +
+
+
+
+
+ + +
+
+
+ + +
+ + +
+
+ 1 50 of +
+ + +
+
+
+
+
+
+
+ COMPOSE +
+ +
+
+ + + +
+ +
+
+
+ This tab is empty. +
+
+
+
+
+ Why the name "WebGoat"? Developers should not feel bad about not knowing security. Even the best programmers make security errors. What they need is a scapegoat, right? Just blame it on the 'Goat! +
+
+
+ This tab is empty. +
+
+
+
+
+
+ +
+ + \ No newline at end of file diff --git a/webwolf/src/main/resources/templates/requests.html b/webwolf/src/main/resources/templates/requests.html new file mode 100644 index 000000000..15c035d40 --- /dev/null +++ b/webwolf/src/main/resources/templates/requests.html @@ -0,0 +1,56 @@ + + + +
+ + + +
+ + + +
+ + +
+ + × +

+ Challenges in which you need to call your hacker machine WebWolf offers a simple httpd + server functionality which only logs the incoming request. You can use the following URL: + http://localhost:8081/ and the incoming request will be available below. +

+

+ This is by no means a substitution of httpd but it offers enough functionality to callback to a safe + environment and does not require you to host your own httpd server on your local machine. +

+
+ + +

Requests

+
+
+ +
+
+
+
+                    
+
+
+
+
+ + + +
+ + \ No newline at end of file