- Introduced user registration

- Now using Spring Boot for classloading, this way local development does not need to restart the complete server
- Fixed all kinds of dependencies on the names of the lessons necessary to keep in mind during the creation of a lesson.
- Simplied loading of resources, by adding resource mappings in MvcConfig.
- Refactored plugin loading, now only one class is left for loading the lessons.
This commit is contained in:
Nanne Baars
2017-02-25 12:15:07 +01:00
parent 9b86aaba05
commit 259fd19c1b
221 changed files with 1179 additions and 1083 deletions

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:Challenge_content1.adoc"></div>
</div>
</html>

View File

@ -0,0 +1 @@
challenge.title=WebGoat Challenge

View File

@ -0,0 +1 @@
This is the challenge

View File

@ -1,6 +1,7 @@
package org.owasp.webgoat.plugin;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.springframework.web.bind.annotation.RequestMapping;
@ -40,14 +41,15 @@ import java.io.IOException;
* @since August 11, 2016
*/
@AssignmentPath("/clientSideFiltering/attack1")
public class Attack extends AssignmentEndpoint {
@AssignmentHints({"ClientSideFilteringHint1", "ClientSideFilteringHint2", "ClientSideFilteringHint3", "ClientSideFilteringHint4"})
public class ClientSideFilteringAssignment extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST)
public @ResponseBody AttackResult completed(@RequestParam String answer) throws IOException {
if ("450000".equals(answer)) {
return trackProgress(success().build());
} else {
return trackProgress(failed().build());
}
public
@ResponseBody
AttackResult completed(@RequestParam String answer) throws IOException {
return trackProgress("450000".equals(answer) ?
success().feedback("assignment.solved").build() :
failed().feedback("ClientSideFiltering.incorrect").build());
}
}

View File

@ -6,34 +6,51 @@ package org.owasp.webgoat.plugin;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.SneakyThrows;
import org.owasp.webgoat.assignments.Endpoint;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import javax.annotation.PostConstruct;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
public class Salaries extends Endpoint {
@Value("${webgoat.user.directory}")
private String webGoatHomeDirectory;
@PostConstruct
@SneakyThrows
public void copyFiles() {
ClassPathResource classPathResource = new ClassPathResource("employees.xml");
File targetDirectory = new File(webGoatHomeDirectory, "/ClientSideFiltering");
if (!targetDirectory.exists()) {
targetDirectory.mkdir();
}
FileCopyUtils.copy(classPathResource.getInputStream(), new FileOutputStream(new File(targetDirectory, "employees.xml")));
}
@RequestMapping(produces = {"application/json"})
@ResponseBody
public List<Map<String, Object>> invoke(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String userId = req.getParameter("userId");
public List<Map<String, Object>> invoke() throws ServletException, IOException {
NodeList nodes = null;
File d = new File(getPluginDirectory(), "ClientSideFiltering/html/employees.xml");
File d = new File(webGoatHomeDirectory, "ClientSideFiltering/employees.xml");
XPathFactory factory = XPathFactory.newInstance();
XPath xPath = factory.newXPath();
InputSource inputSource = new InputSource(new FileInputStream(d));
@ -49,8 +66,7 @@ public class Salaries extends Endpoint {
String expression = sb.toString();
try {
nodes = (NodeList) xPath.evaluate(expression, inputSource,
XPathConstants.NODESET);
nodes = (NodeList) xPath.evaluate(expression, inputSource, XPathConstants.NODESET);
} catch (XPathExpressionException e) {
e.printStackTrace();
}
@ -58,7 +74,7 @@ public class Salaries extends Endpoint {
List json = Lists.newArrayList();
java.util.Map<String, Object> employeeJson = Maps.newHashMap();
for (int i = 0; i < nodes.getLength(); i++) {
if (i != 0 && i % COLUMNS == 0) {
if (i % COLUMNS == 0) {
employeeJson = Maps.newHashMap();
json.add(employeeJson);
}

View File

@ -1,3 +1,3 @@
#lesson_wrapper {height: 435px;width: 500px;}
#lesson_header {background-image: url(../images/lesson1_header.jpg); width: 490px;padding-right: 10px;padding-top: 60px;background-repeat: no-repeat;}
.lesson_workspace {background-image: url(../images/lesson1_workspace.jpg); width: 489px;height: 325px;padding-left: 10px;padding-top: 10px;background-repeat: no-repeat;}
.lesson_workspace {background-image: url(../images/lesson1_workspace.jpg); width: 490px;height: 325px;padding-left: 10px;padding-top: 10px;background-repeat: no-repeat;}

View File

@ -1,22 +1,25 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper"><!-- reuse this block for each 'page' of content -->
<!-- include content here ... will be first page/tab multiple -->
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:ClientSideFiltering_plan.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:ClientSideFiltering_assignment.adoc"></div>
<br/>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<input type="hidden" id="user_id" value="102"/>
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
<form class="attack-form" accept-charset="UNKNOWN" method="POST" name="form" action="/WebGoat/clientSideFiltering/attack1">
<form class="attack-form" accept-charset="UNKNOWN" method="POST" name="form"
action="/WebGoat/clientSideFiltering/attack1">
<link rel="stylesheet" type="text/css"
th:href="@{/plugin_lessons/plugin/ClientSideFiltering/html/clientSideFiltering-stage1.css}"/>
<script th:src="@{/plugin_lessons/plugin/ClientSideFiltering/js/clientSideFiltering.js}"
th:href="@{/lesson_css/clientSideFiltering-stage1.css}"/>
<script th:src="@{/lesson_js/clientSideFiltering.js}"
language="JavaScript"></script>
<input id="userID" value="102" name="userID" type="HIDDEN"/>
<input id="userID" value="101" name="userID" type="HIDDEN"/>
<div id="lesson_wrapper">
<div id="lesson_header"></div>
<div class="lesson_workspace"><br/><br/>
@ -34,7 +37,8 @@
<option value="110" label="Joanne McDougal">Joanne McDougal</option>
</select></p>
<p></p>
<table style="display: none" id="hiddenEmployeeRecords" align="center" border="1" cellpadding="2"
<table style="display: none" id="hiddenEmployeeRecords" align="center" border="1"
cellpadding="2"
cellspacing="0" width="90%">
<div>
</div>
@ -63,11 +67,11 @@
</tbody>
</table>
</form>
<!-- do not remove the two following div's, this is where your feedback/output will land -->
<div class="attack-feedback"></div>
<div class="attack-output"></div>
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
</div>
<!-- do not remove the two following div's, this is where your feedback/output will land -->
<div class="attack-feedback"></div>
<div class="attack-output"></div>
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
</div>

View File

@ -10,10 +10,10 @@ ClientSideFilteringStage1Question=What is Neville Bartholomew's salary?
ClientSideFilteringStage1SubmitAnswer=Submit Answer
ClientSideFilteringStage2Finish=Click here when you believe you have completed the lesson.
ClientSideFilteringChoose=Choose Employee
ClientSideFilteringHint1=Stage 1: The information displayed when an employee is chosen from the drop down menu is stored on the client side.
ClientSideFilteringHint2=Stage 1: Use Firebug to find where the information is stored on the client side.
ClientSideFilteringHint3=Stage 1: Examine the hidden table to see if there is anyone listed who is not in the drop down menu.
ClientSideFilteringHint4=Stage 1: Look in the last row of the hidden table.
ClientSideFilteringHint1=The information displayed when an employee is chosen from the drop down menu is stored on the client side.
ClientSideFilteringHint2=Use Firebug to find where the information is stored on the client side.
ClientSideFilteringHint3=Examine the hidden table to see if there is anyone listed who is not in the drop down menu.
ClientSideFilteringHint4=Look in the last row of the hidden table.
ClientSideFilteringHint5a=Stage 1: You can access the server directly
ClientSideFilteringHint5b=here
ClientSideFilteringHint5c=to see what results are being returned
@ -22,5 +22,6 @@ ClientSideFilteringHint7=Stage 2: The query currently returns all of the content
ClientSideFilteringHint8=Stage 2: The query should only return the information of employees who are managed by Moe Stooge, whose userID is 102
ClientSideFilteringHint9=Stage 2: Try using a filter operator.
ClientSideFilteringHint10=Stage 2: Your filter operator should look something like: [Managers/Manager/text()=
ClientSideFilteringInstructions1=STAGE 1: You are logged in as Moe Stooge, CSO of Goat Hills Financial. You have access to everyone in the company's information, except the CEO, Neville Bartholomew. Or at least you shouldn't have access to the CEO's information. For this exercise, examine the contents of the page to see what extra information you can find.
ClientSideFilteringInstructions1=STAGE 1: You are logged in as Moe Stooge, CSO of Goat Hills Financial. You have access to everyone in the company's information, except the CEO, . Or at least you shouldn't have access to the CEO's information. For this exercise, examine the contents of the page to see what extra information you can find.
ClientSideFilteringInstructions2=STAGE 2: Now, fix the problem. Modify the server to only return results that Moe Stooge is allowed to see.
ClientSideFiltering.incorrect=This is not the salary from Neville Bartholomew...

View File

@ -0,0 +1,5 @@
== Salary manager
You are logged in as Moe Stooge, CSO of Goat Hills Financial. You have access to everyone in the company's information,
except the CEO, Neville Bartholomew. Or at least you shouldn't have access to the CEO's information. For this assignment,
examine the contents of the page to see what extra information you can find.

View File

@ -1,9 +1,9 @@
== HTTP Proxy Overview
Many times proxies are used as a way of accessing otehrwise blocked content. A user might connect to server A, which relays content from server B
... Because Server B is blocked wihtin the user's network. That's not the use case we will be dealing with here, but the concept is the same.
HTTP Proxies receive requesets from a client and relay them. They also typically record them. They act as a man-in-the-middle (keep that in mind if you decide to
Many times proxies are used as a way of accessing otherwise blocked content. A user might connect to server A, which relays content from server B
... Because Server B is blocked within the user's network. That's not the use case we will be dealing with here, but the concept is the same.
HTTP Proxies receive requests from a client and relay them. They also typically record them. They act as a man-in-the-middle (keep that in mind if you decide to
use a proxy server to connect to some other system that is otherwise blocked). We won't get into HTTP vs HTTPS just yet, but that's an important topic in
relationship to proxies.
@ -17,4 +17,4 @@ analyzing the security of a website.
ZAP specifically can also be used in the development process in a CI/CD, DevOps or otherwise automated build/test environment. This lesson does
not currently have any details on that, but it is worth mentioning. There are a number of examples on the internet of it being integrated into a
CI/CD with Jenkins, maven or other build processes.
CI/CD with Jenkins, Maven or other build processes.

View File

@ -24,7 +24,7 @@
</goals>
<configuration>
<backend>html</backend>
<sourceDirectory>src/main/resources/plugin/CrossSiteScripting/lessonPlans/en/</sourceDirectory>
<sourceDirectory>src/main/resources/lessonPlans/en/</sourceDirectory>
</configuration>
</execution>

View File

@ -64,7 +64,7 @@
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content5.adoc"></div>
<img align="middle" th:src="@{/plugin_lessons/plugin/CrossSiteScripting/images/Reflected-XSS.png}" />
<img align="middle" th:src="@{/images/Reflected-XSS.png}" />
</div>
<div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->

View File

@ -5,7 +5,7 @@
<div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
which you put in src/main/resources/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:HttpBasics_plan.adoc"></div>
</div>

View File

@ -1,15 +1,15 @@
=== Use the intercept
To incercept a request, you start by clicking the green button. This will set a break point for the next request.
To intercept a request, you start by clicking the green button. This will set a break point for the next request.
image::plugin_lessons/plugin/HttpProxies/images/proxy-intercept-button.png[Set break/intercept button,style="lesson-image"]
image::images/proxy-intercept-button.png[Set break/intercept button,style="lesson-image"]
NOTE: It is also possible set breakpoints that are triggered on conditions. That won't be covered in this lesson though. You are encouraged to explore.
That's part of what hackers do ... explore!
Once you are interecepting requests and a request is made, it should look something like this:
Once you are intercepting requests and a request is made, it should look something like this:
image::plugin_lessons/plugin/HttpProxies/images/proxy-intercept-details.png[ZAP history tab,1269,337,style="lesson-image"]
image::images/proxy-intercept-details.png[ZAP history tab,1269,337,style="lesson-image"]
=== Intercept and modify a request

View File

@ -15,7 +15,7 @@ Once you have 'installed' ZAP (you don't really install it, just unpack it and r
=== Start ZAP
When ZAP starts, you will be presented with a dialog such as the one below ...
image::plugin_lessons/plugin/HttpProxies/images/zap-start.png[ZAP Start,548,256,style="lesson-image"]
image::images/zap-start.png[ZAP Start,548,256,style="lesson-image"]
=== Configure Proxy's Port
@ -24,4 +24,4 @@ image::plugin_lessons/plugin/HttpProxies/images/zap-start.png[ZAP Start,548,256,
. Choose an available port ... Since WebGoat is using port 8080, use something different like 8090
. Click OK
image::plugin_lessons/plugin/HttpProxies/images/zap-local-proxy.png[ZAP local proxy,800,648,style="lesson-image"]
image::images/zap-local-proxy.png[ZAP local proxy,800,648,style="lesson-image"]

View File

@ -14,7 +14,7 @@ This will send all of your traffic to the proxy. Since we haven't set up a trust
.. input *8090* as the port
.. check the _Use this proxy server for all protocols_ checkbox
image::plugin_lessons/plugin/HttpProxies/images/firefox-proxy-config.png[Firefox Proxy Config,510,634,style="lesson-image"]
image::images/firefox-proxy-config.png[Firefox Proxy Config,510,634,style="lesson-image"]
=== Chrome Proxy Config
@ -26,7 +26,7 @@ image::plugin_lessons/plugin/HttpProxies/images/firefox-proxy-config.png[Firefox
. Input 127..0.0.1 in the first box under _Web Proxy Server_ and your port # (8090 is what used earlier) in the second box (to the right)
. You may also want to clear the _Bypass proxy settings for these Hosts & Domains_ text input at the bottom, but shouldn't need to
image::plugin_lessons/plugin/HttpProxies/images/chrome-manual-proxy.png[Chrome Proxy Config,700,447,style="lesson-image"]
image::images/chrome-manual-proxy.png[Chrome Proxy Config,700,447,style="lesson-image"]
=== Other Proxy Configuration Options

View File

@ -3,4 +3,4 @@
You should now be able to browse somewhere. We suggest starting with a plain http host.
If it's working, ZAP's history tab will start to look something like this.
image::plugin_lessons/plugin/HttpProxies/images/zap-history.png[ZAP history tab,1269,337,style="lesson-image"]
image::images/zap-history.png[ZAP history tab,1269,337,style="lesson-image"]

View File

@ -25,7 +25,7 @@
</goals>
<configuration>
<backend>html</backend>
<sourceDirectory>src/main/resources/plugin/IDOR/lessonPlans/en/</sourceDirectory>
<sourceDirectory>src/main/resources/lessonPlans/en/</sourceDirectory>
</configuration>
</execution>

View File

@ -11,7 +11,6 @@ import org.springframework.web.bind.annotation.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Path;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

Some files were not shown because too many files have changed in this diff Show More