From e34faa13d6269b27196763eb8b03d95fc4c54d40 Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 2 May 2018 16:35:57 -0600 Subject: [PATCH 01/25] fix for periodic fail on StoredXssCommentsTest --- .../webgoat/plugin/StoredXssCommentsTest.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/webgoat-lessons/cross-site-scripting/src/test/java/org/owasp/webgoat/plugin/StoredXssCommentsTest.java b/webgoat-lessons/cross-site-scripting/src/test/java/org/owasp/webgoat/plugin/StoredXssCommentsTest.java index 3187e936b..4e7802e77 100644 --- a/webgoat-lessons/cross-site-scripting/src/test/java/org/owasp/webgoat/plugin/StoredXssCommentsTest.java +++ b/webgoat-lessons/cross-site-scripting/src/test/java/org/owasp/webgoat/plugin/StoredXssCommentsTest.java @@ -33,8 +33,10 @@ import org.mockito.runners.MockitoJUnitRunner; import org.owasp.webgoat.assignments.AssignmentEndpointTest; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.util.Assert; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -80,12 +82,17 @@ public class StoredXssCommentsTest extends AssignmentEndpointTest { */ //Ensures it is vulnerable -// @Test -// public void isNotEncoded() throws Exception { -// //do get to get comments after posting xss payload -// ResultActions taintedResults = mockMvc.perform(MockMvcRequestBuilders.get("/CrossSiteScripting/stored-xss")); -// taintedResults.andExpect(jsonPath("$[0].text",CoreMatchers.is(CoreMatchers.containsString("")))); -// } + @Test + public void isNotEncoded() throws Exception { + //do get to get comments after posting xss payload + ResultActions taintedResults = mockMvc.perform(MockMvcRequestBuilders.get("/CrossSiteScripting/stored-xss")); + MvcResult mvcResult = taintedResults.andReturn(); + assert(mvcResult.getResponse().getContentAsString().contains("4128+3214+0002+1999&field2=111 +link: http://localhost:8080/WebGoat/CrossSiteScripting/attack5a?QTY1=1&QTY2=1&QTY3=1&QTY4=1&field1=4128+3214+0002+1999&field2=111 diff --git a/webgoat-lessons/cross-site-scripting/src/main/resources/lessonPlans/en/CrossSiteScripting_content6a.adoc b/webgoat-lessons/cross-site-scripting/src/main/resources/lessonPlans/en/CrossSiteScripting_content6a.adoc index 656d9f4de..cd815fce0 100644 --- a/webgoat-lessons/cross-site-scripting/src/main/resources/lessonPlans/en/CrossSiteScripting_content6a.adoc +++ b/webgoat-lessons/cross-site-scripting/src/main/resources/lessonPlans/en/CrossSiteScripting_content6a.adoc @@ -1,4 +1,4 @@ -== Ientify Potential for DOM-Based XSS +== Identify Potential for DOM-Based XSS DOM-Based XSS can usually be found by looking for the route configurations in the client-side code. Look for a route that takes inputs that you can ID being 'reflected' to the page. @@ -7,7 +7,7 @@ For this example, you'll want to look for some 'test' code in the route handlers Sometimes, test code gets left in production (and often times test code is very simple and lacks security or any quality controls!). Your objective is to find the route and exploit it. First though ... what is the base route? As an example, look at the URL for this lesson ... -it should look something like /WebGoat/start.mvc#lesson/CrossSiteScripting.lesson/5 (although maybe slightly different). The 'base route' in this case is: +it should look something like /WebGoat/start.mvc#lesson/CrossSiteScripting.lesson/9 (although maybe slightly different). The 'base route' in this case is: *start.mvc#lesson/* The *CrossSiteScripting.lesson/#* after that are parameters that are processed by javascript route handler. From 3d282e163c83071f44b97d95c8445a460c7fb0ff Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Fri, 8 Jun 2018 16:45:27 +0200 Subject: [PATCH 13/25] Show newest comments first This prevents new comments from not being displayed after a comment containing invalid html has been posted. --- .../owasp/webgoat/plugin/StoredXssComments.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/webgoat-lessons/cross-site-scripting/src/main/java/org/owasp/webgoat/plugin/StoredXssComments.java b/webgoat-lessons/cross-site-scripting/src/main/java/org/owasp/webgoat/plugin/StoredXssComments.java index 022abc883..8fbff0518 100644 --- a/webgoat-lessons/cross-site-scripting/src/main/java/org/owasp/webgoat/plugin/StoredXssComments.java +++ b/webgoat-lessons/cross-site-scripting/src/main/java/org/owasp/webgoat/plugin/StoredXssComments.java @@ -49,10 +49,7 @@ import org.owasp.encoder.*; import static org.springframework.http.MediaType.ALL_VALUE; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.util.*; import static org.springframework.web.bind.annotation.RequestMethod.GET; @@ -72,20 +69,19 @@ public class StoredXssComments extends AssignmentEndpoint { comments.add(new Comment("secUriTy", DateTime.now().toString(fmt), "Comment for Unit Testing")); comments.add(new Comment("webgoat", DateTime.now().toString(fmt), "This comment is safe")); comments.add(new Comment("guest", DateTime.now().toString(fmt), "This one is safe too.")); - 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() ?")); } @RequestMapping(method = GET, produces = MediaType.APPLICATION_JSON_VALUE,consumes = ALL_VALUE) @ResponseBody public Collection retrieveComments() { - Collection allComments = Lists.newArrayList(); + List allComments = Lists.newArrayList(); Collection newComments = userComments.get(webSession.getUserName()); + allComments.addAll(comments); if (newComments != null) { allComments.addAll(newComments); } - - allComments.addAll(comments); - + Collections.reverse(allComments); return allComments; } From a7b82985d4cc3fab14bd411beb0375cac85a44c2 Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Fri, 8 Jun 2018 19:31:32 +0200 Subject: [PATCH 14/25] Fix usage of JJWT API which expects base64 encoded strings as key --- .../java/org/owasp/webgoat/plugin/JWTSecretKeyEndpoint.java | 3 ++- .../jwt/src/main/resources/lessonPlans/en/JWT_weak_keys | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpoint.java b/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpoint.java index 5748681f5..f3f2ab8b7 100644 --- a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpoint.java +++ b/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpoint.java @@ -1,6 +1,7 @@ package org.owasp.webgoat.plugin; import com.google.common.collect.Lists; +import io.jsonwebtoken.impl.TextCodec; import org.owasp.webgoat.assignments.AssignmentEndpoint; import org.owasp.webgoat.assignments.AssignmentHints; import org.owasp.webgoat.assignments.AssignmentPath; @@ -23,7 +24,7 @@ import java.util.List; @AssignmentHints({"jwt-secret-hint1", "jwt-secret-hint2", "jwt-secret-hint3"}) public class JWTSecretKeyEndpoint extends AssignmentEndpoint { - public static final String JWT_SECRET = "victory"; + public static final String JWT_SECRET = TextCodec.BASE64.encode("victory"); private static final String WEBGOAT_USER = "WebGoat"; private static final List expectedClaims = Lists.newArrayList("iss", "iat", "exp", "aud", "sub", "username", "Email", "Role"); diff --git a/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_weak_keys b/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_weak_keys index b8da3bf02..d57483f2e 100644 --- a/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_weak_keys +++ b/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_weak_keys @@ -9,5 +9,5 @@ dictionary attack is not feasible. Once you have a token you can start an offlin Given we have the following token try to find out secret key and submit a new key with the userId changed to WebGoat. ``` -eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJpYXQiOjE1MjQyMTA5MDQsImV4cCI6MTYxODkwNTMwNCwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJ0b21Ad2ViZ29hdC5jb20iLCJ1c2VybmFtZSI6IlRvbSIsIkVtYWlsIjoidG9tQHdlYmdvYXQuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.m-jSyfYEsVzD3CBI6N39wZ7AcdKdp_GiO7F_Ym12u-0 +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJpYXQiOjE1MjQyMTA5MDQsImV4cCI6MTYxODkwNTMwNCwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJ0b21Ad2ViZ29hdC5jb20iLCJ1c2VybmFtZSI6IlRvbSIsIkVtYWlsIjoidG9tQHdlYmdvYXQuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.vPe-qQPOt78zK8wrbN1TjNJj3LeX9Qbch6oo23RUJgM ``` \ No newline at end of file From bae3e75ae23f65626354cf822c760a8d9887c3ec Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Mon, 11 Jun 2018 16:43:16 +0200 Subject: [PATCH 15/25] Fix minor issues in hint view --- .../js/goatApp/controller/LessonController.js | 3 ++- .../static/js/goatApp/view/HintView.js | 20 +++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/webgoat-container/src/main/resources/static/js/goatApp/controller/LessonController.js b/webgoat-container/src/main/resources/static/js/goatApp/controller/LessonController.js index 11b8279cf..f9bfadf6e 100644 --- a/webgoat-container/src/main/resources/static/js/goatApp/controller/LessonController.js +++ b/webgoat-container/src/main/resources/static/js/goatApp/controller/LessonController.js @@ -79,6 +79,7 @@ define(['jquery', this.listenTo(this.lessonHintView, 'hints:hideButton', this.onHideHintsButton); this.lessonContentView.navToPage(pageNum); this.lessonHintView.hideHints(); + this.lessonHintView.showFirstHint(); //this.lessonHintView.selectHints(); this.titleView.render(this.lessonInfoModel.get('lessonTitle')); return; @@ -160,7 +161,7 @@ define(['jquery', } // this.lessonHintView.render(); - if (this.lessonHintView.getHintsCount > 0) { + if (this.lessonHintView.getHintsCount() > 0) { this.helpControlsView.showHintsButton(); } else { this.helpControlsView.hideHintsButton(); diff --git a/webgoat-container/src/main/resources/static/js/goatApp/view/HintView.js b/webgoat-container/src/main/resources/static/js/goatApp/view/HintView.js index f8b4a2159..a1d83ef89 100644 --- a/webgoat-container/src/main/resources/static/js/goatApp/view/HintView.js +++ b/webgoat-container/src/main/resources/static/js/goatApp/view/HintView.js @@ -32,21 +32,19 @@ function($, toggleLabel: function() { if (this.isVisible()) { - $('show-hints-button').text('Hide hints'); + $('#show-hints-button').text('Hide hints'); } else { - $('show-hints-button').text('Show hints'); + $('#show-hints-button').text('Show hints'); } }, render:function() { if (this.isVisible()) { - this.$el.hide(350); + this.$el.hide(350, this.toggleLabel.bind(this)); } else if (this.hintsToShow.length > 0) { - this.$el.show(350); + this.$el.show(350, this.toggleLabel.bind(this)); } - this.toggleLabel() - if (this.hintsToShow.length > 0) { this.hideShowPrevNextButtons(); } @@ -90,9 +88,9 @@ function($, hideHints: function() { if (this.$el.is(':visible')) { - this.$el.hide(350); + this.$el.hide(350, this.toggleLabel.bind(this)); } - }, + }, showNextHint: function() { this.curHint = (this.curHint < this.hintsToShow.length -1) ? this.curHint+1 : this.curHint; @@ -106,6 +104,12 @@ function($, this.displayHint(this.curHint); }, + showFirstHint: function() { + this.curHint = 0; + this.hideShowPrevNextButtons(); + this.displayHint(this.curHint); + }, + displayHint: function(curHint) { if(this.hintsToShow.length == 0) { // this.hideHints(); From f383454440ec75bd77b6eeb289cc4da9939668d6 Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Mon, 11 Jun 2018 16:53:32 +0200 Subject: [PATCH 16/25] Fix spelling in JWT lesson --- .../src/main/resources/lessonPlans/en/JWT_refresh.adoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_refresh.adoc b/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_refresh.adoc index 3b91e0bfa..571bfcc21 100644 --- a/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_refresh.adoc +++ b/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_refresh.adoc @@ -63,15 +63,15 @@ whether the location is still the same if not revoke all the tokens and let the === Need for refresh tokens Does it make sense to use a refresh token in a modern single page application (SPA)? As we have seen in the section -about storing tokens there are two option: web storage or a cookie which mean a refresh token is right beside an -access token, so if the access token is leaked changes are the refresh token will also be compromised. Most of the time -there is a difference of course, the access token is send when you make an API call, the refresh token is only send +about storing tokens there are two options: web storage or a cookie which mean a refresh token is right beside an +access token, so if the access token is leaked chances are the refresh token will also be compromised. Most of the time +there is a difference of course. The access token is sent when you make an API call, the refresh token is only sent when a new access token should be obtained, which in most cases is a different endpoint. If you end up on the same -server you can chose to only use the access token. +server you can choose to only use the access token. As stated above using an access token and a separate refresh token gives some leverage for the server not to check the access token over and over. Only perform the check when the user needs a new access token. -It is certainly possible to only use an access token, at the server you store the exact same information you would +It is certainly possible to only use an access token. At the server you store the exact same information you would store for a refresh token, see previous paragraph. This way you need to check the token each time but this might be suitable depending on the application. In the case the refresh tokens are stored for validation it is important to protect these tokens as well (at least use a hash function to store them in your database). From 268adbcf7edcc5166da4b63073f00d4c40922c44 Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Tue, 12 Jun 2018 17:35:57 +0200 Subject: [PATCH 17/25] Move assignments to correct package so that hints are shown --- .../{introduction => advanced}/SqlInjectionLesson6a.java | 4 ++-- .../{introduction => advanced}/SqlInjectionLesson6b.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/{introduction => advanced}/SqlInjectionLesson6a.java (97%) rename webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/{introduction => advanced}/SqlInjectionLesson6b.java (98%) diff --git a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson6a.java b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/advanced/SqlInjectionLesson6a.java similarity index 97% rename from webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson6a.java rename to webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/advanced/SqlInjectionLesson6a.java index 136723f8d..dd31c61cc 100644 --- a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson6a.java +++ b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/advanced/SqlInjectionLesson6a.java @@ -1,10 +1,11 @@ -package org.owasp.webgoat.plugin.introduction; +package org.owasp.webgoat.plugin.advanced; 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.owasp.webgoat.plugin.introduction.SqlInjectionLesson5a; import org.owasp.webgoat.session.DatabaseUtilities; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -55,7 +56,6 @@ public class SqlInjectionLesson6a extends AssignmentEndpoint { AttackResult completed(@RequestParam String userid_6a) throws IOException { return injectableQuery(userid_6a); // The answer: Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from user_system_data -- - } protected AttackResult injectableQuery(String accountName) { diff --git a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson6b.java b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/advanced/SqlInjectionLesson6b.java similarity index 98% rename from webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson6b.java rename to webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/advanced/SqlInjectionLesson6b.java index 77bd7b66e..74fc5d2ad 100644 --- a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson6b.java +++ b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/advanced/SqlInjectionLesson6b.java @@ -1,5 +1,5 @@ -package org.owasp.webgoat.plugin.introduction; +package org.owasp.webgoat.plugin.advanced; import org.owasp.webgoat.assignments.AssignmentEndpoint; import org.owasp.webgoat.assignments.AssignmentPath; From 56fc983414b130445fba3b8dfb8f2813f60e450c Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Tue, 12 Jun 2018 17:36:44 +0200 Subject: [PATCH 18/25] Update database layout so that proposed solution works --- .../java/org/owasp/webgoat/session/CreateDB.java | 12 ++++++------ .../lessonPlans/en/SqlInjection_content6a.adoc | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/session/CreateDB.java b/webgoat-container/src/main/java/org/owasp/webgoat/session/CreateDB.java index 1805bd161..d658b072a 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/session/CreateDB.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/session/CreateDB.java @@ -232,7 +232,7 @@ public class CreateDB { // Create the new table try { - String createTableStatement = "CREATE TABLE user_system_data (" + "userid varchar(5) not null primary key," + String createTableStatement = "CREATE TABLE user_system_data (" + "userid int not null primary key," + "user_name varchar(12)," + "password varchar(10)," + "cookie varchar(30)" + ")"; statement.executeUpdate(createTableStatement); } catch (SQLException e) { @@ -240,11 +240,11 @@ public class CreateDB { } // Populate - String insertData1 = "INSERT INTO user_system_data VALUES ('101','jsnow','passwd1', '')"; - String insertData2 = "INSERT INTO user_system_data VALUES ('102','jdoe','passwd2', '')"; - String insertData3 = "INSERT INTO user_system_data VALUES ('103','jplane','passwd3', '')"; - String insertData4 = "INSERT INTO user_system_data VALUES ('104','jeff','jeff', '')"; - String insertData5 = "INSERT INTO user_system_data VALUES ('105','dave','dave', '')"; + String insertData1 = "INSERT INTO user_system_data VALUES (101,'jsnow','passwd1', '')"; + String insertData2 = "INSERT INTO user_system_data VALUES (102,'jdoe','passwd2', '')"; + String insertData3 = "INSERT INTO user_system_data VALUES (103,'jplane','passwd3', '')"; + String insertData4 = "INSERT INTO user_system_data VALUES (104,'jeff','jeff', '')"; + String insertData5 = "INSERT INTO user_system_data VALUES (105,'dave','passW0rD', '')"; statement.executeUpdate(insertData1); statement.executeUpdate(insertData2); statement.executeUpdate(insertData3); diff --git a/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_content6a.adoc b/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_content6a.adoc index 17e5a279d..fde2040a3 100644 --- a/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_content6a.adoc +++ b/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_content6a.adoc @@ -3,7 +3,7 @@ Lets try to exploit a join to another table. One of the tables in the WebGoat database is: ------------------------------------------------------- -CREATE TABLE user_system_data (userid varchar(5) not null primary key, +CREATE TABLE user_system_data (userid int not null primary key, user_name varchar(12), password varchar(10), cookie varchar(30)); From 1d2575a2115de9ef780949746edce56fb8eda074 Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Tue, 12 Jun 2018 10:49:24 +0200 Subject: [PATCH 19/25] Allow - in usernames because CSRF lesson requires username starting with prefix crsf- #476 --- .../src/main/java/org/owasp/webgoat/users/UserForm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/users/UserForm.java b/webgoat-container/src/main/java/org/owasp/webgoat/users/UserForm.java index c9e3b7d70..e2062cbdd 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/users/UserForm.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/users/UserForm.java @@ -17,7 +17,7 @@ public class UserForm { @NotNull @Size(min=6, max=20) - @Pattern(regexp = "[a-zA-Z0-9]*", message = "can only contain letters and digits") + @Pattern(regexp = "[a-zA-Z0-9-]*", message = "can only contain letters, digits, and -") private String username; @NotNull @Size(min=6, max=10) From 3b9b695ef1ac604d427eef23b608eec25c9ef490 Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Tue, 12 Jun 2018 17:35:00 +0200 Subject: [PATCH 20/25] Check host header instead of origin which might not be present #475 --- .../main/java/org/owasp/webgoat/plugin/CSRFFeedback.java | 6 +++--- .../java/org/owasp/webgoat/plugin/CSRFFeedbackTest.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/webgoat-lessons/csrf/src/main/java/org/owasp/webgoat/plugin/CSRFFeedback.java b/webgoat-lessons/csrf/src/main/java/org/owasp/webgoat/plugin/CSRFFeedback.java index 0acd8bbfe..501da489b 100644 --- a/webgoat-lessons/csrf/src/main/java/org/owasp/webgoat/plugin/CSRFFeedback.java +++ b/webgoat-lessons/csrf/src/main/java/org/owasp/webgoat/plugin/CSRFFeedback.java @@ -64,11 +64,11 @@ public class CSRFFeedback extends AssignmentEndpoint { private boolean hostOrRefererDifferentHost(HttpServletRequest request) { String referer = request.getHeader("referer"); - String origin = request.getHeader("origin"); + String host = request.getHeader("host"); if (referer != null) { - return !referer.contains(origin); + return !referer.contains(host); } else { - return true; //this case referer is null or origin does not matter we cannot compare so we return true which should of course be false + return true; } } diff --git a/webgoat-lessons/csrf/src/test/java/org/owasp/webgoat/plugin/CSRFFeedbackTest.java b/webgoat-lessons/csrf/src/test/java/org/owasp/webgoat/plugin/CSRFFeedbackTest.java index 495a2cf9b..cb5edba91 100644 --- a/webgoat-lessons/csrf/src/test/java/org/owasp/webgoat/plugin/CSRFFeedbackTest.java +++ b/webgoat-lessons/csrf/src/test/java/org/owasp/webgoat/plugin/CSRFFeedbackTest.java @@ -46,7 +46,7 @@ public class CSRFFeedbackTest extends LessonTest { mockMvc.perform(post("/csrf/feedback/message") .contentType(MediaType.TEXT_PLAIN) .cookie(new Cookie("JSESSIONID", "test")) - .header("origin", "localhost:8080") + .header("host", "localhost:8080") .header("referer", "webgoat.org") .content("{\"name\": \"Test\", \"email\": \"test1233@dfssdf.de\", \"subject\": \"service\", \"message\":\"dsaffd\"}")) .andExpect(jsonPath("lessonCompleted", is(true))) From b47bb96534021e81dd07d8a557c45a3ce0c96fcf Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Wed, 13 Jun 2018 16:11:28 +0200 Subject: [PATCH 21/25] Update changed password in tests --- .../webgoat/plugin/introduction/SqlInjectionLesson6aTest.java | 2 +- .../webgoat/plugin/introduction/SqlInjectionLesson6bTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson6aTest.java b/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson6aTest.java index 3500b8efa..344db1dbe 100644 --- a/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson6aTest.java +++ b/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson6aTest.java @@ -64,7 +64,7 @@ public class SqlInjectionLesson6aTest extends LessonTest { .andExpect(status().isOk()) .andExpect(jsonPath("$.lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", containsString("dave"))); + .andExpect(jsonPath("$.feedback", containsString("passW0rD"))); } @Test diff --git a/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson6bTest.java b/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson6bTest.java index a7abd0d61..7341a6d3a 100644 --- a/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson6bTest.java +++ b/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson6bTest.java @@ -30,7 +30,7 @@ public class SqlInjectionLesson6bTest extends LessonTest { @Test public void submitCorrectPassword() throws Exception { mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack6b") - .param("userid_6b", "dave")) + .param("userid_6b", "passW0rD")) .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true))); } From b0fbeaff2c84be90f487967b1761850b12649a40 Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Wed, 13 Jun 2018 17:56:23 +0200 Subject: [PATCH 22/25] This improves the text of the lesson about XSS --- .../lessonPlans/en/CrossSiteScripting_content6a.adoc | 10 +++++----- .../lessonPlans/en/CrossSiteScripting_content6b.adoc | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/webgoat-lessons/cross-site-scripting/src/main/resources/lessonPlans/en/CrossSiteScripting_content6a.adoc b/webgoat-lessons/cross-site-scripting/src/main/resources/lessonPlans/en/CrossSiteScripting_content6a.adoc index cd815fce0..c1a3ab6a7 100644 --- a/webgoat-lessons/cross-site-scripting/src/main/resources/lessonPlans/en/CrossSiteScripting_content6a.adoc +++ b/webgoat-lessons/cross-site-scripting/src/main/resources/lessonPlans/en/CrossSiteScripting_content6a.adoc @@ -1,15 +1,15 @@ == Identify Potential for DOM-Based XSS DOM-Based XSS can usually be found by looking for the route configurations in the client-side code. -Look for a route that takes inputs that you can ID being 'reflected' to the page. +Look for a route that takes inputs that are being 'reflected' to the page. For this example, you'll want to look for some 'test' code in the route handlers (WebGoat uses backbone as its primary javascript library). Sometimes, test code gets left in production (and often times test code is very simple and lacks security or any quality controls!). Your objective is to find the route and exploit it. First though ... what is the base route? As an example, look at the URL for this lesson ... -it should look something like /WebGoat/start.mvc#lesson/CrossSiteScripting.lesson/9 (although maybe slightly different). The 'base route' in this case is: +it should look something like /WebGoat/start.mvc#lesson/CrossSiteScripting.lesson/9. The 'base route' in this case is: *start.mvc#lesson/* +The *CrossSiteScripting.lesson/9* after that are parameters that are processed by the javascript route handler. -The *CrossSiteScripting.lesson/#* after that are parameters that are processed by javascript route handler. - -So, what is test route for this test code? +So, what is the route for the test code that stayed in the app during production? +To answer this question, you have to check the javascript source. \ No newline at end of file diff --git a/webgoat-lessons/cross-site-scripting/src/main/resources/lessonPlans/en/CrossSiteScripting_content6b.adoc b/webgoat-lessons/cross-site-scripting/src/main/resources/lessonPlans/en/CrossSiteScripting_content6b.adoc index 3fd67b860..4b35ae2a2 100644 --- a/webgoat-lessons/cross-site-scripting/src/main/resources/lessonPlans/en/CrossSiteScripting_content6b.adoc +++ b/webgoat-lessons/cross-site-scripting/src/main/resources/lessonPlans/en/CrossSiteScripting_content6b.adoc @@ -8,4 +8,4 @@ The function you want to execute is ... Sure, you could just use console/debug to trigger it, but you need to trigger it via a URL in a new tab. -Once you do trigger it, a subsequent response will come to the browser with a random number. Put that random number in below. +Once you do trigger it, a subsequent response will come to your browser's console with a random number. Put that random number in below. From e5ec2c1ee056af591e065d98ce6a635f58bdc6f6 Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Wed, 13 Jun 2018 17:56:57 +0200 Subject: [PATCH 23/25] Fix html attribute --- webgoat-lessons/csrf/src/main/resources/html/CSRF.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webgoat-lessons/csrf/src/main/resources/html/CSRF.html b/webgoat-lessons/csrf/src/main/resources/html/CSRF.html index fc7463461..71d08a816 100644 --- a/webgoat-lessons/csrf/src/main/resources/html/CSRF.html +++ b/webgoat-lessons/csrf/src/main/resources/html/CSRF.html @@ -20,7 +20,7 @@ action="/WebGoat/csrf/basic-get-flag" enctype="application/json;charset=UTF-8"> - + From 81aac93dfe28419df6b8d5d4420bdbdecb66455b Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Wed, 13 Jun 2018 17:58:52 +0200 Subject: [PATCH 24/25] Usage base64 encoded password as expected by JJWT --- .../main/java/org/owasp/webgoat/plugin/JWTVotesEndpoint.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTVotesEndpoint.java b/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTVotesEndpoint.java index c963212ee..49363b3b1 100644 --- a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTVotesEndpoint.java +++ b/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTVotesEndpoint.java @@ -5,6 +5,7 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwt; import io.jsonwebtoken.JwtException; import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.impl.TextCodec; import org.apache.commons.lang3.StringUtils; import org.owasp.webgoat.assignments.AssignmentEndpoint; import org.owasp.webgoat.assignments.AssignmentHints; @@ -25,7 +26,6 @@ import java.time.Duration; import java.time.Instant; import java.util.Date; import java.util.Map; -import java.util.concurrent.TimeUnit; import static java.util.Comparator.comparingLong; import static java.util.Optional.ofNullable; @@ -39,7 +39,7 @@ import static java.util.stream.Collectors.toList; @AssignmentHints({"jwt-change-token-hint1", "jwt-change-token-hint2", "jwt-change-token-hint3", "jwt-change-token-hint4", "jwt-change-token-hint5"}) public class JWTVotesEndpoint extends AssignmentEndpoint { - public static final String JWT_PASSWORD = "victory"; + public static final String JWT_PASSWORD = TextCodec.BASE64.encode("victory"); private static String validUsers = "TomJerrySylvester"; private static int totalVotes = 38929; From c7da546249ce95f2f53374fc4d6979ead674deb1 Mon Sep 17 00:00:00 2001 From: Matthias Grundmann Date: Thu, 14 Jun 2018 11:00:43 +0200 Subject: [PATCH 25/25] Improve text for lesson about CSRF login --- .../src/main/resources/lessonPlans/en/CSRF_Login.adoc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/webgoat-lessons/csrf/src/main/resources/lessonPlans/en/CSRF_Login.adoc b/webgoat-lessons/csrf/src/main/resources/lessonPlans/en/CSRF_Login.adoc index ea480f495..dfc8ec854 100644 --- a/webgoat-lessons/csrf/src/main/resources/lessonPlans/en/CSRF_Login.adoc +++ b/webgoat-lessons/csrf/src/main/resources/lessonPlans/en/CSRF_Login.adoc @@ -16,9 +16,11 @@ the activities of the user. image::images/login-csrf.png[caption="Figure: ", title="Login CSRF from Robust Defenses for Cross-Site Request Forgery", width="800", height="500", style="lesson-image" link="http://seclab.stanford.edu/websec/csrf/csrf.pdf"] {blank} -For more information read the following http://seclab.stanford.edu/websec/csrf/csrf.pdf[paper] +For more information read the following http://seclab.stanford.edu/websec/csrf/csrf.pdf[paper]. -In this assignment try to see if WebGoat is also vulnerable for a login CSRF attack. First create a user -based on your own username prefixed with csrf. So if your username is `tom` you must create -a new user called `csrf-tom` +In this assignment try to see if WebGoat is also vulnerable for a login CSRF attack. +Leave this tab open and in another tab create a user based on your own username prefixed with `csrf-`. +So if your username is `tom` you must create a new user called `csrf-tom`. +Login as the new user. This is what an attacker would do using CSRF. Then click the button in the original tab. +Because you are logged in as a different user, the attacker learns that you clicked the button.