168 lines
8.2 KiB
Markdown
168 lines
8.2 KiB
Markdown
---
|
||
name: host-sec-check
|
||
description: >-
|
||
Linux/VPS 主机安全检查、入侵取证与用户确认后的分阶段加固:覆盖矿机、隐藏进程/ld.so.preload、对外端口、SSH/Docker/k8s、cron/systemd、hugepage/OOM、SSH/防火墙/Fail2ban。触发:安全检查、安全加固、新机初始化、被黑、入侵、矿机、排查端口、对公网放开、host security、hardening、compromise、/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/...`。
|
||
6. 不要把 root 密码、临时密码、私钥、webhook 或 token 作为命令行参数、环境变量或聊天内容传递;优先使用现有密钥、控制台或交互式 `passwd`。
|
||
7. 加固不是“改 SSH 端口”竞赛:端口更改只减少噪声,必须先确认云安全组、主机防火墙和第二条登录路径。
|
||
|
||
收集脚本(可选,先跑再解读):
|
||
|
||
```bash
|
||
bash <skill-dir>/scripts/collect.sh USER@HOST
|
||
```
|
||
|
||
`<skill-dir>` 是本 skill 目录。脚本只采集,不修改系统。
|
||
|
||
自动修复默认先生成计划:
|
||
|
||
```bash
|
||
bash <skill-dir>/scripts/remediate.sh USER@HOST --plan --fix ssh-perms --fix fail2ban --ignore-ip ADMIN_CIDR
|
||
```
|
||
|
||
只有用户明确批准具体修复项后,才可使用 `--apply` 和精确确认串。每次应用前必须备份,应用后必须验证;脚本输出的 `BACKUP_ID` 可用于精确回滚。防火墙、SSH 登录策略、Docker/k8s 绑定、恶意文件、重启和密钥/token 轮换只生成计划,不由此入口自动执行。详细边界见自动修复资料。
|
||
|
||
## 流程
|
||
|
||
按顺序做。每步记下「正常 / 可疑 / 未查到」。需要逐项展开时再读检查清单。
|
||
|
||
如果用户明确要求「加固」「新机初始化」「配置 SSH/防火墙」,先完成只读快照,再阅读并执行加固资料。加固采用分阶段、可验证、可回滚流程;不能把远程一键脚本直接当作安全默认值。
|
||
|
||
### 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. 持久化
|
||
|
||
发现持久化信号或需要深查时,再读持久化资料。至少查:
|
||
|
||
- 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. 补漏(本次检查没做或做得浅的)
|
||
|
||
见 checklist 后半:补丁、SUID、世界可写、意外用户、IPv6、定时器、内核模块、出站 C2、云安全组、备份是否可用。
|
||
|
||
加固模式还要额外记录:
|
||
|
||
- SSH 的 `sshd -t` 与 `sshd -T` 生效结果,不只看配置文件中的 grep
|
||
- 防火墙实际后端(nftables/iptables/ufw)及 IPv4/IPv6 规则
|
||
- Fail2ban jail、日志后端、白名单和当前封禁状态
|
||
- 云安全组/平台防火墙是否已放行管理入口(查不到必须标未验证)
|
||
- 新管理员的密钥登录是否能在第二条会话中成功,再关闭 root/密码登录
|
||
- Docker 的端口绑定、特权、socket/宿主机挂载;不要无条件改 `daemon.json`
|
||
- 变更前备份、变更后验证、失败时的控制台回滚路径
|
||
|
||
## 检查清单(按需)
|
||
|
||
需要逐项展开时,读取 [references/checklist.md](references/checklist.md)。
|
||
|
||
## 持久化资料(按需)
|
||
|
||
发现持久化信号或需要深查时,读取 [references/persistence.md](references/persistence.md)。
|
||
|
||
## 加固资料(按需)
|
||
|
||
用户明确要求加固时,读取 [references/hardening.md](references/hardening.md)。
|
||
|
||
## 自动修复资料(按需)
|
||
|
||
用户批准执行修复时,读取 [references/remediation.md](references/remediation.md)。
|
||
|
||
## 报告格式
|
||
|
||
先给结论(是否沦陷、最可能入口、对外还开着什么),再给证据表,最后给 **需用户点头的处置清单**。不要默默清理。
|
||
|
||
```
|
||
结论: 沦陷 / 可疑 / 未见异常
|
||
最可能入口: …
|
||
对外端口: …
|
||
持久化: …
|
||
隐藏/矿机: …
|
||
容器/编排: …
|
||
未查项: …
|
||
建议处置: (等确认)
|
||
```
|
||
|
||
## 处置(仅在用户同意后)
|
||
|
||
原则见 [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` 仍在
|