我被黑了
唉,之前我一直觉得:
个人小破站嘛,又不是大公司生产环境,应该没人盯我吧。
结果现实狠狠给了我一巴掌。
这次不是演练,不是靶场,也不是 CTF。
是真的被黑了。CPU 飙高,机器里被塞了挖矿程序、后门服务、隐藏动态库,甚至还有把机器当代理节点卖带宽的东西。
第一次遇到这种事,老实说还是挺吓人的。
事情的起点
我的 Home Lab 大概是这样:
- 家里一台 PVE。
- 上面跑了一堆 VM。
- 里面还有一个 K8s 集群。
- 公网入口放在云服务器上。
- 云服务器通过 FRP 把流量转回家里。
- 平时跑博客、导航页、镜像站、Alist、监控、RAG,还有一些 K8s 实验。
架构看起来还挺像模像样:
用户浏览器
-> 公网 VPS
-> FRP
-> 家里 proxy VM
-> K8s Ingress
-> 各种服务
当初搭起来的时候还挺开心,感觉自己终于拥有了一个小型“数据中心”。
然后我就犯了一个非常经典的错:
为了方便,我把 SSH 也通过 FRP 映射到了公网。
而且还是密码登录。
而且 root 也能登。
现在回头看,这已经不是“留了个门”,这是把门牌号、门铃和备用钥匙一起挂门口了。
最早发现不对劲
最开始发现问题,是因为 master 机器 CPU 不正常。
一开始我还以为是 K8s 抽风。
毕竟 master 上跑着控制面组件,什么 kube-apiserver、etcd、controller-manager、scheduler,看起来谁都有嫌疑。
我甚至还怀疑过是不是某个 Pod 起飞了,或者监控组件太能吃。
结果越查越不对劲。
机器里出现了一些看着就很不妙的东西:
/etc/ld.so.preload
/usr/local/lib/sshdd.so
/etc/systemd/system/log.service
/usr/bin/log
/var/log/log
/var/tmp/cli
/var/tmp/traff
/etc/log
看到 /etc/ld.so.preload 的时候,我心里基本凉了一半。
这玩意不是普通脚本误跑。
它可以让系统在启动程序时先加载某个动态库,常见玩法就是隐藏进程、隐藏文件、劫持命令输出。
也就是说,机器不只是“跑了个坏程序”,而是已经被人动到系统层了。
后面继续查,还看到:
- 有伪装成 systemd 的可疑用户。
- sudoers 里出现过免密配置。
- 登录日志被清过。
- 一些系统命令和包状态被动过。
这时候就不用嘴硬了。
不是故障,是入侵。
入侵路线
最后把日志、FRP 配置和时间线串起来,路线大概是这样:
公网扫描
-> VPS 上的 frps
-> 家里 proxy VM 上的 frpc
-> master SSH 映射
-> root 密码爆破成功
-> 写后门、挖矿、清日志
关键点在 SSH 日志。
在出事时间附近,master 上能看到大量 root 登录失败。
来源看起来是家里的 proxy VM。
但这不代表 proxy VM 是攻击者本体。
因为 FRP 转发过来之后,master 看到的来源就是内网 proxy。
真正的公网来源,要去 VPS 的 frps 日志里找。
而 frps 日志里,也确实能看到有人频繁连接那个 master SSH 映射。
所以这次不是玄学,也不是 K8s 神秘漏洞。
真正的入口非常朴素:
公网暴露 SSH + root 密码登录 + 密码被猜中
很土。
但很有效。
一开始我还怀疑 K8s
因为被打的是 master,所以第一反应真的很容易往 K8s 上想。
是不是 apiserver 暴露了?
是不是某个服务有漏洞?
是不是 Ingress 被扫了?
是不是哪个镜像不干净?
但证据不支持。
真正能连成线的是:
- FRP 里确实存在 master SSH 映射。
- master 当时允许 root 密码登录。
- 日志里有大量 root 爆破。
- 某个时间点出现了一次密码登录成功。
- 后门文件落地时间和这个时间点能对上。
所以这次的结论很简单:
K8s 背锅了,但它不是入口。
锅在我自己把 SSH 放到公网,还让密码登录。
那些后门都在干嘛
我把可疑文件先挪走保存,没有运行样本,只做静态分析。
里面大概有几类东西。
1. 挖矿程序
这个应该就是 CPU 高的主要原因。
样本里能看到类似这些关键词:
XMRig
miner
pool
stratum
基本就是门罗币挖矿那套。
表现也很符合:CPU 长时间很高,机器风扇和负载都不太对劲。
2. 隐藏组件
/etc/ld.so.preload 配合可疑 .so 动态库,常见用途就是隐藏恶意进程和文件。
这也是最让我不舒服的地方。
因为它会影响你“看到的系统状态”。
也就是说,机器可能已经不完全可信了。
你执行 ls、ps、top,看到的东西不一定是真的。
这感觉就像在自己家里找东西,但灯是别人控制的。
3. 持久化服务
还有一个伪装得很随意的 systemd 服务:
log.service
ExecStart=/usr/bin/log -sshd
Restart=always
名字叫 log,看起来像系统日志。
但实际是在拉恶意程序。
Restart=always 的意思也很直白:
你杀了它,它还会起来。
4. 清理痕迹
样本脚本里还能看到清日志的行为。
比如删 auth.log、wtmp、btmp、lastlog、.bash_history 之类的东西。
这也解释了为什么后面 last 查登录历史不完整。
攻击者不是进来随便看看。
它是很熟练地落地、隐藏、持久化、清痕迹。
5. 带宽变现代理
除了挖矿,还有一个东西不怎么吃 CPU,但也很恶心。
它会把你的机器当代理节点,拿去卖带宽。
样本里能看到类似这些字符串:
TraffMonetizer
Inbound
Outgoing
EarnLast30Days
所以这台机器不只是被拿去挖矿。
还可能变成别人访问互联网的出口。
这件事比 CPU 高更麻烦,因为出口 IP 是你的。
处理方案
当时处理顺序大概是这样:
- 先停 proxy 上的 frpc。
- 禁止 frpc 自动重启。
- 关掉 master SSH 的公网映射。
- 在 PVE 上临时限制 proxy 的转发。
- 把 master 上的可疑文件挪到证据目录。
- 删除后门用户和 sudoers 免密。
- 恢复被动过的系统命令和包状态。
- SSH 禁止密码登录。
- 整理样本、哈希、时间线。
最重要的是前面三步:
先断入口,再清后门。
如果入口还开着,清理就是跟对方拔河。
你这边删一个,它那边再种一个。
真的会把人整麻。
最后恢复业务
确认入口关掉、后门清掉之后,我才慢慢恢复业务。
恢复的时候也没有一口气全开。
先恢复博客、导航页、镜像站这些 HTTP 业务。
管理口就先别急着往公网放了。
这次最应该记住的就是:
业务入口和管理入口一定要分开。
公网可以有博客。
公网可以有普通 Web 服务。
但 SSH、ArgoCD、Harbor、Prometheus 这种管理面,最好不要裸奔在公网。
真要远程管理,老老实实用 VPN、Tailscale、WireGuard,或者至少做 IP 白名单。
这次最大的教训
个人服务也会被扫
我以前总觉得:
我一个个人博客,谁闲着没事搞我?
后来发现,攻击者根本不需要认识我。
它也不关心我是谁。
它就是扫公网。
扫到 SSH,开始爆破。
撞上一个密码,自动投递脚本。
一套流水线走完,机器就开始替别人赚钱。
这不是“有人盯上我”。
这是互联网的背景噪音。
不要把 SSH 映射到公网
尤其不要这样:
公网端口 -> FRP -> 内网 SSH
这个链路太舒服了。
舒服到攻击者也很喜欢。
以后我的原则是:
- 公网只放必要的 HTTP/HTTPS。
- SSH 不走公网 FRP。
- 远程管理走 VPN。
- 管理入口加白名单。
- 密码登录关掉。
- root 登录关掉或限制为密钥。
密码登录真的该关
SSH 最少也要这样:
PasswordAuthentication no
PermitRootLogin prohibit-password
更严格一点就是:
PermitRootLogin no
密码登录只要放公网,就迟早被撞。
不是今天,就是以后。
被 rootkit 碰过的机器不要太信
这次出现了 ld.so.preload、可疑动态库、systemd 后门、清日志行为。
所以即使清理完,也不应该长期完全信任这台机器。
最稳的方案还是:
备份业务数据
重装系统
重建节点
重新加入集群
轮换所有密码和 token
清理适合止血。
重建才是安心。
小结
这次真的算是给我上了一课。
之前搭内网穿透的时候,我还觉得自己挺聪明:
家里服务终于能从公网访问了,爽!
结果这次发现,方便是真的方便,危险也是真的危险。
Home Lab 可以是玩具,但公网不是游乐场。
只要你把端口放出去,它面对的就是全世界的扫描器、爆破器和自动化脚本。
这次还好,没什么重要业务,主要损失是时间、心态和一点电费。
但它把一个事情讲得非常明白:
不要因为是个人项目,就把安全当成以后再说。
以后继续折腾。
但该关的门,还是得关。
不然下一次 CPU 又起飞,我可能就没这么淡定了。