昨天晚上收到博客邮箱通知我的网站管理员密码被改了,注意是通知不是验证,直接绕过验证码改了我的密码,重新登录发现后台多了4个陌生的账号,一番排查下来确认是被一个叫 wp2shell 的自动化攻击工具打进来的。整个过程从发现到封堵,花了一天时间。这篇文章重点说说 wp2shell 这个工具——它的攻击方式、留下的指纹,以及我是怎么识别和清理的。
![图片[1]-wp2shell来袭 请迅速检查WordPress版本号-长川三记](https://www.ccc.cx/wp-content/uploads/2026/08/20260804224831847-cover-padlock.jpg)
发现:后台多了四个管理员账号
最初是例行检查时发现的:站点后台的管理员列表里,除了我自己,还躺着四个从未见过的账号。用户名是一串 w2s_ 开头的随机十六进制字符,比如 w2s_8f3a9c2e1d4b5a67 这种。这四个账号全部是 administrator 权限,注册时间都在深夜,邮箱是 @wp2shell.local 这种一看就不是正常人的格式。
w2s_ 前缀、@wp2shell.local 邮箱、深夜注册、清一色管理员——这四样凑在一起,基本可以确定是 wp2shell 干的。
wp2shell 是什么
wp2shell 是一个 WordPress 自动化入侵工具,公开的名字就写在它创建的后门账号里——w2s_ 前缀和 @wp2shell.local 邮箱,都是它的签名。它不是一个漏洞本身,而是一套自动化利用流程:先通过某个 RCE 漏洞或配置错误拿到目标服务器的 PHP 执行权限,然后直接在服务端创建管理员账号。
关键点在这里:这些账号是直接用 PHP 在服务端创建的,绕过了正常的注册流程。所以它们身上会留下普通注册用户不会有的痕迹——比如 register_ip 字段记录的是云厂商机房 IP(Google Cloud / Azure 的美西段),而不是真实的访问 IP。这种元数据只有拿到 PHP 执行上下文的代码才能写进去,看到它就等于确认攻击者已经拿下了服务器的代码执行能力。
攻击者创建这些账号后并不会登录后台做任何事,也不写文章、不改配置,就是把门留着——账号本身是后门,方便之后随时从 wp-login 进来。这也是 wp2shell 这类工具的典型行为模式:不追求立即破坏,先留后门,慢慢用。
它这次是怎么进来的
顺着 wp2shell 账号追查漏洞入口,确认了攻击链。WordPress 6.9.4 及之前的版本存在一个 REST API 批量请求接口(/wp-json/batch/v1)的路由混淆缺陷。这个接口在处理嵌套的批量请求时,内层 POST 请求携带的查询参数没有被正确过滤,直接拼进了 SQL 查询,形成了可被利用的注入点。攻击者可以未登录就读取数据库里的任意内容——包括管理员密码的哈希。拿到哈希之后,破解、再通过插件上传功能植入后门,一整条链就通了。
这个漏洞的影响范围是 WordPress 6.8.0 到 7.0.1,官方在 6.8.6、6.9.5、7.0.2 三个版本中修复。我的站点当时停留在 6.9.4,正好在受影响区间内。
服务器日志里的攻击时间线
结论不是猜出来的,是查日志查出来的。站点被入侵后,我在 nginx 访问日志里翻到了完整的攻击记录:
- 6月3日:有人开始试探
/wp-json/batch/v1/users、/wp-json/batch/v1/members这类路径——早期枚举,当时返回 404。 - 7月21日、7月22日:一个 UA 标识为
l9scan(leakix.net 的漏洞扫描器)的爬虫,两次向/?rest_route=/batch/v1发起批量 POST 请求,每次都是 4 连发,服务器返回 207(Multi-Status,批量请求部分成功)——这是自动化扫描器验证漏洞可利用的典型特征。 - 7月23日 15:08:一批伪装成 Chrome/Mac 浏览器的请求,向
/wp-json/batch/v1和/?rest_route=/batch/v1连续 POST,返回 207,其中一次响应体高达 35KB——这是真正的漏洞利用,攻击者从数据库里读走了数据。35KB 的响应说明不是空手而归。
207 状态码是批量接口”部分成功”的标记,出现在日志里基本等于漏洞被实锤利用。时间线也对得上:后门账号的注册时间是 7月24日到8月初,正好在 7月23日的利用之后。
另外日志里还能看到更早的攻击尝试:5月17日有人对 xmlrpc.php 连发 POST(当时还没关闭 xmlrpc),5月18日对 wp-login.php 做了每 5 秒一次的登录尝试,5月16日还有一批 /.env 文件探测。这些都没有得手,但它们说明站点从上线开始就一直被自动化工具扫描——这也是这类小站点的常态,攻击者不是针对你,而是全网扫,扫到谁算谁。
还有个细节值得说:源站日志里所有攻击请求的来源 IP 都显示为 CDN 回源地址,真实攻击者 IP 被 CDN 隐藏了。所以后门账号里的 register_ip 是云厂商机房 IP 这件事,反而进一步印证了账号是攻击者通过 PHP 代码写入的——只有拿到服务器端执行权限,才能看到 CDN 透传过来的那种地址。
识别:wp2shell 的指纹特征
如果你也怀疑自己的站点被 wp2shell 打过,可以照着这几个特征查:
- 用户名:
w2s_或wp2_开头,后面跟一长串十六进制字符 - 邮箱:
@wp2shell.local或@wp2shell.invalid结尾 - 角色:一定是 administrator
- 注册 IP:
register_ip元数据是云厂商机房 IP(GCP/Azure/AWS 的美西段) - session_tokens:空的——账号创建后从未真正登录过后台
- 内容:零发帖、零改动,纯粹是留门
可以用一条 SQL 把可疑账号捞出来:
SELECT ID, user_login, user_email, user_registered
FROM wp_users
WHERE user_login REGEXP '^(w2s|wp2)_[0-9a-f]{6,}'
OR user_email LIKE '%@wp2shell.%';
我这边实际查出来 4 个,全部命中。文件层面反而很干净——wp2shell 的破坏都在数据库里,文件系统可以没有任何后门文件,所以只扫文件是不行的,必须查用户表。
修复过程
1. 清掉后门账号
第一时间删除了那四个 w2s_ 开头的管理员账号。这里有个坑:这类账号是用 PHP 直接写入数据库的,只改密码没有用——攻击者只要还留着漏洞渠道,随时能再创建一批。所以账号必须删干净,同时封堵漏洞入口。
2. 升级 WordPress 核心
站点从 6.9.4 升级到 7.0.2。
3. 封堵暴露面
漏洞修完之后,顺手做了一遍暴露面检查,发现站点上有好几个本不该公网可访问的路径:
wp-config.php—— 数据库密码文件,直接 200wp-content/debug.log—— 调试日志,直接 200wp-admin/install.php—— WordPress 安装脚本,直接 200readme.html/version.php—— 泄露版本信息的文件
用 nginx 在站点配置里加了一条屏蔽规则,把这些路径全部返回 404。这里有个小坑:一开始想直接在站点配置文件里加规则,但 server 块是 server 和 { 分两行写的,正则没匹配上。后来改成把规则单独写进一个独立的配置文件,再在主配置里 include 进来——规则独立存放,后续面板更新配置也不会被覆盖。
还有个有意思的发现:屏蔽规则在源站生效后,从 CDN 访问还是能拿到 200——因为 CDN 缓存了旧响应。readme.html、debug.log 这几个文件被 CDN 缓存了几十分钟,带个随机参数访问才能看到真实的 404。这提醒我,CDN 能缓存到这些文件,本身就说明它们之前是公开可读的,源站封完还得记得清 CDN 缓存才算闭环。
4. 改密码
最后把 SSH 密码、后台密码、数据库密码全部换掉,并重置了 WordPress 的盐值。攻击者可能已经拿到过密码哈希,光删账号不动密码,等于给别人留了一扇随时能推开的门。
几点教训
后门账号是入侵的信号,不是入侵本身。 看到异常管理员账号,第一反应应该是顺着查漏洞入口,而不是删了账号就当没事。wp2shell 账号删了,漏洞不补,别人还能换个方式再进来。
文件扫描干净不代表站点干净。 wp2shell 的入侵痕迹全在数据库里(用户表、元数据),文件系统可以零后门。排查入侵一定要查数据库层,只扫文件会漏。
及时升级不是一句空话。 漏洞在 6.9.5 / 7.0.2 修复,我的站点停在 6.9.4 被利用,中间只差一个小版本。WordPress 这类受众极广的开源软件,漏洞披露到被批量扫描利用往往只有几天,升级窗口很短。
暴露面检查要当成常规操作。 wp-config.php、install.php、debug.log 这些文件对公网应该是不可见的,但很多站点(包括我这次)都没注意。装完站扫一遍,能少很多麻烦。
这次入侵没有造成实际的数据损失和内容篡改,算是不幸中的万幸——攻击者只是留了门,还没来得及进门做坏事。但整个过程跑下来,最大的感受是:WordPress 站点不是装好就完事了,升级、加固、盯异常,哪一样都省不得。













暂无评论内容