快速发现重复UID应排序后比对/etc/passwd第三字段:awk -F: '{print $3, $1}' /etc/passwd | sort -n | uniq -w 4 -d;注意需先sort再uniq,且RHEL 8+等系统须同步检查getent passwd。

如何快速发现系统中重复的UID
Linux允许不同用户名拥有相同UID,但实际运维中这常导致权限混乱、日志归属错误甚至提权漏洞。最直接的检查方式是排序后比对/etc/passwd中的第三字段(UID)。
实操建议:
- 用
awk -F: '{print $3, $1}' /etc/passwd | sort -n | uniq -w 4 -d:只匹配前4位数字(覆盖0–9999范围),避免UID 100和1000被误判为重复 - 注意
uniq必须配合sort使用,否则无法识别非相邻重复项 - 跳过系统账户(UID awk -F: '$3 >= 1000 {print $3, $1}' /etc/passwd | sort -n | uniq -w 4 -d
- 某些发行版(如RHEL 8+)默认启用
nsswitch集成SSSD或LDAP,仅查/etc/passwd可能漏掉远程用户,需同步检查getent passwd输出
为什么useradd没报错却创建了隐藏账户
隐藏账户通常指UID在系统保留范围内(如0–999)、家目录设为/dev/null或/var/empty、shell设为/usr/sbin/nologin或/bin/false,但未被useradd拒绝——因为默认策略不校验这些组合是否合理。
实操建议:
-
useradd本身不阻止UID 0重复创建,也不校验home路径是否存在或是否可写,需靠后续检查兜底 - 检查“伪用户”是否异常:运行
awk -F: '$3 ,重点关注shell非标准且UID偏低的条目 - 家目录为空或指向
/dev/null时,ls -ld会显示Permission denied或No such file,但useradd仍认为创建成功 - 若启用了
PAM模块(如pam_umask或自定义策略),可能静默跳过部分校验,需检查/etc/pam.d/useradd
getent passwd输出和/etc/passwd不一致怎么办
这是最常见的排查盲区:管理员只扫/etc/passwd,却忽略getent从NSS后端(如LDAP、SSSD、Winbind)拉取的用户数据,而攻击者常通过伪造后端响应注入UID重复账户。
实操建议:
- 必须用
getent passwd | awk -F: '{print $3, $1}' | sort -n | uniq -w 4 -d全量比对,不能只信本地文件 -
getent结果受/etc/nsswitch.conf中passwd:行控制,若含ldap或sss,需确认对应服务是否可信、配置是否被篡改 - SSSD缓存可能导致
getent返回已删除的旧用户,执行sss_cache -E清空后重试 - 某些恶意模块会hook
getpwent()系统调用,绕过getent——此时需用strace -e trace=getpwent getent passwd \| head -20确认真实调用链
排查时容易被忽略的UID 0变体
UID 0不等于只有root一行。攻击者常创建root2、adm(注意不是系统自带的adm组)、sync等同UID账户,利用历史遗留配置或SUID程序提权。
实操建议:
- 单独检查UID 0:
awk -F: '$3 == 0 {print $1, $6, $7}' /etc/passwd,重点看家目录和shell是否异常(如/tmp或/dev/shm) - 注意
sync、shutdown、halt等系统账户默认UID非0,但若被手动改过UID=0,useradd不会拦截 - 某些容器镜像或自动化脚本会批量创建UID 0账户并禁用密码,仅靠
passwd -S查状态不够,得结合chage -l看密码过期时间是否为never且最近修改时间异常新 - 内核级UID伪造极少见,但若发现
ps aux | grep '^[[:space:]]*0'有大量UID 0进程不属于root用户,需怀疑内核模块或eBPF hook
真正难的是区分“合法但危险”的配置和“非法但隐蔽”的植入——比如CI/CD系统用UID 0跑构建任务,或某监控工具要求固定UID,这些都需要结合进程树、启动服务、审计日志(aureport -m -i)交叉验证,不能单靠静态文件扫描下结论。










