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
form_id
nonce
d2bcf0795d

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 验证,可能被绕过

攻击场景

  1. 直接攻击: 攻击者可以直接向 /wp-admin/admin-ajax.php 发送POST请求,action为 ht_form_temp_file_upload

  2. 绕过前端验证: 前端使用 accept 属性限制文件类型,但攻击者可以轻松绕过

  3. 文件执行: 上传的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 修复建议

修复方案

  1. 升级到最新版本:升级最新版本。目前已发布升级补丁,获取链接:
  2. 临时缓解措施:
    限制文件类型:同Fields.php中限制。
    添加访问控制:移除 wp_ajax_nopriv_ 钩子或添加适当的权限检查。
    添加内容验证:实现文件内容验证(不仅仅是扩展名)。
    添加路径控制:使用安全的文件存储位置,上传不回显路径;

免责声明:本文仅用于安全研究目的,未经授权不得用于非法渗透测试活动。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐