From: Daniel Owens via Fulldisclosure <fulldisclosure () seclists org>
Date: Sun, 1 Nov 2026 22:23:31 +0000
Description
Apache Struts2 Core version 7.4.0 and below attempt to prevent arbitrary code execution via Object-Graph Navigation
Language (OGNL) through several different mechanisms but only in a cursory fashion -- the libraries only guard against
immediate calls evaluated by the OGNL engine via `SecurityMemberAccess`, but an allowed call that, instead, accepts
nested arguments and, itself, invokes reflection internally executes outside of the scope of said cursory protections,
thereby enabling attackers to bypass the limited protections entirely.
It should be noted that this attack, obviously, only works in locations where the information system runs the
input/output through an OGNL parser and executor. Moreover, there is a key difference between Struts2 Core 6.x and
below and 7.x -- 7.x favours a whitelist-based approach that is coupled with some blacklisting, while 6.x and below
only check a blacklist (if anything at all). This means that for successful exploitation in 6.x and below, attackers
can simply find a call that uses reflection and that isn't explicitly blacklisted (e.g., `java.beans.Statement` and
`java.beans.Expression`), embed the otherwise disallowed reflective call, and watch it run. In 7.x, however, attackers
must use something that has been explicitly allowed, first, as the wrapper, which raises the bar for exploitation,
reducing the likelihood for most systems running 7.x (if someone does not realise that the Struts2 Core library only
provides cursory protections, they will not understand the risk and may accidentally add something like
`java.beans.Statement`), but does not reduce the impact or eliminate the risk.
Impact
Attackers can bypass the Apache Struts2 Core and OGNL library's protections against arbitrary code execution via
malicious OGNL through nested calls, thereby executing arbitrary code on the information system. Importantly, through
this, attackers can bypass not only the class/method checks, but also the static/non-static checks, allowing attackers
to, for example, call to `ProcessBuilder`, dump the environment variables via `System.getenv(String)`, and various
other such calls.
Steps to Reproduce
Sample Query
The following will work on Apache Struts2 Core versions 6.x and below (assuming that `query` runs through the OGNL
parser, etc. -- this can happen on the request, but also if the string is reflected back in, say, a JSP via tags that
do as such) without much effort. On Apache Struts2 Core 7.x, though, `java.beans.Expression` would need to be
whitelisted, first.
GET
/search.action?query=new+java.beans.Expression(new+java.beans.Expression(%40java.lang.ProcessBuilder%40class,'new',new+Object%5B%5D%7Bnew+String%5B%5D%7B'/bin/sh','-c','id+%3E+%3C%3CREPLACE+ME+--+a+fresh+marker+file+path%3E%3E'%7D%7D).getValue(),'start',new+Object%5B0%5D).getValue()
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/
Current thread:
- Apache Struts2 Core Arbitrary Code Execution via OGNL Sandbox Escape Daniel Owens via Fulldisclosure (Nov 01)