Files
.pouch/skills/host-sec-check/SKILL.md
T
2026-09-04 11:54:07 +08:00

6.1 KiB
Raw Blame History

name, description
name description
host-sec-check 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)。
  4. 怀疑进程隐藏时,不要只信宿主机 ps。 从不加载宿主机 ld.so.preload 的容器读 /proc 和文件。
  5. 宿主机 chattr 可能被隐藏库挡住;改 immutable 文件用 Ubuntu/Alpine 自带 chattr 操作 bind-mount 的 /host/...。

收集脚本(可选,先跑再解读):

bash <skill-dir>/scripts/collect.sh USER@HOST

<skill-dir> 是本 skill 目录。脚本只采集,不修改系统。

流程

按顺序做。每步记下「正常 / 可疑 / 未查到」。完整项见 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。至少查:

  • 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。

  • 停并删除未授权容器;镜像也删
  • 矿机二进制:删掉后用 空文件 + 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 仍在