--- name: host-sec-check description: >- Linux/VPS 主机安全检查与入侵取证:先取证再处置。覆盖矿机、ld.so.preload 进程隐藏、带宽挂机容器、对外端口、SSH/Docker/k8s 入口、cron/systemd 持久化、hugepage/OOM。 Use when: 安全检查, 被黑, 入侵, 矿机, 排查端口, 对公网放开, rpcbind, 挂机赚钱, Portainer, 安全审计, host security, compromise, cryptominer, exposure, /host-sec-check. --- # host-sec-check 对一台 Linux 主机做安全检查。默认 **只读取证 + 出报告**。清理、关端口、重启、轮换密钥必须用户明确同意后再做。 需要:SSH 目标(`user@host` 或 ssh config 别名)、哪张网卡/IP 算公网。没有公网 IP 就只报「监听面」,并标明未做外部探测。 ## 不适用 - Web 应用代码审计、依赖 CVE 扫描(可在报告里列为后续) - 云厂商安全组控制台(能查就查,查不到就写「未验证」) - 未获准的破坏性操作(`rm -rf`、整盘 wipe、强制重启) ## 铁律 1. **先取证,后动手。** 重启、删文件、停服务会毁掉证据。 2. **不要把密钥打进对话。** token、密码、authorized_keys、kubeconfig 只写「存在/已轮换/路径」,不贴原文。 3. **sudo 失败不要停。** 用户在 `docker` 组时,用特权容器 `nsenter` 看宿主机(见 [references/access.md](references/access.md))。 4. **怀疑进程隐藏时,不要只信宿主机 `ps`。** 从**不加载宿主机 `ld.so.preload` 的容器**读 `/proc` 和文件。 5. 宿主机 `chattr` 可能被隐藏库挡住;改 immutable 文件用 **Ubuntu/Alpine 自带 chattr** 操作 bind-mount 的 `/host/...`。 收集脚本(可选,先跑再解读): ```bash bash /scripts/collect.sh USER@HOST ``` `` 是本 skill 目录。脚本只采集,不修改系统。 ## 流程 按顺序做。每步记下「正常 / 可疑 / 未查到」。完整项见 [references/checklist.md](references/checklist.md)。 ### 1. 快照 - 主机名、发行版、uptime、负载、`free -h`、`df -h`、公网/内网/Tailscale IP - `ss -lntup`(最好 root) - `docker ps -a`、compose 项目 - 若有 k3s/k8s:agent 是否在跑、能否 `kubectl get pods -A` ### 2. 入口 - sshd:`Port`、`PermitRootLogin`、`PasswordAuthentication`、`authorized_keys`(root 与所有 UID≥1000) - `last` / `lastb` / `journalctl -u ssh`:异常登录;**无交互登录却出现 docker run 也是入口信号** - sudoers、`docker` 组(= root)、NOPASSWD - 对公网的管理面:Portainer / Cockpit / 面板 / k8s apiserver / Docker 端口,尤其 `-p 0.0.0.0:…` 且挂了 `docker.sock` 或 `/:/host` - 单元文件或 compose 里的明文 token(k3s `--token`、agent secret) ### 3. 持久化 读 [references/persistence.md](references/persistence.md)。至少查: - crontab(root 与所有用户)、`/etc/cron.*` - `/etc/systemd/system/*.service`、timers - `/etc/ld.so.preload`(用**外部** cat/hexdump,宿主机 cat 可能被藏空) - `chattr +i` 的异常二进制(`lsattr`) - 隐藏 Docker 数据根(非 `/var/lib/docker` 的 dockerd `--data-root`) ### 4. 进程与隐藏库 - 从特权容器列 `/proc/*/cmdline`(绕过 preload) - 对照宿主机 `ps`:只在容器视角出现的进程 = 隐藏 - `/proc/*/maps` 是否映射陌生 `.so`(`libgcwrap`、`libprocesshider`、随机名) - 矿机常见名:`perfcc`、`xmrig`、`kdevtmpfsi`、`javavm64`;同体积多副本(例如都是 11MB) - hugepage:`grep Huge /proc/meminfo`。`nr_hugepages>0` 且进程列表对不上,多半是矿机预留 ### 5. 容器与编排 - `docker ps -a`:镜像名含 earnfm / packetstream / repocket / traffmonetizer / honeygain / proxyrack / bitping / antgain 等挂机池 - inspect:`Privileged`、Binds(`docker.sock`、`/:/host`)、Ports 是否 `0.0.0.0` - 第二套 dockerd / 异常 `--bridge` - k8s:节点上是否有与 Git 仓库无关的 workload;控制面不健康时从 kubelet `pods/*/etc-hosts` 读 Pod 名 ### 6. 对外暴露 - 本机 `0.0.0.0` / `[::]` 监听 - **从另一台机器探测公网 IP**(含 IPv6)。只看 `ss` 会漏安全组,只看安全组会漏「监听但没防火墙」 - 高危:`rpcbind :111`、明文 HTTP 应用端口、Docker/Portainer、k8s 6443、数据库 - 管理 SSH 若可走 Tailscale,公网 SSH 算多余攻击面 ### 7. 资源与日志 - 无 swap + 高 hugepage → 应用易 OOM - `journalctl` / `auth.log` 在处置时间点附近;日志空也要记 - 出站连接:`ss -tp` 看陌生 IP(不要把结果里的密钥打出来) ### 8. 补漏(本次 vvps2 没做或做得浅的) 见 checklist 后半:补丁、SUID、世界可写、意外用户、IPv6、定时器、内核模块、出站 C2、云安全组、备份是否可用。 ## 报告格式 先给结论(是否沦陷、最可能入口、对外还开着什么),再给证据表,最后给 **需用户点头的处置清单**。不要默默清理。 ``` 结论: 沦陷 / 可疑 / 未见异常 最可能入口: … 对外端口: … 持久化: … 隐藏/矿机: … 容器/编排: … 未查项: … 建议处置: (等确认) ``` ## 处置(仅在用户同意后) 原则见 [references/cleanup.md](references/cleanup.md)。 - 停并删除未授权容器;镜像也删 - 矿机二进制:删掉后用 **空文件 + `chattr +i` 占路径** - 清空并锁定 `/etc/ld.so.preload` - 关公网绑定:改成 `127.0.0.1` 或 Tailscale IP(若回源走 Tailscale 主机名,必须绑 TS IP,不能只绑 loopback) - 停无用服务(如 `rpcbind.socket` + `rpcbind.service`,必要时 mask) - 重启才能卸掉仍映射已删 `.so` 的老进程(sshd/dockerd)。先取证再重启 - 轮换:暴露过的 token、面板、k3s bootstrap。控制面 API 不通就不要假轮换,写阻塞原因 ## 验证 - 公网探测:已关端口失败;该留的业务域名仍 200 - `ss`:无 `0.0.0.0:已关端口` - `grep -l libgcwrap /proc/*/maps`(或同类库)重启后为 0 - 占位文件仍在且 immutable - 业务容器 `restart: always` 仍在