XSS lesson completion fixes (#669)

* XSS lesson completion fixes

* removed log all

* lesson progress capable of deprecated assignments in the database

* fixed unit test for lesson progress
This commit is contained in:
René Zubcevic 2019-09-29 14:46:18 +02:00 committed by GitHub
parent 45c7949118
commit 0319c477b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 218 additions and 58 deletions

View File

@ -45,6 +45,7 @@ public class Assignment {
private Long id; private Long id;
private String name; private String name;
private String path; private String path;
@Transient @Transient
private List<String> hints; private List<String> hints;
@ -64,4 +65,14 @@ public class Assignment {
this.path = path; this.path = path;
this.hints = hints; this.hints = hints;
} }
/**
* Set path is here to overwrite stored paths.
* Since a stored path can no longer be used in a lesson while
* the lesson (name) itself is still part of the lesson.
* @param pathName
*/
public void setPath(String pathName) {
this.path = pathName;
}
} }

View File

@ -30,6 +30,7 @@ package org.owasp.webgoat.service;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.lessons.Assignment;
import org.owasp.webgoat.lessons.Category; import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.LessonMenuItem; import org.owasp.webgoat.lessons.LessonMenuItem;
import org.owasp.webgoat.lessons.LessonMenuItemType; import org.owasp.webgoat.lessons.LessonMenuItemType;
@ -45,6 +46,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -88,7 +90,8 @@ public class LessonMenuService {
lessonItem.setLink(lesson.getLink()); lessonItem.setLink(lesson.getLink());
lessonItem.setType(LessonMenuItemType.LESSON); lessonItem.setType(LessonMenuItemType.LESSON);
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson); LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
lessonItem.setComplete(lessonTracker.isLessonSolved()); boolean lessonSolved = lessonCompleted(lessonTracker.getLessonOverview(), lesson);
lessonItem.setComplete(lessonSolved);
categoryItem.addChild(lessonItem); categoryItem.addChild(lessonItem);
} }
categoryItem.getChildren().sort((o1, o2) -> o1.getRanking() - o2.getRanking()); categoryItem.getChildren().sort((o1, o2) -> o1.getRanking() - o2.getRanking());
@ -97,4 +100,27 @@ public class LessonMenuService {
return menu; return menu;
} }
/**
* This determines if the lesson is complete based on data in the database
* and the list of assignments actually linked to the existing current lesson.
* This way older removed assignments will not prevent a lesson from being completed.
* @param map
* @param currentLesson
* @return
*/
private boolean lessonCompleted(Map<Assignment, Boolean> map, Lesson currentLesson) {
boolean result = true;
for (Map.Entry<Assignment, Boolean> entry : map.entrySet()) {
Assignment storedAssignment = entry.getKey();
for (Assignment lessonAssignment: currentLesson.getAssignments()) {
if (lessonAssignment.getName().equals(storedAssignment.getName())) {
result = result && entry.getValue();
break;
}
}
}
return result;
}
} }

View File

@ -47,7 +47,7 @@ public class LessonProgressService {
String successMessage = ""; String successMessage = "";
boolean lessonCompleted = false; boolean lessonCompleted = false;
if (lessonTracker != null) { if (lessonTracker != null) {
lessonCompleted = lessonTracker.isLessonSolved(); lessonCompleted = lessonCompleted(lessonTracker.getLessonOverview(),webSession.getCurrentLesson());
successMessage = "LessonCompleted"; //@todo we still use this?? successMessage = "LessonCompleted"; //@todo we still use this??
} }
json.put("lessonCompleted", lessonCompleted); json.put("lessonCompleted", lessonCompleted);
@ -70,19 +70,56 @@ public class LessonProgressService {
List<LessonOverview> result = Lists.newArrayList(); List<LessonOverview> result = Lists.newArrayList();
if ( currentLesson != null ) { if ( currentLesson != null ) {
LessonTracker lessonTracker = userTracker.getLessonTracker(currentLesson); LessonTracker lessonTracker = userTracker.getLessonTracker(currentLesson);
result = toJson(lessonTracker.getLessonOverview()); result = toJson(lessonTracker.getLessonOverview(), currentLesson);
} }
return result; return result;
} }
private List<LessonOverview> toJson(Map<Assignment, Boolean> map) { private List<LessonOverview> toJson(Map<Assignment, Boolean> map, Lesson currentLesson) {
List<LessonOverview> result = new ArrayList(); List<LessonOverview> result = new ArrayList();
for (Map.Entry<Assignment, Boolean> entry : map.entrySet()) { for (Map.Entry<Assignment, Boolean> entry : map.entrySet()) {
result.add(new LessonOverview(entry.getKey(), entry.getValue())); Assignment storedAssignment = entry.getKey();
for (Assignment lessonAssignment: currentLesson.getAssignments()) {
if (lessonAssignment.getName().equals(storedAssignment.getName())
&& !lessonAssignment.getPath().equals(storedAssignment.getPath())) {
//here a stored path in the assignments table will be corrected for the JSON output
//with the value of the actual expected path
storedAssignment.setPath(lessonAssignment.getPath());
result.add(new LessonOverview(storedAssignment, entry.getValue()));
break;
} else if (lessonAssignment.getName().equals(storedAssignment.getName())) {
result.add(new LessonOverview(storedAssignment, entry.getValue()));
break;
}
}
//assignments not in the list will not be put in the lesson progress JSON output
} }
return result; return result;
} }
/**
* Get the lesson completed based on Assignment data from the database
* while ignoring assignments no longer in the application.
* @param map
* @param currentLesson
* @return
*/
private boolean lessonCompleted(Map<Assignment, Boolean> map, Lesson currentLesson) {
boolean result = true;
for (Map.Entry<Assignment, Boolean> entry : map.entrySet()) {
Assignment storedAssignment = entry.getKey();
for (Assignment lessonAssignment: currentLesson.getAssignments()) {
if (lessonAssignment.getName().equals(storedAssignment.getName())) {
result = result && entry.getValue();
break;
}
}
}
return result;
}
@AllArgsConstructor @AllArgsConstructor
@Getter @Getter

View File

@ -1,10 +1,10 @@
package org.owasp.webgoat.session; package org.owasp.webgoat.session;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.users.WebGoatUser; import org.owasp.webgoat.users.WebGoatUser;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import java.io.Serializable;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
@ -37,10 +37,10 @@ import java.sql.SQLException;
* @version $Id: $Id * @version $Id: $Id
* @since October 28, 2003 * @since October 28, 2003
*/ */
@Slf4j public class WebSession implements Serializable {
public class WebSession {
private final WebGoatUser currentUser; private static final long serialVersionUID = -4270066103101711560L;
private final WebGoatUser currentUser;
private final WebgoatContext webgoatContext; private final WebgoatContext webgoatContext;
private Lesson currentLesson; private Lesson currentLesson;

View File

@ -50,7 +50,7 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class LessonMenuServiceTest { public class LessonMenuServiceTest {
@Mock @Mock(lenient=true)
private LessonTracker lessonTracker; private LessonTracker lessonTracker;
@Mock @Mock
private Course course; private Course course;

View File

@ -76,6 +76,7 @@ public class LessonProgressServiceTest {
when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); when(userTrackerRepository.findByUser(any())).thenReturn(userTracker);
when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker); when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker);
when(websession.getCurrentLesson()).thenReturn(lesson); when(websession.getCurrentLesson()).thenReturn(lesson);
when(lesson.getAssignments()).thenReturn(List.of(assignment));
when(lessonTracker.getLessonOverview()).thenReturn(Maps.newHashMap(assignment, true)); when(lessonTracker.getLessonOverview()).thenReturn(Maps.newHashMap(assignment, true));
this.mockMvc = MockMvcBuilders.standaloneSetup(new LessonProgressService(userTrackerRepository, websession)).build(); this.mockMvc = MockMvcBuilders.standaloneSetup(new LessonProgressService(userTrackerRepository, websession)).build();
} }

View File

@ -123,4 +123,20 @@ public class GeneralLessonTest extends IntegrationTest {
checkResults("/ChromeDevTools/"); checkResults("/ChromeDevTools/");
} }
@Test
public void authByPass() {
startLesson("AuthBypass");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("secQuestion2", "John");
params.put("secQuestion3", "Main");
params.put("jsEnabled", "1");
params.put("verifyMethod", "SEC_QUESTIONS");
params.put("userId", "12309746");
checkAssignment(url("/auth-bypass/verify-account"), params, true);
checkResults("/auth-bypass/");
}
} }

View File

@ -238,5 +238,18 @@ public abstract class IntegrationTest {
.extract().path("lessonCompleted"), CoreMatchers.is(expectedResult)); .extract().path("lessonCompleted"), CoreMatchers.is(expectedResult));
} }
public void checkAssignmentWithGet(String url, Map<String, ?> params, boolean expectedResult) {
Assert.assertThat(
RestAssured.given()
.when()
.config(restConfig)
.cookie("JSESSIONID", getWebGoatCookie())
.queryParams(params)
.get(url)
.then()
.statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(expectedResult));
}
} }

View File

@ -0,0 +1,68 @@
package org.owasp.webgoat;
import org.junit.Test;
import io.restassured.RestAssured;
import java.util.HashMap;
import java.util.Map;
public class XSSTest extends IntegrationTest {
@Test
public void crossSiteScriptingAssignments() {
startLesson("CrossSiteScripting");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("answer_xss_1", "yes");
checkAssignment(url("/CrossSiteScripting/attack1"), params, true);
params.clear();
params.put("QTY1", "1");
params.put("QTY2", "1");
params.put("QTY3", "1");
params.put("QTY4", "1");
params.put("field1", "<script>alert('XSS+Test')</script>");
params.put("field2", "111");
checkAssignmentWithGet(url("/CrossSiteScripting/attack5a"), params, true);
params.clear();
params.put("DOMTestRoute", "start.mvc#test");
checkAssignment(url("/CrossSiteScripting/attack6a"), params, true);
params.clear();
params.put("param1", "42");
params.put("param2", "24");
String result =
RestAssured.given()
.when()
.config(restConfig)
.cookie("JSESSIONID", getWebGoatCookie())
.header("webgoat-requested-by", "dom-xss-vuln")
.header("X-Requested-With", "XMLHttpRequest")
.formParams(params)
.post(url("/CrossSiteScripting/phone-home-xss"))
.then()
.statusCode(200)
.extract().path("output");
String secretNumber = result.substring("phoneHome Response is ".length());
params.clear();
params.put("successMessage", secretNumber);
checkAssignment(url("/CrossSiteScripting/dom-follow-up"), params, true);
params.clear();
params.put("question_0_solution", "Solution 4: No because the browser trusts the website if it is acknowledged trusted, then the browser does not know that the script is malicious.");
params.put("question_1_solution", "Solution 3: The data is included in dynamic content that is sent to a web user without being validated for malicious content.");
params.put("question_2_solution", "Solution 1: The script is permanently stored on the server and the victim gets the malicious script when requesting information from the server.");
params.put("question_3_solution", "Solution 2: They reflect the injected script off the web server. That occurs when input sent to the web server is part of the request.");
params.put("question_4_solution", "Solution 4: No there are many other ways. Like HTML, Flash or any other type of code that the browser executes.");
checkAssignment(url("/CrossSiteScripting/quiz"), params, true);
checkResults("/CrossSiteScripting/");
}
}

View File

@ -27,15 +27,18 @@ import org.jsoup.Jsoup;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
import org.owasp.webgoat.assignments.AssignmentEndpoint; import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints; import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult; import org.owasp.webgoat.assignments.AttackResult;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@RestController //@RestController
@Deprecated
//TODO This assignment seems not to be in use in the UI
// it is there to make sure the lesson can be marked complete
// in order to restore it, make it accessible through the UI and uncomment RestController
@AssignmentHints(value = {"xss-mitigation-3-hint1", "xss-mitigation-3-hint2", "xss-mitigation-3-hint3", "xss-mitigation-3-hint4"}) @AssignmentHints(value = {"xss-mitigation-3-hint1", "xss-mitigation-3-hint2", "xss-mitigation-3-hint3", "xss-mitigation-3-hint4"})
public class CrossSiteScriptingLesson3 extends AssignmentEndpoint { public class CrossSiteScriptingLesson3 extends AssignmentEndpoint {
@PostMapping("CrossSiteScripting/attack3") @PostMapping("/CrossSiteScripting/attack3")
@ResponseBody @ResponseBody
public AttackResult completed(@RequestParam String editor) { public AttackResult completed(@RequestParam String editor) {
String unescapedString = org.jsoup.parser.Parser.unescapeEntities(editor, true); String unescapedString = org.jsoup.parser.Parser.unescapeEntities(editor, true);

View File

@ -24,28 +24,26 @@ package org.owasp.webgoat.xss;
import org.owasp.webgoat.assignments.AssignmentEndpoint; import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints; import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult; import org.owasp.webgoat.assignments.AttackResult;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.tools.*; import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@RestController //@RestController
@Deprecated
//TODO This assignment seems not to be in use in the UI
//it is there to make sure the lesson can be marked complete
//in order to restore it, make it accessible through the UI and uncomment RestController@Slf4j
@Slf4j
@AssignmentHints(value = {"xss-mitigation-4-hint1"}) @AssignmentHints(value = {"xss-mitigation-4-hint1"})
public class CrossSiteScriptingLesson4 extends AssignmentEndpoint { public class CrossSiteScriptingLesson4 extends AssignmentEndpoint {
@PostMapping("CrossSiteScripting/attack4") @PostMapping("/CrossSiteScripting/attack4")
@ResponseBody @ResponseBody
public AttackResult completed(@RequestParam String editor2) { public AttackResult completed(@RequestParam String editor2) {
String editor = editor2.replaceAll("\\<.*?>", ""); String editor = editor2.replaceAll("\\<.*?>", "");
System.out.println(editor); log.debug(editor);
if ((editor.contains("Policy.getInstance(\"antisamy-slashdot.xml\"") || editor.contains(".scan(newComment, \"antisamy-slashdot.xml\"") || editor.contains(".scan(newComment, new File(\"antisamy-slashdot.xml\")")) && if ((editor.contains("Policy.getInstance(\"antisamy-slashdot.xml\"") || editor.contains(".scan(newComment, \"antisamy-slashdot.xml\"") || editor.contains(".scan(newComment, new File(\"antisamy-slashdot.xml\")")) &&
editor.contains("new AntiSamy();") && editor.contains("new AntiSamy();") &&
@ -53,10 +51,10 @@ public class CrossSiteScriptingLesson4 extends AssignmentEndpoint {
editor.contains("CleanResults") && editor.contains("CleanResults") &&
editor.contains("MyCommentDAO.addComment(threadID, userID") && editor.contains("MyCommentDAO.addComment(threadID, userID") &&
editor.contains(".getCleanHTML());")) { editor.contains(".getCleanHTML());")) {
System.out.println("true"); log.debug("true");
return trackProgress(success().feedback("xss-mitigation-4-success").build()); return trackProgress(success().feedback("xss-mitigation-4-success").build());
} else { } else {
System.out.println("false"); log.debug("false");
return trackProgress(failed().feedback("xss-mitigation-4-failed").build()); return trackProgress(failed().feedback("xss-mitigation-4-failed").build());
} }
} }

View File

@ -25,15 +25,11 @@ package org.owasp.webgoat.xss;
import org.owasp.webgoat.assignments.AssignmentEndpoint; import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints; import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult; import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.UserSessionData; import org.owasp.webgoat.session.UserSessionData;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@RestController @RestController
@AssignmentHints(value = {"xss-reflected-5a-hint-1", "xss-reflected-5a-hint-2", "xss-reflected-5a-hint-3", "xss-reflected-5a-hint-4"}) @AssignmentHints(value = {"xss-reflected-5a-hint-1", "xss-reflected-5a-hint-2", "xss-reflected-5a-hint-3", "xss-reflected-5a-hint-4"})

View File

@ -25,14 +25,11 @@ package org.owasp.webgoat.xss;
import org.owasp.webgoat.assignments.AssignmentEndpoint; import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints; import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult; import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.UserSessionData; import org.owasp.webgoat.session.UserSessionData;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.io.IOException;
@RestController @RestController
@AssignmentHints(value = {"xss-reflected-6a-hint-1", "xss-reflected-6a-hint-2", "xss-reflected-6a-hint-3", "xss-reflected-6a-hint-4"}) @AssignmentHints(value = {"xss-reflected-6a-hint-1", "xss-reflected-6a-hint-2", "xss-reflected-6a-hint-3", "xss-reflected-6a-hint-4"})

View File

@ -34,7 +34,7 @@ public class CrossSiteScriptingQuiz extends AssignmentEndpoint {
String[] solutions = {"Solution 4", "Solution 3", "Solution 1", "Solution 2", "Solution 4"}; String[] solutions = {"Solution 4", "Solution 3", "Solution 1", "Solution 2", "Solution 4"};
boolean[] guesses = new boolean[solutions.length]; boolean[] guesses = new boolean[solutions.length];
@PostMapping("/cross-site-scripting/quiz") @PostMapping("/CrossSiteScripting/quiz")
@ResponseBody @ResponseBody
public AttackResult completed(@RequestParam String[] question_0_solution, @RequestParam String[] question_1_solution, @RequestParam String[] question_2_solution, @RequestParam String[] question_3_solution, @RequestParam String[] question_4_solution) throws IOException { public AttackResult completed(@RequestParam String[] question_0_solution, @RequestParam String[] question_1_solution, @RequestParam String[] question_2_solution, @RequestParam String[] question_3_solution, @RequestParam String[] question_4_solution) throws IOException {
int correctAnswers = 0; int correctAnswers = 0;
@ -59,7 +59,7 @@ public class CrossSiteScriptingQuiz extends AssignmentEndpoint {
} }
} }
@GetMapping("/cross-site-scripting/quiz") @GetMapping("/CrossSiteScripting/quiz")
@ResponseBody @ResponseBody
public boolean[] getResults() { public boolean[] getResults() {
return this.guesses; return this.guesses;

View File

@ -28,7 +28,6 @@ import org.owasp.webgoat.session.UserSessionData;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.security.SecureRandom; import java.security.SecureRandom;
@RestController @RestController

View File

@ -24,14 +24,10 @@ package org.owasp.webgoat.xss;
import org.owasp.webgoat.assignments.AssignmentEndpoint; import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints; import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult; import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.UserSessionData; import org.owasp.webgoat.session.UserSessionData;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/** /**
* Created by jason on 11/23/16. * Created by jason on 11/23/16.
*/ */

View File

@ -20,7 +20,7 @@
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
*/ */
package org.owasp.webgoat.xss; package org.owasp.webgoat.xss.mitigation;
import org.owasp.webgoat.lessons.Category; import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.lessons.Lesson;

View File

@ -20,7 +20,7 @@
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
*/ */
package org.owasp.webgoat.xss; package org.owasp.webgoat.xss.stored;
import org.owasp.webgoat.lessons.Category; import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.lessons.Lesson;

View File

@ -20,23 +20,21 @@
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
*/ */
package org.owasp.webgoat.xss; package org.owasp.webgoat.xss.stored;
import org.owasp.webgoat.assignments.AssignmentEndpoint; import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult; import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.UserSessionData; import org.owasp.webgoat.session.UserSessionData;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.io.IOException;
/** /**
* Created by jason on 11/23/16. * Created by jason on 11/23/16.
*/ */
@RestController @RestController
public class StoredCrossSiteScriptingVerifier extends AssignmentEndpoint { public class StoredCrossSiteScriptingVerifier extends AssignmentEndpoint {
@PostMapping("/CrossSiteScripting/stored-xss-follow-up") //TODO This assignment seems not to be in use in the UI
@PostMapping("/CrossSiteScriptingStored/stored-xss-follow-up")
@ResponseBody @ResponseBody
public AttackResult completed(@RequestParam String successMessage) { public AttackResult completed(@RequestParam String successMessage) {
UserSessionData userSessionData = getUserSessionData(); UserSessionData userSessionData = getUserSessionData();

View File

@ -20,7 +20,7 @@
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
*/ */
package org.owasp.webgoat.xss; package org.owasp.webgoat.xss.stored;
import com.beust.jcommander.internal.Lists; import com.beust.jcommander.internal.Lists;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
@ -30,20 +30,18 @@ import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.owasp.webgoat.assignments.AssignmentEndpoint; import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult; import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.WebSession; import org.owasp.webgoat.session.WebSession;
import org.owasp.webgoat.xss.Comment;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.owasp.encoder.*;
import static org.springframework.http.MediaType.ALL_VALUE; import static org.springframework.http.MediaType.ALL_VALUE;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
@RestController @RestController
public class StoredXssComments extends AssignmentEndpoint { public class StoredXssComments extends AssignmentEndpoint {
@ -64,7 +62,8 @@ public class StoredXssComments extends AssignmentEndpoint {
comments.add(new Comment("guest", DateTime.now().toString(fmt), "Can you post a comment, calling webgoat.customjs.phoneHome() ?")); comments.add(new Comment("guest", DateTime.now().toString(fmt), "Can you post a comment, calling webgoat.customjs.phoneHome() ?"));
} }
@GetMapping(path = "/CrossSiteScripting/stored-xss", produces = MediaType.APPLICATION_JSON_VALUE, consumes = ALL_VALUE) //TODO This assignment seems not to be in use in the UI
@GetMapping(path = "/CrossSiteScriptingStored/stored-xss", produces = MediaType.APPLICATION_JSON_VALUE, consumes = ALL_VALUE)
@ResponseBody @ResponseBody
public Collection<Comment> retrieveComments() { public Collection<Comment> retrieveComments() {
List<Comment> allComments = Lists.newArrayList(); List<Comment> allComments = Lists.newArrayList();
@ -77,7 +76,8 @@ public class StoredXssComments extends AssignmentEndpoint {
return allComments; return allComments;
} }
@PostMapping("/CrossSiteScripting/stored-xss") //TODO This assignment seems not to be in use in the UI
@PostMapping("/CrossSiteScriptingStored/stored-xss")
@ResponseBody @ResponseBody
public AttackResult createNewComment(@RequestBody String commentStr) { public AttackResult createNewComment(@RequestBody String commentStr) {
Comment comment = parseJson(commentStr); Comment comment = parseJson(commentStr);

View File

@ -182,7 +182,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/cross-site-scripting/quiz" action="/WebGoat/CrossSiteScripting/quiz"
enctype="application/json;charset=UTF-8" role="form"> enctype="application/json;charset=UTF-8" role="form">
<div id="q_container"></div> <div id="q_container"></div>
<br /> <br />

View File

@ -28,6 +28,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import org.owasp.webgoat.assignments.AssignmentEndpointTest; import org.owasp.webgoat.assignments.AssignmentEndpointTest;
import org.owasp.webgoat.xss.stored.StoredXssComments;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
@ -53,7 +54,7 @@ public class StoredXssCommentsTest extends AssignmentEndpointTest {
@Test @Test
public void success() throws Exception { public void success() throws Exception {
ResultActions results = mockMvc.perform(MockMvcRequestBuilders.post("/CrossSiteScripting/stored-xss") ResultActions results = mockMvc.perform(MockMvcRequestBuilders.post("/CrossSiteScriptingStored/stored-xss")
.content("{\"text\":\"someTextHere<script>webgoat.customjs.phoneHome()</script>MoreTextHere\"}") .content("{\"text\":\"someTextHere<script>webgoat.customjs.phoneHome()</script>MoreTextHere\"}")
.contentType(MediaType.APPLICATION_JSON)); .contentType(MediaType.APPLICATION_JSON));
@ -63,7 +64,7 @@ public class StoredXssCommentsTest extends AssignmentEndpointTest {
@Test @Test
public void failure() throws Exception { public void failure() throws Exception {
ResultActions results = mockMvc.perform(MockMvcRequestBuilders.post("/CrossSiteScripting/stored-xss") ResultActions results = mockMvc.perform(MockMvcRequestBuilders.post("/CrossSiteScriptingStored/stored-xss")
.content("{\"text\":\"someTextHere<script>alert('Xss')</script>MoreTextHere\"}") .content("{\"text\":\"someTextHere<script>alert('Xss')</script>MoreTextHere\"}")
.contentType(MediaType.APPLICATION_JSON)); .contentType(MediaType.APPLICATION_JSON));
@ -80,7 +81,7 @@ public class StoredXssCommentsTest extends AssignmentEndpointTest {
@Test @Test
public void isNotEncoded() throws Exception { public void isNotEncoded() throws Exception {
//do get to get comments after posting xss payload //do get to get comments after posting xss payload
ResultActions taintedResults = mockMvc.perform(MockMvcRequestBuilders.get("/CrossSiteScripting/stored-xss")); ResultActions taintedResults = mockMvc.perform(MockMvcRequestBuilders.get("/CrossSiteScriptingStored/stored-xss"));
MvcResult mvcResult = taintedResults.andReturn(); MvcResult mvcResult = taintedResults.andReturn();
assert(mvcResult.getResponse().getContentAsString().contains("<script>console.warn")); assert(mvcResult.getResponse().getContentAsString().contains("<script>console.warn"));
} }