背景
2026 年 8 月 11 日,我的 WordPress 站点被发现多了 6 篇不是我发布的文章——内容全是盗版软件、影视资源的推广链接。这不是一次复杂的 0day 攻击,而是利用 WordPress 一个默认开启但常被忽视的接口:XML-RPC。本文记录了完整的攻击过程、取证方法和处置措施,希望能给同样使用 WordPress 的站长提供参考。
事件发现
当天下午,我登录后台时注意到文章列表中出现了 6 篇异常文章,作者显示为管理员账号。内容均为盗版 Crack / RePack / WEBRip 推广,夹杂随机字符串(如 a67zj9vwtkqymy9txui3hf1b,这是自动化 SEO 验证的典型特征)。我自己的 5 篇真实文章未被改动。
攻击时间线
| 时间 | 事件 |
|---|---|
| 站点部署日 | 部署 WordPress,安全配置为默认状态(XML-RPC 开启、密码可预测) |
| 部署后数日 | 攻击者持续探测,xmlrpc.php 累计被请求 1480 次 |
| 事发日 06:43 | 第一批垃圾文章注入(2 篇) |
| 事发日 09:43 | 第二批(2 篇) |
| 事发日 12:44 | 第三批(2 篇)——每批间隔约 3 小时,符合自动化脚本特征 |
| 事发日 14:49 | 我发现异常,开始排查处置 |
攻击过程分析
经过日志审计,还原出以下攻击链:
① 端口探测 / 指纹识别
└─ 识别目标为 WordPress(通过响应头、/wp-login.php 等特征)
② 选定薄弱入口:XML-RPC 接口(/xmlrpc.php)
├─ WordPress 默认启用该接口
├─ 支持 system.multicall:单次 HTTP 请求可批量尝试数百组凭证
└─ 完全绕过 wp-login.php 的登录失败限制
③ 凭证破解
└─ 原密码为「站点名+年份+感叹号」模式,属于字典攻击高优先级条目
④ 利用管理员权限注入内容
└─ 通过 XML-RPC 的 wp.newPost 方法批量创建文章
(不走浏览器后台,因此后台操作日志无痕迹)
⑤ 目标:SEO 劫持 / 内容农场推广
攻击者为什么选择 XML-RPC?因为它有两个”免费午餐”:无失败次数限制 + 绕过常规访问日志。这正是 WordPress 垃圾文章注入的经典攻击路径——system.multicall 允许在单次 HTTP 请求中批量尝试数百组凭证,而 WordPress 内置的登录防爆破机制仅保护 /wp-login.php 页面,对 XML-RPC 接口完全不生效。
取证过程
我从五个层面进行了审计:
文章层
6 篇垃圾文章(盗版资源推广),真实文章 5 篇未被动。
账号层
用户表仅 1 个管理员账号,无新增用户、无提权痕迹,排除”新建后门账号”模式。
文件层
wp-config.php修改时间为部署日,未被篡改- 主题目录所有文件修改时间均在部署窗口内,无新近后门
wp-content/uploads/下 0 个 .php 文件,无 webshell
日志层(关键证据)
xmlrpc.php请求计数:1480 条(攻击通道直接证据)- REST API POST 记录:0 条——佐证文章非通过 REST 创建
- 后台
post.phpPOST 记录:0 条——佐证文章非通过浏览器后台创建
以上两者为零 + XML-RPC 高计数,形成完整证据闭环。
计划任务层
wp_options.cron 共 16 个任务,全部为 WP 核心 / 已知插件的正常任务,无恶意定时任务。
处置措施
| # | 措施 | 方式 |
|---|---|---|
| 1 | 下架垃圾文章 | 6 篇移入回收站 → 确认后永久删除 |
| 2 | 封堵 XML-RPC 通道(双重) | ① 主题层:add_filter('xmlrpc_enabled','__return_false') + 移除 X-Pingback 头② Nginx 层: location = /xmlrpc.php { return 403; } |
| 3 | 更换管理员密码 | 强随机 16 位密码 |
| 4 | 清除全部登录会话 | 攻击者既有会话立即失效 |
| 5 | 安装登录限速插件 | Limit Login Attempts Reloaded(失败 4 次锁定 20 分钟) |
| 6 | 清理缓存 | 确保封堵即时生效 |
根因分析
| 根因 | 说明 |
|---|---|
| XML-RPC 默认开启且无防护 | WordPress 默认启用该接口,无失败次数限制,部署时未关闭 |
| 密码模式可预测 | 「站点名+年份+感叹号」模式,字典攻击高优先级命中 |
| 缺乏登录监控 | 无登录失败告警/日志插件,攻击过程不可见 |
核心结论:本次事件属于”可预防的配置型漏洞被自动化攻击命中”,非 0day 或源码级漏洞。攻击者不需要高超技术——1480 次请求 + 可预测密码 = 破解成功。这说明 WordPress 默认配置的安全性不足,站长必须在部署后主动加固。
后续加固建议
| 优先级 | 措施 | 说明 |
|---|---|---|
| P0 | 初始密码立即改为强随机密码 | 禁用「站点名+年份」等可预测模式 |
| P0 | 关闭或限制 XML-RPC | 如果不用博客客户端/Trackback,直接 Nginx 层 403 |
| P1 | 安装登录限速插件 | Limit Login Attempts Reloaded 或类似插件 |
| P1 | 配置自动备份 | 每日备份 + 本地保留多份,防内容丢失 |
| P2 | 关闭/停用不需要的插件 | 减少攻击面 |
| P3 | 迁移管理员登录路径 | 自定义登录地址,降低被探测概率 |
经验教训
- 部署 WordPress 的安全基线:初始密码必须强随机;XML-RPC 默认关闭或加 Nginx 层拒绝;安装登录限速插件。这三件事应该在部署当天就完成,而不是等到被攻击后才补。
- 密码纪律:任何系统密码禁用可预测模式;不同系统使用不同密码。1480 次请求就破解成功,说明密码强度是第一道也是最关键的一道防线。
- 部署纪律:所有脚本内嵌代码(PHP/Shell)修改生产文件前,必须先做语法验证再上线——本次处置过程中,因脚本变量转义错误曾造成全站短暂 500,属于”处置时自伤”,值得警惕。
- 监控意识:即使是小站点也需关注异常内容。攻击自动化程度极高,从探测到注入完全无人值守,发现越早损失越小。
写在最后
这次事件没有造成数据泄露或不可逆损失,6 篇垃圾文章删除后站点恢复正常。但它提醒了一个事实:WordPress 的默认配置是为兼容性而非安全性优化的。作为站长,我们需要在部署的第一天就主动加固,而不是依赖”我的站点太小没人会攻击”的侥幸心理。
如果你也使用 WordPress,建议现在就去检查:xmlrpc.php 是否可访问、管理员密码是否足够强、是否安装了登录限速插件。三分钟的自查,可能省去三个小时的应急处置。