安全基线清单动辄上百条,真坐到一台跑着业务的生产机前,低峰期窗口往往只有一个小时。与其把 CIS、等保条目从上到下刷一遍、刷到一半超时,不如先挑一组高价值、低误报的项做透:账号侧的 UID 0 异常账号,文件权限侧的 SUID/SGID、全局可写目录、无属主文件。这几项的共同点是不会误报——命中就意味着有人动过手脚或历史遗留没清,值得当场确认;而且命令几分钟就能跑完,结论可以复核、可以回滚。
这篇文章按一个晚上能做完的节奏组织:先做可回滚快照,再逐项盘点、判断、小步变更、验证,最后留一份下轮可对比的记录。所有命令默认以 root 在一台主机本地执行,通过跳板机批量下发请自行分批。需要说清楚边界:这是日常基线抽查,不替代完整等保测评,也不等于入侵排查——如果命中项看起来像被人刻意留下的,先取证、后处置,不要急着删。

先划范围:这一轮动什么、不动什么
抽查前先把影响面写下来,后面每一步都对照这张表判断“要不要动”。执行位置均为目标主机本地 shell,预期现象是“干净主机上输出很少”。
| 检查项 | 执行命令要点 | 干净主机预期 | 命中后的动作上限 |
|---|---|---|---|
| UID 0 账号 | /etc/passwd 第三字段 | 只有 root 一行 | 先锁定,不删除 |
| 可登录账号 | shell 为 bash/sh/zsh | 与人员清单一致 | 记录,交业务确认 |
| SUID 文件 | find / -xdev -perm -4000 -type f | 数十个,均属基础组件 | 先摘位观察 |
| SGID 文件与目录 | -perm -2000 | 同上,目录多为协作目录 | 确认归属后改 |
| 全局可写目录 | -perm -0002 且无 sticky | 基本为 0 | 补 sticky 或收权限 |
| 无属主文件 | -nouser -o -nogroup | 基本为 0 | 确认后 chown 或归档 |
需要观察的业务路径提前列清楚:SSH 登录与 su/sudo、密码修改、crontab 与 systemd timer、Nginx/PHP-FPM 的读文件与上传目录写入、备份任务的读取权限。这几条路径覆盖了本轮绝大多数变更可能踩到的点,验证阶段会逐条过。
第 0 步:留下能一键回滚的快照
这一步不做完,后面任何 chmod、usermod 都不要敲。所有输出放进同一个带时间戳的目录,方便事后比对。
mkdir -p /root/baseline-$(date +%F) && cd /root/baseline-$(date +%F)
cp -a /etc/passwd /etc/shadow /etc/group /etc/gshadow .
cp -a /etc/sudoers /etc/sudoers.d ./ 2>/dev/null
visudo -c # 预期:parsed OK,顺手确认 sudoers 本身没坏
stat -c '%a %U %G %n' /etc/passwd /etc/shadow /etc/group文件权限侧,把关键目录当前的 mode、属主、ACL 和扩展属性一并存下来,这是回滚的唯一依据:
for d in /etc /bin /sbin /usr/bin /usr/sbin /var/www /tmp /var/tmp /home; do
find "$d" -xdev -printf '%m %u %g %pn' 2>/dev/null
done > perms-snapshot.txt
getfacl -R -p /var/www > acl-www.bak 2>/dev/null-xdev 是必须的,否则 find / 会爬进挂载的 NFS 或对象存储,跑几十分钟还带出一堆与主机无关的路径。快照文件本身按敏感件处理,/etc/shadow 副本别留在 web 目录或家目录里。
第 1 步:UID 0 账号,只应该有 root 一个
awk -F: '$3==0 {print $1, $3, $7}' /etc/passwd
awk -F: '($2==""){print $1}' /etc/shadow
getent group 0预期输出只有 root 0 /bin/bash(或 /bin/sh),空口令账号一行都没有。多出来的 UID 0 账号无论名字多像系统账号,都要当成待确认项处理:攻击者留后门时经常这么干,因为登录进去直接就是 root。
判断顺序:先查它是不是配置管理工具、监控 agent、容器基础镜像带入的账号,再查 shell 历史、last、/var/log/secure(或 auth.log)里有没有它的登录记录。确认是历史遗留且无人使用,走锁定而不是删除:
passwd -S backupadmin # 记录当前状态,回滚时对照
usermod -L backupadmin # 锁定密码
usermod -s /sbin/nologin backupadmin回滚用 usermod -U backupadmin 并恢复原 shell。之所以不直接 userdel,是因为删除会连同家目录、邮件、以及被其他服务引用的 UID 一起带走,出问题时没有退路。真要删,放在观察一到两周之后、并确认 find / -uid <UID> 无结果再说。

第 2 步:SUID/SGID 清单,和包记录对一遍
SUID 位让程序以文件属主身份运行,属主是 root 时进程就带 root 权限;SGID 作用于文件是以属组身份运行,作用于目录是新建文件继承目录属组。正常系统里这类文件不多,且都来自软件包。
find / -xdev -type f -perm -4000 -printf '%m %u %g %pn' 2>/dev/null | sort -k4 > suid.txt
find / -xdev ( -type f -o -type d ) -perm -2000 -printf '%m %u %g %pn' 2>/dev/null | sort -k4 > sgid.txt预期现象:输出几十行,路径集中在 /usr/bin、/usr/sbin、/usr/libexec,属主是 root,典型的有 su、sudo、passwd、mount、umount、newgrp、gpasswd、chsh、crontab、pkexec、ssh-keysign、unix_chkpwd、fusermount 等。具体名单随发行版和安装的包不同,别拿别人的清单硬套。
判断最省力的方式是问包管理器“这个文件的权限是不是被改过”:
# RHEL/CentOS/Rocky
rpm -Va 2>/dev/null | awk 'substr($0,2,1)=="M"'
# Debian/Ubuntu:能查内容校验,权限变化覆盖有限,需人工比对
dpkg --verify 2>/dev/null | headrpm -Va 输出 9 位标记,第二位是 M 表示权限位相对包内记录发生了变化——这类文件优先看。反过来,一个 SUID 文件如果 rpm -qf 报“not owned by any package”,那就不是装出来的,是后加的,必须查清来源再处置。
命中非基线 SUID 文件时的最小动作是先摘位、保留文件,而不是删:
stat -c '%a %U %G %n' /path/to/suspect # 记下原 mode,例如 4755
chmod u-s /path/to/suspect # 或 chmod 0755回滚就是 chmod 4755 /path/to/suspect(按记下的原值)。摘位后要立刻验证依赖它的功能:自己写的小工具摘位后可能直接报权限不足,那就说明它确实在被业务调用,回到确认环节。SGID 目录(如团队协作目录)摘位会影响新建文件的属组继承,改之前确认目录里有没有跨组共享的写入需求。
第 3 步:全局可写目录与无属主文件
全局可写本身不致命,缺了 sticky 位才致命——没有 t 位,任何用户都能删改别人在该目录下的文件。
find / -xdev -type d -perm -0002 ! -perm -1000 -printf '%m %u %g %pn' 2>/dev/null
find / -xdev -type f -perm -0002 -printf '%m %u %g %pn' 2>/dev/null
find / -xdev ( -nouser -o -nogroup ) -printf '%m %u %g %pn' 2>/dev/null预期:/tmp、/var/tmp、/dev/shm 是全局可写但带 sticky(mode 1777),第一条命令应该输出为空;第二条在干净主机上通常也只有 /tmp 下运行中的临时文件。Web 上传目录、缓存目录、session 目录是常见的“合理例外”,但它们应该由服务账号持有,而不是 nobody 或 777。
处置分两类:
- 缺 sticky 的共享目录:
chmod +t /path,回滚chmod -t /path。这一条对业务几乎无感,可以先做。 - 全局可写的业务目录:先确认写入方是谁,再收成
chmod o-w,或改成属组可写chmod 2775并chown root:webteam。回滚用快照里记下的原 mode。收紧后必须验证上传、缓存写入、session 落盘,Nginx/PHP 报Permission denied就是收过头了。
无属主文件说明创建它的账号已经被删(或 UID 变更),这类文件在 find / -uid 类排查里会成为噪声,也可能被任意新账号“继承”。确认内容无价值就移到归档目录,有价值则 chown 给明确的账号,别直接 chown root 了事——那只是把问题藏起来。
第 4 步:小步变更、逐项验证、留好回滚
变更别一次性推完。按下面的节奏走,每一项之间留出观察窗口,出问题能立刻定位到是哪一步。
| 顺序 | 变更内容 | 观察窗口 | 必验路径 |
|---|---|---|---|
| 1 | 共享目录补 sticky | 即时 | 无业务影响,抽查即可 |
| 2 | 锁定可疑 UID 0 账号 | 10 分钟 | SSH 登录、sudo、密码修改 |
| 3 | 摘掉非基线 SUID 位 | 30 分钟 | 对应命令执行、cron、备份脚本 |
| 4 | 收紧全局可写业务目录 | 1 小时 | Web 上传、缓存、session |
验证清单固定四条,每条都给出预期现象:
- 登录:新开一个 SSH 会话(别关现有会话),
su -和sudo -l正常,普通用户passwd能改自己密码——验证 SUID 摘位没误伤passwd和sudo。 - 计划任务:
crontab -l对业务账号可读,systemctl list-timers里的任务在窗口内正常触发,/var/log/cron或 journal 无Permission denied。 - Web:
nginx -t通过,站点首页 200,上传一张测试图成功,PHP 错误日志无新告警。 - 备份:手动触发一次备份任务,确认能读到被收紧的目录。
任何一条不符合预期,按快照回滚该单项,不要连带回滚整批——这正是分步做的意义。回滚命令提前写进变更单,写的时候就用快照里记下的原始 mode,别靠回忆。
复盘:把这一轮变成下一轮的对照
收尾时把三份东西归档到同一个目录:perms-snapshot.txt、suid.txt/sgid.txt、以及一份变更记录(谁、什么时候、改了哪个路径、原值、现值、验证结论)。下一轮抽查可以直接和新快照 diff,命中项会明显变少,窗口也能压得更短。
频率上,账号与 SUID 这组适合按月跑一次全量,全局可写目录按季度,业务目录权限在每次发版或装新插件后补一次抽查。WordPress 站点尤其要注意插件安装目录——上传目录被改成 777 是极常见的“临时修一下”,事后没人改回来。
最后提醒一句:本轮所有动作都建立在业务确认之上。删账号、改系统文件权限这类不可逆或影响面大的操作,无论如何都要有明确的授权记录和可执行的回滚命令,否则宁可先只记录、不处置。
- crontab
- it2021
- it2021.com
- nginx
- shell
- WordPress





上海 上海 1F
先做快照这点很关键