wp2shell来袭 请迅速检查WordPress版本号

昨天晚上收到博客邮箱通知我的网站管理员密码被改了,注意是通知不是验证,直接绕过验证码改了我的密码,重新登录发现后台多了4个陌生的账号,一番排查下来确认是被一个叫 wp2shell 的自动化攻击工具打进来的。整个过程从发现到封堵,花了一天时间。这篇文章重点说说 wp2shell 这个工具——它的攻击方式、留下的指纹,以及我是怎么识别和清理的。

图片[1]-wp2shell来袭 请迅速检查WordPress版本号-长川三记

发现:后台多了四个管理员账号

最初是例行检查时发现的:站点后台的管理员列表里,除了我自己,还躺着四个从未见过的账号。用户名是一串 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 打过,可以照着这几个特征查:

  1. 用户名w2s_wp2_ 开头,后面跟一长串十六进制字符
  2. 邮箱@wp2shell.local@wp2shell.invalid 结尾
  3. 角色:一定是 administrator
  4. 注册 IPregister_ip 元数据是云厂商机房 IP(GCP/Azure/AWS 的美西段)
  5. session_tokens:空的——账号创建后从未真正登录过后台
  6. 内容:零发帖、零改动,纯粹是留门

可以用一条 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 —— 数据库密码文件,直接 200
  • wp-content/debug.log —— 调试日志,直接 200
  • wp-admin/install.php —— WordPress 安装脚本,直接 200
  • readme.html / version.php —— 泄露版本信息的文件

用 nginx 在站点配置里加了一条屏蔽规则,把这些路径全部返回 404。这里有个小坑:一开始想直接在站点配置文件里加规则,但 server 块是 server{ 分两行写的,正则没匹配上。后来改成把规则单独写进一个独立的配置文件,再在主配置里 include 进来——规则独立存放,后续面板更新配置也不会被覆盖。

还有个有意思的发现:屏蔽规则在源站生效后,从 CDN 访问还是能拿到 200——因为 CDN 缓存了旧响应。readme.htmldebug.log 这几个文件被 CDN 缓存了几十分钟,带个随机参数访问才能看到真实的 404。这提醒我,CDN 能缓存到这些文件,本身就说明它们之前是公开可读的,源站封完还得记得清 CDN 缓存才算闭环。

4. 改密码

最后把 SSH 密码、后台密码、数据库密码全部换掉,并重置了 WordPress 的盐值。攻击者可能已经拿到过密码哈希,光删账号不动密码,等于给别人留了一扇随时能推开的门。

几点教训

后门账号是入侵的信号,不是入侵本身。 看到异常管理员账号,第一反应应该是顺着查漏洞入口,而不是删了账号就当没事。wp2shell 账号删了,漏洞不补,别人还能换个方式再进来。

文件扫描干净不代表站点干净。 wp2shell 的入侵痕迹全在数据库里(用户表、元数据),文件系统可以零后门。排查入侵一定要查数据库层,只扫文件会漏。

及时升级不是一句空话。 漏洞在 6.9.5 / 7.0.2 修复,我的站点停在 6.9.4 被利用,中间只差一个小版本。WordPress 这类受众极广的开源软件,漏洞披露到被批量扫描利用往往只有几天,升级窗口很短。

暴露面检查要当成常规操作。 wp-config.phpinstall.phpdebug.log 这些文件对公网应该是不可见的,但很多站点(包括我这次)都没注意。装完站扫一遍,能少很多麻烦。

这次入侵没有造成实际的数据损失和内容篡改,算是不幸中的万幸——攻击者只是留了门,还没来得及进门做坏事。但整个过程跑下来,最大的感受是:WordPress 站点不是装好就完事了,升级、加固、盯异常,哪一样都省不得。

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容