直接写 !/bin/bash 无效,因 ! 排除仅在同授权行内对白名单生效;须用 Cmnd_Alias 集中定义逃逸命令并全局禁用,配合 Defaults requiretty、noexec、env_reset 三层约束,再以 sudo -n 实测验证。

为什么直接写 !su 或 !/bin/bash 不起作用
sudoers 的 ! 排除语法只在「同一授权行内」生效,且必须与白名单命令共存。单独写 %users ALL=(ALL) !/bin/bash 会被忽略——因为没有前置允许项,排除无从谈起。更危险的是,用户仍可通过 sudo -i、sudo su -、sudo /usr/bin/python3 -c "import pty; pty.spawn('/bin/bash')" 等方式绕过。真正的封锁必须基于「显式禁止 + 执行约束 + 环境隔离」三层叠加。
用 Cmnd_Alias 集中定义逃逸命令集再全局禁用
把所有已知可提权的命令路径和参数组合打包进一个别名,比零散写 ! 更可靠,也便于审计和更新:
Cmnd_Alias ESCAPE_CMDS = /bin/sh, /bin/bash, /bin/zsh, /usr/bin/sh, /usr/bin/bash, /bin/su, /usr/bin/su, /usr/bin/python3 -c *, /usr/bin/perl -e *, /usr/bin/ruby -e *, /usr/bin/find * -exec sh \;, /usr/bin/awk 'BEGIN {system("")}'- 然后对目标组(如
%ops)应用两行规则:%ops ALL=(root) NOPASSWD: /usr/bin/systemctl *, /usr/bin/journalctl *%ops ALL=(ALL) !ESCAPE_CMDS - 注意第二行中的
(ALL)是关键:它覆盖所有目标用户身份(包括 root),确保即使某条逃逸命令意外落在第一行白名单之外,也会被第二行拦截
必须配合 Defaults 级硬性约束
仅靠命令级黑名单远远不够。以下三项 Defaults 设置缺一不可:
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
-
Defaults requiretty:强制命令必须在真实 TTY 中执行,阻断 web shell、cron、SSH 命令注入等非交互调用场景 -
Defaults noexec:禁止在 sudo 环境中执行子进程(如less /etc/shadow内部调用!/bin/sh) -
Defaults env_reset(默认已启用):清空用户环境变量,防止PWD、PATH被污染用于劫持命令
这三者加起来,才能让 sudo -l 显示的权限真正等于实际可执行的权限。
验证是否真被封死:用 sudo -n 实测每种逃逸路径
别信配置写完了就安全了。必须以目标用户身份逐条测试:
-
sudo -n /bin/bash→ 应报sudo: a password is required或直接拒绝 -
sudo -n su -→ 同上 -
sudo -n python3 -c "import os; os.system('/bin/sh')"→ 必须失败(noexec会拦截) -
sudo -n -l→ 输出里不能出现任何 shell、su、python3 -c 等字样
最容易被忽略的是 sudo -n 这个开关:它跳过密码提示,让失败立刻暴露;而普通 sudo 会卡在输密码界面,让人误以为“没配生效”其实是“被 requiretty 拦住了”。

















