[
https://issues.apache.org/jira/browse/WW-5705?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Lukasz Lenart updated WW-5705:
------------------------------
Description:
{{StrutsParameterAuthorizer#isAuthorized}} derives the root property of a
parameter name by cutting at the first nesting character ({{.}}, {{[}} or
{{(}}), then lower-cases its first character:
{code:java}int nestingIndex = indexOfAny(parameterName, NESTING_CHARS_STR);
String rootProperty = nestingIndex == -1 ? parameterName :
parameterName.substring(0, nestingIndex);
String normalisedRootProperty = Character.toLowerCase(rootProperty.charAt(0)) +
rootProperty.substring(1);
{code}
When the name _begins_ with a nesting character, {{nestingIndex}} is 0,
{{substring(0, 0)}} yields an empty string, and {{charAt(0)}} throws
{{StringIndexOutOfBoundsException}}. The exception escapes the interceptor.
h2. Reachability
* {{ParametersInterceptor}} is *not* affected: {{isAcceptableName()}} applies
{{ACCEPTED_PATTERNS}}, which requires a leading word character, before
authorization.
* The JSON plugin *is*: {{JSONInterceptor}} authorizes at
{{isAcceptableNode()}}, whereas the accepted-pattern check runs later, in
{{isAcceptableLeafName()}}, and only for leaf keys.
* The REST plugin's {{ContentTypeInterceptor}} authorizes body-derived paths
with no accepted- or excluded-pattern check beforehand.
Reproduced with the container's own {{StrutsParameterAuthorizer}}, under the
shipped default {{struts.parameters.requireAnnotations=true}}, with a JSON body
whose root key is {{.foo}} - the exception escapes
{{JSONInterceptor.intercept()}}.
h2. Affected versions
The expression dates from WW-5352 (6.4.0), but nothing reached it with such a
name until WW-5624 wired the JSON and REST body channels through the authorizer
in 7.2.0.
6.x is not affected: {{requireAnnotations}} has no default there, there is no
{{ParameterAuthorizer}} at all, and {{ParametersInterceptor}} - its only caller
- filters names through the accepted patterns first.
h2. Impact
A failed request. No authorization bypass, no amplification, nothing persists
beyond the single request. Triaged as an ordinary robustness bug rather than a
vulnerability.
h2. Fix
A name beginning with a nesting character names no root property, so
authorization rejects it before normalisation rather than computing one.
The change is already included in the WW-5698 pull request
https://github.com/apache/struts/pull/1872 (commit {{2f3ce9601}}), since that
PR routes ModelDriven parameters through the same expression. It can be split
into its own PR if the release notes should attribute it separately.
was:
{{StrutsParameterAuthorizer#isAuthorized}} derives the root property of a
parameter name by cutting at the first nesting character ({{.}}, {{[}} or
{{(}}), then lower-cases its first character:
{code:java}
int nestingIndex = indexOfAny(parameterName, NESTING\_CHARS\_STR);
String rootProperty = nestingIndex == -1 ? parameterName :
parameterName.substring(0, nestingIndex);
String normalisedRootProperty = Character.toLowerCase(rootProperty.charAt(0)) +
rootProperty.substring(1);
{code}
When the name _begins_ with a nesting character, {{nestingIndex}} is 0,
{{substring(0, 0)}} yields an empty string, and {{charAt(0)}} throws
{{StringIndexOutOfBoundsException}}. The exception escapes the interceptor.
h4. Reachability
* {{ParametersInterceptor}} is *not* affected: {{isAcceptableName()}} applies
{{ACCEPTED\_PATTERNS}}, which requires a leading {{\w+}}, before authorization.
* The JSON plugin *is*: {{JSONInterceptor}} authorizes at
{{isAcceptableNode()}}, whereas the accepted-pattern check runs later, in
{{isAcceptableLeafName()}}, and only for leaf keys.
* The REST plugin's {{ContentTypeInterceptor}} authorizes body-derived paths
with no accepted- or excluded-pattern check beforehand.
Reproduced with the container's own {{StrutsParameterAuthorizer}}, under the
shipped default {{struts.parameters.requireAnnotations=true}}, with a JSON body
of {{{}{".foo":"x"}{}}} - the exception escapes {{JSONInterceptor.intercept()}}.
h4. Affected versions
The expression dates from WW-5352 (6.4.0), but nothing reached it with such a
name until WW-5624 wired the JSON and REST body channels through the authorizer
in 7.2.0.
6.x is not affected: {{requireAnnotations}} has no default there, there is no
{{ParameterAuthorizer}} at all, and {{ParametersInterceptor}} - its only caller
- filters names through the accepted patterns first.
h4. Impact
A failed request. No authorization bypass, no amplification, nothing persists
beyond the single request. Triaged as an ordinary robustness bug rather than a
vulnerability.
h4. Fix
A name beginning with a nesting character names no root property, so
authorization rejects it before normalisation rather than computing one.
The change is already included in the WW-5698 pull request
https://github.com/apache/struts/pull/1872 (commit {{2f3ce9601}}), since that
PR routes ModelDriven parameters through the same expression. It can be split
into its own PR if the release notes should attribute it separately.
> StringIndexOutOfBoundsException authorizing a parameter name that begins with
> a nesting character
> -------------------------------------------------------------------------------------------------
>
> Key: WW-5705
> URL: https://issues.apache.org/jira/browse/WW-5705
> Project: Struts 2
> Issue Type: Bug
> Affects Versions: 7.2.1, 7.3.0
> Reporter: Lukasz Lenart
> Priority: Major
> Fix For: 7.4.0
>
>
> {{StrutsParameterAuthorizer#isAuthorized}} derives the root property of a
> parameter name by cutting at the first nesting character ({{.}}, {{[}} or
> {{(}}), then lower-cases its first character:
> {code:java}int nestingIndex = indexOfAny(parameterName, NESTING_CHARS_STR);
> String rootProperty = nestingIndex == -1 ? parameterName :
> parameterName.substring(0, nestingIndex);
> String normalisedRootProperty = Character.toLowerCase(rootProperty.charAt(0))
> + rootProperty.substring(1);
> {code}
> When the name _begins_ with a nesting character, {{nestingIndex}} is 0,
> {{substring(0, 0)}} yields an empty string, and {{charAt(0)}} throws
> {{StringIndexOutOfBoundsException}}. The exception escapes the interceptor.
> h2. Reachability
> * {{ParametersInterceptor}} is *not* affected: {{isAcceptableName()}} applies
> {{ACCEPTED_PATTERNS}}, which requires a leading word character, before
> authorization.
> * The JSON plugin *is*: {{JSONInterceptor}} authorizes at
> {{isAcceptableNode()}}, whereas the accepted-pattern check runs later, in
> {{isAcceptableLeafName()}}, and only for leaf keys.
> * The REST plugin's {{ContentTypeInterceptor}} authorizes body-derived paths
> with no accepted- or excluded-pattern check beforehand.
> Reproduced with the container's own {{StrutsParameterAuthorizer}}, under the
> shipped default {{struts.parameters.requireAnnotations=true}}, with a JSON
> body whose root key is {{.foo}} - the exception escapes
> {{JSONInterceptor.intercept()}}.
> h2. Affected versions
> The expression dates from WW-5352 (6.4.0), but nothing reached it with such a
> name until WW-5624 wired the JSON and REST body channels through the
> authorizer in 7.2.0.
> 6.x is not affected: {{requireAnnotations}} has no default there, there is no
> {{ParameterAuthorizer}} at all, and {{ParametersInterceptor}} - its only
> caller - filters names through the accepted patterns first.
> h2. Impact
> A failed request. No authorization bypass, no amplification, nothing persists
> beyond the single request. Triaged as an ordinary robustness bug rather than
> a vulnerability.
> h2. Fix
> A name beginning with a nesting character names no root property, so
> authorization rejects it before normalisation rather than computing one.
> The change is already included in the WW-5698 pull request
> https://github.com/apache/struts/pull/1872 (commit {{2f3ce9601}}), since that
> PR routes ModelDriven parameters through the same expression. It can be split
> into its own PR if the release notes should attribute it separately.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)