Author: lukaszlenart Date: Sun Jun 20 19:20:11 2010 New Revision: 956389 URL: http://svn.apache.org/viewvc?rev=956389&view=rev Log: Resolved critical Xwork vulnerability
Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/interceptor/ParametersInterceptorTest.java Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java?rev=956389&r1=956388&r2=956389&view=diff ============================================================================== --- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java (original) +++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java Sun Jun 20 19:20:11 2010 @@ -15,16 +15,6 @@ */ package com.opensymphony.xwork2.interceptor; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.ValidationAware; @@ -41,6 +31,16 @@ import com.opensymphony.xwork2.util.logg import com.opensymphony.xwork2.util.logging.LoggerFactory; import com.opensymphony.xwork2.util.reflection.ReflectionContextState; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * <!-- START SNIPPET: description --> @@ -134,7 +134,8 @@ public class ParametersInterceptor exten Set<Pattern> acceptParams = Collections.emptySet(); static boolean devMode = false; - private String acceptedParamNames = "[[\\p{Graph}\\s]&&[^,#:=]]*"; + // Allowed names of parameters + private String acceptedParamNames = "[a-zA-Z0-9\\.\\]\\[_'\\s]+"; private Pattern acceptedPattern = Pattern.compile(acceptedParamNames); private ValueStackFactory valueStackFactory; Modified: struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/interceptor/ParametersInterceptorTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/interceptor/ParametersInterceptorTest.java?rev=956389&r1=956388&r2=956389&view=diff ============================================================================== --- struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/interceptor/ParametersInterceptorTest.java (original) +++ struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/interceptor/ParametersInterceptorTest.java Sun Jun 20 19:20:11 2010 @@ -15,15 +15,6 @@ */ package com.opensymphony.xwork2.interceptor; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import ognl.PropertyAccessor; - import com.opensymphony.xwork2.Action; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionProxy; @@ -43,6 +34,14 @@ import com.opensymphony.xwork2.ognl.acce import com.opensymphony.xwork2.util.CompoundRoot; import com.opensymphony.xwork2.util.ValueStack; import com.opensymphony.xwork2.util.ValueStackFactory; +import ognl.PropertyAccessor; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; /** @@ -53,10 +52,8 @@ import com.opensymphony.xwork2.util.Valu public class ParametersInterceptorTest extends XWorkTestCase { public void testParameterNameAware() { - ParametersInterceptor pi = new ParametersInterceptor(); - container.inject(pi); - final Map actual = new HashMap(); - pi.setValueStackFactory(createValueStackFactory(actual)); + ParametersInterceptor pi = createParametersInterceptor(); + final Map actual = injectValueStackFactory(pi); ValueStack stack = createStubValueStack(actual); final Map expected = new HashMap() { { @@ -149,6 +146,31 @@ public class ParametersInterceptorTest e assertNull(session.get("user5")); } + public void testAccessToOgnlInternals() throws Exception { + // given + Map<String, Object> params = new HashMap<String, Object>(); + params.put("blah", "This is blah"); + params.put("('\\u0023_memberAccess[\\'allowStaticMethodAccess\\']')(meh)", "true"); + params.put("('(aaa)(('\\u0023context[\\'xwork.MethodAccessor.denyMethodExecution\\']\\u003d\\u0023foo')(\\u0023foo\\u003dnew java.lang.Boolean(\"false\")))", ""); + params.put("(asdf)(('\\u0023rt.exit(1)')(\\u0023rt\\u0...@java.lang.runtime@getRuntime()))", "1"); + + HashMap<String, Object> extraContext = new HashMap<String, Object>(); + extraContext.put(ActionContext.PARAMETERS, params); + + ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, "", extraContext); + ValueStack stack = proxy.getInvocation().getStack(); + + // when + proxy.execute(); + proxy.getAction(); + + //then + assertEquals("This is blah", ((SimpleAction) proxy.getAction()).getBlah()); + Object allowMethodAccess = stack.findValue("\u0023_memberAccess['allowStaticMethodAccess']"); + assertNotNull(allowMethodAccess); + assertEquals(Boolean.FALSE, allowMethodAccess); + } + public void testParameters() throws Exception { Map<String, Object> params = new HashMap<String, Object>(); params.put("blah", "This is blah"); @@ -339,8 +361,7 @@ public class ParametersInterceptorTest e } public void testNoOrdered() throws Exception { - ParametersInterceptor pi = new ParametersInterceptor(); - container.inject(pi); + ParametersInterceptor pi = createParametersInterceptor(); final Map<String, Object> actual = new LinkedHashMap<String, Object>(); pi.setValueStackFactory(createValueStackFactory(actual)); ValueStack stack = createStubValueStack(actual); @@ -390,21 +411,17 @@ public class ParametersInterceptorTest e } public void testSetOrdered() throws Exception { - ParametersInterceptor pi = new ParametersInterceptor(); - container.inject(pi); + ParametersInterceptor pi = createParametersInterceptor(); assertEquals("ordered should be false by default", false, pi.isOrdered()); pi.setOrdered(true); assertEquals(true, pi.isOrdered()); } public void testExcludedParametersAreIgnored() throws Exception { - ParametersInterceptor pi = new ParametersInterceptor(); - container.inject(pi); + ParametersInterceptor pi = createParametersInterceptor(); pi.setExcludeParams("dojo\\..*"); - final Map actual = new HashMap(); - pi.setValueStackFactory(createValueStackFactory(actual)); - ValueStack stack = createStubValueStack(actual); - container.inject(stack); + final Map actual = injectValueStackFactory(pi); + ValueStack stack = injectValueStack(actual); final Map<String, Object> expected = new HashMap<String, Object>() { { @@ -422,6 +439,57 @@ public class ParametersInterceptorTest e assertEquals(expected, actual); } + public void testInternalParametersAreIgnored() throws Exception { + // given + ParametersInterceptor interceptor = createParametersInterceptor(); + final Map actual = injectValueStackFactory(interceptor); + ValueStack stack = injectValueStack(actual); + + + final Map<String, Object> expected = new HashMap<String, Object>() { + { + put("ordinary.bean", "value"); + } + }; + + Map<String, Object> parameters = new HashMap<String, Object>() { + { + put("ordinary.bean", "value"); + put("#some.internal.object", "true"); + put("(bla)#some.internal.object", "true"); + put("#some.internal.object(bla)#some.internal.object", "true"); + put("#_some.internal.object", "true"); + put("\u0023_some.internal.object", "true"); + put("\u0023_some.internal.object,[dfd],bla(\u0023_some.internal.object)", "true"); + put("\\u0023_some.internal.object", "true"); + } + }; + + // when + interceptor.setParameters(new NoParametersAction(), stack, parameters); + + // then + assertEquals(expected, actual); + } + + private ValueStack injectValueStack(Map actual) { + ValueStack stack = createStubValueStack(actual); + container.inject(stack); + return stack; + } + + private Map injectValueStackFactory(ParametersInterceptor interceptor) { + final Map actual = new HashMap(); + interceptor.setValueStackFactory(createValueStackFactory(actual)); + return actual; + } + + private ParametersInterceptor createParametersInterceptor() { + ParametersInterceptor pi = new ParametersInterceptor(); + container.inject(pi); + return pi; + } + private ValueStackFactory createValueStackFactory(final Map<String, Object> context) { OgnlValueStackFactory factory = new OgnlValueStackFactory() { @Override