Code-Racing / brickyard

0 stars 0 forks source link

CONTRAST: Trust Boundary Violation from "input" Parameter on "/servlet-2.5/session-put-value" page #58

Open valvolineford opened 4 years ago

valvolineford commented 4 years ago

Vulnerability ID: ONYF-K7L6-WI8D-5X3W

Application Name: Pluto

Vulnerability Link: http://localhost:19080/Contrast/static/ng/index.html#/7c6cfec5-a187-4d5e-984a-d11d96d2ef63/applications/0f9338c6-352f-418b-9d89-696406640d91/vulns/ONYF-K7L6-WI8D-5X3W

What Happened?

We tracked the following data from "input" Parameter:

GET /servlet-2.5/session-put-value?input=value

...which was accessed within the following code:

com.contrastsecurity.testapp.servlet25.session.SessionPutValueServlet#sinkToSessionValue(), line 48

...and be placed in the session as:

value

What's the risk?

The application takes untrusted data that comes from the user and places it in trusted data storage: the HTTP session object on the server. Developers are likely to assume that data stored in the session came from the application itself, and not the user, and may use the data in a way that's unsafe. For example, storing role information in the session that came from a request parameter is obviously unsafe. When estimating exploitability, consider that the application may use the same session variable key in different places. All the application's storage of data in session should be done safely to make sure it doesn't expose any risk should a malicious user change a stored data value arbitrarily.

Recommendation

Unfortunately, there is no simple API change that can be made to address this because this is a "business logic" problem. Here are some key ways to avoid running into session puzzling vulnerabilities or session race condition flaws:

1) Ensure every distinct use of the session utilizes a unique key to avoid functionality stepping on each other and possibly opening up flaws 2) Always validate the data provided by the user before storing it in session to make sure its correct for the current user, in case some other code decides to use and trust this stored value 3) Use beans instead of Strings that more clearly indicate the purpose of the data to make it less likely to be repurposed by an attacker

Let's go through a fictional example of an UNSAFE usage of the same session variable under different conditions:

// Login.java
if(successfullyAuthenticated) {
   session.setAttribute("user", userName);
}
// ForgotPasswordController.java
/**
 * The user forgot their password, so we'll kickoff the
 * wizard for them to recover it.
 */
session.setAttribute("user", request.getParameter("user"));

The "user" session key is holding the username of the person claimed to have forgotten their password. But another Java class uses that same key for another purpose: // ShoppingCartCheckoutController.java CreditCard[] userCreditCards = CCUtil.getCreditCards(session.getAttribute("user")); In this scenario, an attacker could start the Forgot Password workflow and pass in a victim's username. Then they would navigate to the checkout page where they would see the victim's credit cards instead of their own because of the clobbered "user" key in the HttpSession. To fix our example, we'll make the two different uses for that variable have unique keys: // Login.java session.setAttribute("authenticated.user", userName); // ForgotPasswordController.java session.setAttribute("forgotpw.user", request.getParameter("user")); // ShoppingCartCheckoutController.java CreditCard[] userCreditCards = CCUtil.getCreditCards(session.getAttribute("authenticated.user"));

First Event


Stack:
  org.apache.catalina.connector.RequestFacade.getParameter(RequestFacade.java:355)
  com.contrastsecurity.testapp.servlet25.session.SessionPutValueServlet.doGet(SessionPutValueServlet.java:27)
  javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
  javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
  org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
  org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
  org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
  org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
  org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
  org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
  org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
  org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
  org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
  org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
  org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
  org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
  org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
  org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
  org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
  java.lang.Thread.run(Thread.java:701)

Last Event


Stack:
  org.apache.catalina.session.StandardSessionFacade.putValue(StandardSessionFacade.java:136)
  com.contrastsecurity.testapp.servlet25.session.SessionPutValueServlet.sinkToSessionValue(SessionPutValueServlet.java:48)
  com.contrastsecurity.testapp.servlet25.session.SessionPutValueServlet.doGet(SessionPutValueServlet.java:33)
  javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
  javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
  org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
  org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
  org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
  org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
  org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
  org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
  org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
  org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
  org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
  org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
  org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
  org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
  org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
  org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
  org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
  java.lang.Thread.run(Thread.java:701)

HTTP Request

GET http://localhost:32908/servlet-2.5/session-put-value?input=value HTTP/1.0 Connection: Keep-Alive Host: localhost:32908 Contrast-Mq-Name: queue-365-HttpServlet25ForwardCompatibleMixin.it_tests_http_session_sinks-contrastsecurity-docker.jfrog.io/contrast/jboss-servlet-2.5:4.2.2.GA-rev1 User-Agent: okhttp/3.9.1 Accept-Encoding: gzip

References

https://www.owasp.org/index.php/Top_10_2013-A2-Broken_Authentication_and_Session_Management