diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/controller/ListUsers.java b/webgoat-container/src/main/java/org/owasp/webgoat/controller/ListUsers.java deleted file mode 100644 index 226bc5ec4..000000000 --- a/webgoat-container/src/main/java/org/owasp/webgoat/controller/ListUsers.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.owasp.webgoat.controller; - -import com.sun.corba.se.spi.activation.EndPointInfo; -import org.owasp.webgoat.assignments.*; -import org.owasp.webgoat.session.UserSessionData; -import org.owasp.webgoat.users.UserService; -import org.owasp.webgoat.users.WebGoatUser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.ModelAndView; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; - -/** - * Created by jason on 1/5/17. - */ - -@Controller -public class ListUsers { - - @Autowired - private UserService userService; - - @RequestMapping(path = {"list_users", "/"}, method = {RequestMethod.GET,RequestMethod.POST}) - public ModelAndView listUsers(HttpServletRequest request) { - - ModelAndView model = new ModelAndView(); - model.setViewName("list_users"); - List allUsers = userService.getAllUsers(); - model.addObject("numUsers",allUsers.size()); - model.addObject("allUsers",allUsers); - - return model; - } - -} diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/users/WebGoatUser.java b/webgoat-container/src/main/java/org/owasp/webgoat/users/WebGoatUser.java index e96f524e8..b6e9fc776 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/users/WebGoatUser.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/users/WebGoatUser.java @@ -43,6 +43,7 @@ public class WebGoatUser implements UserDetails { this.role = role; } + public void createUser() { this.user = new User(username, password, getAuthorities()); } @@ -51,6 +52,18 @@ public class WebGoatUser implements UserDetails { return Collections.singleton(new SimpleGrantedAuthority(getRole())); } + public String getRole() { + return this.role; + } + + public String getUsername() { + return this.username; + } + + public String getPassword() { + return this.password; + } + @Override public boolean isAccountNonExpired() { return this.user.isAccountNonExpired(); @@ -70,6 +83,8 @@ public class WebGoatUser implements UserDetails { public boolean isEnabled() { return this.user.isEnabled(); } + + } diff --git a/webgoat-container/src/main/resources/templates/list_users.html b/webgoat-container/src/main/resources/templates/list_users.html index be67a9de4..5e2b3045b 100644 --- a/webgoat-container/src/main/resources/templates/list_users.html +++ b/webgoat-container/src/main/resources/templates/list_users.html @@ -123,8 +123,15 @@
- TEST ... Users in WebGoat -
Admin sees this ... + Users in WebGoat + su +
+

WebGoat Users

+
+ +
    Hash:
+
    Admin:
+
diff --git a/webgoat-lessons/missing-function-ac/src/main/java/org/owasp/webgoat/plugin/DisplayUser.java b/webgoat-lessons/missing-function-ac/src/main/java/org/owasp/webgoat/plugin/DisplayUser.java new file mode 100644 index 000000000..1b2515e77 --- /dev/null +++ b/webgoat-lessons/missing-function-ac/src/main/java/org/owasp/webgoat/plugin/DisplayUser.java @@ -0,0 +1,89 @@ +package org.owasp.webgoat.plugin; + + +import lombok.Getter; +import org.owasp.webgoat.users.WebGoatUser; +import org.springframework.security.core.GrantedAuthority; + +import java.security.MessageDigest; +import java.util.Base64; + +/** + * ************************************************************************************************ + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * please see http://www.owasp.org/ + *

+ * Copyright (c) 2002 - 20014 Bruce Mayhew + *

+ * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + *

+ * Getting Source ============== + *

+ * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software + * projects. + *

+ * + */ + + +public class DisplayUser { + //intended to provide a display version of WebGoatUser for admins to view user attributes + + + private String username; + private boolean admin; + private String userHash; + + public DisplayUser(WebGoatUser user) { + this.username = user.getUsername(); + this.admin = false; + + for (GrantedAuthority authority : user.getAuthorities()) { + this.admin = (authority.getAuthority().contains("WEBGOAT_ADMIN")) ? true : false; + } + + // create userHash on the fly + //TODO: persist userHash + try { + this.userHash = genUserHash(user.getUsername(), user.getPassword()); + } catch (Exception ex) { + //TODO: implement better fallback operation + this.userHash = "Error generating user hash"; + } + + } + + protected String genUserHash (String username, String password) throws Exception { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + // salting is good, but static & too predictable ... short too for a salt + String salted = password + "DeliberatelyInsecure1234" + username; + //md.update(salted.getBytes("UTF-8")); // Change this to "UTF-16" if needed + byte[] hash = md.digest(salted.getBytes("UTF-8")); + String encoded = Base64.getEncoder().encodeToString(hash); + return encoded; + } + + + public String getUsername() { + return username; + } + + public boolean isAdmin() { + return admin; + } + + public String getUserHash() { + return userHash; + } + +} diff --git a/webgoat-lessons/missing-function-ac/src/main/java/org/owasp/webgoat/plugin/HiddenMenuItems.java b/webgoat-lessons/missing-function-ac/src/main/java/org/owasp/webgoat/plugin/HiddenMenuItems.java index 5b3d8887c..70c52b016 100644 --- a/webgoat-lessons/missing-function-ac/src/main/java/org/owasp/webgoat/plugin/HiddenMenuItems.java +++ b/webgoat-lessons/missing-function-ac/src/main/java/org/owasp/webgoat/plugin/HiddenMenuItems.java @@ -38,14 +38,14 @@ public class HiddenMenuItems extends AssignmentEndpoint { AttackResult completed(String hiddenMenu1, String hiddenMenu2, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //overly simple example for success. See other existing lesssons for ways to detect 'success' or 'failure' - if (hiddenMenu1.equals("List Users") && hiddenMenu2.equals("Add User")) { + if (hiddenMenu1.equals("Users") && hiddenMenu2.equals("Config")) { return trackProgress(success() .output("") .feedback("access-control.hidden-menus.success") .build()); } - if (hiddenMenu1.equals("Add User") && hiddenMenu2.equals("List Users")) { + if (hiddenMenu1.equals("Config") && hiddenMenu2.equals("Users")) { return trackProgress(success() .output("") .feedback("access-control.hidden-menus.close") diff --git a/webgoat-lessons/missing-function-ac/src/main/java/org/owasp/webgoat/plugin/MissingFunctionACUsers.java b/webgoat-lessons/missing-function-ac/src/main/java/org/owasp/webgoat/plugin/MissingFunctionACUsers.java new file mode 100644 index 000000000..88dc7dee8 --- /dev/null +++ b/webgoat-lessons/missing-function-ac/src/main/java/org/owasp/webgoat/plugin/MissingFunctionACUsers.java @@ -0,0 +1,78 @@ +package org.owasp.webgoat.plugin; + +import com.sun.corba.se.spi.activation.EndPointInfo; +import org.owasp.webgoat.assignments.*; +import org.owasp.webgoat.session.UserSessionData; +import org.owasp.webgoat.users.UserService; +import org.owasp.webgoat.users.WebGoatUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by jason on 1/5/17. + */ + +@Controller +public class MissingFunctionACUsers { + + + // this will actually put controllers on the /WebGoat/* path ... the jsp for list_users restricts what can be seen, but the add_user is not controlled carefully + @Autowired + private UserService userService; + + @RequestMapping(path = {"users", "/"}, method = RequestMethod.GET) + public ModelAndView listUsers(HttpServletRequest request) { + + ModelAndView model = new ModelAndView(); + model.setViewName("list_users"); + List allUsers = userService.getAllUsers(); + model.addObject("numUsers",allUsers.size()); + //add display user objects in place of direct users + List displayUsers = new ArrayList<>(); + for (WebGoatUser user : allUsers) { + displayUsers.add(new DisplayUser(user)); + } + model.addObject("allUsers",displayUsers); + + return model; + } + + @RequestMapping(path = {"users", "/"}, method = RequestMethod.GET,consumes = "application/json") + @ResponseBody + public List usersService(HttpServletRequest request) { + + List allUsers = userService.getAllUsers(); + List displayUsers = new ArrayList<>(); + for (WebGoatUser user : allUsers) { + displayUsers.add(new DisplayUser(user)); + } + return displayUsers; + } + + @RequestMapping(path = {"users","/"}, method = RequestMethod.POST, consumes = "application/json", produces = "application/json") + @ResponseBody + //@PreAuthorize() + public WebGoatUser addUser(@RequestBody WebGoatUser newUser) { + try { + userService.addUser(newUser.getUsername(),newUser.getPassword(),newUser.getRole()); + return userService.loadUserByUsername(newUser.getUsername()); + } catch (Exception ex) { + System.out.println("Error creating new User" + ex.getMessage()); + ex.printStackTrace(); + //TODO: implement error handling ... + } finally { + // no streams or other resources opened ... nothing to do, right? + } + return null; + } + + //@RequestMapping(path = {"user/{username}","/"}, method = RequestMethod.DELETE, consumes = "application/json", produces = "application/json") + //TODO implement delete method with id param and authorization + +} diff --git a/webgoat-lessons/missing-function-ac/src/main/java/org/owasp/webgoat/plugin/MissingFunctionACYourHash.java b/webgoat-lessons/missing-function-ac/src/main/java/org/owasp/webgoat/plugin/MissingFunctionACYourHash.java new file mode 100644 index 000000000..44b12c49c --- /dev/null +++ b/webgoat-lessons/missing-function-ac/src/main/java/org/owasp/webgoat/plugin/MissingFunctionACYourHash.java @@ -0,0 +1,34 @@ +package org.owasp.webgoat.plugin; + +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentHints; +import org.owasp.webgoat.assignments.AssignmentPath; +import org.owasp.webgoat.assignments.AttackResult; +import org.owasp.webgoat.users.UserService; +import org.owasp.webgoat.users.WebGoatUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@AssignmentPath("/access-control/user-hash") +@AssignmentHints({"access-control.hash.hint1","access-control.hash.hint2","access-control.hash.hint3", + "access-control.hash.hint4","access-control.hash.hint5","access-control.hash.hint6","access-control.hash.hint7", + "access-control.hash.hint8","access-control.hash.hint9"}) +public class MissingFunctionACYourHash extends AssignmentEndpoint { + + @Autowired + private UserService userService; + + @PostMapping(produces = {"application/json"}) + public @ResponseBody + AttackResult completed(String userHash) { + String currentUser = getWebSession().getUserName(); + WebGoatUser user = userService.loadUserByUsername(currentUser); + DisplayUser displayUser = new DisplayUser(user); + if (userHash.equals(displayUser.getUserHash())) { + return trackProgress(success().feedback("access-control.hash.success").build()); + } else { + return trackProgress(success().feedback("access-control.hash.close").build()); + } + } +} diff --git a/webgoat-lessons/missing-function-ac/src/main/resources/html/MissingFunctionAC.html b/webgoat-lessons/missing-function-ac/src/main/resources/html/MissingFunctionAC.html index 20dfca3d2..e6cc66c42 100644 --- a/webgoat-lessons/missing-function-ac/src/main/resources/html/MissingFunctionAC.html +++ b/webgoat-lessons/missing-function-ac/src/main/resources/html/MissingFunctionAC.html @@ -30,8 +30,8 @@

@@ -57,25 +57,26 @@
- - +
- - - - - +
- - - +
+
+
- +

Your Hash:

+
+ - - - +
- +
+
+
+ +
diff --git a/webgoat-lessons/missing-function-ac/src/main/resources/i18n/WebGoatLabels.properties b/webgoat-lessons/missing-function-ac/src/main/resources/i18n/WebGoatLabels.properties index 6f028a433..3b077c5d3 100644 --- a/webgoat-lessons/missing-function-ac/src/main/resources/i18n/WebGoatLabels.properties +++ b/webgoat-lessons/missing-function-ac/src/main/resources/i18n/WebGoatLabels.properties @@ -6,4 +6,17 @@ access-control.hidden-menus.failure=Please try again. access-control.hidden-menus.hint1=You can inspect the DOM or review the source in the proxy request/response cycle. access-control.hidden-menus.hint2=Look for indications of something that would not be available to a typical user -access-control.hidden-menus.hint3=Look for something a super-user or administator might have available to them \ No newline at end of file +access-control.hidden-menus.hint3=Look for something a super-user or administator might have available to them + +access-control.hash.success=Congrats! You really succeeded when you added the user. +access-control.hash.close=Keep trying, this one may take several attempts & steps to achieve. See the hints for help. + +access-control.hash.hint1=If you haven't found the hidden menus from the earlier exercise, go do that now. +access-control.hash.hint2=When you look at the users page, there is a hint that more info is viewable by a given role of user. +access-control.hash.hint3=Have you tried tampering the GET request? Can you find supported or unsupported methods? Can you trigger 500 errors? +access-control.hash.hint4=There are actually two ways to solve this one. The first involves just changing a request header. +access-control.hash.hint5=If the request to view users, were a 'service' or 'RESTful' endpoint, what would be different about it? +access-control.hash.hint6=If you're still looking for hints ... try changing the Content-type header in the GET request. +access-control.hash.hint7=The harder way involves changing the Content-type AND the method ... As well as a proper payload for the request. Look at how registration works first and extrapolate out from there. +access-control.hash.hint8=See if you can add a user with a webgoat admin role, and if more is visible once you log in as that user. +access-control.hash.hint9=If you create a new user with the admin role ... The role should include 'WEBGOAT' and 'ADMIN' in the role name. You'll have to do some guessing beyond that. \ No newline at end of file diff --git a/webgoat-lessons/missing-function-ac/src/main/resources/lessonPlans/en/missing-function-ac-03-list-users.adoc b/webgoat-lessons/missing-function-ac/src/main/resources/lessonPlans/en/missing-function-ac-03-list-users.adoc deleted file mode 100644 index 8bbab9125..000000000 --- a/webgoat-lessons/missing-function-ac/src/main/resources/lessonPlans/en/missing-function-ac-03-list-users.adoc +++ /dev/null @@ -1,10 +0,0 @@ -== Just Try It - -As the previous page noted, sometimes apps rely on client controls. to control access (obscurity). If you can find items that don't have visible links, just try them, see what happens. Yes, it -can be that simple! - -=== Gathering User Info - -Often times, data dumps from vulnerabilities such as sql injection, but they can also come from poor or lacking access control. Use the info. you already gathered to pull the list of users and -then provide the CC# for Chaos Monkey. - diff --git a/webgoat-lessons/missing-function-ac/src/main/resources/lessonPlans/en/missing-function-ac-03-users.adoc b/webgoat-lessons/missing-function-ac/src/main/resources/lessonPlans/en/missing-function-ac-03-users.adoc new file mode 100644 index 000000000..630b344c9 --- /dev/null +++ b/webgoat-lessons/missing-function-ac/src/main/resources/lessonPlans/en/missing-function-ac-03-users.adoc @@ -0,0 +1,10 @@ +== Just Try It + +As the previous page noted, sometimes apps rely on client controls. to control access (obscurity). If you can find items that don't have visible links, just try them, see what happens. Yes, it +can be that simple! + +=== Gathering User Info + +Often times, data dumps from vulnerabilities such as sql injection, but they can also come from poor or lacking access control. + +It will likely take multiple steps and multiple attempts to get this one. Pay attention to the comments, leaked info. and you'll need to guess some. You may need to use another browser/account along the way. Start with the info. you already gathered (hidden menu items) to see if you can pull the list of users and then provide the 'Hash' for your own user account. \ No newline at end of file