问题场景:
凌晨两点,监控告警弹出一行刺眼的红字——/data/cache/inc_archives.php 文件被修改,后台内容页生成数量从预期的 3000 篇骤降至 17 篇,且列表页分页链接全部指向 404,我揉了揉眼睛,打开服务器终端,输入 ls -la /var/www/html,发现根目录多出一个名为 .temp 的隐藏目录,权限为 755,属主是 www,这不是正常现象,第一反应:被挂马了。
织梦CMS内容页生成数量错误排查实录,从挂马清理到整站迁移的硬核运维手册
第一步:应急隔离与木马清理
- 立即切断外网访问:在云防火墙安全组中临时封禁 80/443 端口,仅保留 SSH(22)和数据库端口。
- 找出所有异常文件:执行
find /var/www/html -name "*.php" -mtime -3列出最近三天被修改的 PHP 文件,发现除了index.php、plus/arc.php被篡改外,include/common.inc.php也被插入一段 base64 加密代码。 - 清除木马:用
grep -r "eval(" /var/www/html定位所有执行函数,手动将eval(base64_decode(...))字段替换为空白,并删除.temp目录下所有文件。注意:不要直接删目录,先chmod 000 .temp冻结它,防止后续日志回写,再执行rm -rf .temp。 - 修复核心文件:从官方渠道下载同版本织梦源码,比对
md5sum后覆盖include和plus下的受损文件。切记:不要覆盖data目录和config.cache.bak.php,否则会丢失站点配置。
第二步:恢复内容页生成数量
问题根源在于木马修改了 arc_list 表索引,执行:
REPAIR TABLE `dede_archives`; ANALYZE TABLE `dede_archives`;
然后在后台“系统 -> 数据更新 -> 文档索引重建”中,勾选所有栏目,点击“开始重建”,如果数量仍不对,检查 dede_archives 表中 mid(栏目ID)字段是否有脏数据,用 DELETE FROM dede_archives WHERE mid=0 清理。
第三步:后台路径修改与文件权限加固
- 后台目录改名:将
/admin重命名为/backend_2024(禁止用数字简单叠加,用大小写字母+数字组合),修改data/common.inc.php中$cfg_admin_rename变量为“backend_2024”。 - 文件权限最小化:
- 目录权限:
find /var/www/html -type d -exec chmod 755 {} \; - 文件权限:
find /var/www/html -type f -exec chmod 644 {} \; - 敏感文件:
chmod 600 /var/www/html/data/common.inc.php,并加immutable属性(chattr +i)。 - 上传目录(
/uploads):改为chmod 755并设置 write-only 子目录,同时禁止 PHP 执行:在 Nginx 中配置location ~ ^/uploads/.*\.(php|php5)$ { deny all; }。
- 目录权限:
第四步:整站搬家全流程(宝塔面板环境)
- 备份:使用宝塔“网站备份”功能,同时通过 SSH 执行
tar -zcvf site.tar.gz /var/www/html(排除缓存),数据库用mysqldump -u root -p --single-transaction --master-data=2 dedecms > db.sql。 - 迁移:在新服务器上解压
site.tar.gz到/var/www/html,导入数据库。 - 配置适配:修改
data/common.inc.php中的数据库主机、账号、密码。 - 权限重置:重新执行第三步的权限命令,否则 redis 或 memcached 写入会失败。
第五步:域名更换后的数据替换技巧
- 直接替换数据库:
UPDATE dede_addonarticle SET body = REPLACE(body, 'http://old.com', 'http://new.com'); UPDATE dede_archives SET arcurl = REPLACE(arcurl, 'http://old.com', 'http://new.com'); UPDATE dede_arctype SET typlink = REPLACE(typlink, 'http://old.com', 'http://new.com');
- 忽略缓存:后台“系统 -> 性能优化 -> 更新系统缓存”并强制刷新浏览器。
- 防踩坑页中还有绝对路径 /images/ 开头的资源,统一用
sed -i替换配置文件中的$cfg_basehost,并在include/helpers/url.helper.php中找到GetCurUrl()函数,将HTTP_HOST的引用改为从$cfg_basehost读取。
第六步:数据库备份与恢复的完整操作
- 定期备份:写一个 Shell 脚本,保留最近 30 天备份,上传到 OSS:
#!/bin/bash DATE=$(date +%Y%m%d) mysqldump -u [user] -p[password] [database] | gzip > /backup/db_$DATE.sql.gz find /backup -name "*.sql.gz" -mtime +30 -delete
- 恢复演练:不要只做备份不测试,每季度选一台测试机,导入数据库并访问
index.php,验证所有栏目和内容页数量是否一致,恢复时注意从dede_sysconfig表中读取cfg_version,若版本不同需要先升级。
收尾:
所有操作结束后,在服务器上执行 chkrootkit 和 lynis audit system 扫描残留后门,将内容页生成数量错误的根因记录下来——木马在 dede_archives 表中插入大量 mid=0 的垃圾记录,导致统计计数失效。运维没有魔法,只有每一步都严格落地的流程。 照做这套流程,你也能在 30 分钟内把站点从幽灵手上抢回来。



发表评论