Add path traversal lesson

This commit is contained in:
Nanne Baars 2020-03-03 21:37:24 +01:00 committed by Nanne Baars
parent c4c28f544f
commit 6c25cf8e43
72 changed files with 1286 additions and 146 deletions

View File

@ -64,7 +64,7 @@ public abstract class AssignmentEndpoint {
* @param assignment * @param assignment
*/ */
protected AttackResult.AttackResultBuilder success(AssignmentEndpoint assignment) { protected AttackResult.AttackResultBuilder success(AssignmentEndpoint assignment) {
return AttackResult.builder(messages).lessonCompleted(true).feedback("assignment.solved").assignment(assignment); return AttackResult.builder(messages).lessonCompleted(true).attemptWasMade().feedback("assignment.solved").assignment(assignment);
} }
/** /**
@ -79,7 +79,7 @@ public abstract class AssignmentEndpoint {
* @param assignment * @param assignment
*/ */
protected AttackResult.AttackResultBuilder failed(AssignmentEndpoint assignment) { protected AttackResult.AttackResultBuilder failed(AssignmentEndpoint assignment) {
return AttackResult.builder(messages).lessonCompleted(false).feedback("assignment.not.solved").assignment(assignment); return AttackResult.builder(messages).lessonCompleted(false).attemptWasMade().feedback("assignment.not.solved").assignment(assignment);
} }
protected AttackResult.AttackResultBuilder informationMessage(AssignmentEndpoint assignment) { protected AttackResult.AttackResultBuilder informationMessage(AssignmentEndpoint assignment) {

View File

@ -29,8 +29,6 @@ import lombok.Getter;
import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringEscapeUtils;
import org.owasp.webgoat.i18n.PluginMessages; import org.owasp.webgoat.i18n.PluginMessages;
import java.util.Objects;
public class AttackResult { public class AttackResult {
@ -43,6 +41,7 @@ public class AttackResult {
private String output; private String output;
private Object[] outputArgs; private Object[] outputArgs;
private AssignmentEndpoint assignment; private AssignmentEndpoint assignment;
private boolean attemptWasMade = false;
public AttackResultBuilder(PluginMessages messages) { public AttackResultBuilder(PluginMessages messages) {
this.messages = messages; this.messages = messages;
@ -80,8 +79,13 @@ public class AttackResult {
return this; return this;
} }
public AttackResultBuilder attemptWasMade() {
this.attemptWasMade = true;
return this;
}
public AttackResult build() { public AttackResult build() {
return new AttackResult(lessonCompleted, messages.getMessage(feedbackResourceBundleKey, feedbackArgs), messages.getMessage(output, output, outputArgs), assignment.getClass().getSimpleName()); return new AttackResult(lessonCompleted, messages.getMessage(feedbackResourceBundleKey, feedbackArgs), messages.getMessage(output, output, outputArgs), assignment.getClass().getSimpleName(), attemptWasMade);
} }
public AttackResultBuilder assignment(AssignmentEndpoint assignment) { public AttackResultBuilder assignment(AssignmentEndpoint assignment) {
@ -98,12 +102,15 @@ public class AttackResult {
private String output; private String output;
@Getter @Getter
private final String assignment; private final String assignment;
@Getter
private boolean attemptWasMade;
public AttackResult(boolean lessonCompleted, String feedback, String output, String assignment) { public AttackResult(boolean lessonCompleted, String feedback, String output, String assignment, boolean attemptWasMade) {
this.lessonCompleted = lessonCompleted; this.lessonCompleted = lessonCompleted;
this.feedback = StringEscapeUtils.escapeJson(feedback); this.feedback = StringEscapeUtils.escapeJson(feedback);
this.output = StringEscapeUtils.escapeJson(output); this.output = StringEscapeUtils.escapeJson(output);
this.assignment = assignment; this.assignment = assignment;
this.attemptWasMade = attemptWasMade;
} }
public static AttackResultBuilder builder(PluginMessages messages) { public static AttackResultBuilder builder(PluginMessages messages) {

View File

@ -0,0 +1,100 @@
package org.owasp.webgoat;
import io.restassured.RestAssured;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.security.core.token.Sha512DigestUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Map;
public class PathTraversalTest extends IntegrationTest {
private static String OS = System.getProperty("os.name").toLowerCase();
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
private File folder;
@Before
public void setup() throws IOException {
this.folder = temporaryFolder.newFolder();
}
@Test
public void assignment1() throws IOException {
startLesson("PathTraversal");
var fileToUpload = temporaryFolder.newFile("test.jpg");
Files.write(fileToUpload.toPath(), "This is a test" .getBytes());
Assert.assertThat(
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.multiPart("uploadedFile", "test.jpg", Files.readAllBytes(fileToUpload.toPath()))
.param("fullName", "../John Doe")
.post("/WebGoat/PathTraversal/profile-upload")
.then()
.statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(true));
}
@Test
public void assignment2() throws IOException {
startLesson("PathTraversal");
var fileToUpload = temporaryFolder.newFile("test.jpg");
Files.write(fileToUpload.toPath(), "This is a test" .getBytes());
Assert.assertThat(
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.multiPart("uploadedFileFix", "test.jpg", Files.readAllBytes(fileToUpload.toPath()))
.param("fullNameFix", "..././John Doe")
.post("/WebGoat/PathTraversal/profile-upload-fix")
.then()
.statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(true));
}
@Test
public void assignment3() throws IOException {
startLesson("PathTraversal");
var fileToUpload = temporaryFolder.newFile("test.jpg");
Files.write(fileToUpload.toPath(), "This is a test" .getBytes());
Assert.assertThat(
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.multiPart("uploadedFileRetrieval", "../test.jpg", Files.readAllBytes(fileToUpload.toPath()))
.post("/WebGoat/PathTraversal/profile-upload-remove-user-input")
.then()
.statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(true));
}
@Test
public void assignment4() throws IOException {
startLesson("PathTraversal");
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.get("/WebGoat/PathTraversal/random?id=../../path-traversal-secret")
.then()
.statusCode(200)
.content(CoreMatchers.is("You found it submit the SHA-512 hash of your username as answer"));
checkAssignment("/WebGoat/PathTraversal/random", Map.of("secret", Sha512DigestUtils.shaHex(getWebgoatUser())), true);
}
}

View File

@ -23,8 +23,7 @@
<form class="attack-form" accept-charset="UNKNOWN" id="verify-account-form" <form class="attack-form" accept-charset="UNKNOWN" id="verify-account-form"
method="POST" name="form" method="POST" name="form"
successCallback="onBypassResponse" successCallback="onBypassResponse"
action="/WebGoat/auth-bypass/verify-account" action="/WebGoat/auth-bypass/verify-account">
enctype="application/json;charset=UTF-8">
<p>Verify Your Account by answering the questions below:</p> <p>Verify Your Account by answering the questions below:</p>
<p>What is the name of your favorite teacher?</p> <p>What is the name of your favorite teacher?</p>
@ -45,7 +44,6 @@
method="POST" name="form" method="POST" name="form"
successCallback="onBypassResponse" successCallback="onBypassResponse"
action="/WebGoat/auth-bypass/verify-account" action="/WebGoat/auth-bypass/verify-account"
enctype="application/json;charset=UTF-8"
style="display:none"><!-- start off hidden --> style="display:none"><!-- start off hidden -->
<p>Please provide a new password for your account</p> <p>Please provide a new password for your account</p>

View File

@ -16,8 +16,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" name="fieldRestrictions" <form class="attack-form" accept-charset="UNKNOWN" name="fieldRestrictions"
method="POST" method="POST"
action="/WebGoat/BypassRestrictions/FieldRestrictions" action="/WebGoat/BypassRestrictions/FieldRestrictions">
enctype="application/json;charset=UTF-8">
<div>Select field with two possible values</div> <div>Select field with two possible values</div>
<select name="select"> <select name="select">
@ -49,7 +48,6 @@
id="frontendValidation" id="frontendValidation"
method="POST" method="POST"
action="/WebGoat/BypassRestrictions/frontendValidation/" action="/WebGoat/BypassRestrictions/frontendValidation/"
enctype="application/json;charset=UTF-8"
onsubmit="return validate()"> onsubmit="return validate()">
<div> <div>
<strong>Field 1:</strong> exactly three lowercase characters(^[a-z]{3}$) <strong>Field 1:</strong> exactly three lowercase characters(^[a-z]{3}$)

View File

@ -18,8 +18,7 @@
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/challenge/1" action="/WebGoat/challenge/1"
style="width: 200px;" style="width: 200px;">
enctype="application/json;charset=UTF-8">
<div class="form-group"> <div class="form-group">
<label for="exampleInputEmail1" th:text="#{username}">Username</label> <label for="exampleInputEmail1" th:text="#{username}">Username</label>

View File

@ -25,8 +25,7 @@
<div class="col-lg-12"> <div class="col-lg-12">
<form id="login-form" class="attack-form" accept-charset="UNKNOWN" <form id="login-form" class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/challenge/5" action="/WebGoat/challenge/5" role="form">
enctype="application/json;charset=UTF-8" role="form">
<div class="form-group"> <div class="form-group">
<input type="text" name="username_login" id="username4" tabindex="1" <input type="text" name="username_login" id="username4" tabindex="1"
class="form-control" placeholder="Username" value=""/> class="form-control" placeholder="Username" value=""/>

View File

@ -29,8 +29,7 @@
<div class="col-lg-12"> <div class="col-lg-12">
<form id="login-form" class="attack-form" accept-charset="UNKNOWN" <form id="login-form" class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/challenge/6" action="/WebGoat/challenge/6" role="form">
enctype="application/json;charset=UTF-8" role="form">
<div class="form-group"> <div class="form-group">
<input type="text" name="username_login" id="username4" tabindex="1" <input type="text" name="username_login" id="username4" tabindex="1"
class="form-control" placeholder="Username" value=""/> class="form-control" placeholder="Username" value=""/>
@ -65,8 +64,7 @@
</form> </form>
<form id="register-form" class="attack-form" accept-charset="UNKNOWN" <form id="register-form" class="attack-form" accept-charset="UNKNOWN"
method="PUT" name="form" method="PUT" name="form"
action="/WebGoat/challenge/6" action="/WebGoat/challenge/6" style="display: none;" role="form">
enctype="application/json;charset=UTF-8" style="display: none;" role="form">
<div class="form-group"> <div class="form-group">
<input type="text" name="username_reg" id="username" tabindex="1" <input type="text" name="username_reg" id="username" tabindex="1"
class="form-control" placeholder="Username" value=""/> class="form-control" placeholder="Username" value=""/>

View File

@ -28,8 +28,7 @@ f94008f801fceb8833a30fe56a8b26976347edcf First version of WebGoat Cloud website
<form id="login-form" class="attack-form" accept-charset="UNKNOWN" <form id="login-form" class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/challenge/7" action="/WebGoat/challenge/7" role="form">
enctype="application/json;charset=UTF-8" role="form">
<div class="form-group"> <div class="form-group">
<div class="input-group"> <div class="input-group">

View File

@ -24,8 +24,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="DOMFollowUp" method="POST" name="DOMFollowUp"
action="/WebGoat/ChromeDevTools/dummy" action="/WebGoat/ChromeDevTools/dummy">
enctype="application/json;charset=UTF-8">
<input name="successMessage" value="" type="TEXT" /> <input name="successMessage" value="" type="TEXT" />
<input name="submitMessage" value="Submit" type="SUBMIT"/> <input name="submitMessage" value="Submit" type="SUBMIT"/>
</form> </form>
@ -46,8 +45,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/ChromeDevTools/network" action="/WebGoat/ChromeDevTools/network">
enctype="application/json;charset=UTF-8">
<script> <script>
// sample custom javascript in the recommended way ... // sample custom javascript in the recommended way ...
// a namespace has been assigned for it, but you can roll your own if you prefer // a namespace has been assigned for it, but you can roll your own if you prefer
@ -68,8 +66,7 @@
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/ChromeDevTools/network" action="/WebGoat/ChromeDevTools/network">
enctype="application/json;charset=UTF-8">
<table> <table>
<tr> <tr>
<td>What is the number you found: </td> <td>What is the number you found: </td>

View File

@ -29,8 +29,7 @@
<div class="container-fluid"> <div class="container-fluid">
<form id="quiz-form" class="attack-form" accept-charset="UNKNOWN" <form id="quiz-form" class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="cia/quiz" action="cia/quiz" role="form">
enctype="application/json;charset=UTF-8" role="form">
<div id="q_container"></div> <div id="q_container"></div>
<br /> <br />
<input name="Quiz_solutions" value="Submit answers" type="SUBMIT"/> <input name="Quiz_solutions" value="Submit answers" type="SUBMIT"/>

View File

@ -83,8 +83,7 @@
<div class="container-fluid"> <div class="container-fluid">
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/clientSideFiltering/getItForFree" action="/WebGoat/clientSideFiltering/getItForFree">
enctype="application/json;charset=UTF-8">
<input id="discount" type="hidden" value="0"/> <input id="discount" type="hidden" value="0"/>
<div class="row"> <div class="row">

View File

@ -37,8 +37,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" name="intercept-request" <form class="attack-form" accept-charset="UNKNOWN" name="intercept-request"
method="POST" method="POST"
action="/WebGoat/HttpBasics/intercept-request" action="/WebGoat/HttpBasics/intercept-request">
enctype="application/json;charset=UTF-8">
<input type="text" value="doesn't matter really" name="changeMe" /> <input type="text" value="doesn't matter really" name="changeMe" />
<input type="submit" value="Submit" /> <input type="submit" value="Submit" />

View File

@ -12,8 +12,7 @@
<div id="lessonContent"> <div id="lessonContent">
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/CrossSiteScripting/attack1" action="/WebGoat/CrossSiteScripting/attack1">
enctype="application/json;charset=UTF-8">
<table> <table>
<tr> <tr>
<td>Were the cookies the same on each tab?</td> <td>Were the cookies the same on each tab?</td>
@ -48,8 +47,7 @@
<div id="lessonContent"> <div id="lessonContent">
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="GET" name="xss-5a" method="GET" name="xss-5a"
action="/WebGoat/CrossSiteScripting/attack5a" action="/WebGoat/CrossSiteScripting/attack5a">
enctype="application/json;charset=UTF-8">
<hr width="90%" /> <hr width="90%" />
<center> <center>
<h1>Shopping Cart</h1> <h1>Shopping Cart</h1>
@ -145,8 +143,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="DOMTestRoute" method="POST" name="DOMTestRoute"
action="/WebGoat/CrossSiteScripting/attack6a" action="/WebGoat/CrossSiteScripting/attack6a">
enctype="application/json;charset=UTF-8">
<input name="DOMTestRoute" value="" type="TEXT" /> <input name="DOMTestRoute" value="" type="TEXT" />
<input name="SubmitTestRoute" value="Submit" type="SUBMIT"/> <input name="SubmitTestRoute" value="Submit" type="SUBMIT"/>
</form> </form>
@ -161,8 +158,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="DOMFollowUp" method="POST" name="DOMFollowUp"
action="/WebGoat/CrossSiteScripting/dom-follow-up" action="/WebGoat/CrossSiteScripting/dom-follow-up">
enctype="application/json;charset=UTF-8">
<input name="successMessage" value="" type="TEXT" /> <input name="successMessage" value="" type="TEXT" />
<input name="submitMessage" value="Submit" type="SUBMIT"/> <input name="submitMessage" value="Submit" type="SUBMIT"/>
</form> </form>
@ -182,8 +178,7 @@
<div class="container-fluid"> <div class="container-fluid">
<form id="quiz-form" class="attack-form" accept-charset="UNKNOWN" <form id="quiz-form" class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/CrossSiteScripting/quiz" action="/WebGoat/CrossSiteScripting/quiz" role="form">
enctype="application/json;charset=UTF-8" role="form">
<div id="q_container"></div> <div id="q_container"></div>
<br /> <br />
<input name="Quiz_solutions" value="Submit answers" type="SUBMIT"/> <input name="Quiz_solutions" value="Submit answers" type="SUBMIT"/>

View File

@ -21,7 +21,7 @@
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content8b.adoc"></div> <div class="adoc-content" th:replace="doc:CrossSiteScripting_content8b.adoc"></div>
<div class="attack-container" style="height: 100%; border: none !important;min-height: 450px;"> <div class="attack-container" style="height: 100%; border: none !important;min-height: 450px;">
<form id="codesubmit" style="height: 100%; min-height: 350px;" class="attack-form" accept-charset="UNKNOWN" method="POST" name="form" action="/WebGoat/CrossSiteScripting/attack3" enctype="application/json;charset=UTF-8"> <form id="codesubmit" style="height: 100%; min-height: 350px;" class="attack-form" accept-charset="UNKNOWN" method="POST" name="form" action="/WebGoat/CrossSiteScripting/attack3">
<div> <div>
<div id="editor" style="position: absolute; top: 0; right: 0; bottom: 0; left: 0; height: 350px;" name="editor"></div> <div id="editor" style="position: absolute; top: 0; right: 0; bottom: 0; left: 0; height: 350px;" name="editor"></div>
<script th:src="@{/js/libs/ace/src-noconflict/ace.js}" type="text/javascript" charset="utf-8"></script> <script th:src="@{/js/libs/ace/src-noconflict/ace.js}" type="text/javascript" charset="utf-8"></script>
@ -41,7 +41,7 @@
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content8c.adoc"></div> <div class="adoc-content" th:replace="doc:CrossSiteScripting_content8c.adoc"></div>
<div class="attack-container" style="height: 100%; border: none !important;min-height: 450px;"> <div class="attack-container" style="height: 100%; border: none !important;min-height: 450px;">
<form id="codesubmit2" style="height: 100%; min-height: 350px;" class="attack-form" accept-charset="UNKNOWN" method="POST" name="form" action="/WebGoat/CrossSiteScripting/attack4" enctype="application/json;charset=UTF-8"> <form id="codesubmit2" style="height: 100%; min-height: 350px;" class="attack-form" accept-charset="UNKNOWN" method="POST" name="form" action="/WebGoat/CrossSiteScripting/attack4">
<div> <div>
<div id="editor2" style="position: absolute; top: 0; right: 0; bottom: 0; left: 0; height: 350px;" name="editor2"></div> <div id="editor2" style="position: absolute; top: 0; right: 0; bottom: 0; left: 0; height: 350px;" name="editor2"></div>
<script th:src="@{/js/libs/ace/src-noconflict/ace.js}" type="text/javascript" charset="utf-8"></script> <script th:src="@{/js/libs/ace/src-noconflict/ace.js}" type="text/javascript" charset="utf-8"></script>

View File

@ -67,8 +67,7 @@
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="DOMFollowUp" method="POST" name="DOMFollowUp"
action="/WebGoat/CrossSiteScripting/stored-xss-follow-up" action="/WebGoat/CrossSiteScripting/stored-xss-follow-up">
enctype="application/json;charset=UTF-8">
<input name="successMessage" value="" type="TEXT" /> <input name="successMessage" value="" type="TEXT" />
<input name="submitMessage" value="Submit" type="SUBMIT"/> <input name="submitMessage" value="Submit" type="SUBMIT"/>
</form> </form>

View File

@ -17,8 +17,7 @@
method="POST" name="form1" method="POST" name="form1"
target="_blank" target="_blank"
successCallback="" successCallback=""
action="/WebGoat/csrf/basic-get-flag" action="/WebGoat/csrf/basic-get-flag">
enctype="application/json;charset=UTF-8">
<input name="csrf" type="hidden" value="false"/> <input name="csrf" type="hidden" value="false"/>
<input type="submit" name="submit"/> <input type="submit" name="submit"/>
@ -36,8 +35,7 @@
<form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-1" <form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-1"
method="POST" name="form2" method="POST" name="form2"
successCallback="" successCallback=""
action="/WebGoat/csrf/confirm-flag-1" action="/WebGoat/csrf/confirm-flag-1">
enctype="application/json;charset=UTF-8">
Confirm Flag Value: Confirm Flag Value:
<input type="text" length="6" name="confirmFlagVal" value=""/> <input type="text" length="6" name="confirmFlagVal" value=""/>
@ -214,8 +212,7 @@
</div> </div>
<form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-feedback" <form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-feedback"
method="POST" name="form2" method="POST" name="form2"
action="/WebGoat/csrf/feedback" action="/WebGoat/csrf/feedback">
enctype="application/json;charset=UTF-8">
Confirm Flag Value: Confirm Flag Value:
<input type="text" length="6" name="confirmFlagVal" value=""/> <input type="text" length="6" name="confirmFlagVal" value=""/>
@ -239,8 +236,7 @@
</div> </div>
<form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-login" <form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-login"
method="POST" name="form2" method="POST" name="form2"
action="/WebGoat/csrf/login" action="/WebGoat/csrf/login">
enctype="application/json;charset=UTF-8">
Press the button below when your are logged in as the other user<br/> Press the button below when your are logged in as the other user<br/>

View File

@ -13,8 +13,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" id="task" name="task" <form class="attack-form" accept-charset="UNKNOWN" id="task" name="task"
method="POST" method="POST"
action="/WebGoat/HtmlTampering/task" action="/WebGoat/HtmlTampering/task">
enctype="application/json;charset=UTF-8">
<script> <script>
var regex = /^2999.99$/; var regex = /^2999.99$/;
var price = 2999.99; var price = 2999.99;

View File

@ -21,11 +21,10 @@
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like --> <!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/HttpBasics/attack1" action="/WebGoat/HttpBasics/attack1">
enctype="application/json;charset=UTF-8">
<div id="lessonContent"> <div id="lessonContent">
<form accept-charset="UNKNOWN" method="POST" name="form" <form accept-charset="UNKNOWN" method="POST" name="form"
action="#attack/307/100" enctype=""> action="#attack/307/100">
Enter Your Name: <input name="person" value="" type="TEXT"/><input Enter Your Name: <input name="person" value="" type="TEXT"/><input
name="SUBMIT" value="Go!" type="SUBMIT"/> name="SUBMIT" value="Go!" type="SUBMIT"/>
</form> </form>
@ -52,8 +51,7 @@
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like --> <!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/HttpBasics/attack2" action="/WebGoat/HttpBasics/attack2">
enctype="application/json;charset=UTF-8">
<script> <script>
// sample custom javascript in the recommended way ... // sample custom javascript in the recommended way ...
// a namespace has been assigned for it, but you can roll your own if you prefer // a namespace has been assigned for it, but you can roll your own if you prefer

View File

@ -32,8 +32,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" name="intercept-request" <form class="attack-form" accept-charset="UNKNOWN" name="intercept-request"
method="POST" method="POST"
action="/WebGoat/HttpProxies/intercept-request" action="/WebGoat/HttpProxies/intercept-request">
enctype="application/json;charset=UTF-8">
<input type="text" value="doesn't matter really" name="changeMe" /> <input type="text" value="doesn't matter really" name="changeMe" />
<input type="submit" value="Submit" /> <input type="submit" value="Submit" />

View File

@ -22,8 +22,7 @@
<!-- modify the action to point to the intended endpoint --> <!-- modify the action to point to the intended endpoint -->
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/IDOR/login" action="/WebGoat/IDOR/login">
enctype="application/json;charset=UTF-8">
<table> <table>
<tr> <tr>
<td>user/pass</td> <td>user/pass</td>
@ -58,8 +57,7 @@
<!-- modify the action to point to the intended endpoint --> <!-- modify the action to point to the intended endpoint -->
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="GET" name="form" method="GET" name="form"
action="/WebGoat/IDOR/profile" action="/WebGoat/IDOR/profile">
enctype="application/json;charset=UTF-8">
<script th:src="@{/lesson_js/idor.js}" /> <script th:src="@{/lesson_js/idor.js}" />
<input name="View Profile" value="View Profile" type="button" onclick="onViewProfile();" /> <input name="View Profile" value="View Profile" type="button" onclick="onViewProfile();" />
@ -82,8 +80,7 @@
<!-- modify the action to point to the intended endpoint --> <!-- modify the action to point to the intended endpoint -->
<form class="attack-form" <form class="attack-form"
method="POST" name="diff-form" method="POST" name="diff-form"
action="IDOR/diff-attributes" action="IDOR/diff-attributes">
enctype="application/json;charset=UTF-8">
<input name="attributes" type="text" /> <input name="attributes" type="text" />
<input name="Submit Diffs" value="Submit Diffs" type="submit" /> <input name="Submit Diffs" value="Submit Diffs" type="submit" />
</form> </form>
@ -110,8 +107,7 @@
<!-- modify the action to point to the intended endpoint --> <!-- modify the action to point to the intended endpoint -->
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/IDOR/profile/alt-path" action="/WebGoat/IDOR/profile/alt-path">
enctype="application/json;charset=UTF-8">
<div class="adoc-content" th:replace="doc:IDOR_inputAltPath.adoc"></div> <div class="adoc-content" th:replace="doc:IDOR_inputAltPath.adoc"></div>
<input name="url" value="WebGoat/" type="text"/> <input name="url" value="WebGoat/" type="text"/>
<input name="submit" value="Submit" type="SUBMIT"/> <input name="submit" value="Submit" type="SUBMIT"/>
@ -138,8 +134,7 @@
<!-- modify the action to point to the intended endpoint --> <!-- modify the action to point to the intended endpoint -->
<form class="attack-form" accept-charset="UNKNOWN" id="view-other" <form class="attack-form" accept-charset="UNKNOWN" id="view-other"
method="GET" name="view-other-profile" method="GET" name="view-other-profile"
action="/WebGoat/IDOR/profile/{userId}" action="/WebGoat/IDOR/profile/{userId}">
enctype="application/json;charset=UTF-8">
<script th:src="@{/lesson_js/idor.js}" /> <script th:src="@{/lesson_js/idor.js}" />
<input name="View Profile" value="View Profile" type="submit" /> <input name="View Profile" value="View Profile" type="submit" />
@ -163,8 +158,7 @@
<!-- modify the action to point to the intended endpoint --> <!-- modify the action to point to the intended endpoint -->
<form class="attack-form" accept-charset="UNKNOWN" id="edit-other" <form class="attack-form" accept-charset="UNKNOWN" id="edit-other"
method="GET" name="edit-other-profile" method="GET" name="edit-other-profile"
action="/WebGoat/IDOR/profile/{userId}" action="/WebGoat/IDOR/profile/{userId}">
enctype="application/json;charset=UTF-8">
<script th:src="@{/lesson_js/idor.js}" /> <script th:src="@{/lesson_js/idor.js}" />
<input name="View Profile" value="View Profile" type="submit" /> <input name="View Profile" value="View Profile" type="submit" />

View File

@ -27,8 +27,7 @@
language="JavaScript"></script> language="JavaScript"></script>
<form class="attack-form" accept-charset="UNKNOWN" name="task" <form class="attack-form" accept-charset="UNKNOWN" name="task"
method="POST" method="POST"
action="/WebGoat/InsecureDeserialization/task" action="/WebGoat/InsecureDeserialization/task">
enctype="application/json;charset=UTF-8">
<input type="textarea" rows="4" cols="40" value="" name="token" placeholder="token"/> <input type="textarea" rows="4" cols="40" value="" name="token" placeholder="token"/>
<input type="submit" value="Submit" /> <input type="submit" value="Submit" />

View File

@ -18,8 +18,7 @@
language="JavaScript"></script> language="JavaScript"></script>
<form class="attack-form" accept-charset="UNKNOWN" name="task" <form class="attack-form" accept-charset="UNKNOWN" name="task"
method="POST" method="POST"
action="#attack/307/100" action="#attack/307/100">
enctype="application/json;charset=UTF-8">
<!--- <!---
<input type="hidden" value="" name="username" id="SecretUsername"/> <input type="hidden" value="" name="username" id="SecretUsername"/>
<input type="hidden" value="" name="password" id="SecretPassword"/> <input type="hidden" value="" name="password" id="SecretPassword"/>
@ -30,8 +29,7 @@
<br></br> <br></br>
<form class="attack-form" accept-charset="UNKNOWN" name="task" <form class="attack-form" accept-charset="UNKNOWN" name="task"
method="POST" method="POST"
action="/WebGoat/InsecureLogin/task" action="/WebGoat/InsecureLogin/task">
enctype="application/json;charset=UTF-8">
<input type="text" value="" name="username" placeholder="username"/> <input type="text" value="" name="username" placeholder="username"/>
<input type="password" value="" name="password" placeholder="password" /> <input type="password" value="" name="password" placeholder="password" />

View File

@ -72,8 +72,7 @@ $(document).ready(
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" method="POST"
successCallback="jwtSigningCallback" successCallback="jwtSigningCallback"
action="/WebGoat/JWT/votings" action="/WebGoat/JWT/votings">
enctype="application/json;charset=UTF-8">
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
@ -167,8 +166,7 @@ $(document).ready(
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" method="POST"
additionalHeaders="addBearerToken" additionalHeaders="addBearerToken"
action="/WebGoat/JWT/refresh/checkout" action="/WebGoat/JWT/refresh/checkout">
enctype="application/json;charset=UTF-8">
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="col-sm-12 col-md-10 col-md-offset-1"> <div class="col-sm-12 col-md-10 col-md-offset-1">
@ -284,8 +282,7 @@ $(document).ready(
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" method="POST"
action="/WebGoat/JWT/final/delete?token=eyJ0eXAiOiJKV1QiLCJraWQiOiJ3ZWJnb2F0X2tleSIsImFsZyI6IkhTMjU2In0.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJpYXQiOjE1MjQyMTA5MDQsImV4cCI6MTYxODkwNTMwNCwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJqZXJyeUB3ZWJnb2F0LmNvbSIsInVzZXJuYW1lIjoiSmVycnkiLCJFbWFpbCI6ImplcnJ5QHdlYmdvYXQuY29tIiwiUm9sZSI6WyJDYXQiXX0.CgZ27DzgVW8gzc0n6izOU638uUCi6UhiOJKYzoEZGE8" action="/WebGoat/JWT/final/delete?token=eyJ0eXAiOiJKV1QiLCJraWQiOiJ3ZWJnb2F0X2tleSIsImFsZyI6IkhTMjU2In0.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJpYXQiOjE1MjQyMTA5MDQsImV4cCI6MTYxODkwNTMwNCwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJqZXJyeUB3ZWJnb2F0LmNvbSIsInVzZXJuYW1lIjoiSmVycnkiLCJFbWFpbCI6ImplcnJ5QHdlYmdvYXQuY29tIiwiUm9sZSI6WyJDYXQiXX0.CgZ27DzgVW8gzc0n6izOU638uUCi6UhiOJKYzoEZGE8">
enctype="application/json;charset=UTF-8">
<div class="container-fluid"> <div class="container-fluid">
<div id="toast"></div> <div id="toast"></div>
<div class="col-sm-6 col-md-4 col-lg-3 mt-4"> <div class="col-sm-6 col-md-4 col-lg-3 mt-4">

View File

@ -21,8 +21,7 @@
<div class="col-md-4"> <div class="col-md-4">
<form class="attack-form" accept-charset="UNKNOWN" novalidate="novalidate" <form class="attack-form" accept-charset="UNKNOWN" novalidate="novalidate"
method="POST" method="POST"
action="/WebGoat/PasswordReset/simple-mail" action="/WebGoat/PasswordReset/simple-mail">
enctype="application/json;charset=UTF-8">
<div style="padding: 20px;" id="password-login-2"> <div style="padding: 20px;" id="password-login-2">
<h4 style="border-bottom: 1px solid #c5c5c5;"><i class="glyphicon glyphicon-user"></i> <h4 style="border-bottom: 1px solid #c5c5c5;"><i class="glyphicon glyphicon-user"></i>
Account Account
@ -56,8 +55,7 @@
<form class="attack-form" accept-charset="UNKNOWN" novalidate="novalidate" <form class="attack-form" accept-charset="UNKNOWN" novalidate="novalidate"
method="POST" method="POST"
action="/WebGoat/PasswordReset/simple-mail/reset" action="/WebGoat/PasswordReset/simple-mail/reset">
enctype="application/json;charset=UTF-8">
<div style="display: none;" id="password-reset-2"> <div style="display: none;" id="password-reset-2">
<h4 class="">Forgot your password?</h4> <h4 class="">Forgot your password?</h4>
@ -104,8 +102,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" method="POST"
action="/WebGoat/PasswordReset/questions" action="/WebGoat/PasswordReset/questions">
enctype="application/json;charset=UTF-8">
<div class="container-fluid"> <div class="container-fluid">
<div class="col-md-4"> <div class="col-md-4">
<article class="card-body"> <article class="card-body">
@ -145,8 +142,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/PasswordReset/SecurityQuestions" action="/WebGoat/PasswordReset/SecurityQuestions">
enctype="application/json;charset=UTF-8">
<select name="question"> <select name="question">
<option>What is your favorite animal?</option> <option>What is your favorite animal?</option>
<option>In what year was your mother born?</option> <option>In what year was your mother born?</option>
@ -178,8 +174,7 @@
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" method="POST"
action="/WebGoat/PasswordReset/reset/login" action="/WebGoat/PasswordReset/reset/login">
enctype="application/json;charset=UTF-8">
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">
@ -191,7 +186,7 @@
<form id="login-form" class="attack-form" accept-charset="UNKNOWN" <form id="login-form" class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/PasswordReset/reset/login" action="/WebGoat/PasswordReset/reset/login"
enctype="application/json;charset=UTF-8" role="form"> role="form">
<fieldset> <fieldset>
<div class="form-group input-group"> <div class="form-group input-group">
<span class="input-group-addon"> @ </span> <span class="input-group-addon"> @ </span>
@ -227,7 +222,7 @@
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/PasswordReset/ForgotPassword/create-password-reset-link" action="/WebGoat/PasswordReset/ForgotPassword/create-password-reset-link"
enctype="application/json;charset=UTF-8" role="form"> role="form">
<fieldset> <fieldset>
<span class="help-block"> <span class="help-block">
Email address you use to log in to your account Email address you use to log in to your account

View File

@ -0,0 +1,11 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>path-traversal</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId>
<version>v8.0.0-SNAPSHOT</version>
</parent>
</project>

View File

@ -0,0 +1,41 @@
/*
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
*
* Copyright (c) 2002 - 2019 Bruce Mayhew
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Getting Source ==============
*
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
*/
package org.owasp.webgoat.path_traversal;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.Lesson;
import org.springframework.stereotype.Component;
@Component
public class PathTraversal extends Lesson {
@Override
public Category getDefaultCategory() {
return Category.INJECTION;
}
@Override
public String getTitle() {
return "path-traversal-title";
}
}

View File

@ -0,0 +1,41 @@
package org.owasp.webgoat.path_traversal;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.WebSession;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Base64;
import static org.springframework.http.MediaType.ALL_VALUE;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@RestController
@AssignmentHints({"path-traversal-profile.hint1", "path-traversal-profile.hint2", "path-traversal-profile.hint3"})
public class ProfileUpload extends ProfileUploadBase {
public ProfileUpload(@Value("${webgoat.server.directory}") String webGoatHomeDirectory, WebSession webSession) {
super(webGoatHomeDirectory, webSession);
}
@PostMapping(value = "/PathTraversal/profile-upload", consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE)
@ResponseBody
public AttackResult uploadFileHandler(@RequestParam("uploadedFile") MultipartFile file, @RequestParam(value = "fullName", required = false) String fullName) {
return super.execute(file, fullName);
}
@GetMapping("/PathTraversal/profile-picture")
@ResponseBody
public ResponseEntity<?> getProfilePicture() {
return super.getProfilePicture();
}
}

View File

@ -0,0 +1,93 @@
package org.owasp.webgoat.path_traversal;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.WebSession;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Base64;
@AllArgsConstructor
public class ProfileUploadBase extends AssignmentEndpoint {
private String webGoatHomeDirectory;
private WebSession webSession;
protected AttackResult execute(MultipartFile file, String fullName) {
if (file.isEmpty()) {
return failed(this).feedback("path-traversal-profile-empty-file").build();
}
if (StringUtils.isEmpty(fullName)) {
return failed(this).feedback("path-traversal-profile-empty-name").build();
}
var uploadDirectory = new File(this.webGoatHomeDirectory, "/PathTraversal/" + webSession.getUserName());
if (uploadDirectory.exists()) {
FileSystemUtils.deleteRecursively(uploadDirectory);
}
try {
uploadDirectory.mkdirs();
var uploadedFile = new File(uploadDirectory, fullName);
uploadedFile.createNewFile();
FileCopyUtils.copy(file.getBytes(), uploadedFile);
if (userAttemptedToSolveLesson(uploadDirectory, uploadedFile)) {
return solvedIt(uploadedFile);
}
return informationMessage(this).feedback("path-traversal-profile-updated").feedbackArgs(uploadedFile.getAbsoluteFile()).build();
} catch (IOException e) {
return failed(this).output(e.getMessage()).build();
}
}
private boolean userAttemptedToSolveLesson(File expectedUploadDirectory, File uploadedFile) throws IOException {
return !expectedUploadDirectory.getCanonicalPath().equals(uploadedFile.getParentFile().getCanonicalPath());
}
private AttackResult solvedIt(File uploadedFile) throws IOException {
if (uploadedFile.getCanonicalFile().getParentFile().getName().endsWith("PathTraversal")) {
return success(this).build();
}
return failed(this).build();
}
public ResponseEntity<?> getProfilePicture() {
var profilePictureDirectory = new File(this.webGoatHomeDirectory, "/PathTraversal/" + webSession.getUserName());
var profileDirectoryFiles = profilePictureDirectory.listFiles();
if (profileDirectoryFiles != null && profileDirectoryFiles.length > 0) {
try (var inputStream = new FileInputStream(profileDirectoryFiles[0])) {
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE))
.body(Base64.getEncoder().encode(FileCopyUtils.copyToByteArray(inputStream)));
} catch (IOException e) {
return defaultImage();
}
} else {
return defaultImage();
}
}
@SneakyThrows
private ResponseEntity<?> defaultImage() {
var inputStream = getClass().getResourceAsStream("/images/account.png");
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE))
.body(Base64.getEncoder().encode(FileCopyUtils.copyToByteArray(inputStream)));
}
}

View File

@ -0,0 +1,35 @@
package org.owasp.webgoat.path_traversal;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.WebSession;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import static org.springframework.http.MediaType.ALL_VALUE;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@RestController
@AssignmentHints({"path-traversal-profile-fix.hint1", "path-traversal-profile-fix.hint2", "path-traversal-profile-fix.hint3"})
public class ProfileUploadFix extends ProfileUploadBase {
public ProfileUploadFix(@Value("${webgoat.server.directory}") String webGoatHomeDirectory, WebSession webSession) {
super(webGoatHomeDirectory, webSession);
}
@PostMapping(value = "/PathTraversal/profile-upload-fix", consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE)
@ResponseBody
public AttackResult uploadFileHandler(
@RequestParam("uploadedFileFix") MultipartFile file,
@RequestParam(value = "fullNameFix", required = false) String fullName) {
return super.execute(file, fullName != null ? fullName.replaceAll("../", "") : "");
}
@GetMapping("/PathTraversal/profile-picture-fix")
@ResponseBody
public ResponseEntity<?> getProfilePicture() {
return super.getProfilePicture();
}
}

View File

@ -0,0 +1,29 @@
package org.owasp.webgoat.path_traversal;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.WebSession;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import static org.springframework.http.MediaType.ALL_VALUE;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@RestController
@AssignmentHints({"path-traversal-profile-remove-user-input.hint1", "path-traversal-profile-remove-user-input.hint2", "path-traversal-profile-remove-user-input.hint3"})
public class ProfileUploadRemoveUserInput extends ProfileUploadBase {
public ProfileUploadRemoveUserInput(@Value("${webgoat.server.directory}") String webGoatHomeDirectory, WebSession webSession) {
super(webGoatHomeDirectory, webSession);
}
@PostMapping(value = "/PathTraversal/profile-upload-remove-user-input", consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE)
@ResponseBody
public AttackResult uploadFileHandler(@RequestParam("uploadedFileRetrieval") MultipartFile file) {
return super.execute(file, file.getOriginalFilename());
}
}

View File

@ -0,0 +1,88 @@
package org.owasp.webgoat.path_traversal;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AttackResult;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.token.Sha512DigestUtils;
import org.springframework.security.crypto.codec.Hex;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.util.Base64;
import static org.springframework.util.FileCopyUtils.copy;
import static org.springframework.util.ResourceUtils.getFile;
@RestController
@AssignmentHints({"path-traversal-profile-retrieve.hint1", "path-traversal-profile-retrieve.hint2", "path-traversal-profile-retrieve.hint3, path-traversal-profile-retrieve.hint4", "path-traversal-profile-retrieve.hint5"})
@Slf4j
public class ProfileUploadRetrieval extends AssignmentEndpoint {
private final File catPicturesDirectory;
public ProfileUploadRetrieval(@Value("${webgoat.server.directory}") String webGoatHomeDirectory) {
this.catPicturesDirectory = new File(webGoatHomeDirectory, "/PathTraversal/" + "/cats");
this.catPicturesDirectory.mkdirs();
}
@PostConstruct
public void initAssignment() {
for (int i = 1; i <= 10; i++) {
try {
copy(getFile(getClass().getResource("/images/cats/" + i + ".jpg")), new File(catPicturesDirectory, i + ".jpg"));
} catch (Exception e) {
log.error("Unable to copy pictures", e);
}
}
var secretDirectory = this.catPicturesDirectory.getParentFile().getParentFile();
try {
Files.writeString(secretDirectory.toPath().resolve("path-traversal-secret.jpg"), "You found it submit the SHA-512 hash of your username as answer");
} catch (IOException e) {
log.error("Unable to write secret in: {}", secretDirectory, e);
}
}
@PostMapping("/PathTraversal/random")
protected AttackResult execute(@RequestParam(value = "secret", required = false) String secret) {
if (Sha512DigestUtils.shaHex(getWebSession().getUserName()).equalsIgnoreCase(secret)) {
return success(this).build();
}
return failed(this).build();
}
@GetMapping("/PathTraversal/random")
@ResponseBody
public ResponseEntity<?> getProfilePicture(@RequestParam(value = "id", required = false) String id) {
var catPicture = new File(catPicturesDirectory, (id == null ? RandomUtils.nextInt(1, 11) : id) + ".jpg");
try {
if (catPicture.getName().toLowerCase().contains("path-traversal-secret.jpg")) {
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE))
.body(FileCopyUtils.copyToByteArray(catPicture));
}
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE))
.location(new URI("/PathTraversal/random?id=" + catPicture.getName()))
.body(Base64.getEncoder().encode(FileCopyUtils.copyToByteArray(catPicture)));
} catch (IOException | URISyntaxException e) {
log.error("Unable to download picture", e);
}
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE))
.body(StringUtils.arrayToCommaDelimitedString(catPicture.getParentFile().listFiles()).getBytes());
}
}

View File

@ -0,0 +1,57 @@
.upload-container
{
width: 500px;
margin: 20px auto;
}
.preview
{
padding: 10px;
position: relative;
}
.preview i
{
color: white;
font-size: 35px;
transform: translate(50px,130px);
}
.preview-img
{
border-radius: 100%;
box-shadow: 0px 0px 5px 2px rgba(0,0,0,0.7);
}
.browse-button
{
width: 200px;
height: 200px;
border-radius: 100%;
position: absolute; /* Tweak the position property if the element seems to be unfit */
top: 10px;
left: 150px;
background: linear-gradient(180deg, transparent, black);
opacity: 0;
transition: 0.3s ease;
}
.browse-button:hover
{
opacity: 1;
}
.browse-input
{
width: 200px;
height: 200px;
border-radius: 100%;
transform: translate(-1px,-26px);
opacity: 0;
}
.Error
{
color: crimson;
font-size: 13px;
}

View File

@ -0,0 +1,212 @@
<html xmlns:th="http://www.thymeleaf.org">
<script th:src="@{/lesson_js/path_traversal.js}" language="JavaScript"></script>
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/path_traversal.css}"/>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:PathTraversal_intro.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:PathTraversal_upload.adoc"></div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="upload-container">
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
onsubmit='return false'
contentType="false"
successCallback="profileUploadCallback"
failureCallback="profileUploadCallback"
informationalCallback="profileUploadCallback"
prepareData="profileUpload"
enctype="multipart/form-data"
action="/WebGoat/PathTraversal/profile-upload">
<div class="preview text-center">
<img class="preview-img" th:src="@{/images/account.png}" alt="Preview Image" width="200"
height="200" id="preview"/>
<div class="browse-button">
<i class="fa fa-pencil"></i>
<input class="browse-input" type="file" required name="uploadedFile" id="uploadedFile"/>
</div>
<span class="Error"></span>
</div>
<div class="form-group">
<label>Full Name:</label>
<input class="form-control" type="text" id="fullName" name="fullName" required value="test"
placeholder="Enter Your Full Name"/>
<span class="Error"></span>
</div>
<div class="form-group">
<label>Email:</label>
<input class="form-control" type="email" id="email" name="email" required
placeholder="Enter Your Email" value="test@test.com"/>
<span class="Error"></span>
</div>
<div class="form-group">
<label>Password:</label>
<input class="form-control" type="password" id="password" name="password" required
placeholder="Enter Password" value="test"/>
<span class="Error"></span>
</div>
<div class="form-group">
<button class="btn btn-primary btn-block" value="Submit">Update</button>
</div>
</form>
</div>
<br/>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:PathTraversal_upload_fix.adoc"></div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="upload-container">
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
onsubmit='return false'
contentType="false"
successCallback="profileUploadCallbackFix"
failureCallback="profileUploadCallbackFix"
informationalCallback="profileUploadCallbackFix"
prepareData="profileUploadFix"
enctype="multipart/form-data"
action="/WebGoat/PathTraversal/profile-upload-fix">
<div class="preview text-center">
<img class="preview-img-fix" th:src="@{/images/account.png}" alt="Preview Image" width="200"
height="200" id="previewFix"/>
<div class="browse-button">
<i class="fa fa-pencil"></i>
<input class="browse-input" type="file" required name="uploadedFile" id="uploadedFileFix"/>
</div>
<span class="Error"></span>
</div>
<div class="form-group">
<label>Full Name:</label>
<input class="form-control" type="text" id="fullNameFix" name="fullName" required value="test"
placeholder="Enter Your Full Name"/>
<span class="Error"></span>
</div>
<div class="form-group">
<label>Email:</label>
<input class="form-control" type="email" id="emailFix" name="email" required
placeholder="Enter Your Email" value="test@test.com"/>
<span class="Error"></span>
</div>
<div class="form-group">
<label>Password:</label>
<input class="form-control" type="password" id="passwordFix" name="password" required
placeholder="Enter Password" value="test"/>
<span class="Error"></span>
</div>
<div class="form-group">
<button class="btn btn-primary btn-block" value="Submit">Update</button>
</div>
</form>
</div>
<br/>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:PathTraversal_upload_remove_user_input.adoc"></div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="upload-container">
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
onsubmit='return false'
contentType="false"
successCallback="profileUploadCallbackRemoveUserInput"
failureCallback="profileUploadCallbackRemoveUserInput"
informationalCallback="profileUploadCallbackRemoveUserInput"
prepareData="profileUploadFix"
enctype="multipart/form-data"
action="/WebGoat/PathTraversal/profile-upload-remove-user-input">
<div class="preview text-center">
<img class="preview-img-fix" th:src="@{/images/account.png}" alt="Preview Image" width="200"
height="200" id="previewRemoveUserInput"/>
<div class="browse-button">
<i class="fa fa-pencil"></i>
<input class="browse-input" type="file" required name="uploadedFile"
id="uploadedFileRemoveUserInput"/>
</div>
<span class="Error"></span>
</div>
<div class="form-group">
<label>Full Name:</label>
<input class="form-control" type="text" id="fullNameRemoveUserInput" name="fullName" required
value="test"
placeholder="Enter Your Full Name"/>
<span class="Error"></span>
</div>
<div class="form-group">
<label>Email:</label>
<input class="form-control" type="email" id="emailRemoveUserInput" name="email" required
placeholder="Enter Your Email" value="test@test.com"/>
<span class="Error"></span>
</div>
<div class="form-group">
<label>Password:</label>
<input class="form-control" type="password" id="passwordRemoveUserInput" name="password" required
placeholder="Enter Password" value="test"/>
<span class="Error"></span>
</div>
<div class="form-group">
<button class="btn btn-primary btn-block" value="Submit">Update</button>
</div>
</form>
</div>
<br/>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:PathTraversal_retrieval.adoc"></div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="upload-container">
<div class="form-group">
<button class="btn btn-primary btn-block" onclick="newRandomPicture()">Show random cat picture</button>
</div>
<div>
<img id="randomCatPicture" th:src="@{/images/cats/1.jpg}"/>
</div>
<br/>
<form class="attack-form" method="POST" name="form" action="/WebGoat/PathTraversal/random">
<div class="form-group">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
style="font-size:20px"></i></div>
<input type="text" class="form-control" id="pathTraversalSecret" name="secret"/>
</div>
<div class="input-group" style="margin-top: 10px">
<button type="submit" class="btn btn-primary">Submit secret</button>
</div>
</div>
</form>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
</div>
</html>

View File

@ -0,0 +1,46 @@
#
# This file is part of WebGoat, an Open Web Application Security Project utility. For details,
# please see http://www.owasp.org/
# <p>
# Copyright (c) 2002 - 2017 Bruce Mayhew
# <p>
# This program is free software; you can redistribute it and/or modify it under the terms of the
# GNU General Public License as published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
# <p>
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
# <p>
# You should have received a copy of the GNU General Public License along with this program; if
# not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
# <p>
# Getting Source ==============
# <p>
# Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
# projects.
# <p>
#
path-traversal-title=Path traversal
path-traversal-profile-updated=Profile has been updated, your image is available at: {0}"
path-traversal-profile-empty-file=File appears to be empty please upload a non empty file
path-traversal-profile-empty-name=Name is empty
path-traversal-profile.hint1=Try updating the profile WebGoat will display the location
path-traversal-profile.hint2=Look at the displayed location how is the file name on the server constructed?
path-traversal-profile.hint3=Does the server validate any input given in the full name field?
path-traversal-profile-fix.hint1=Take a look what happens compared to the previous assignment
path-traversal-profile-fix.hint2=The new and improved version removes `../` from the input, can you bypass this?
path-traversal-profile-fix.hint3=Try to construct a full name which after cleaning still has `../` in the full name
path-traversal-profile-remove-user-input.hint1=Take a look what happened to the file name
path-traversal-profile-remove-user-input.hint2=Can we still manipulate the request?
path-traversal-profile-remove-user-input.hint3=You can try to use a proxy to intercept the POST request
path-traversal-profile-retrieve.hint1=Can you specify the image to be fetched?
path-traversal-profile-retrieve.hint2=Look at the location header...
path-traversal-profile-retrieve.hint3=Use /random?id=1 for example to fetch a specific image
path-traversal-profile-retrieve.hint4=Use /random/?id=../../1.jpg to navigate to a different directory
path-traversal-profile-retrieve.hint5=Do you see a difference when retrieving a file or a directory?

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -0,0 +1,62 @@
webgoat.customjs.profileUpload = function () {
var picture = document.getElementById("uploadedFile").files[0];
var formData = new FormData();
formData.append("uploadedFile", picture);
formData.append("fullName", $("#fullName").val());
formData.append("email", $("#email").val());
formData.append("password", $("#password").val());
return formData;
}
webgoat.customjs.profileUploadCallback = function () {
$.get("PathTraversal/profile-picture", function (result, status) {
document.getElementById("preview").src = "data:image/png;base64," + result;
});
}
webgoat.customjs.profileUploadFix = function () {
var picture = document.getElementById("uploadedFileFix").files[0];
var formData = new FormData();
formData.append("uploadedFileFix", picture);
formData.append("fullNameFix", $("#fullNameFix").val());
formData.append("emailFix", $("#emailFix").val());
formData.append("passwordFix", $("#passwordFix").val());
return formData;
}
webgoat.customjs.profileUploadCallbackFix = function () {
$.get("PathTraversal/profile-picture", function (result, status) {
document.getElementById("previewFix").src = "data:image/png;base64," + result;
});
}
webgoat.customjs.profileUploadRemoveUserInput = function () {
var picture = document.getElementById("uploadedFileRemoveUserInput").files[0];
var formData = new FormData();
formData.append("uploadedFile", picture);
formData.append("fullName", $("#fullNameRemoveUserInput").val());
formData.append("email", $("#emailRemoveUserInput").val());
formData.append("password", $("#passwordRemoveUserInput").val());
return formData;
}
webgoat.customjs.profileUploadCallbackRemoveUserInput = function () {
$.get("PathTraversal/profile-picture", function (result, status) {
document.getElementById("previewRemoveUserInput").src = "data:image/png;base64," + result;
});
}
webgoat.customjs.profileUploadCallbackRetrieval = function () {
$.get("PathTraversal/profile-picture", function (result, status) {
document.getElementById("previewRetrieval").src = "data:image/png;base64," + result;
});
}
function newRandomPicture() {
$.get("PathTraversal/random", function (result, status) {
document.getElementById("randomCatPicture").src = "data:image/png;base64," + result;
});
}

View File

@ -0,0 +1,37 @@
=== Path traversal
A path(directory) traversal is a vulnerability where an attacker is able to access or store files and directories outside
the location where the application is running. This may lead to reading files from other directories and in case of a file
upload overwriting critical system files.
=== How does it work?
For example let's assume we have an application which hosts some files and they can be requested in the following
format: `http://example.com/file=report.pdf` now as an attacker you are interested in other files of course so
you try `http://example.com/../../../../../etc/passwd`. In this case you try walk up to the root of the filesystem
and then go into `/etc/passwd` to gain access to this file. The `../` is called dot-dot-slash which is another name
for this attack.
Of course this is a very simple example and in most cases this will not work as frameworks implemented controls for
this, so we need to get a little more creative and start encoding `../` before the request is sent to the server.
For example if we URL encode `../` you will get `%2e%2e%2f` and the web server receiving this request will decode
it again to `../`.
Also note that avoiding applications filtering those encodings double encoding might work as well. Double encoding
might be necessary in the case where you have a system A which calls system B. System A will only decode once and
will call B with the still encoded URL.
Now let's try some examples
1. Example with upload where you have to overwrite one of the files
1a Example upload where developer implemented a fix by removing ../ from the path
1b No longer using name of user to store file so you need proxy to intercept
2. Example with download for example the idea is to download a pdf but there is also a txt file
3. Same as 2 with blacklisting implemented (see example from Workpress plugin)
4. Zip path traversal where you have to create a zip file which overwrites a file in another directory
- Run app with least priviledge
- Before storing the file calculate the location
- Same for reading is it actually reading from the directory you allow

View File

@ -0,0 +1,6 @@
=== Retrieving other files with a path traversal
Path traversals are not limited to file uploads also when retrieving files it can be the case that a path traversal
is possible to retrieve other files from the system. In this assignment try to find a file called `secret.txt`

View File

@ -0,0 +1,12 @@
=== Path traversal while uploading files
In this assignment the goal is to overwrite a specific file on the file system. Of course WebGoat cares about the users
so you need to upload your file to the following location which is outside the normal upload location.
|===
|OS |Location
|`operatingSystem:os[]`
|`webGoatTempDir:temppath[]PathTraversal/`
|===

View File

@ -0,0 +1,11 @@
=== Path traversal while uploading files
Again the same assignment but can you bypass the implemented fix?
|===
|OS |Location
|`operatingSystem:os[]`
|`webGoatTempDir:temppath[]PathTraversal/`
|===

View File

@ -0,0 +1,12 @@
=== Path traversal while retrieving files
Finally the upload is no longer vulnerable at least help us to verify :-)
In this assignment you need to get the contents of the following file:
|===
|OS |Location
|`operatingSystem:os[]`
|`webGoatTempDir:temppath[]PathTraversal/secret.txt`
|===

View File

@ -0,0 +1,42 @@
=== Path traversal mitigation
As we saw in the previous assignments protecting a file upload can be a daunting task. The thing comes down to trusting
input without validating it.
In the examples shown before a solution might be to not trust user input and create a random file name on the
server side.
If you really need to save it based on user input the best way to keep you save is to check the canonical path the
file will be saved. For example in Java:
[source]
----
var multiPartFile = ...
var targetFile = new File("/tmp", multiPartFile.getOriginalName());
var canonicalPath = targetFile.getCanonicalPath();
if (!canonicalPath.startWith("/tmp") {
throw new IllegalArgumentException("Invalid filename");
}
IOUtils.copy(multiPartFile.getBytes(), targetFile);
----
The canonical path function will resolve to a absolute path, removing `.` and `..` etc. By checking whether the canonical
path is inside the expected directory the path traversal will be avoided.
For path traversals while retrieving one can apply the same technique described above but as a defence in depth you
can also implement a mitigation by running the application under a specific not privileged user which is not allowed to read and write
in any other directory.
Make sure that in any case you build detection for catching these cases but be careful with returning explicit information
to the user. Every small detail might give the attacker knowledge about your system.
==== Spring Boot protection
By default Spring Boot has protection for usage of for example `../` in a path. The implementation can be found in
`StrictHttpFirewall` class. This will protect endpoint where the user input is part of the `path` like `/test/1.jpg`
if you replace `1.jpg` with `../../secret.txt` it will block the request. With query parameters that protection
will not be there.
In the lesson about "File uploads" more examples of vulnerabilities are shown.

View File

@ -0,0 +1,14 @@
=== Path traversal while uploading files
The developer became aware of the vulnerability by not validating the input of the `full name` input field.
A fix was made in an attempt to solve this vulnerability.
Again the same assignment but can you bypass the implemented fix?
|===
|OS |Location
|`operatingSystem:os[]`
|`webGoatTempDir:temppath[]PathTraversal/`
|===

View File

@ -0,0 +1,58 @@
package org.owasp.webgoat.path_traversal;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.owasp.webgoat.plugins.LessonTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class)
public class ProfileUploadFixTest extends LessonTest {
@Autowired
private PathTraversal pathTraversal;
@Before
public void setup() {
Mockito.when(webSession.getCurrentLesson()).thenReturn(pathTraversal);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
Mockito.when(webSession.getUserName()).thenReturn("unit-test");
}
@Test
public void solve() throws Exception {
var profilePicture = new MockMultipartFile("uploadedFileFix", "../picture.jpg", "text/plain", "an image".getBytes());
mockMvc.perform(MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload-fix")
.file(profilePicture)
.param("fullNameFix", "..././John Doe"))
.andExpect(status().is(200))
.andExpect(jsonPath("$.assignment", CoreMatchers.equalTo("ProfileUploadFix")))
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
}
@Test
public void normalUpdate() throws Exception {
var profilePicture = new MockMultipartFile("uploadedFileFix", "picture.jpg", "text/plain", "an image".getBytes());
mockMvc.perform(MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload-fix")
.file(profilePicture)
.param("fullNameFix", "John Doe"))
.andExpect(status().is(200))
.andExpect(jsonPath("$.feedback", CoreMatchers.containsString("/unit-test\\/John Doe\\\"")))
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
}
}

View File

@ -0,0 +1,55 @@
package org.owasp.webgoat.path_traversal;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.owasp.webgoat.plugins.LessonTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class)
public class ProfileUploadRemoveUserInputTest extends LessonTest {
@Autowired
private PathTraversal pathTraversal;
@Before
public void setup() {
Mockito.when(webSession.getCurrentLesson()).thenReturn(pathTraversal);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
Mockito.when(webSession.getUserName()).thenReturn("unit-test");
}
@Test
public void solve() throws Exception {
var profilePicture = new MockMultipartFile("uploadedFileRetrieval", "../picture.jpg", "text/plain", "an image".getBytes());
mockMvc.perform(MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload-remove-user-input")
.file(profilePicture)
.param("fullNameFix", "John Doe"))
.andExpect(status().is(200))
.andExpect(jsonPath("$.assignment", CoreMatchers.equalTo("ProfileUploadRemoveUserInput")))
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
}
@Test
public void normalUpdate() throws Exception {
var profilePicture = new MockMultipartFile("uploadedFileRetrieval", "picture.jpg", "text/plain", "an image".getBytes());
mockMvc.perform(MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload-remove-user-input")
.file(profilePicture)
.param("fullNameFix", "John Doe"))
.andExpect(status().is(200))
.andExpect(jsonPath("$.feedback", CoreMatchers.containsString("/unit-test\\/picture.jpg\\\"")))
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
}
}

View File

@ -0,0 +1,76 @@
package org.owasp.webgoat.path_traversal;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.owasp.webgoat.plugins.LessonTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.core.token.Sha512DigestUtils;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@RunWith(SpringJUnit4ClassRunner.class)
public class ProfileUploadRetrievalTest extends LessonTest {
@Autowired
private PathTraversal pathTraversal;
@Before
public void setup() {
Mockito.when(webSession.getCurrentLesson()).thenReturn(pathTraversal);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
Mockito.when(webSession.getUserName()).thenReturn("unit-test");
}
@Test
public void solve() throws Exception {
//Look at the response
mockMvc.perform(MockMvcRequestBuilders.get("/PathTraversal/random"))
.andExpect(status().is(200))
.andExpect(header().exists("Location"))
.andExpect(header().string("Location", containsString("?id=")))
.andExpect(content().contentTypeCompatibleWith(MediaType.IMAGE_JPEG));
//Browse the directories
mockMvc.perform(MockMvcRequestBuilders.get("/PathTraversal/random?id=../../"))
.andExpect(status().is(200))
.andExpect(content().string(containsString("/path-traversal-secret.jpg")))
.andExpect(content().contentTypeCompatibleWith(MediaType.IMAGE_JPEG));
//Retrieve the secret file (note: .jpg is added by the server)
mockMvc.perform(MockMvcRequestBuilders.get("/PathTraversal/random?id=../../path-traversal-secret"))
.andExpect(status().is(200))
.andExpect(content().string("You found it submit the SHA-512 hash of your username as answer"))
.andExpect(content().contentTypeCompatibleWith(MediaType.IMAGE_JPEG));
//Post flag
mockMvc.perform(MockMvcRequestBuilders.post("/PathTraversal/random").param("secret", Sha512DigestUtils.shaHex("unit-test")))
.andExpect(status().is(200))
.andExpect(jsonPath("$.assignment", equalTo("ProfileUploadRetrieval")))
.andExpect(jsonPath("$.lessonCompleted", is(true)));
}
@Test
public void shouldReceiveRandomPicture() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/PathTraversal/random"))
.andExpect(status().is(200))
.andExpect(header().exists("Location"))
.andExpect(content().contentTypeCompatibleWith(MediaType.IMAGE_JPEG));
}
@Test
public void unknownFileShouldGiveDirectoryContents() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/PathTraversal/random?id=test"))
.andExpect(status().is(200))
.andExpect(content().string(containsString("cats/8.jpg")))
.andExpect(content().contentTypeCompatibleWith(MediaType.IMAGE_JPEG));
}
}

View File

@ -0,0 +1,56 @@
package org.owasp.webgoat.path_traversal;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.owasp.webgoat.plugins.LessonTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class)
public class ProfileUploadTest extends LessonTest {
@Autowired
private PathTraversal pathTraversal;
@Before
public void setup() {
Mockito.when(webSession.getCurrentLesson()).thenReturn(pathTraversal);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
Mockito.when(webSession.getUserName()).thenReturn("unit-test");
}
@Test
public void solve() throws Exception {
var profilePicture = new MockMultipartFile("uploadedFile", "../picture.jpg", "text/plain", "an image".getBytes());
mockMvc.perform(MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload")
.file(profilePicture)
.param("fullName", "../John Doe"))
.andExpect(status().is(200))
.andExpect(jsonPath("$.assignment", CoreMatchers.equalTo("ProfileUpload")))
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
}
@Test
public void normalUpdate() throws Exception {
var profilePicture = new MockMultipartFile("uploadedFile", "picture.jpg", "text/plain", "an image".getBytes());
mockMvc.perform(MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload")
.file(profilePicture)
.param("fullName", "John Doe"))
.andExpect(status().is(200))
.andExpect(jsonPath("$.feedback", CoreMatchers.containsString("/PathTraversal\\/unit-test\\/John Doe\\\"")))
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
}
}

View File

@ -40,6 +40,7 @@
<module>secure-passwords</module> <module>secure-passwords</module>
<module>webgoat-lesson-template</module> <module>webgoat-lesson-template</module>
<module>crypto</module> <module>crypto</module>
<module>path-traversal</module>
</modules> </modules>
<dependencies> <dependencies>

View File

@ -21,7 +21,6 @@
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SecurePasswords/assignment" action="/WebGoat/SecurePasswords/assignment"
enctype="application/json;charset=UTF-8"
autocomplete="off"> autocomplete="off">
<table> <table>
<tr> <tr>

View File

@ -16,7 +16,6 @@
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjection/attack2" action="/WebGoat/SqlInjection/attack2"
enctype="application/json;charset=UTF-8"
autocomplete="off"> autocomplete="off">
<table> <table>
<tr> <tr>
@ -41,7 +40,6 @@
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjection/attack3" action="/WebGoat/SqlInjection/attack3"
enctype="application/json;charset=UTF-8"
autocomplete="off"> autocomplete="off">
<table> <table>
<tr> <tr>
@ -66,7 +64,6 @@
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjection/attack4" action="/WebGoat/SqlInjection/attack4"
enctype="application/json;charset=UTF-8"
autocomplete="off"> autocomplete="off">
<table> <table>
<tr> <tr>
@ -91,7 +88,6 @@
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjection/attack5" action="/WebGoat/SqlInjection/attack5"
enctype="application/json;charset=UTF-8"
autocomplete="off"> autocomplete="off">
<table> <table>
<tr> <tr>
@ -147,8 +143,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjection/assignment5a" action="/WebGoat/SqlInjection/assignment5a">
enctype="application/json;charset=UTF-8">
<table> <table>
<tr> <tr>
<td>SELECT * FROM user_data WHERE first_name = 'John' AND last_name = '</td> <td>SELECT * FROM user_data WHERE first_name = 'John' AND last_name = '</td>
@ -193,8 +188,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjection/assignment5b" action="/WebGoat/SqlInjection/assignment5b">
enctype="application/json;charset=UTF-8">
<table> <table>
<tr> <tr>
<td>Login_Count:</td> <td>Login_Count:</td>
@ -223,7 +217,6 @@
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjection/attack8" action="/WebGoat/SqlInjection/attack8"
enctype="application/json;charset=UTF-8"
autocomplete="off"> autocomplete="off">
<table> <table>
<tr> <tr>
@ -252,7 +245,6 @@
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjection/attack9" action="/WebGoat/SqlInjection/attack9"
enctype="application/json;charset=UTF-8"
autocomplete="off"> autocomplete="off">
<table> <table>
<tr> <tr>
@ -282,7 +274,6 @@
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjection/attack10" action="/WebGoat/SqlInjection/attack10"
enctype="application/json;charset=UTF-8"
autocomplete="off"> autocomplete="off">
<table> <table>
<tr> <tr>

View File

@ -20,8 +20,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjectionAdvanced/attack6a" action="/WebGoat/SqlInjectionAdvanced/attack6a">
enctype="application/json;charset=UTF-8">
<table> <table>
<tr> <tr>
<td>Name:</td> <td>Name:</td>
@ -34,8 +33,7 @@
</form> </form>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjectionAdvanced/attack6b" action="/WebGoat/SqlInjectionAdvanced/attack6b">
enctype="application/json;charset=UTF-8">
<table> <table>
<tr> <tr>
<td>Password:</td> <td>Password:</td>
@ -82,7 +80,7 @@
<form id="login-form" class="attack-form" accept-charset="UNKNOWN" <form id="login-form" class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjectionAdvanced/challenge_Login" action="/WebGoat/SqlInjectionAdvanced/challenge_Login"
enctype="application/json;charset=UTF-8" role="form"> role="form">
<div class="form-group"> <div class="form-group">
<input type="text" name="username_login" id="username4" tabindex="1" <input type="text" name="username_login" id="username4" tabindex="1"
class="form-control" placeholder="Username" value=""/> class="form-control" placeholder="Username" value=""/>
@ -118,7 +116,7 @@
<form id="register-form" class="attack-form" accept-charset="UNKNOWN" <form id="register-form" class="attack-form" accept-charset="UNKNOWN"
method="PUT" name="form" method="PUT" name="form"
action="/WebGoat/SqlInjectionAdvanced/challenge" action="/WebGoat/SqlInjectionAdvanced/challenge"
enctype="application/json;charset=UTF-8" style="display: none;" role="form"> style="display: none;" role="form">
<div class="form-group"> <div class="form-group">
<input type="text" name="username_reg" id="username" tabindex="1" <input type="text" name="username_reg" id="username" tabindex="1"
class="form-control" placeholder="Username" value=""/> class="form-control" placeholder="Username" value=""/>
@ -171,7 +169,7 @@
<form id="quiz-form" class="attack-form" accept-charset="UNKNOWN" <form id="quiz-form" class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjectionAdvanced/quiz" action="/WebGoat/SqlInjectionAdvanced/quiz"
enctype="application/json;charset=UTF-8" role="form"> role="form">
<div id="q_container"></div> <div id="q_container"></div>
<br /> <br />
<input name="Quiz_solutions" value="Submit answers" type="SUBMIT"/> <input name="Quiz_solutions" value="Submit answers" type="SUBMIT"/>

View File

@ -23,7 +23,7 @@
<div class="adoc-content" th:replace="doc:SqlInjection_jdbc_completion.adoc"></div> <div class="adoc-content" th:replace="doc:SqlInjection_jdbc_completion.adoc"></div>
<div class="attack-container"> <div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" method="POST" name="form" action="/WebGoat/SqlInjectionMitigations/attack10a" enctype="application/json;charset=UTF-8"> <form class="attack-form" accept-charset="UNKNOWN" method="POST" name="form" action="/WebGoat/SqlInjectionMitigations/attack10a">
<div> <div>
<p>Connection conn = DriverManager.<input type="text" name="field1" id="field1" />(DBURL, DBUSER, DBPW);</p> <p>Connection conn = DriverManager.<input type="text" name="field1" id="field1" />(DBURL, DBUSER, DBPW);</p>
<p><input type="text" name="field2" id="field2" /> = conn.<input type="text" name="field3" id="field3" />("SELECT status FROM users WHERE name=<input type="text" name="field4" id="field4" /> AND mail=<input type="text" name="field5" id="field5" />");</p> <p><input type="text" name="field2" id="field2" /> = conn.<input type="text" name="field3" id="field3" />("SELECT status FROM users WHERE name=<input type="text" name="field4" id="field4" /> AND mail=<input type="text" name="field5" id="field5" />");</p>
@ -42,7 +42,7 @@
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:SqlInjection_jdbc_newcode.adoc"></div> <div class="adoc-content" th:replace="doc:SqlInjection_jdbc_newcode.adoc"></div>
<div class="attack-container" style="border: none !important; height: 100%; min-height: 300px;"> <div class="attack-container" style="border: none !important; height: 100%; min-height: 300px;">
<form id="codesubmit" style="height: 100%; min-height: 300px;" class="attack-form" accept-charset="UNKNOWN" method="POST" name="form" action="/WebGoat/SqlInjectionMitigations/attack10b" enctype="application/json;charset=UTF-8"> <form id="codesubmit" style="height: 100%; min-height: 300px;" class="attack-form" accept-charset="UNKNOWN" method="POST" name="form" action="/WebGoat/SqlInjectionMitigations/attack10b">
<div> <div>
<div id="editor" style="position: absolute; top: 0; right: 0; bottom: 0; left: 0; height: 300px;" name="editor"></div> <div id="editor" style="position: absolute; top: 0; right: 0; bottom: 0; left: 0; height: 300px;" name="editor"></div>
<script th:src="@{/js/libs/ace/src-noconflict/ace.js}" type="text/javascript" charset="utf-8"></script> <script th:src="@{/js/libs/ace/src-noconflict/ace.js}" type="text/javascript" charset="utf-8"></script>
@ -78,8 +78,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjectionMitigations/attack12a" action="/WebGoat/SqlInjectionMitigations/attack12a">
enctype="application/json;charset=UTF-8">
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="panel panel-primary"> <div class="panel panel-primary">

View File

@ -12,8 +12,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SSRF/task1" action="/WebGoat/SSRF/task1">
enctype="application/json;charset=UTF-8">
<table> <table>
<tr> <tr>
<input type="hidden" id="url" name="url" value="images/tom.png"/> <input type="hidden" id="url" name="url" value="images/tom.png"/>
@ -35,8 +34,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SSRF/task2" action="/WebGoat/SSRF/task2">
enctype="application/json;charset=UTF-8">
<table> <table>
<tr> <tr>
<input type="hidden" id="url" name="url" value="images/cat.png"/> <input type="hidden" id="url" name="url" value="images/cat.png"/>

View File

@ -144,11 +144,10 @@
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like --> <!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/VulnerableComponents/attack1" action="/WebGoat/VulnerableComponents/attack1">
enctype="application/json;charset=UTF-8">
<div id="lessonContent"> <div id="lessonContent">
<form accept-charset="UNKNOWN" method="POST" name="form" <form accept-charset="UNKNOWN" method="POST" name="form"
action="#attack/307/100" enctype=""> action="#attack/307/100">
<table> <table>
<tr> <tr>
<td>Enter the contact's xml representation:</td> <td>Enter the contact's xml representation:</td>

View File

@ -47,8 +47,7 @@
<!-- modify the action to point to the intended endpoint and set other attributes as desired --> <!-- modify the action to point to the intended endpoint and set other attributes as desired -->
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/lesson-template/sample-attack" action="/WebGoat/lesson-template/sample-attack">
enctype="application/json;charset=UTF-8">
<table> <table>
<tr> <tr>
<td>two random params</td> <td>two random params</td>

View File

@ -85,8 +85,7 @@ green when the user solves the assignment. To make this work in the html we need
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/lesson-template/sample-attack" action="/WebGoat/lesson-template/sample-attack">
enctype="application/json;charset=UTF-8">
<table> <table>
<tr> <tr>
<td>two random params</td> <td>two random params</td>

View File

@ -16,8 +16,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/WebWolf/mail/" action="/WebGoat/WebWolf/mail/">
enctype="application/json;charset=UTF-8">
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">
@ -38,8 +37,7 @@
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/WebWolf/mail/send" action="/WebGoat/WebWolf/mail/send">
enctype="application/json;charset=UTF-8">
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">
@ -76,8 +74,7 @@
<br/> <br/>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/WebWolf/landing/" action="/WebGoat/WebWolf/landing/">
enctype="application/json;charset=UTF-8">
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">

View File

@ -34,6 +34,11 @@
<artifactId>client-side-filtering</artifactId> <artifactId>client-side-filtering</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>crypto</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>cross-site-scripting</artifactId> <artifactId>cross-site-scripting</artifactId>
@ -89,6 +94,11 @@
<artifactId>jwt</artifactId> <artifactId>jwt</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>path-traversal</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>sql-injection</artifactId> <artifactId>sql-injection</artifactId>
@ -143,11 +153,6 @@
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lesson-template</artifactId> <artifactId>webgoat-lesson-template</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>crypto</artifactId>
<version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>