WordPress HT Contact Form Widget 任意文件上传漏洞 | CVE-2025-7340保姆级别 复现&研究
·
0x0 背景介绍
Thе HT Cоntасt Fоrm Widɡеt Fоr Elеmеntоr Pаɡе Buildеr & Gutеnbеrɡ Blосkѕ & Fоrm Buildеr. 插件在 WоrdPrеѕѕ 中由于 tеmр_filе_uрlоаd 函数中缺少文件类型验证,影响至 2.2.1 及之前版本都存在任意文件上传漏洞。这使得未认证的攻击者可以在受影响站点的服务器上上传任意文件,可能导致远程代码执行。
0x1 环境搭建
1. Ubuntu24+Docker环境复现
- 另存为install.sh并赋予执行权限chmod +x install.sh
#!/bin/bash
echo "部署 WordPress HT Contact Form Widget 任意文件上传漏洞 (CVE-2025-7340)"
echo -e "\n======= 重建阶段 ======="
echo "[*] 创建新目录..."
mkdir -p /root/contactform-cve && cd /root/contactform-cve
# 创建 docker-compose.yml
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
wordpress:
image: wordpress:6.5-php8.2-apache
container_name: ht-contactform-vuln
ports:
- "8081:80"
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wpuser
WORDPRESS_DB_PASSWORD: rootpass
WORDPRESS_DB_NAME: wordpress
volumes:
- ./wp-content:/var/www/html/wp-content
depends_on:
- db
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 15s
timeout: 10s
retries: 6
db:
image: mariadb:10.11
container_name: contactform-db
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: wordpress
MYSQL_USER: wpuser
MYSQL_PASSWORD: rootpass
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-u", "root", "-prootpass"]
interval: 10s
timeout: 5s
retries: 10
volumes:
db_data:
EOF
echo "[+] 启动环境..."
docker compose up -d
# 增强服务等待检测
echo "[*] 等待服务启动..."
until [ $(curl -s -w %{http_code} -o /dev/null http://localhost:8081/wp-admin/install.php) -eq 200 ]; do
echo -n "."
sleep 2
done
echo -e "\n[√] 服务已就绪"
# 下载漏洞插件
echo "[+] 下载 HT Contact Form Widget 插件 (2.2.1)"
PLUGIN_URL="https://downloads.wordpress.org/plugin/ht-contactform.2.2.1.zip"
if ! wget -q "$PLUGIN_URL"; then
echo "[!] 下载失败,使用备用镜像..."
wget -q "https://mirror.ghproxy.com/$PLUGIN_URL"
fi
# 安装unzip
if ! command -v unzip &> /dev/null; then
echo "[*] 安装unzip..."
apt-get update -qq > /dev/null && apt-get install -y -qq unzip > /dev/null
fi
echo "[*] 解压插件..."
mkdir -p wp-content/plugins
unzip -q ht-contactform.2.2.1.zip -d wp-content/plugins/
echo "[*] 设置权限..."
docker exec ht-contactform-vuln chown -R www-data:www-data /var/www/html/wp-content
echo -e "\n======= 完成 ======="
echo "访问地址: http://localhost:8081"
echo "安装配置:"
echo " 站点标题: WordPress HT Contact Form Widget 任意文件上传漏洞 (CVE-2025-7340)"
echo " 用户: admin"
echo " 密码: 默认强密码即可"
echo " 电子邮件: CVE-2025-7340@163.com"
echo
echo "登录后台启用插件: http://localhost:8081/wp-admin/plugins.php"
echo "手动启用 'ht-contactform' 插件"
2. 成功页面,需手动启用插件:

3. 复测环境需手动创建一个表单并发布出去,这样就可以获取到检查的form id,HT Contact Form->Forms->
- 标题:Test1.0
- 组件随便写入一个即可

4. 发布文章:点击当前页面的新建->文章 搜索区块-> HT Form -> 参考如下

5. 发布成功后可用查看并利用了,为什么要发布稍后看漏洞解析就明白了

0x2 漏洞复现
python检测
https://github.com/Kai-One001/WordPress-HT-Contact-CVE-2025-7340-RCE/blob/main/RCE.py
- 因为该漏洞需要获取插件的发布文章的
nonce、form_id,所以我增加了-r参数会根据输入的日期进行遍历漏洞利用
复现截图

复现流量特征 (PACP)
0、请求包含插件发布的文章后会存在Nonce和表单ID

表单ID

nonce

1、直接访问/wp-admin/admin-ajax.php

2、后续Shell命令执行:

0x3 漏洞原理分析
漏洞位置
漏洞位置:ht-contactform/admin/Includes/Services/FileManager.php
关键函数:temp_file_upload()
1. 主要漏洞点:temp_file_upload 函数
#63行
public function temp_file_upload($file) {
$destination = "{$this->dir}/temp";
$this->maybe_create_directories($destination);
// Validate file
$validation = $this->validate($file);
if (!$validation['valid']) {
wp_send_json_error($validation['message']);
return;
}
// Process the file
$filename = $this->process_filename($file['name']);
$file_path = "{$destination}/$filename";
// Move file to temporary directory
if (move_uploaded_file($file['tmp_name'], $file_path)) {
wp_send_json_success([
'file_id' => $filename,
'file_name' => $file['name'],
'file_size' => $file['size']
]);
return;
}
}
2. 漏洞入口点:AJAX处理
文件位置: ht-contactform/admin/Includes/Ajax.php:
#46-47行
add_action('wp_ajax_ht_form_temp_file_upload', [$this, 'temp_file_upload']);
add_action('wp_ajax_nopriv_ht_form_temp_file_upload', [$this, 'temp_file_upload']);
问题: 使用了 wp_ajax_nopriv_ 钩子,这意味着未经身份验证的用户也可以访问文件上传功能。
问题根因分析:
- 缺少文件类型验证:
FileManager.php的validate函数中,只检查PHP上传错误,完全没有验证文件类型、扩展名或MIME类型。 - 文件类型配置未被使用:插件在
Fields.php中定义了允许的文件,但是只在表单渲染时用于前端验证(accept 属性),服务器端完全没有使用这些配置进行验证。 - 文件名处理不够安全:
sanitize_file_name()主要处理特殊字符,不会阻止危险扩展名,攻击者仍然可以上传.php、.php3、.phtml等文件;
3. 访问控制问题
// Ajax.php 第46-47行
add_action('wp_ajax_ht_form_temp_file_upload', [$this, 'temp_file_upload']);
add_action('wp_ajax_nopriv_ht_form_temp_file_upload', [$this, 'temp_file_upload']);
问题分析:
- 非登录用户也可以访问上传功能
- 仅依赖 nonce 验证,可能被绕过
攻击场景
-
直接攻击: 攻击者可以直接向 /wp-admin/admin-ajax.php 发送POST请求,action为 ht_form_temp_file_upload
-
绕过前端验证: 前端使用 accept 属性限制文件类型,但攻击者可以轻松绕过
-
文件执行: 上传的PHP文件可能被Web服务器执行,导致远程代码执行
1. 双重扩展名绕过
shell.php.jpg
shell.php.png
shell.php.gif
2. 大小写绕过
shell.PHP
shell.Php
shell.pHp
3. 空字节注入(如果服务器配置允许)
shell.php%00.jpg
0x4 修复建议
修复方案
- 升级到最新版本:升级最新版本。目前已发布升级补丁,获取链接:
- 临时缓解措施:
限制文件类型:同Fields.php中限制。
添加访问控制:移除 wp_ajax_nopriv_ 钩子或添加适当的权限检查。
添加内容验证:实现文件内容验证(不仅仅是扩展名)。
添加路径控制:使用安全的文件存储位置,上传不回显路径;
免责声明:本文仅用于安全研究目的,未经授权不得用于非法渗透测试活动。
更多推荐
所有评论(0)