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"));
Vulnerability ID: EBTM-XRUO-KXO5-GPB2
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/EBTM-XRUO-KXO5-GPB2
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:
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
Last Event
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