一、问题的本质:为什么 sudo su - 能绕过防线?
在日常运维中,很多管理员会遇到这样的困惑:
建立普通用户并添加到 sudoers 后,发现该用户可以通过
sudo su -或sudo su配合自己的密码直接切换到 root。这不就是"串权"了吗?
核心问题在于:大多数教程只教了你一半。 网上常见的 wheel 组限制方案,只能拦截直接 使用 su - root 的路径,却对 sudo su - 这条"借道"路径束手无策。
要理解这一点,必须先搞清楚 Linux 中两条截然不同的提权路径:
| 路径 | 命令示例 | 认证机制 | 控制文件 |
|---|---|---|---|
| su 路径 | su -, su - root |
PAM 认证栈 | /etc/pam.d/su |
| sudo 路径 | sudo su -, sudo -i |
sudoers 策略 + PAM | /etc/sudoers + /etc/pam.d/sudo |
这两条路径独立运行、互不干涉。只封住一条,另一条依然是敞开的。
二、PAM 是什么?------可插拔认证模块
PAM(Pluggable Authentication Modules,可插拔认证模块)是 Linux 系统中一套分层、模块化 的认证框架。它的设计哲学是:将认证逻辑从应用程序中剥离出来,通过配置文件动态组合。
2.1 PAM 的四类管理模块
每个 PAM 配置文件(位于 /etc/pam.d/ 下)都包含四类管理标记:
| 标记 | 作用 | 示例场景 |
|---|---|---|
auth |
验证用户身份(你是谁?) | 密码校验、双因素认证 |
account |
账户有效性检查(你能用吗?) | 账户是否过期、登录时间限制 |
password |
密码修改策略(你能改吗?) | 密码复杂度、历史密码限制 |
session |
会话管理(你做了什么?) | 环境变量设置、审计日志记录 |
2.2 控制标记:决定模块的"话语权"
PAM 使用控制标记决定当某个模块失败时,整体认证流程该如何继续:
| 控制标记 | 行为 | 通俗解释 |
|---|---|---|
required |
必须成功,失败继续检查但最终拒绝 | "一票否决,但面子给足" |
requisite |
必须成功,失败立即终止 | "一票否决,当场翻脸" |
sufficient |
成功则跳过后续,失败忽略 | "过了这村没这店" |
optional |
成败不影响结果 | "仅供参考" |
理解
requiredvsrequisite的区别至关重要:requisite在失败时立即返回,避免暴露过多系统信息(如提示"密码错误"前就被拒绝),是更安全的做法。
三、实战第一步:用 pam_wheel.so 锁住 su 大门
3.1 为什么选 pam_wheel.so?
pam_wheel.so 是 PAM 中专门用于实施 "wheel 组"策略 的模块。它的核心功能是:只允许特定用户组成员使用 su 切换到 root(或目标用户) 。
根据官方手册,该模块支持多个关键参数:
| 参数 | 作用 |
|---|---|
use_uid |
检查调用者的真实 UID,而非从终端会话获取的用户名(防伪造) |
group=name |
指定自定义组名,替代默认的 wheel |
deny |
反向逻辑:wheel 组成员被禁止使用 su |
root_only |
仅在目标用户是 root(UID=0)时才检查 |
trust |
wheel 组成员免密通过(极度危险,生产环境禁用) |
3.2 配置 /etc/pam.d/su
打开配置文件:
bash
sudo vim /etc/pam.d/su
你会看到类似以下的内容:
text
#%PAM-1.0
auth sufficient pam_rootok.so
#auth required pam_wheel.so use_uid
auth substack system-auth
auth include postlogin
account sufficient pam_succeed_if.so uid = 0 use_uid quiet
account include system-auth
password include system-auth
session include system-auth
session include postlogin
session optional pam_xauth.so
关键操作: 找到被注释掉的 pam_wheel.so 行,取消注释:
text
auth required pam_wheel.so use_uid
各配置组合的效果解析
根据 openEuler 社区的技术文档,这两行的组合决定了谁能使用 su :
pam_rootok.so |
pam_wheel.so |
效果 |
|---|---|---|
| 开启(默认) | 注释(默认) | 所有用户 都能使用 su,root 切换免密 |
| 注释 | 注释 | 所有用户都能使用 su,但 root 切换也需密码 |
| 开启 | 开启 | 只有 root 和 wheel 组成员 能使用 su |
| 注释 | 开启 | 只有 wheel 组成员 能使用 su,root 也被限制 |
推荐配置: 保留
pam_rootok.so(让 root 能免密切换,方便救援),同时开启pam_wheel.so use_uid。这样 root 和 wheel 组成员可用su,其他用户一律拒绝。
3.3 为什么必须加 use_uid?
use_uid 参数的含义是:检查调用进程的真实 UID,而不是尝试从终端会话获取用户名。
如果没有 use_uid,攻击者可能通过环境变量伪造或终端会话劫持来绕过检查。加上 use_uid 后,PAM 直接读取进程的真实 UID,与 /etc/passwd 和 /etc/group 中的记录比对,无法伪造。
3.4 配合 /etc/login.defs(可选增强)
某些发行版支持在 /etc/login.defs 中添加:
bash
SU_WHEEL_ONLY yes
这行配置会进一步强化 su 命令的行为,确保只有 wheel 组成员才能切换用户。不过现代 Linux 中,pam_wheel.so 已足够,此配置更多是历史兼容 。
四、实战第二步:用 /etc/sudoers 堵住 sudo su - 的后门
4.1 为什么 pam_wheel.so 拦不住 sudo su -?
这是许多管理员的误区。让我们拆解 sudo su - 的执行流程:
-
sudo 阶段 :用户执行
sudo su -,系统先检查/etc/sudoers。- 如果用户有
ALL权限,sudo 允许其以 root 身份执行/bin/su -。 - 此时 sudo 的 PAM 认证已完成,与
/etc/pam.d/su无关。
- 如果用户有
-
su 阶段 :
su命令被 root 身份调用,进入/etc/pam.d/su。pam_rootok.so发现当前 UID 已经是 0(root),直接通过!pam_wheel.so检查的是"调用 su 的进程"------此时是 root,自然通过。
结论: sudo su - 完全绕过了 pam_wheel.so 对普通用户的限制,因为 su 是以 root 身份被调用的。
4.2 在 sudoers 中配置命令黑名单
编辑 sudoers 文件(必须使用 visudo,它会检查语法,防止配置错误导致系统锁死):
bash
sudo visudo
为用户添加规则,允许所有命令,但明确禁止 su 和 bash:
text
kong ALL=(ALL) ALL,!/bin/su,!/bin/su -,!/bin/bash,!/bin/sh
规则解析
| 字段 | 含义 |
|---|---|
kong |
目标用户名 |
ALL= |
在所有主机上生效 |
(ALL) |
可以以任何用户身份执行(包括 root) |
ALL |
允许执行所有命令 |
!/bin/su |
但禁止 执行 /bin/su |
!/bin/bash |
但禁止 执行 /bin/bash(防止 sudo bash 绕过) |
注意: 必须同时禁止
su、bash、sh等可以获取交互式 shell 的命令。只禁止su是不够的,因为用户可以通过sudo bash直接获得 root shell 。
4.3 更精细的白名单策略(推荐生产环境)
与其用黑名单"防漏",不如用白名单"精确授权":
text
kong ALL=(ALL) /usr/bin/systemctl *, /usr/bin/cat /var/log/*, !/bin/su, !/bin/bash
这种配置只允许用户执行特定维护命令,从根本上消除提权可能。
五、完整流程图:双重防护机制

上图展示了完整的认证流程:
- su 路径 (上方):普通用户调用
su→ 经过pam_wheel.so检查 → 非 wheel 成员直接被拒绝(红色箭头)。 - sudo 路径 (下方):普通用户调用
sudo su -→ sudoers 解析权限 → 发现!/bin/su规则 → 拒绝执行(红色箭头)。 - wheel 组成员(绿色):无论走 su 还是 sudo 路径,只要配置允许,均可通行。
六、验证与排错
6.1 验证 pam_wheel.so 是否生效
以非 wheel 用户登录,尝试:
bash
su - root
预期结果:
text
Password:
su: Permission denied
即使输入正确密码也应被拒绝。
6.2 验证 sudoers 限制是否生效
bash
sudo su -
预期结果:
text
Sorry, user kong is not allowed to execute '/bin/su -' as root on localhost.
6.3 查看 PAM 调试日志
如果配置未生效,可开启调试:
bash
# 临时开启(CentOS/RHEL)
sudo touch /etc/pam_debug
# 或查看系统日志
sudo tail -f /var/log/secure # CentOS/RHEL
sudo tail -f /var/log/auth.log # Debian/Ubuntu
日志中会显示每个 PAM 模块的返回状态(success、ignore、auth_err 等)。
七、常见误区与陷阱
误区 1:"加了 wheel 组就安全了"
错误。 只加 wheel 组只能防 su - root,防不了 sudo su -。两条路径必须分别配置。
误区 2:usermod -g wheel 和 usermod -aG wheel 一样
完全不同:
bash
# 危险!将用户主组改为 wheel,可能破坏原有权限
usermod -g wheel kong
# 正确!将 wheel 作为附加组
usermod -aG wheel kong
-g 修改的是主组 (GID),会替换用户原有主组;-aG 是追加附加组,不影响现有权限。
误区 3:只禁止 su,不禁止 bash
存在绕过风险。 如果用户有 sudo ALL 权限但只被禁止了 su,他可以:
bash
sudo bash # 直接获得 root shell
sudo -i # 等效于 sudo su -
sudo /bin/sh # 使用其他 shell
必须同时禁止所有交互式 shell。
误区 4:使用 chmod 777 /etc/sudoers
绝对禁止。 /etc/sudoers 的权限必须是 0440(r--r-----)。任何其他权限都会导致 sudo 拒绝读取,系统提示权限错误。修改时始终使用 visudo。
八、总结:最小权限原则的实践
| 防护层级 | 配置文件 | 核心配置 | 拦截对象 |
|---|---|---|---|
| 第一层 | /etc/pam.d/su |
auth required pam_wheel.so use_uid |
非 wheel 用户使用 su |
| 第二层 | /etc/sudoers |
ALL,!/bin/su,!/bin/bash |
授权用户使用 sudo su - |
| 第三层 | /etc/login.defs |
SU_WHEEL_ONLY yes(可选) |
强化 su 限制 |
最终效果:
- 非 wheel 普通用户:
su -被拒绝,sudo su -被拒绝,彻底无法获得 root。 - wheel 组成员:保留
su -权限(知道 root 密码即可),或根据 sudoers 规则使用sudo。 - root 用户:始终保留救援通道(通过
pam_rootok.so)。
这种"PAM 管入口,sudoers 管行为"的双重防护,是 Linux 权限管理中最经典、最可靠的纵深防御实践。