feat: add host-sec-check
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
# 取证入口(无 sudo 时)
|
||||
|
||||
目标用户常见情况:`sudo` 要密码,但在 `docker` 组。Docker 组等价于 root。
|
||||
|
||||
## 读宿主机(绕过 preload)
|
||||
|
||||
容器用自己的 libc,**不会**加载宿主机 `/etc/ld.so.preload`。
|
||||
|
||||
```bash
|
||||
docker run --rm -i --privileged --pid=host --net=host -v /:/host alpine:latest \
|
||||
cat /host/etc/ld.so.preload
|
||||
hexdump -C /host/etc/ld.so.preload # 在容器内
|
||||
```
|
||||
|
||||
列隐藏进程:
|
||||
|
||||
```bash
|
||||
docker run --rm --privileged --pid=host alpine:latest sh -c \
|
||||
'for d in /proc/[0-9]*; do
|
||||
pid=${d#/proc/}
|
||||
cmd=$(tr "\0" " " < "$d/cmdline" 2>/dev/null) || continue
|
||||
[ -n "$cmd" ] && echo "$pid $cmd"
|
||||
done'
|
||||
```
|
||||
|
||||
## 改宿主机(systemctl / chattr)
|
||||
|
||||
`chroot /host /usr/bin/chattr` 会加载宿主机 preload,可能 **stat 不到** 被藏文件。
|
||||
|
||||
用发行版自带 chattr 操作 `/host/...`:
|
||||
|
||||
```bash
|
||||
docker run --rm -i --privileged --pid=host --net=host -v /:/host ubuntu:latest bash -s <<'SH'
|
||||
chattr -i /host/etc/ld.so.preload
|
||||
: > /host/etc/ld.so.preload
|
||||
chattr +i /host/etc/ld.so.preload
|
||||
lsattr /host/etc/ld.so.preload
|
||||
SH
|
||||
```
|
||||
|
||||
systemctl / reboot:
|
||||
|
||||
```bash
|
||||
docker run --rm --privileged --pid=host --net=host alpine:latest \
|
||||
nsenter -t 1 -m -u -i -n -- systemctl disable --now UNIT
|
||||
```
|
||||
|
||||
不要用业务容器当跳板;用 `alpine`/`ubuntu` 临时 `--rm`。查到一半时 `docker ps` 里出现的随机名容器就是这个跳板。
|
||||
@@ -0,0 +1,75 @@
|
||||
# 检查项
|
||||
|
||||
每项:做了 / 跳过(原因) / 可疑。
|
||||
|
||||
## A. 快照
|
||||
|
||||
- [ ] 主机名、OS、内核、uptime
|
||||
- [ ] CPU/负载、内存(含 hugepage、swap)、磁盘
|
||||
- [ ] 网卡:公网 v4/v6、内网、Tailscale/VPN
|
||||
- [ ] 监听端口 + 进程(root `ss -lntup`)
|
||||
- [ ] 本机防火墙:nft/iptables/ufw;INPUT 策略
|
||||
- [ ] 云安全组(做不到就写未查)
|
||||
|
||||
## B. 身份与入口
|
||||
|
||||
- [ ] sshd 配置:端口、root、密码、Pubkey
|
||||
- [ ] 所有 `authorized_keys`(含 `/root`、`/home/*`、git 用户)
|
||||
- [ ] `last` / `lastb` / ssh journal
|
||||
- [ ] `/etc/passwd` 里 UID 0、系统外用户、登录 shell
|
||||
- [ ] sudoers、NOPASSWD、docker/lxd/libvirt 组
|
||||
- [ ] 对公网的面板:Portainer/Cockpit/宝塔/1Panel/k8s/Docker TCP
|
||||
- [ ] 单元或 compose 里的明文 bootstrap token
|
||||
|
||||
## C. 持久化
|
||||
|
||||
- [ ] 用户与系统 crontab、`/etc/cron.*`
|
||||
- [ ] systemd 服务与 timer(非发行版默认)
|
||||
- [ ] `ld.so.preload` + 对应 `.so`(容器视角 hexdump)
|
||||
- [ ] `lsattr` 发现的 immutable 异常文件
|
||||
- [ ] rc.local、profile.d、bashrc 后门
|
||||
- [ ] 第二套 container runtime
|
||||
|
||||
## D. 进程
|
||||
|
||||
- [ ] 容器视角 vs 宿主机 `ps` 差集
|
||||
- [ ] maps 里的陌生 so
|
||||
- [ ] 矿机/挖矿/proxy 客户端特征名与同体积副本
|
||||
- [ ] hugepage 预留但无对应进程
|
||||
- [ ] 高 CPU 且不在业务名单里的进程
|
||||
|
||||
## E. 容器 / k8s
|
||||
|
||||
- [ ] `docker ps -a` 与 inspect(privileged、sock、`/:/host`、`0.0.0.0`)
|
||||
- [ ] 挂机赚钱镜像名单
|
||||
- [ ] k8s/k3s:节点 Ready、该节点 Pod 列表
|
||||
- [ ] API 不通时:kubelet `pods/*/etc-hosts`、crictl
|
||||
- [ ] 工作负载是否能在 Git/编排仓库里对上
|
||||
|
||||
## F. 暴露
|
||||
|
||||
- [ ] `0.0.0.0` 与 `[::]` 监听清单
|
||||
- [ ] **从外部**扫公网 IPv4(和 IPv6)
|
||||
- [ ] rpcbind :111、DB、Redis、应用明文端口
|
||||
- [ ] 管理 SSH 是否可收到 VPN
|
||||
- [ ] 证书/域名入口是否可被 IP:端口绕过
|
||||
|
||||
## G. 补漏(容易漏)
|
||||
|
||||
- [ ] IPv6 公网地址同样在听
|
||||
- [ ] 世界可写目录、异常 SUID
|
||||
- [ ] 未装补丁 / `apt` 过期很久
|
||||
- [ ] 出站长连接(C2)
|
||||
- [ ] 内核模块 `lsmod` 异常
|
||||
- [ ] 时间偏移(影响日志)
|
||||
- [ ] 备份是否还能用(清理前不要删数据盘)
|
||||
- [ ] 日志被清空或 journal vacuum
|
||||
- [ ] Web 根目录 webshell(若有 nginx/caddy/apache)
|
||||
- [ ] `.git` 或备份文件可下载
|
||||
- [ ] 云 metadata 是否对容器开放
|
||||
|
||||
## H. 报告与处置确认
|
||||
|
||||
- [ ] 结论表
|
||||
- [ ] 用户确认后再改
|
||||
- [ ] 改完公网+域名双侧验证
|
||||
@@ -0,0 +1,59 @@
|
||||
# 处置(用户同意之后)
|
||||
|
||||
## 顺序
|
||||
|
||||
1. 证据已落盘(collect 输出、关键 ls/hexdump/docker inspect)
|
||||
2. 停进程 / 停容器
|
||||
3. 删或占位文件
|
||||
4. 关公网端口
|
||||
5. 最后才重启(卸已加载的隐藏库)
|
||||
|
||||
## 占位
|
||||
|
||||
对矿机路径(`/usr/bin/perfcc`、`/tmp/javavm64`、隐藏 docker 根名等):
|
||||
|
||||
```bash
|
||||
chattr -i "$path" 2>/dev/null
|
||||
rm -f "$path"
|
||||
: > "$path"
|
||||
chmod 000 "$path"
|
||||
chattr +i "$path"
|
||||
```
|
||||
|
||||
`/etc/ld.so.preload` 占空文件,权限 `644` + immutable,让动态链接器能读到「没有库」。
|
||||
|
||||
目录型隐藏根:停进程并卸挂载后删除,再在同名路径放 immutable 空文件,阻止再 `mkdir`。
|
||||
|
||||
改 immutable 时用容器自带 `chattr` 操作 `/host/...`,不要 `chroot` 到宿主机再跑 chattr。见 access.md。
|
||||
|
||||
## 容器
|
||||
|
||||
```bash
|
||||
docker stop NAME && docker rm NAME
|
||||
docker rmi IMAGE
|
||||
```
|
||||
|
||||
不要 `docker system prune -a`。
|
||||
|
||||
## 端口
|
||||
|
||||
- 入口在本机 loopback → `127.0.0.1:PORT:CONTAINER`
|
||||
- 入口走 Tailscale 主机名 → 必须绑 **当前 Tailscale IPv4**,不能只绑 127.0.0.1
|
||||
- 可同时绑 loopback + Tailscale,禁止 `0.0.0.0` / `[::]`
|
||||
|
||||
改 compose 后 force-recreate,再从公网 IP 和业务域名两边探测。
|
||||
|
||||
## rpcbind
|
||||
|
||||
```bash
|
||||
systemctl disable --now rpcbind.socket rpcbind.service
|
||||
systemctl mask rpcbind.socket rpcbind.service
|
||||
```
|
||||
|
||||
无对外 NFS 再做。确认 `:111` 消失。
|
||||
|
||||
## 重启
|
||||
|
||||
重启前确认业务是 `restart: always`,并告知会短暂中断。
|
||||
|
||||
重启后:`grep -l <so名> /proc/*/maps` 为 0;若已清 hugepage 则 `HugePages_Total` 为 0;域名 200。
|
||||
@@ -0,0 +1,40 @@
|
||||
# 持久化位置
|
||||
|
||||
按这个名单扫。出现「刚被排查时时间戳又刷新」= 仍有 watchdog。
|
||||
|
||||
## 定时
|
||||
|
||||
- `crontab -u root -l` 以及 `/var/spool/cron/crontabs/*`
|
||||
- `/etc/cron.d/` `/etc/cron.hourly/` `/etc/cron.daily/` `/etc/cron.weekly/`
|
||||
- systemd timers:`systemctl list-timers --all`
|
||||
|
||||
## 服务
|
||||
|
||||
- `/etc/systemd/system/*.service`(尤其非发行版默认的)
|
||||
- `ExecStart` 指向 `/tmp`、`/dev/shm`、`/root/.config`、随机短名
|
||||
- `Restart=always` 的陌生服务
|
||||
|
||||
## 动态链接器
|
||||
|
||||
- `/etc/ld.so.preload`:内容常是 `/lib/libXXX.so`(约十几字节)。宿主机 `cat` 可能显示空,用容器 hexdump
|
||||
- 对应 `.so` 可能 `chattr +i`、setgid
|
||||
- 常见名:`libgcwrap.so`、`libpprocps.so`、`libfsnldev.so`、`libprocesshider.so`
|
||||
|
||||
## 二进制与分身
|
||||
|
||||
- `/usr/bin` `/bin` `/usr/local/bin` `/tmp` 下刚改过的可执行文件
|
||||
- 同字节大小的多份拷贝(矿机改名)
|
||||
- 占位对抗:空文件 `chmod 000` + `chattr +i`(见 cleanup.md)
|
||||
|
||||
## 隐藏运行时
|
||||
|
||||
- 第二套 dockerd:`--data-root` 不在 `/var/lib/docker`,`--host unix://` 异常路径
|
||||
- 混淆文件名(把 docker 子命令拼进无关单词)
|
||||
- k3s 的 `containerd-shim` 被借去跑 **moby** namespace + 异常 `--address`
|
||||
|
||||
## 登录与启动
|
||||
|
||||
- `~/.bashrc` / `/etc/profile.d` 里 curl|bash
|
||||
- `/etc/rc.local`
|
||||
- SSH `authorized_keys` 多出来的 key
|
||||
- 意外用户、UID 0 非 root
|
||||
Reference in New Issue
Block a user