最近本站出现了一次比较严重的异常跳转事件。未登录状态下访问首页时,页面会在启动动画之后跳转到一个伪装成 Cloudflare 验证的页面,并提示访问者打开终端、复制命令、执行所谓的验证操作。

我都懵了,我并没有主动接入过 Cloudflare。经过排查,最终确认这是一次 WordPress 后台被非法登录后,通过恶意插件向前台注入混淆 JS 脚本的事件

这篇文章记录一下我这次从发现异常、使用浏览器开发者工具定位异常请求、反查服务器文件、追查日志,到清理和加固的过程。


一开始发现的问题

最开始发现异常时,网站并不是说打不开。首页还能加载,原本的启动动画也会正常出现。但动画结束后,页面会突然跳转到一个看起来很像 Cloudflare 验证的界面。但是我并没有接入过cloudflare啊。

然后这个页面会诱导用户进行类似这样的操作:

伪造的验证页面

后来才知道这种叫做clickfix攻击,诱导用户主动执行命令。只要访客照做,就可能被植入恶意程序。

比较奇怪的是,我登录 WordPress 后台后,再访问网站,页面看起来又是正常的。也就是说,它对不同访问状态有不同表现:

未登录访客:看到伪装 Cloudflare 验证页
已登录管理员:看到正常网站

所以应该不是浏览器缓存,是服务器端根据访客状态输出了不同内容。


先排除 DNS 和 Cloudflare

因为页面伪装成 Cloudflare,所以第一反应是检查域名解析和响应头。

我先确认 kokorotsuki.com 是否仍然指向自己的 VPS:

dig +short kokorotsuki.com

结果显示域名仍然解析到我的 VPS IP,并没有解析到 Cloudflare。

接着查看 HTTP 响应头:

curl -I https://kokorotsuki.com

响应头显示的是 Nginx 和 WordPress,并没有 Cloudflare 相关 header。

因此可以先排除:

DNS 被改
域名商解析异常
真正的 Cloudflare 验证页面

也就是说,这个所谓 Cloudflare 页面就不是 Cloudflare 发出来的,而是有人在我的网站里伪装了一个假的 Cloudflare 页面。


在浏览器开发者模式中发现异常脚本请求

为了确认这个伪 Cloudflare 页面到底是从哪里加载出来的,我打开了浏览器开发者工具,进入 Network 面板,然后重新访问了首页。

在网络请求里,我发现页面加载过程中出现了一个非常可疑的外部脚本请求:

https://id-verif-code.info/api.php?s=8402fb1338daab6a166e91aa8c92a20798acfa98fb75c5a2&_v=29769525

这个请求的特征很明显:

请求类型是 JavaScript
来源不是本站域名
地址包含 id-verif-code.info
路径是 api.php
参数带有一串可疑 hash
响应内容会被前台页面直接执行

这一步基本可以确认,伪 Cloudflare 页面不是浏览器自己生成的,也不是正常的 Cloudflare 验证,而是本站页面中被插入了外部恶意脚本。

同时我还在前台源码中看到了经过混淆处理的 JavaScript。里面出现了这些特征:

atob(...)
Uint8Array
TextDecoder
new Function(...)
id-verif-code.info/api.php?s=...

这些特征说明,页面中存在一个混淆 JS loader。它会先解码隐藏的代码,再通过 new Function() 动态执行,最后加载远程恶意脚本。

之后为了进一步确认这不是单纯的浏览器扩展、本地缓存或代理造成的现象,我又在服务器上使用 curl 模拟普通访客访问首页,并把返回的 HTML 保存下来检查。

cd /var/www/html/kokorotsuki.com/public_html
curl -s \
-A 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36' \
https://kokorotsuki.com/ \
-o /tmp/koko-public.html

然后搜索页面中的可疑脚本特征:

grep -niE 'atob\(|new Function|TextDecoder|id-verif|api\.php\?s=|createElement\(.*script|appendChild\(.*script|eval\(' /tmp/koko-public.html

结果在服务器返回的 HTML 中同样发现了这些恶意 JS 特征。

因此这一步可以确认这个异常脚本不是浏览器插件注入的,而是访问本站时,服务器返回的页面内容中就已经包含了恶意 JavaScript脚本。


从前台恶意代码反查服务器文件

既然 HTML 里已经有恶意代码,就可以用其中一段特征字符串在服务器里搜索。

我从混淆脚本中取了一段字符串,然后在 WordPress 目录里 grep:

cd /var/www/html/kokorotsuki.com/public_html
needle='VBoJEh8IFRMSVFUHFRpU'
sudo grep -RIn --binary-files=without-match "$needle" . 2>/dev/null

同时也查了一遍数据库,确认它是不是藏在文章内容、option 或其他数据表里:

wp db search "$needle" --all-tables --allow-root

最后 grep 结果直接指向了一个插件文件:

wp-content/plugins/a11y-image-attributes-fix/a11y-image-attributes-fix.php:29

这个插件名字看起来像是“图片无障碍属性修复”之类的插件,但实际上它就是前台恶意 JS 注入的直接来源。

也就是说,主题 JS 文件和 WordPress core 一个没有被篡改,是攻击者上传了一个伪装成普通插件的恶意插件。


隔离恶意插件

确认源头后直接在 SSH 里把它物理移走,并保留证据。

cd /var/www/html/kokorotsuki.com/public_html
mkdir -p /root/kokoro-incident-20260808
cp -a wp-content/plugins/a11y-image-attributes-fix \
/root/kokoro-incident-20260808/a11y-image-attributes-fix.evidence
wp --skip-plugins --skip-themes plugin deactivate a11y-image-attributes-fix --allow-root || true
mv wp-content/plugins/a11y-image-attributes-fix \
/root/kokoro-incident-20260808/a11y-image-attributes-fix.removed

移走后我重新抓取首页源码然后再搜索恶意特征

curl -s \
-H 'Cache-Control: no-cache' \
-A 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36' \
https://kokorotsuki.com/?clean-test=$(date +%s) \
-o /tmp/koko-after-clean.html
grep -niE 'atob\(|new Function|TextDecoder|id-verif|api\.php\?s=|id-verif-code' \
/tmp/koko-after-clean.html

这次没有再出现恶意特征了,说明前台注入已经停止了。


继续查有没有其他落地点

虽然前台 JS 的直接来源找到了,但我不好说只有这一个恶意插件。因为攻击者既然能上传插件,说不定就还上传了其他东西。

然后我就开始按时间查最近新增和修改的 PHP 文件:

find wp-content -type f \( -name '*.php' -o -name '*.js' \) \
-newermt '2026-08-06 00:00:00' \
-printf '%TY-%Tm-%Td %TH:%TM:%TS %p\n' | sort

结果又发现了几个同一天出现的可疑项目:

wp-content/plugins/wp-security-helper/
wp-content/themes/category-template-1786089947/
wp-content/updraft/top-1786089961.php

其中:

wp-security-helper
看起来像安全插件,但去网上一搜发现就是木马。
category-template-1786089947
看起来像一个普通主题目录,但里面有可疑 PHP 写文件逻辑。
top-1786089961.php
位于 updraft 目录中,是通过文件管理器创建的 PHP 文件。

于是我继续把这些项目也隔离:

cd /var/www/html/kokorotsuki.com/public_html
INC=/root/kokoro-incident-20260808
mkdir -p "$INC"
wp --skip-plugins --skip-themes plugin deactivate wp-security-helper a11y-image-attributes-fix --allow-root || true
for p in \
  wp-content/plugins/wp-security-helper \
  wp-content/themes/category-template-1786089947 \
  wp-content/updraft/top-1786089961.php
do
  if [ -e "$p" ]; then
    cp -a "$p" "$INC/$(basename "$p").evidence"
    mv "$p" "$INC/$(basename "$p").removed"
    echo "moved: $p"
  fi
done

到这里基本确认这不是单点注入了。


从 Nginx 日志还原攻击时间线

清理文件只是第一步,我还需要知道攻击者是怎么进来的。

于是我开始查看 Nginx access log,重点搜索:

wp-login.php
wp-admin
plugin-install.php
update.php?action=upload-plugin
wp-file-manager
admin-ajax.php
updraft

日志里出现了非常关键的记录。攻击者并不是从前台页面的漏洞啥的打穿网站的,而是居然成功登录了 WordPress 后台!!!!!

主要时间节点如下。时间以服务器日志为准。


2026-08-07 01:05 左右
IP 157.22.100.146 访问 wp-login.php,并 POST 登录成功。
随后进入 wp-admin、plugin-install.php、update.php?action=upload-plugin。
之后上传并启用了文件管理器类插件。
2026-08-07 01:06 左右
同一攻击链通过文件管理器在 wp-content/updraft/ 创建 top-1786089961.php,并访问该文件测试。
2026-08-07 01:05 至 01:06 左右
服务器中出现可疑主题 wp-content/themes/category-template-1786089947。
该主题中包含具有写文件行为的 PHP 文件,疑似备用落地点。
2026-08-07 14:02 至 14:03 左右
IP 213.232.122.28 成功登录 WordPress 后台,并上传或激活 wp-security-helper 插件。
2026-08-07 14:12 至 14:13 左右
IP 185.61.223.245 成功登录 WordPress 后台,并上传 a11y-image-attributes-fix 插件。
该插件负责向前台页面注入混淆 JS,并加载 id-verif-code.info 的远程脚本。

这几个 IP 在本次事件里的分工大概是:

157.22.100.146
第一波后台操作,上传文件管理器,并通过文件管理器写入 updraft PHP 后门。
213.232.122.28
第二波后台操作,上传或激活 wp-security-helper,疑似用于隐藏痕迹或维持权限。
185.61.223.245
第三波后台操作,上传 a11y-image-attributes-fix,最终造成前台 JS 注入和假 Cloudflare 页面。

虽然查了一下是机房IP。


检查是不是 WordPress 核心或者常用插件被改了

为了避免误判,我继续检查 WordPress 核心文件完整性。

wp core verify-checksums --allow-root

结果显示 WordPress 核心文件校验通过。

然后检查 Jetpack 和 WP Statistics:

wp plugin verify-checksums jetpack --allow-root
wp plugin verify-checksums wp-statistics --allow-root

这两个插件也校验通过。

所以这次事件真正的前台污染源应该还是是后来上传的恶意插件。


排查其他可能入口

这次我也检查了几个可能方向。

首先是 WordPress 忘记密码接口。日志8月4号的时候里面确实有一些访问 lostpassword 的请求:

/wp-login.php?action=lostpassword

但我没有看到 resetpass、rp_key 之类完成密码重置的明确证据。因此目前判断 forgotten password 不是主要入口。

然后是 SSH 登录。服务器日志里有一大堆 SSH 爆破尝试虽然都失败了,但成功登录记录对应的都是我自己的登录行为,所以外人并没有成功登录SSH。

再看 DNS 和 drive 子域,也没有发现它们直接参与这次攻击的证据。攻击链集中在主站 WordPress:

/wp-login.php
/wp-admin/
/wp-admin/update.php?action=upload-plugin
/wp-admin/admin.php?page=wp_file_manager
/wp-content/updraft/top-1786089961.php

所以这次事件最合理的结论是:

攻击者拿到了 WordPress 后台凭据或会话,然后通过正常后台入口上传恶意组件。

为什么攻击者会知道我的网站和后台?

这次还有一个很关键的背景,在7月30号我还在学校,学校网络安全系统曾出现疑似 AMOS / Atomic macOS Stealer 相关告警。学校的网管还发邮件我提示我电脑被攻击了。同时 8月4号Gmail 也出现过异常尝试登录的警告。

AMOS 这类 macOS 信息窃取器可能会窃取:

浏览器保存密码
浏览器 Cookie
登录会话
Gmail 账号信息
密码管理器或钥匙串中的数据
浏览器历史记录

我在浏览器里保存过 WordPress 登录信息,攻击者拿到的应该是类似这样的组合:

https://kokorotsuki.com/wp-login.php
用户名
密码
Cookie
访问历史

所以泄露数据本身就可能包含网站地址。

结合 Gmail 异常登录、AMOS 告警和 WordPress 后台成功登录日志,我认为这次更像是:

账号凭据先泄露
↓
攻击者拿到 WordPress 后台访问能力
↓
再对网站进行投毒

撤销长期凭据和旧会话

确认后台被登录后,开始撤销所有长期凭据。

cd /var/www/html/kokorotsuki.com/public_html
wp user application-password delete 1 --all --allow-root
wp user session destroy 1 --all --allow-root
wp config shuffle-salts --allow-root

这里重点是 Application Password。因为它和普通 WordPress 密码不同,有时候即使你改了后台密码,它仍然可能保持有效。因此必须单独删除。

同时也重置了 WordPress salts,用来强制旧 Cookie 失效。


锁 WordPress 文件权限

这次事件能落地成功,还有一个重要原因:当时 plugins、themes、updraft 等目录对 www-data 来说过于宽松。

在 WordPress 里,Web 服务用户通常是 www-data。如果它可以写 plugins 和 themes,那么一旦后台被拿到,攻击者就能很方便地上传插件或写入后门。

我把关键目录改成 root 拥有,只保留 uploads 可写:

cd /var/www/html/kokorotsuki.com/public_html
sudo chown root:www-data .
sudo chmod 755 .
sudo chown root:www-data wp-config.php
sudo chmod 640 wp-config.php
sudo chown -R root:www-data wp-admin wp-includes wp-content/plugins wp-content/themes
sudo find wp-admin wp-includes wp-content/plugins wp-content/themes -type d -exec chmod 755 {} \;
sudo find wp-admin wp-includes wp-content/plugins wp-content/themes -type f -exec chmod 644 {} \;
sudo chown root:www-data wp-content
sudo chmod 755 wp-content
sudo chown -R root:www-data wp-content/updraft wp-content/upgrade
sudo find wp-content/updraft wp-content/upgrade -type d -exec chmod 755 {} \;
sudo find wp-content/updraft wp-content/upgrade -type f -exec chmod 644 {} \;
sudo chown -R www-data:www-data wp-content/uploads
sudo find wp-content/uploads -type d -exec chmod 755 {} \;
sudo find wp-content/uploads -type f -exec chmod 644 {} \;

修正后检查结果应该是:

WordPress 根目录:不可被 www-data 写入
wp-admin:不可被 www-data 写入
wp-includes:不可被 www-data 写入
plugins:不可被 www-data 写入
themes:不可被 www-data 写入
updraft:不可被 www-data 写入
uploads:可被 www-data 写入
wp-config.php:root:www-data 640

这一步直接禁止用WordPress 后台上传插件了。以后需要更新插件时可以通过 SSH 临时更新,更新完了再锁回去。


禁止上传目录执行 PHP

只锁权限还不够,因为 WordPress 的 uploads 本来就必须可写。为了防止以后有 PHP 文件被写进 uploads、updraft、upgrade、cache 这类目录,就在 Nginx 中加入规则:

location ^~ /wp-content/updraft/ {
    deny all;
}
location ^~ /wp-content/upgrade/ {
    deny all;
}
location ~* ^/wp-content/(uploads|updraft|upgrade|cache)/.*\.(php|phtml|phar|php[0-9]?)$ {
    deny all;
}

然后测试:

sudo nginx -t
sudo systemctl reload nginx
curl -I https://kokorotsuki.com/wp-content/uploads/wp-personal-data-exports/index.php
curl -I https://kokorotsuki.com/wp-content/updraft/
curl -I https://kokorotsuki.com/wp-content/upgrade/

理想状态是:

uploads 中的 PHP:403
updraft:403
upgrade:403

这样即使以后某个文件被写进去,也不能通过浏览器直接执行。


最终确认前台已经恢复

最后再次用未登录 UA 抓取首页:

cd /var/www/html/kokorotsuki.com/public_html
curl -s \
-H 'Cache-Control: no-cache' \
-A 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36' \
"https://kokorotsuki.com/?final-check=$(date +%s)" \
-o /tmp/koko-final.html
grep -niE 'id-verif-code|api\.php\?s=|new Function|TextDecoder|atob\(' /tmp/koko-final.html

清理后没有再出现恶意注入特征。

然后前台假 Cloudflare 页面也消失了。


本次事件的结论

这次事件可以定性为:

WordPress 后台凭据或会话泄露后,攻击者登录后台,并通过恶意插件进行前台 JavaScript 注入。

完整攻击链大概是:

Mac / Gmail / 浏览器凭据可能先泄露
↓
攻击者成功登录 WordPress 后台
↓
上传文件管理器
↓
写入 updraft PHP 后门
↓
上传可疑主题作为备用落地点
↓
上传 wp-security-helper 伪装安全插件
↓
上传 a11y-image-attributes-fix 恶意插件
↓
前台注入混淆 JavaScript
↓
访客看到伪装 Cloudflare 验证页面

后续已经做和还要做的事情

目前已经完成:

移除 a11y-image-attributes-fix 恶意插件
隔离 wp-security-helper 可疑插件
隔离 wp-file-manager 文件管理器残留
隔离 category-template-1786089947 可疑主题
隔离 updraft 目录中的 PHP 后门
校验 WordPress core
校验 Jetpack / WP Statistics
更新插件
撤销 Application Password
踢出旧登录会话
重置 WordPress salts
修正 wp-config.php 权限
锁定 wp-admin / wp-includes / plugins / themes / updraft
禁止 uploads / updraft / upgrade / cache 执行 PHP
启用 WordPress 2FA

接下来还会继续处理:

处理 Mac 的 AMOS 风险
重置所有关键账号密码
SSH 改为 key-only 登录
继续监控 Nginx 和 WordPress 日志

教训与感想

现在才知道个人网站就算是访问量不大也会被被攻击。这自动化攻击只要后台账号密码泄露,博客也可能很快被拿来挂马。

这次最危险的地方是,这个伪装的页面质感也太像了吧,我一度以为是我装的什么插件自动配置了cloudflare。而且网站在登录状态下看起来一切正常,未登录访客才会看到伪装成 Cloudflare 的页面。碰巧最近正好回国,网络状态发生改变,如果没有开浏览器开发者工具看请求,还真以为只是缓存或网络问题呢。

而且这次严重程度也太大了吧,源头上我电脑感染了amos窃密木马导致保存的所有密码被泄露了,然后wordpress后台权限居然完全失控了,还被插入了一堆后门,最后还被挂马变成钓鱼网站我真的服了。

真正的血泪教训是本地设备的网站安全啊😭。居然Mac被木马套走浏览器密码之后,会有人拿我泄漏的密码撞库,明明只是个wordpress站点而已,有啥价值啊服了。这就是社会工程学吗太恐怖了我mac有点不敢用了操。


给访问者的提醒

如果访问本站时看到任何要求你打开终端、复制命令、执行所谓验证、安装不明软件的页面,请一定不要执行。

本站绝对不会要求访问者通过终端命令完成验证,也不会要求安装额外程序才能浏览页面。

2026/08/08

@Kokorotsuki_上