#304 update to IDOR. Still experiencing 400 on EditOwnProfile endpoint
This commit is contained in:
parent
c2988eb771
commit
fe4f568fc0
@ -25,11 +25,11 @@ public class IDORDiffAttributes extends AssignmentEndpoint {
|
|||||||
if (diffAttribs.length < 2) {
|
if (diffAttribs.length < 2) {
|
||||||
return AttackResult.failed("You did not list two attributes string delimited");
|
return AttackResult.failed("You did not list two attributes string delimited");
|
||||||
}
|
}
|
||||||
if (diffAttribs[0].toLowerCase().equals("userid") && diffAttribs[1].toLowerCase().equals("admin") ||
|
if (diffAttribs[0].toLowerCase().trim().equals("userid") && diffAttribs[1].toLowerCase().trim().equals("role") ||
|
||||||
diffAttribs[1].toLowerCase().equals("userid") && diffAttribs[0].toLowerCase().equals("admin")) {
|
diffAttribs[1].toLowerCase().trim().equals("userid") && diffAttribs[0].toLowerCase().trim().equals("role")) {
|
||||||
return AttackResult.success("Correct, the two attributes not displayed are userId & admin. Keep those in mind");
|
return trackProgress(AttackResult.success("Correct, the two attributes not displayed are userId & role. Keep those in mind"));
|
||||||
} else {
|
} 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."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package org.owasp.webgoat.plugin;
|
|||||||
import org.owasp.webgoat.endpoints.AssignmentEndpoint;
|
import org.owasp.webgoat.endpoints.AssignmentEndpoint;
|
||||||
import org.owasp.webgoat.lessons.AttackResult;
|
import org.owasp.webgoat.lessons.AttackResult;
|
||||||
import org.owasp.webgoat.session.UserSessionData;
|
import org.owasp.webgoat.session.UserSessionData;
|
||||||
|
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 javax.servlet.http.HttpServletRequest;
|
||||||
@ -41,18 +42,34 @@ import java.util.Map;
|
|||||||
* @since January 3, 2017
|
* @since January 3, 2017
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Path("/IDOR/{userId}/profile-edit")
|
@Path("IDOR/profile/{userId}")
|
||||||
public class IDOREditOwnProfiile extends AssignmentEndpoint {
|
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
|
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."));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,9 +73,7 @@ public class IDORLogin extends AssignmentEndpoint {
|
|||||||
initIDORInfo();
|
initIDORInfo();
|
||||||
UserSessionData userSessionData = getUserSessionData();
|
UserSessionData userSessionData = getUserSessionData();
|
||||||
|
|
||||||
System.out.println("----:" + username + ":----");
|
|
||||||
if (idorUserInfo.containsKey(username)) {
|
if (idorUserInfo.containsKey(username)) {
|
||||||
System.out.println("****:" + username);
|
|
||||||
if ("tom".equals(username) && idorUserInfo.get("tom").get("password").equals(password)) {
|
if ("tom".equals(username) && idorUserInfo.get("tom").get("password").equals(password)) {
|
||||||
userSessionData.setValue("idor-authenticated-as", username);
|
userSessionData.setValue("idor-authenticated-as", username);
|
||||||
userSessionData.setValue("idor-authenticated-user-id", idorUserInfo.get(username).get("id"));
|
userSessionData.setValue("idor-authenticated-user-id", idorUserInfo.get(username).get("id"));
|
||||||
|
@ -34,17 +34,15 @@ public class IDORViewOwnProfile extends Endpoint{
|
|||||||
try {
|
try {
|
||||||
if (userSessionData.getValue("idor-authenticated-as").equals("tom")) {
|
if (userSessionData.getValue("idor-authenticated-as").equals("tom")) {
|
||||||
//going to use session auth to view this one
|
//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);
|
UserProfile userProfile = new UserProfile(authUserId);
|
||||||
details.put("userId",userProfile.getUserId());
|
details.put("userId",userProfile.getUserId());
|
||||||
details.put("name",userProfile.getName());
|
details.put("name",userProfile.getName());
|
||||||
details.put("color",userProfile.getColor());
|
details.put("color",userProfile.getColor());
|
||||||
details.put("size",userProfile.getSize());
|
details.put("size",userProfile.getSize());
|
||||||
details.put("admin",userProfile.isAdmin());
|
details.put("role",userProfile.getRole());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
details.put("error","You do not have privileges to view the profile.");
|
details.put("error","You do not have privileges to view the profile. Authenticate as tom first please.");
|
||||||
System.out.println("Not auth'd as tom");
|
|
||||||
}
|
}
|
||||||
}catch (Exception ex) {
|
}catch (Exception ex) {
|
||||||
System.out.println(ex.getMessage());
|
System.out.println(ex.getMessage());
|
||||||
|
@ -32,27 +32,23 @@ public class IDORViewOwnProfileAltUrl extends AssignmentEndpoint{
|
|||||||
try {
|
try {
|
||||||
if (userSessionData.getValue("idor-authenticated-as").equals("tom")) {
|
if (userSessionData.getValue("idor-authenticated-as").equals("tom")) {
|
||||||
//going to use session auth to view this one
|
//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/
|
//don't care about http://localhost:8080 ... just want WebGoat/
|
||||||
String[] urlParts = url.split("/");
|
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)) {
|
if (urlParts[0].equals("WebGoat") && urlParts[1].equals("IDOR") && urlParts[2].equals("profile") && urlParts[3].equals(authUserId)) {
|
||||||
UserProfile userProfile = new UserProfile(authUserId);
|
UserProfile userProfile = new UserProfile(authUserId);
|
||||||
details.put("userId", userProfile.getUserId());
|
details.put("userId", userProfile.getUserId());
|
||||||
details.put("name", userProfile.getName());
|
details.put("name", userProfile.getName());
|
||||||
details.put("color", userProfile.getColor());
|
details.put("color", userProfile.getColor());
|
||||||
details.put("size", userProfile.getSize());
|
details.put("size", userProfile.getSize());
|
||||||
details.put("admin", userProfile.isAdmin());
|
details.put("role", userProfile.getRole());
|
||||||
return AttackResult.success("congratultions, you have used the alternate Url/route to view your own profile.",details.toString());
|
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 {
|
} 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) {
|
} catch (Exception ex) {
|
||||||
System.out.println(ex.getMessage());
|
System.out.println(ex.getMessage());
|
||||||
|
@ -9,6 +9,7 @@ public class UserProfile {
|
|||||||
private String color;
|
private String color;
|
||||||
private String size;
|
private String size;
|
||||||
private boolean isAdmin;
|
private boolean isAdmin;
|
||||||
|
private int role;
|
||||||
// anyting else?
|
// anyting else?
|
||||||
|
|
||||||
public UserProfile() {}
|
public UserProfile() {}
|
||||||
@ -26,11 +27,13 @@ public class UserProfile {
|
|||||||
this.name = "Tom Cat";
|
this.name = "Tom Cat";
|
||||||
this.size = "small";
|
this.size = "small";
|
||||||
this.isAdmin = false;
|
this.isAdmin = false;
|
||||||
|
this.role = 3;
|
||||||
} else if (id.equals("2342388")) {
|
} else if (id.equals("2342388")) {
|
||||||
this.color = "brown";
|
this.color = "brown";
|
||||||
this.name = "Buffalo Bill";
|
this.name = "Buffalo Bill";
|
||||||
this.size = "large";
|
this.size = "large";
|
||||||
this.isAdmin = false;
|
this.isAdmin = false;
|
||||||
|
this.role = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -40,6 +43,7 @@ public class UserProfile {
|
|||||||
return "userId" + this.userId + htmlBreak +
|
return "userId" + this.userId + htmlBreak +
|
||||||
"name" + this.name + htmlBreak +
|
"name" + this.name + htmlBreak +
|
||||||
"size" + this.size + htmlBreak +
|
"size" + this.size + htmlBreak +
|
||||||
|
"role" + this.role + htmlBreak +
|
||||||
"isAdmin" + this.isAdmin;
|
"isAdmin" + this.isAdmin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,4 +87,13 @@ public class UserProfile {
|
|||||||
public void setAdmin(boolean admin) {
|
public void setAdmin(boolean admin) {
|
||||||
isAdmin = admin;
|
isAdmin = admin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getRole() {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRole(int role) {
|
||||||
|
this.role = role;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ public class ViewOtherUserProfileEndpoint extends AssignmentEndpoint {
|
|||||||
if (userSessionData.getValue("idor-authenticated-as").equals("bill") || userSessionData.getValue("idor-authenticated-as").equals("tom")) {
|
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"));
|
System.out.println("**** authenticated as " + userSessionData.getValue("idor-authenticated-as"));
|
||||||
//logged in
|
//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
|
//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);
|
UserProfile userProfile = new UserProfile(userId);
|
||||||
return trackProgress(AttackResult.failed("still working"));
|
return trackProgress(AttackResult.failed("still working"));
|
||||||
|
@ -127,6 +127,36 @@
|
|||||||
</div>
|
</div>
|
||||||
</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">
|
<div class="lesson-page-wrapper">
|
||||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
<!-- 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,
|
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||||
|
@ -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).
|
@ -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.
|
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
=== Guessing & Predicting Patterns
|
=== 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.
|
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.
|
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?
|
So, what do you think is a likely pattern to view your own profile explicitly using a direct object reference?
|
Loading…
x
Reference in New Issue
Block a user