DedeCMS会员中心mtypes.php SQL注入漏洞修复深析:数组键名注入根因、intval补丁与系统化排查

DedeCMS会员中心mtypes.php SQL注入漏洞修复深析:数组键名注入根因、intval补丁与系统化排查
张文保 更新 22 分钟阅读 2,662 阅读
本文目录
  1. 漏洞原理:数组键名 SQL 注入
  2. 补丁的关键改动
  3. 为什么 intval 比 HtmlReplace 强
  4. 补丁还不够:mtypes.php 里的其它注入点
  5. 系统化排查 DedeCMS 整套代码的注入风险
  6. 用 grep 扫"foreach + 拼 SQL"模式
  7. 重点排查路径
  8. 已知的 DedeCMS 高危 CVE
  9. SQL 注入的攻击面与影响
  10. 攻击者能做什么
  11. 防御纵深
  12. 用 PDO 预处理语句重构 mtypes.php
  13. 补丁部署的注意事项
  14. 升级前务必备份
  15. 同时清模板缓存
  16. 验证补丁生效
  17. 长期建议:彻底升级或迁移
  18. 运行时防御:上 WAF
  19. 监控与告警
  20. 应急响应流程(如果发现已被入侵)
  21. 找 webshell 的 grep 命令速查
  22. 常见问题解答
  23. 怎么知道我的站有没有被攻击过?
  24. HtmlReplace 真的不能防 SQL 注入吗?
  25. DedeCMS 已经停止维护,补丁从哪里拿?
  26. 升级 DedeBIZ 会影响现有数据吗?
  27. 会员中心是否要彻底关闭?
  28. 修补丁后还要不要清 Web 服务器缓存?
  29. WAF 拦截的请求会影响真实用户吗?
  30. 预处理语句会比拼字符串 SQL 慢吗?
  31. DedeCMS V5.7 SP3 / SP4 修了多少漏洞?
  32. 2026 年还能新装 DedeCMS 吗?
  33. 权威参考资料
摘要:DedeCMS会员中心的mtypes.php只过滤了数组的值却漏了键名,攻击者构造特殊键名就能注入SQL,这就是CVE-2018-9134。本文讲透数组键名注入的根因和intval补丁的关键改动,点出补丁还不够、文件里其它注入点,再用PDO预处理重构、给系统化排查整套代码的方法、WAF兜底和被入侵后的应急响应。

DedeCMS 会员中心的 /member/mtypes.php 在 2014 年被披露存在 SQL 注入漏洞——攻击者通过分类管理表单的 mtypename[id] 数组键名注入恶意 SQL,能直接读取/修改数据库内容(含管理员密码哈希)。这是 DedeCMS 历史上影响最广的漏洞之一,至今很多老站没打补丁仍在裸奔。

这一篇把这个漏洞讲透:根因(PHP 数组键名直接拼到 SQL 里)、原帖给的补丁完整解析、为什么 intval() 是关键、补丁后还有哪些 SQL 注入点、如何系统化扫描整套 DedeCMS 的注入风险、与 WAF / fail2ban 的协同防御、2026 年还在用 DedeCMS 的安全建议。

漏洞原理:数组键名 SQL 注入

原始漏洞代码(/member/mtypes.php):

foreach ($mtypename as $id => $name) {
    $name = HtmlReplace($name);   // ✅ 对 $name 做了过滤
    $query = "UPDATE `#@__mtypes` SET mtypename='$name' WHERE mtypeid='$id' AND mid='$cfg_ml->M_ID'";
    //                                                              ↑↑↑↑
    //                                                          $id 没过滤!
    $dsql->ExecuteNoneQuery($query);
}

开发者过滤了数组的 $name)但忘了过滤 $id)。PHP 数组的键名可以是任意字符串——攻击者构造一个表单:

<form method="POST" action="/member/mtypes.php?dopost=save">
    <input name="mtypename[1' OR '1'='1]" value="payload" />
</form>

提交后 PHP 解析得到 $mtypename = ["1' OR '1'='1" => "payload"]。foreach 循环时 $id = "1' OR '1'='1",直接拼到 SQL:

UPDATE `dede_mtypes` SET mtypename='payload' WHERE mtypeid='1' OR '1'='1' AND mid='123'

WHERE 条件被打穿——所有 mtypes 行都被改成 mtypename='payload'。更高级的攻击者能用 UNION SELECT ... 读取其它表(dede_admin 拿管理员密码哈希)。

补丁的关键改动

原帖给的补丁就一行关键改动:

foreach ($mtypename as $id => $name) {
    $name = HtmlReplace($name);
    $id = intval($id);   // ← 关键:把 $id 强制转成整数
    $query = "UPDATE `#@__mtypes` SET mtypename='$name' WHERE mtypeid='$id' AND mid='$cfg_ml->M_ID'";
    $dsql->ExecuteNoneQuery($query);
}

intval("1' OR '1'='1") 会得到 1(PHP 的 intval 解析到第一个非数字字符就停)。攻击 payload 被中和。

为什么 intval 比 HtmlReplace 强

过滤方式能防 SQL 注入吗能防 XSS 吗
HtmlReplace(DedeCMS 内置)不可靠可(转义 HTML 实体)
addslashes不可靠(GBK 字符集下能绕过)不可
mysqli_real_escape_string对引号内场景可靠不可
intval对纯整数场景绝对可靠不可(但整数 ID 不参与 HTML 输出)
预处理语句(PDO / mysqli prepare)绝对可靠不可

对 ID 这种"应该是整数"的字段,intval() 是最稳的——任何非数字内容直接变 0 或截断到第一个数字。预处理语句更通用但 DedeCMS 老代码大量用字符串拼接 SQL,临时性补丁里 intval 性价比最高。

补丁还不够:mtypes.php 里的其它注入点

原帖只补了 UPDATE 这一处,但同文件里还有 DELETE 操作 $delids 也存在风险点:

$delids = '0';
$mtypeidarr = array_filter($mtypeidarr, 'is_numeric');
foreach($mtypeidarr as $delid) {
    $delids .= ','.$delid;
}
$query = "DELETE FROM `#@__mtypes` WHERE mtypeid IN ($delids) AND mid='$cfg_ml->M_ID';";

这里 array_filter(..., 'is_numeric') 已经过滤了非数字键值。但 is_numeric() 接受 "123e+0" 这种科学计数法,理论上可以 "1,2);DROP TABLE x;--" 这种被 is_numeric 拒掉,所以这里相对安全。但严谨做法是每个 $delid 也 intval 一遍

foreach($mtypeidarr as $delid) {
    $delid = intval($delid);   // 双保险
    $delids .= ',' . $delid;
}

系统化排查 DedeCMS 整套代码的注入风险

mtypes.php 不是孤例——DedeCMS V5.6 / V5.7 / 早期 SP 版本里类似的"数组键名直拼 SQL"漏洞还有十几处。要系统化排查:

用 grep 扫"foreach + 拼 SQL"模式

cd /www/wwwroot/yoursite.com/

# 找所有 foreach 后面跟 query 拼接的代码
grep -rn "foreach.*as.*=>" --include="*.php" -A 5 | \
    grep -B 1 -E "(query|sql).*\\\$" | head -100

每条命中行都需要人工审查:"键名是否被过滤?值是否被过滤?"。

重点排查路径

  • /member/ — 会员中心,前台用户可达;
  • /dede/ — 后台,要求登录但 CSRF 可能放大攻击;
  • /include/payment/ — 支付回调,外部可触发;
  • /plus/ — 插件目录,历史漏洞最多;
  • /api/ — 各种 API 入口。

已知的 DedeCMS 高危 CVE

CVE位置类型受影响版本
CVE-2018-9134/member/mtypes.phpSQL 注入(本文)V5.7 SP1 之前
CVE-2018-7700/uploads/任意文件上传V5.7 SP1 之前
CVE-2019-8362/dede/file_manage_view.phpRCEV5.7 SP2 之前
CVE-2020-25008/include/dialog/任意文件读取V5.8.1 之前
CVE-2022-23047/dede/article_string_mix.phpSQL 注入V5.7.106 之前

5 条只是"明显的"——实际累计高危漏洞超过 50 条。建议:① 升级到最新社区分叉 DedeBIZ;② 定期跑 D 盾、河马等漏洞扫描器;③ 上 WAF 兜底。

SQL 注入的攻击面与影响

攻击者能做什么

  • 读取任意表UNION SELECT password FROM dede_admin 拿管理员密码;
  • 修改任意数据UPDATE dede_admin SET pwd='伪造哈希' WHERE id=1
  • 删除整表DROP TABLE dede_archives
  • 写文件:MySQL 的 SELECT ... INTO OUTFILE '/path/shell.php'(需要 FILE 权限),写 webshell;
  • 读文件:MySQL 的 LOAD_FILE('/etc/passwd')(需要 FILE 权限);
  • RCE:组合注入 + outfile 写入 PHP webshell,再访问执行任意命令。

防御纵深

即使 PHP 代码有注入,也能通过其它层次缓解:

  • 数据库账号最小权限:DedeCMS 数据库用户只给 SELECT/INSERT/UPDATE/DELETE,不给 FILE / DROP,注入也写不了 webshell;
  • WAF:Cloudflare / 阿里云 WAF 自带 SQL 注入特征拦截,能挡 80% 自动化扫描;
  • Web 服务器禁止 PHP 在上传目录执行:即使 webshell 写到 /uploads/,Nginx 配置 location /uploads/ 拦 .php 请求;
  • fail2ban 拉黑高频 SQL 注入特征请求

用 PDO 预处理语句重构 mtypes.php

临时补丁是 intval。彻底修复用 PDO 预处理,永久无忧:

// 假设把 DedeCMS 的 $dsql 替换成 PDO 实例
$pdo = new PDO('mysql:host=localhost;dbname=dede;charset=utf8mb4', $user, $pass);

foreach ($mtypename as $id => $name) {
    $stmt = $pdo->prepare("UPDATE dede_mtypes SET mtypename = :name WHERE mtypeid = :id AND mid = :mid");
    $stmt->execute([
        ':name' => HtmlReplace($name),
        ':id'   => (int)$id,                  // 显式转 int
        ':mid'  => (int)$cfg_ml->M_ID,
    ]);
}

预处理语句的好处:参数永远不会被解释为 SQL 关键字,无论攻击者怎么构造 payload 都不会破坏 SQL 结构。性能上 PDO 预处理还能让数据库缓存执行计划,比拼字符串 SQL 还略快。

补丁部署的注意事项

升级前务必备份

cp /www/wwwroot/yoursite.com/member/mtypes.php /backup/mtypes.php.$(date +%Y%m%d)

万一打补丁打错或冲突,能 1 分钟回滚。

同时清模板缓存

修改 PHP 文件后清 data/tplcache/,避免老缓存还在用旧版逻辑。

验证补丁生效

用 sqlmap 测试一下:

sqlmap -u "https://yoursite.com/member/mtypes.php?dopost=save" \
       --data="mtypename[1*]=test&cfg_ml=1" \
       --cookie="DedeUserID=xx; DedeLoginTime=xx" \
       --level=3 --risk=2

未打补丁的版本会被 sqlmap 立刻发现注入;打了补丁的应报"no injection point found"。

长期建议:彻底升级或迁移

修一处漏洞只是补一个小坑。彻底解决:

  1. 升级到 DedeBIZ V6.x:社区分叉版,活跃维护,已合并大部分历史 CVE 补丁;
  2. 切到 WordPress + 迁移内容:WordPress 的核心代码经过更严格审计,安全生态更成熟;
  3. 用静态站生成器:Hexo / Hugo / Jekyll 等,没有动态后端就没有 SQL 注入面。

2026 年仍然新建 DedeCMS 站风险远大于收益——历史漏洞之多、社区维护之弱,每个上线日都是赌博。

运行时防御:上 WAF

即使代码有补丁,上 WAF 是额外的兜底。Cloudflare 免费版自带 OWASP 核心规则集,能拦绝大多数自动化扫描器:

Cloudflare WAF Rule (Free Plan):
- SQL Injection (SQLi) protection: ON
- Cross-Site Scripting (XSS) protection: ON
- File Inclusion (LFI/RFI): ON

阿里云 WAF / 腾讯云 WAF 国内方案类似。WAF 不是替代代码补丁——是补丁的补充。代码必须修对,WAF 是兜底。

监控与告警

装好 WAF 后再加监控:

  • fail2ban:扫 access.log 里高频的 ?dopost=save、SQL 注入特征字符串,发现一个 IP 反复试探就拉黑;
  • Web 服务器日志告警:HTTP 500 / 502 错误突增(可能是注入后 SQL 报错);
  • 数据库监控:突然出现的大量 UPDATE / DELETE 事件,流量异常;
  • 邮件告警:管理员账号被改密码、登录 IP 异常都触发邮件。

应急响应流程(如果发现已被入侵)

万一晚一步——发现站点已经被注入或挂马,按以下顺序处理:

  1. 立刻断网:暂停 Nginx / Apache 服务,避免攻击者继续操作;
  2. 全量备份当前状态:包括所有 PHP 文件、数据库、access.log、error.log——证据保全;
  3. 修改所有数据库密码:DedeCMS 数据库账号、管理员账号哈希;
  4. 查 access.log 找入侵时间窗:搜可疑 payload(含 'UNIONSELECT 的 POST 请求),确定攻击起点;
  5. 对比文件 mtimefind . -name "*.php" -newer /var/log/messages -mtime -7 找最近 7 天修改过的 PHP 文件,重点排查是否被加 webshell;
  6. 清理 webshell:常见后门函数 eval() / assert() / preg_replace 加 /e 修饰符,grep 整套代码找;
  7. 修补漏洞:本文 mtypes.php 补丁 + 升级到 DedeBIZ;
  8. 重置所有用户密码:admin、会员都强制重置;
  9. 恢复服务:开 Nginx,监控 24 小时;
  10. 事后复盘:写故障报告,归档攻击轨迹与防御加固清单。

找 webshell 的 grep 命令速查

# 找含 eval 的 PHP 文件
grep -rln "eval(" --include="*.php" /www/wwwroot/yoursite.com/

# 找 base64 编码的 PHP 字符串(webshell 常用伪装)
grep -rln "base64_decode" --include="*.php" /www/wwwroot/yoursite.com/

# 找含 assert 的(assert 也能执行 PHP)
grep -rln "assert(" --include="*.php" /www/wwwroot/yoursite.com/

# 找文件包含 + 用户输入(LFI/RFI)
grep -rEn "(include|require)(_once)?[\s(]+\\\$_(GET|POST|REQUEST)" --include="*.php" /www/wwwroot/yoursite.com/

每条命中的文件都要人工审查——是合法用法还是 webshell。

常见问题解答

怎么知道我的站有没有被攻击过?

三个排查点:① 看 web 服务器 access.log 找 mtypename[ + 引号 / OR / UNION 等可疑 payload;② 看 dede_admin 表有没有意外新增的管理员账号;③ 看 dede_mtypes 表的 mtypename 字段有没有奇怪的值(被 UPDATE 篡改痕迹)。fail2ban 日志和 WAF 告警也是入口。

HtmlReplace 真的不能防 SQL 注入吗?

不能。HtmlReplace 是 DedeCMS 自带的 HTML 转义函数(把 <&lt; 之类),针对 XSS 设计的。对 SQL 没有任何保护——SQL 不解析 HTML 实体。要防 SQL 注入要用 intval / addslashes / 预处理语句。

DedeCMS 已经停止维护,补丁从哪里拿?

三个来源:① DedeBIZ 社区分叉https://www.dedebiz.com/)已经合并了大部分历史 CVE,下载最新版即可;② D 盾 / 河马等国产 PHP 漏洞扫描器自带 DedeCMS 补丁库;③ 自己根据 CVE 公告手动改代码(本文方式)。生产环境推荐方案 ①。

升级 DedeBIZ 会影响现有数据吗?

不会。DedeBIZ 与 DedeCMS V5.7 数据库 schema 兼容——只是替换 PHP 文件,数据库不动。但升级前必须备份所有 PHP 文件 + 数据库,万一新版本与你的自定义模板/插件冲突,能回滚。

会员中心是否要彻底关闭?

看业务。如果你的站不需要会员(纯展示型企业站),关闭整个 /member/ 目录是最安全的——直接 Nginx deny all 这个 location,所有相关漏洞瞬间消失。如果业务需要会员,要么升级 DedeBIZ,要么自己审计代码 + 加 WAF。

修补丁后还要不要清 Web 服务器缓存?

看你用的缓存层。① OPcache(PHP 自带 opcode 缓存)会缓存 PHP 文件解析后的字节码,文件改动后默认监测 mtime 自动失效,但保险起见可 opcache_reset() 或重启 PHP-FPM;② 静态页面缓存(Cloudflare / 阿里云 CDN)跟 PHP 修改无关,但如果你的攻击页 URL 被 CDN 缓存了攻击响应,要清 CDN 缓存。

WAF 拦截的请求会影响真实用户吗?

会,但概率极低。WAF 偶尔会误报(比如用户输入的关键词恰好像 SQL)。Cloudflare WAF 有"挑战模式"——可疑请求弹验证码而不是直接 403,平衡安全与用户体验。生产建议上线前用 Log Mode 跑 1 周看告警准确率,再切到 Block Mode。

预处理语句会比拼字符串 SQL 慢吗?

不会。① 数据库会缓存预处理执行计划,二次执行更快;② PHP PDO 的预处理本质就是给参数加引号 + 转义,开销几乎为零;③ 在大查询里两者性能差异在毫秒级。预处理语句永远是更优选择,没有不用的理由。

DedeCMS V5.7 SP3 / SP4 修了多少漏洞?

SP2 之后官方维护放缓,SP3 / SP4 主要是 PHP 8 兼容修复 + 少量 CVE 补丁。绝大部分高危历史漏洞要靠社区分叉(DedeBIZ)维护。如果你站点版本老于 V5.7 SP2,立刻升级是头等优先。

2026 年还能新装 DedeCMS 吗?

从技术上能,但非常不推荐。原因:① 大量历史漏洞累积;② 官方停更,没有持续安全补丁;③ PHP 8 / MySQL 8 兼容性差;④ 现代 SEO 友好度不如 WordPress;⑤ 模板/插件生态萎缩。新建项目用 WordPress / Hexo / 自研 + 现代框架的成本远低于"用 DedeCMS + 持续打补丁"。

权威参考资料

分享到
标签
版权声明

本文标题:《DedeCMS会员中心mtypes.php SQL注入漏洞修复深析:数组键名注入根因、intval补丁与系统化排查》

本文链接:https://zhangwenbao.com/dedecms-member-center-mtypes-php-injection-vulnerability-repair-method.html

版权声明:本文原创,转载与引用请注明作者与原文链接。许可协议: CC BY 4.0

继续阅读
发表评论
分享到微信 或在下方手动填写
支持 Ctrl + Enter 提交