Wednesday, December 21, 2011

Struts 2 Session Tampering via SessionAware/RequestAware WW-3631

UPDATE: This post was updated on 1/2/2012 to correct the post to take into account the fact that the interfaces mentioned below bind request parameters to String[] rather then String. See the post for exact details.

NOTE 1: I am not the original reporter of this issue. The issue below, with regards to the SessionAware, was originally reported to the Struts 2 team as WW-2264 by Hisato Killing. At that time, it was decided by the Struts 2 team that this was "Not A Problem". Back in May 2011 I identified the identical issue without previous knowledge of Hisato’s bug report and I reported it to the Struts 2 team as WW-3631 (CVE-2011-5057). A former colleague of mine, Abraham Kang who is now a Principal Security Researcher at Fortify an HP Company, urged me to include a reference to the RequestAware Interface and also indicated other *Aware interfaces could also be dangerous.

NOTE 2: This issue does not affect every application that uses Struts 2 - only those that have Actions that implement SessionAware, RequestAware, and possibly other *Aware interfaces either directly or indirectly, and make no attempt to block the auto-binding of the request or session collections.

NOTE 3: Regarding the Secunia Advisor for this issue 47109 - it is listed as "Not Critical". I completely agree as there are very few Struts 2 applications that implement these interfaces. However, if your application does implement these interfaces it is likely a big problem, luckily the solution is fairly easy.

Example implementation of SessionAware:
public class VulnerableAction extends ActionSupport 
implements Action, SessionAware {

  protected Map session;
  public void setSession(final Map session) {
    this.session = session;

As one would expect from the auto-binding of Struts2 that if an Action implements either of these interfaces it allows the auto-binding of data to the current session or request using the most common implementation (any changes made via the auto-binding may not persist past this single request, read on for more details). This could allow unexpected data to exist within the session by passing in request parameters such as "?session.key=value" or "?request.session.key=value" - these types of request parameters would be auto-bound to the current requests session map (generally a class level variable). When Struts2 binds these parameters they are bound as String arrays rather then a simple String. As such, the impact of this vulnerability is somewhat reduced - however, it is possible to use this technique to auto-bind to public setters of objects stored in the session.

If an object has a setValue(String) method and is stored within the session using the key "data" ; if one passed the following query string parameter "?"; this would alter the field and set the value to "authorized". Note, when binding to public setters on objects within the session Struts2 does not force them to be String[].

While the two interfaces only require the implementation of the setSession and setRequest respectively, if one also implemented either getSession or getRequest respectively then the changes to the contents of the session will be persisted to users' actual session - rather than just the current request (e.g. the local member variable).

Doing a Google code search will reveal some open source packages that are vulnerable to this:

Any system that implements Apache 2.x SessionAware, RequestAware, and/or other *Aware interfaces is affected by this unless they explicitly implemented something to block the parameter auto-binding to the implemented setters. Implementing getSession, getRequest, or a getter corresponding to the implemented setter makes the problem worse. The impact of this specific vulnerability is completely dependent upon the application that implements the interface and what the application uses the session data for.

There is an easy solution to this problem. Prevent auto-binding of the request and session via the default parameter interceptor by placing them into the ignored parameter list. Second, a warning should be placed in the JavaDoc for SessionAware, RequestAware, and possibly other *Aware interfaces indicating the possible issues with implementing this class and recommend that any Action that implements these interfaces also implement com.opensymphony.xwork2.interceptor.ParameterNameAware interface and checking to ensure that any parameters starting with “session” and/or “request” are not being auto-bound.

This was reported via Apache's JIRA system in May 2011: The Struts 2 team stated that a fix would be in version 3.x; and they agreed with me that there is an easy fix and any application implementing these interfaces could easily fix the issue themselves. However, as people are obviously using these interfaces in their code and not implementing the fix - I'd like to post this in a little more public fashion to ensure people are aware of the possible issues if they do implement these interfaces.

I should point out a listing of other *Aware interfaces that are likely of interest:
  • org.apache.struts2.interceptor.ApplicationAware
    • may lead to application context tampering
  • org.apache.struts2.interceptor.RequestAware
    • Request collection and/or Session collection tampering
  • org.apache.struts2.interceptor.ServletRequestAware
    • Request collection and/or Session collection tampering and possibly other concerns
  • org.apache.struts2.interceptor.ServletResponseAware
  • org.apache.struts2.interceptor.ParameterAware

An additional research item is the DirectRenderFromEventAction as this implements the SessionAware Interface.

This has also been reported under CVE-2011-5057.
--Jeremy Long