WordPress被挂马实录:4分钟塞进5个后门,手机一打开就跳转
本站部分链接为联盟推广链接。通过这些链接购买,我可能获得佣金...
这不仅不会增加您的实际费用,通常还能让您享受到专属折扣。所有上榜推荐均基于真实项目环境下的自费实测,排名完全由客观测评数据决定。详细规则请查阅《免责声明》。
就在昨天有客户发来消息:”网站用手机打开会跳到乱七八糟的网站,电脑上又好好的。”
我用自己电脑点开,正常。换手机,关掉 WiFi 用流量,开无痕模式点进一篇文章,页面刚加载完,就被带去了别的网站。
这是一个用宝塔面板跑的 WordPress 游戏资源站,主题是 RiPro-V5 加一个定制子主题。下面是我从排查、取证到清理的完整过程,包括一开始走的弯路。如果你的站也有”手机跳恶意网站、电脑不跳”的症状,可以直接跳到后面的自查命令。
症状:电脑一切正常,手机一打开就跳
这类挂马最折磨人的地方,是站长自己几乎碰不到。
你用电脑登后台改文章,什么都看不出来。用手机打开,也可能不跳,因为很多跳转脚本会先判断”是不是第一次来””是不是从搜索引擎点进来””是不是管理员 IP”,满足条件才动手。我自己拿手机测的时候也是时灵时不灵:同一部手机,有时连开几篇都正常,有时点进去就被带走。
后来我在服务器日志里也看到了印证:用我自己的同一部 iPhone 打开某篇文章后,十几秒没有任何请求,接着以空白来路重新打开页面。这是典型的”被带走了,又自己点回来”。
我拿到的第一份文件,干净得反常
客户提供的面板的访问权限,我打包了整个网站目录和数据库。我做的第一件事,是拿 WordPress 官方 7.1.3 的源码,跟他的 wp-admin、wp-includes 逐个文件比对字节,结果全部一致。
插件也比对了,Wordfence、Sucuri 跟官方包一模一样。数据库全库检索 <script、eval(、location.href、atob( 这些特征,零命中。主题后台那个”网站底部自定义JS代码”的框,也是空的。
我又去服务器上看 Nginx 配置、Lua 模块、PHP 的 auto_prepend_file,全都正常。还做了一个很有用的测试:用手机 UA 和电脑 UA 分别去请求纯静态文件 readme.html,再和磁盘上的原文件对比,三个 md5 完全一样。这说明 Nginx 没有按设备往页面里塞东西。
查到这一步我其实有点慌。哪都干净,那跳转是从哪来的?
问题出在时间上。我把文件的修改时间排了一遍,发现有 3 个文件在客户联系我之前的几个小时里刚被改过,其中一个是子主题的 functions.php。再翻 Wordfence 的数据库记录,有个叫 File Manager Advanced 的插件”最近被停用”。
看起来,在我接手之前已经有人动手清过一轮,删了插件、改了文件,只是没清到根上。我拿到的,是一个被收拾过的现场,我问过客户才知道,他按照 AI 的提示自己进行过清理工作,不得不说这确实省去了我清理这些恶意文件的一些时间。
转机:一份”清理前”的备份
后来客户发给我了一份整站备份,打包时间比那次清理还早 3 分钟。
这份就不一样了。根目录一眼就多出两个 PHP 文件,按修改时间一排,整个入侵过程清清楚楚,前后只用了 4 分钟:
凌晨 4 点 36 分,攻击者在后台装了 File Manager Advanced。这个插件本身是正经插件,作者是 wpexpertsio,底层用的是 elFinder,能在 WP 后台直接浏览、上传、编辑服务器文件,官方介绍里还写着能访问 WordPress 根目录以外的文件。对攻击者来说,这就是一个现成的远程文件管理器。
装插件需要管理员权限。所以这里有个让人不舒服的推论:攻击者在 4:36 之前就已经能登录后台了,挂马只是收尾动作。
5 个后门分别藏在哪
两个放在根目录,名字一个随便取,一个故意起得像 WordPress 自带的 wp-activate.php。两个塞进了 wp-includes/block-bindings/,这是 WordPress 核心目录,很多人清理时根本不会往这里看。还有一个寄生在主题的 functions.php 末尾。
根目录还有个 .tmb 文件夹,这是 elFinder 生成缩略图用的。看到它,基本就能确定有人用文件管理器类插件操作过服务器。
Adszx.php:10 个管理员
这个文件只有 2.6KB,注释是印尼语,执行完会输出一句俄语”一切都已完成,安全!”,东拼西凑的味道很重。
它干的事情很简单粗暴:加载 wp-load.php,以 WordPress 的身份批量创建 adminisz1 到 adminisz10 共 10 个账号,全部设成管理员,共用一个写死在代码里的密码。注意,访问这个文件不需要任何登录,谁知道路径谁就能触发。
真正阴的是第二步。它往当前主题的 functions.php 末尾追加了两段代码:一段挂在 pre_user_query 上,后台”用户”列表查询时自动排除这 10 个账号;另一段挂在 user_has_cap 上,任何人想删这 10 个账号,删除权限都会被直接改成 false。
结果就是:攻击者却握着 10 把备用钥匙。改密码?改的是你自己的。
正常情况下一个站该有几个管理员、各个角色能干什么,可以对照这篇 WordPress 五种用户角色的权限区别 看。被挂马的站,用户列表是不可信的,必须去数据库里查,命令我放在后面了。
剥了 16 层,才看到 WebShell 的真身
根目录另一个文件 wp-activajetbxzm.php 有 113KB,打开只有一行 eval(str_rot13(gzinflate(base64_decode("\x4a\x62..."))))。
我写了个小脚本做静态解码,不执行任何代码,一层一层剥。每一层的组合都不一样,base64、gzinflate、gzuncompress、rot13、字符串反转、URL 解码轮番上阵,一共 16 层。这么折腾只有一个目的:躲开按特征码扫描的安全插件。
剥到底,是一个标题叫”JKT48″的 WebShell。它有登录页,密码用 bcrypt 存;登录后能浏览、上传、编辑、删除服务器上的任意文件,还能改名、改权限、打包压缩。函数名全是印尼语,比如 tulisLah、faylSil、kunci。
说白了,攻击者给自己装了一个网页版的服务器文件管理后台,跟宝塔的”文件”菜单差不多好用。
混进 wp-includes 的另外两个
wp-includes/block-bindings/ 这个目录在 WordPress 7.1.3 官方包里只有 4 个文件:pattern-overrides.php、post-data.php、post-meta.php、term-data.php。备份里多了 connects.php 和 index.php。
connects.php 是一个叫”B3T4 Shell”的文件管理型后门。有意思的是,它开头还粘着一大段别人网站的 PHP 报错,里面有巴西某网站的服务器路径。攻击者大概是直接从另一个被黑的站上把输出复制了过来,连垃圾都没擦干净。index.php 则是又一个经过变量名混淆的 WebShell。
为什么藏在这?因为很多人清理挂马只盯着根目录和 uploads,不会想到去核心目录里数文件。你要是只把 WordPress”更新一下”,更新程序覆盖的是官方文件,多出来的文件它不管,后门照样活着。
那手机跳转到底是谁干的?
说实话,这个问题我到现在也没能抓到现场。
清理前的备份里,我把所有文件又搜了一遍跳转特征,没有。主题的核心文件和 translate.js,跟清理后的版本逐字节一致。数据库也是干净的。
真正让我确定方向的,是客户后来补的一句:”宝塔面板下的所有站点都会跳。”同一台服务器上另一个完全不是 WordPress 的站也中招了,那问题就不可能只出在某个 WordPress 文件里,而是在服务器这一层。
那些 WebShell 能读写服务器上的文件,攻击者完全有条件往系统层面继续渗透。具体用了什么手法往页面里注入跳转,我没能确认(不确定:重装前没有抓到注入时的进程和内存现场,只能根据”所有站点都跳、网站文件和配置都干净”推断)。
所以处理方案是:不在原系统上修修补补,直接重装系统,只迁移核实过的数据。服务器重装成了全新的 Debian,WordPress 核心和插件全部重新下载官方包,数据库只导入检查过的那一份。如果你也打算换机器,可以看看换一台干净的 VPS 时有哪些选择。
攻击者是怎么进后台的?
这一段我只能给出线索,给不了定论。
Wordfence 装上之后没几个小时,就记录到有个 IP 在一分钟内对 xmlrpc.php 连续登录失败 20 次被锁;还有带假 UA 的扫描器在全站各种目录里找 cache.php,这是在找别人留下的现成后门。
后台账号是被暴力破解的、密码在别处泄露了,还是从同服务器别的站横向过来的?日志不够,我不确定。能确定的只有一件事:攻击者在装插件之前就有管理员权限。所以清理之后,给登录页加上防暴力破解限制、关掉不用的 XML-RPC,比删后门更关键。那些乱扫路径的请求,也可以用 Nginx 规则直接挡在门外。
照着查你自己的站:6 条命令
下面的命令都在宝塔终端里执行,把 /www/wwwroot/你的站点 换成你自己的网站目录。全部是只读操作,不会改动任何文件。
1. 列出最近 30 天被改过的 PHP 文件
find /www/wwwroot/你的站点 -name "*.php" -mtime -30 -printf "%TY-%Tm-%Td %TH:%TM %p\n" | sort
出现你没动过的文件要警惕,尤其是一堆文件集中在几分钟内被改。
2. 搜索常见后门特征
grep -rlE "eval\s*\(\s*(str_rot13|gzinflate|base64_decode)|pre_user_query|adminisz|B3T4" /www/wwwroot/你的站点 --include=*.php
Wordfence 这类安全插件自己的特征库文件也可能被搜出来,要人工看一下。
3. 在数据库里查所有管理员(绕过后台的隐藏)
sql命令
SELECT u.ID, u.user_login, u.user_email, u.user_registered
FROM wp_users u JOIN wp_usermeta m ON m.user_id = u.ID
WHERE m.meta_key = 'wp_capabilities' AND m.meta_value LIKE '%administrator%';
在宝塔”数据库 → 管理”里执行。表前缀不是 wp_ 的话自己改。拿结果跟后台”用户”页面对比,数量对不上就有鬼。
4. 找文件管理器用过的痕迹
find /www/wwwroot -type d -name ".tmb"
5. 核对 WordPress 核心文件
装了 WP-CLI 的话:
wp core verify-checksums --include-root --path=/www/wwwroot/你的站点 --allow-root
按官方文档,它会把核心文件跟 WordPress.org 的校验值比对,加上 --include-root 还会对根目录里不属于 WordPress 的文件发出警告。但它会不会报告 wp-includes 里多出来的文件,文档没写,我也没实测(不确定)。保险起见,我更推荐下载同版本的官方包,直接对比 wp-includes 目录的文件列表。
6. 测试服务器有没有按手机身份改页面
cd /www/wwwroot/你的站点; md5sum < readme.html
for UA in "Mozilla/5.0 (Windows NT 10.0) Chrome/126" "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) Mobile/15E148"; do
curl -sk --compressed --resolve 你的域名:443:127.0.0.1 -A "$UA" https://你的域名/readme.html | md5sum
done
三个 md5 一样,说明服务器至少没在静态文件上做手脚;手机那行不一样,问题就在服务器层。
清理顺序别搞反
很多人一发现后门就急着删文件,结果删完没两天又中招。顺序很重要。
动手之前,先把整站文件和数据库完整备份一份留作证据,别在原件上动手。这次就是因为先清理、后排查,我拿到的第一份文件几乎没有证据价值。
接着处理 functions.php 末尾那段注入代码。顺序反过来会白忙:不先删这段,adminisz 账号在后台既看不见也删不掉。删掉之后回到后台,就能看到并删除这些账号了。
然后删除根目录和 wp-includes 里多出来的文件,删掉 File Manager Advanced 插件,再用官方包覆盖 WordPress 核心、主题和插件。
紧接着改掉所有凭据:所有管理员密码、数据库密码、宝塔面板密码、SSH 密码,再重新生成 wp-config.php 里的密钥。忘了密码进不去后台的话,可以直接在数据库里重置管理员密码。
如果像这次一样,同服务器其他站点也有异常,那就别在原系统上清了,直接重装。重装后可以在宝塔面板上重新装一遍 WordPress,再导入核实过的数据库和 uploads 目录。嫌麻烦也可以把站点完整搬到新服务器,但前提是搬过去的文件已经确认干净。
这次我学到的几件事
清理前先备份,这条我会一直跟客户强调。被收拾过的现场,等于把证据也一起扫走了。
WordPress 后台的用户列表不可信。 一个 pre_user_query 钩子就能让管理员凭空消失,查账号永远以数据库为准。
别在生产站上装文件管理类插件。 File Manager Advanced 本身没问题,但它太好用了,对攻击者也一样。真要在线改文件,就用宝塔自带的文件管理,至少多一层面板登录。
还有一个小插曲:Wordfence 扫描时报警,说 RiPro 主题的 template-assets.php 里有一个在它域名黑名单上的地址 cdn.bootcdn.net。这是主题内置的 CDN 选项之一,客户实际用的是”本地加载”,所以这次不是它的问题。但如果你的主题能选 BootCDN 加载 jQuery,建议改成本地加载。
自己维护服务器、自己扛安全,对很多做外贸或资源站的站长来说成本确实不低。如果你不想再折腾这些,托管型 WordPress 主机会帮你兜住系统层的安全更新和恶意软件扫描,代价是贵一些、自由度低一些,按自己情况选就好。