diff --git a/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORDiffAttributes.java b/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORDiffAttributes.java index 39de62956..51af860c8 100644 --- a/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORDiffAttributes.java +++ b/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORDiffAttributes.java @@ -25,11 +25,11 @@ public class IDORDiffAttributes extends AssignmentEndpoint { if (diffAttribs.length < 2) { return AttackResult.failed("You did not list two attributes string delimited"); } - if (diffAttribs[0].toLowerCase().equals("userid") && diffAttribs[1].toLowerCase().equals("admin") || - diffAttribs[1].toLowerCase().equals("userid") && diffAttribs[0].toLowerCase().equals("admin")) { - return AttackResult.success("Correct, the two attributes not displayed are userId & admin. Keep those in mind"); + if (diffAttribs[0].toLowerCase().trim().equals("userid") && diffAttribs[1].toLowerCase().trim().equals("role") || + diffAttribs[1].toLowerCase().trim().equals("userid") && diffAttribs[0].toLowerCase().trim().equals("role")) { + return trackProgress(AttackResult.success("Correct, the two attributes not displayed are userId & role. Keep those in mind")); } else { - return AttackResult.failed("Try again. Look in your browser dev tools or Proxy and compare to what's displayed on the screen."); + return trackProgress(AttackResult.failed("Try again. Look in your browser dev tools or Proxy and compare to what's displayed on the screen.")); } } } diff --git a/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDOREditOwnProfiile.java b/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDOREditOwnProfiile.java index c2f1d76ea..64ee2b4aa 100644 --- a/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDOREditOwnProfiile.java +++ b/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDOREditOwnProfiile.java @@ -3,6 +3,7 @@ package org.owasp.webgoat.plugin; import org.owasp.webgoat.endpoints.AssignmentEndpoint; import org.owasp.webgoat.lessons.AttackResult; import org.owasp.webgoat.session.UserSessionData; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; @@ -41,18 +42,34 @@ import java.util.Map; * @since January 3, 2017 */ -@Path("/IDOR/{userId}/profile-edit") +@Path("IDOR/profile/{userId}") public class IDOREditOwnProfiile extends AssignmentEndpoint { - private Map<String,Map<String,String>> idorUserInfo = new HashMap<>(); + @Autowired UserSessionData userSessionData; - @RequestMapping(method = RequestMethod.POST) + @RequestMapping(method = RequestMethod.PUT, consumes = "application/json") public @ResponseBody - AttackResult completed(@PathVariable String userId, @RequestParam String password, HttpServletRequest request) throws IOException { + AttackResult completed(@PathVariable("userId") String userId, @RequestParam UserProfile userSubmittedProfile, HttpServletRequest request) { - UserSessionData userSessionData = getUserSessionData(); + String authUserId = (String)userSessionData.getValue("idor-authenticated-user-id"); + UserProfile currentUserProfile = new UserProfile(authUserId); + if (userSubmittedProfile.getUserId() != null && !userSubmittedProfile.getUserId().equals(authUserId)) { + return AttackResult.failed("Don't worry, we'll get to modifying someone else's profile, just modify your own for now."); + } else if (userSubmittedProfile.getUserId().equals(authUserId)) { + // this is commonly how vulnerable code will act ... updating w/out an authorization check + currentUserProfile.setColor(userSubmittedProfile.getColor()); + currentUserProfile.setRole(userSubmittedProfile.getRole()); + // we will persist in the session object for now + userSessionData.setValue("idor-updated-own-profile",currentUserProfile); - return trackProgress(AttackResult.failed("still working on this")); //TODO: How do we localize messages like this? + + } + + if (currentUserProfile.getColor().equals("black") && currentUserProfile.getRole() <= 1 ) { + return trackProgress(AttackResult.success("Good work! View the updated profile below",userSessionData.getValue("idor-updated-own-profile").toString())); + } else { + return trackProgress(AttackResult.failed("Please try again. Use the hints if need be.")); + } } diff --git a/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORLogin.java b/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORLogin.java index df5fe9fe5..593dc9527 100644 --- a/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORLogin.java +++ b/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORLogin.java @@ -73,9 +73,7 @@ public class IDORLogin extends AssignmentEndpoint { initIDORInfo(); UserSessionData userSessionData = getUserSessionData(); - System.out.println("----:" + username + ":----"); if (idorUserInfo.containsKey(username)) { - System.out.println("****:" + username); if ("tom".equals(username) && idorUserInfo.get("tom").get("password").equals(password)) { userSessionData.setValue("idor-authenticated-as", username); userSessionData.setValue("idor-authenticated-user-id", idorUserInfo.get(username).get("id")); diff --git a/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORViewOwnProfile.java b/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORViewOwnProfile.java index 47ab16b3e..e403cff29 100644 --- a/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORViewOwnProfile.java +++ b/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORViewOwnProfile.java @@ -34,17 +34,15 @@ public class IDORViewOwnProfile extends Endpoint{ try { if (userSessionData.getValue("idor-authenticated-as").equals("tom")) { //going to use session auth to view this one - String authUserId = userSessionData.getValue("idor-authenticated-user-id"); + String authUserId = (String)userSessionData.getValue("idor-authenticated-user-id"); UserProfile userProfile = new UserProfile(authUserId); details.put("userId",userProfile.getUserId()); details.put("name",userProfile.getName()); details.put("color",userProfile.getColor()); details.put("size",userProfile.getSize()); - details.put("admin",userProfile.isAdmin()); - + details.put("role",userProfile.getRole()); } else { - details.put("error","You do not have privileges to view the profile."); - System.out.println("Not auth'd as tom"); + details.put("error","You do not have privileges to view the profile. Authenticate as tom first please."); } }catch (Exception ex) { System.out.println(ex.getMessage()); diff --git a/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORViewOwnProfileAltUrl.java b/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORViewOwnProfileAltUrl.java index feb09dfd1..72106141d 100644 --- a/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORViewOwnProfileAltUrl.java +++ b/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/IDORViewOwnProfileAltUrl.java @@ -32,27 +32,23 @@ public class IDORViewOwnProfileAltUrl extends AssignmentEndpoint{ try { if (userSessionData.getValue("idor-authenticated-as").equals("tom")) { //going to use session auth to view this one - String authUserId = userSessionData.getValue("idor-authenticated-user-id"); + String authUserId = (String)userSessionData.getValue("idor-authenticated-user-id"); //don't care about http://localhost:8080 ... just want WebGoat/ String[] urlParts = url.split("/"); - System.out.println("************"); - System.out.println(urlParts[0]); - System.out.println(urlParts[1]); - System.out.println(urlParts[2]); - System.out.println(urlParts[3]); - System.out.println("************"); if (urlParts[0].equals("WebGoat") && urlParts[1].equals("IDOR") && urlParts[2].equals("profile") && urlParts[3].equals(authUserId)) { UserProfile userProfile = new UserProfile(authUserId); details.put("userId", userProfile.getUserId()); details.put("name", userProfile.getName()); details.put("color", userProfile.getColor()); details.put("size", userProfile.getSize()); - details.put("admin", userProfile.isAdmin()); - return AttackResult.success("congratultions, you have used the alternate Url/route to view your own profile.",details.toString()); + details.put("role", userProfile.getRole()); + return trackProgress(AttackResult.success("congratultions, you have used the alternate Url/route to view your own profile.",details.toString())); + } else { + return trackProgress(AttackResult.failed("please try again. The alternoute route is very similar to the previous way you viewed your profile. Only one difference really")); } } else { - return AttackResult.failed("please try again. The alternoute route is very similar to the previous way you viewed your profile. Only one difference really"); + return trackProgress(AttackResult.failed("You need to authenticate as tom first.")); } } catch (Exception ex) { System.out.println(ex.getMessage()); diff --git a/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/UserProfile.java b/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/UserProfile.java index f5e2f076a..1475a9b03 100644 --- a/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/UserProfile.java +++ b/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/UserProfile.java @@ -9,6 +9,7 @@ public class UserProfile { private String color; private String size; private boolean isAdmin; + private int role; // anyting else? public UserProfile() {} @@ -26,11 +27,13 @@ public class UserProfile { this.name = "Tom Cat"; this.size = "small"; this.isAdmin = false; + this.role = 3; } else if (id.equals("2342388")) { this.color = "brown"; this.name = "Buffalo Bill"; this.size = "large"; this.isAdmin = false; + this.role = 3; } } @@ -40,6 +43,7 @@ public class UserProfile { return "userId" + this.userId + htmlBreak + "name" + this.name + htmlBreak + "size" + this.size + htmlBreak + + "role" + this.role + htmlBreak + "isAdmin" + this.isAdmin; } @@ -83,4 +87,13 @@ public class UserProfile { public void setAdmin(boolean admin) { isAdmin = admin; } + + public int getRole() { + return role; + } + + public void setRole(int role) { + this.role = role; + } + } diff --git a/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/ViewOtherUserProfileEndpoint.java b/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/ViewOtherUserProfileEndpoint.java index 2a2b5c2cf..eb289b505 100644 --- a/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/ViewOtherUserProfileEndpoint.java +++ b/webgoat-lessons/idor/src/main/java/org/owasp/webgoat/plugin/ViewOtherUserProfileEndpoint.java @@ -48,7 +48,7 @@ public class ViewOtherUserProfileEndpoint extends AssignmentEndpoint { if (userSessionData.getValue("idor-authenticated-as").equals("bill") || userSessionData.getValue("idor-authenticated-as").equals("tom")) { System.out.println("**** authenticated as " + userSessionData.getValue("idor-authenticated-as")); //logged in - String authUserId = userSessionData.getValue("idor-authenticated-user-id"); + String authUserId = (String)userSessionData.getValue("idor-authenticated-user-id"); //secure code would check to make sure authUserId matches userId ... and in this endpoint, we won't bother with that UserProfile userProfile = new UserProfile(userId); return trackProgress(AttackResult.failed("still working")); diff --git a/webgoat-lessons/idor/src/main/resources/plugin/IDOR/html/IDOR.html b/webgoat-lessons/idor/src/main/resources/plugin/IDOR/html/IDOR.html index c196f8954..86fc57c0b 100644 --- a/webgoat-lessons/idor/src/main/resources/plugin/IDOR/html/IDOR.html +++ b/webgoat-lessons/idor/src/main/resources/plugin/IDOR/html/IDOR.html @@ -127,6 +127,36 @@ </div> </div> +<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:IDOR_eidtOwn.adoc"></div> + <div class="attack-container"> + <!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat --> + <div> + <!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat --> + <!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework --> + <!-- of course, you can write your own ajax submission /handling in your own javascript if you like --> + + <!-- modify the action to point to the intended endpoint --> + <form class="attack-form" accept-charset="UNKNOWN" + method="GET" name="form" + action="/WebGoat/IDOR/profile" + enctype="application/json;charset=UTF-8"> + <script th:src="@{/plugin_lessons/plugin/IDOR/js/idor.js}" /> + + <input name="View Profile" value="View Profile" type="button" onclick="onViewProfile();" /> + + </form> + </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> +</div> + <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, diff --git a/webgoat-lessons/idor/src/main/resources/plugin/IDOR/lessonPlans/en/IDOR_editOwnProfile.adoc b/webgoat-lessons/idor/src/main/resources/plugin/IDOR/lessonPlans/en/IDOR_editOwnProfile.adoc new file mode 100644 index 000000000..281a4df82 --- /dev/null +++ b/webgoat-lessons/idor/src/main/resources/plugin/IDOR/lessonPlans/en/IDOR_editOwnProfile.adoc @@ -0,0 +1,4 @@ +==== Edit Your Own Profile + +If an application only exposes a way to view your profile or some object (i.e. 'GET' in RESTful), that does not mean you cannot edit it. +Use your intercept proxy to modify the request such that it would modify your profile. Change the color from 'yellow' to 'black' (sans single quotes). \ No newline at end of file diff --git a/webgoat-lessons/idor/src/main/resources/plugin/IDOR/lessonPlans/en/IDOR_login.adoc b/webgoat-lessons/idor/src/main/resources/plugin/IDOR/lessonPlans/en/IDOR_login.adoc new file mode 100644 index 000000000..df1cfdd09 --- /dev/null +++ b/webgoat-lessons/idor/src/main/resources/plugin/IDOR/lessonPlans/en/IDOR_login.adoc @@ -0,0 +1,7 @@ +=== Authenticate First, Abuse Authorization Later + +Many access control issues are succeptible to attack from an authenticated-but-unauthorized user. So, let's start by legitimately authenticating. Then, we will look for ways to bypass or abuse Authorization. + +The id and password for the account in this case are 'tom' and 'cat' (It is an insecure app, right?). + +After authenticating, proceed to the next screen. \ No newline at end of file diff --git a/webgoat-lessons/idor/src/main/resources/plugin/IDOR/lessonPlans/en/IDOR_viewOwnAltPath.adoc b/webgoat-lessons/idor/src/main/resources/plugin/IDOR/lessonPlans/en/IDOR_viewOwnAltPath.adoc index bc2891149..8725db0b4 100644 --- a/webgoat-lessons/idor/src/main/resources/plugin/IDOR/lessonPlans/en/IDOR_viewOwnAltPath.adoc +++ b/webgoat-lessons/idor/src/main/resources/plugin/IDOR/lessonPlans/en/IDOR_viewOwnAltPath.adoc @@ -1,6 +1,7 @@ - === Guessing & Predicting Patterns +==== View Your Own Profile Another Way + The application we are working with seems to follow a RESTful pattern so far as the profile goes. Many apps have roles in which an elevated user may access content of another. In that case, just /profile won't work since the own user's session/authentication data won't tell us whose profile they want view. -So, what do you think is a likely pattern to view your own profile using a direct object reference? \ No newline at end of file +So, what do you think is a likely pattern to view your own profile explicitly using a direct object reference? \ No newline at end of file