UID 0 就是 root
Linux 的权限判断依据是数值型 UID,而不是账号名。只要 /etc/passwd 里某个账号的第三字段为 0,它就和 root 等价——哪怕名字叫 system 或 backup。因此排查异常账号的第一步就是找出所有 UID 0 的条目,再核对哪些属于系统自带、哪些是后来添加的。同时要看可登录 shell 字段与 /etc/shadow 中的口令状态:账号能否真正登录,取决于两者与密码三项一起,而不是只看 /etc/passwd 一行。
基本信息
| 文件 | /etc/passwd(账号)、/etc/shadow(口令状态)、/etc/group(组)、/etc/sudoers(提权配置) |
|---|---|
| passwd 字段 | 账号名:口令占位:UID:GID:说明:家目录:登录 shell |
| 重点判断 | 第三字段为 0 的账号;GID 为 0 的组;可登录 shell 的系统账号 |
| shadow 状态 | 空口令、锁定(! 或 *)、有效期限字段 |
| 关联检查 | 家目录是否存在与创建时间、authorized_keys、计划任务 |
| 容器环境 | 容器内 UID 0 属常态,判断要结合宿主与业务约定 |
典型使用场景
- 找出所有 UID 0 账号,确认是否存在后门账号
- 检查系统账号是否被改成可登录 shell(例如从 nologin 改为 bash)
- 核对空口令或未设置口令的账号
- 检查 sudoers 中新增的提权条目与免密配置
- 通过家目录创建时间推断账号建立时间
- 与登录日志交叉验证新增账号是否被实际使用
扫描
扫描
# 列出所有 UID 0 账号(含账号名、UID、登录 shell)
awk -F: '$3==0 {print $1, $3, $4, $7}' /etc/passwd
# 找出 GID 0 的组与成员
awk -F: '$3==0 {print $1, $4}' /etc/group
# 找出可登录的系统账号(shell 不是 nologin/false)
awk -F: '$3<1000 && $7!~/nologin|false|sync|shutdown|halt/ {print $1, $3, $7}' /etc/passwd
# 检查空口令或异常口令状态
sudo awk -F: '$2=="" {print $1" 空口令"} $2!~/^[!*]/ {print $1" 有可用口令哈希"}' /etc/shadow
# 家目录创建时间,辅助判断账号建立时间
stat -c '%n %w %y' /home/* /root 2>/dev/null | head
# 文件属性:不可变标志会干扰后续处理
lsattr /etc/passwd /etc/shadow 2>/dev/null判读要点
| 观察项 | 含义 | 异常表现 |
|---|---|---|
| UID 0 账号 | 与 root 等权 | 出现非 root 名称的 UID 0 账号 |
| GID 0 成员 | root 组成员 | 普通业务账号被加入 root 组 |
| 登录 shell | 账号能否交互登录 | 系统账号被改为 bash 或 sh |
| shadow 口令状态 | 是否设置口令或被锁定 | 空口令字段,或本应锁定的账号存在可用哈希 |
| 家目录时间 | 账号建立的大致时点 | 创建时间落在入侵窗口内 |
| sudoers 条目 | 提权配置 | 新增免密或全权限条目 |
账号能否登录要三处一起看:passwd 的 shell 字段、shadow 的口令状态、以及是否存在其他认证方式(SSH 密钥、PAM 配置)。只看其中一处容易下错结论。
部分系统自带账号历史上可能带非标准 shell 字段,属于已知基线。先在正常环境上取一份基线清单,再对比目标主机,差异才有意义。