Linux

sudo配置稍有不慎就成提权捷径,visudo里哪些写法看似方便实则把root权限拱手让人?

👤 为我痴狂 👁 5 阅读 ❤ 0 点赞 ➦ 0 分享 📅 2026-11-04
首页› 大数据› Linux› 正文
sudo配置稍有不慎就成提权捷径,visudo里哪些写法看似方便实则把root权限拱手让人?

摘要:sudo 的设计初衷是“最小权限委派”,但在真实运维中,sudoers 文件经常被写成“为了省事”的形态:通配符一把梭、命令参数全放行、脚本解释器直接授权、NOPASSWD 图方便、环境变量继承不设限。这些写法在语法层面完全合法,在语义层面却把“执行某个命令”悄悄放大成“以 root 身份执行任意代码”。本文以“权限语义漂移”为贯穿全文的分析主线,把 sudoers 的授权单元拆解为命令路径、参数匹配、身份切换、环境继承、认证策略五个可独立失效的维度,逐条分析其失效机理、触发条件与可利用路径,并结合公开 CVE、发行版默认配置与可复现的验证方法,给出从“写法纠偏”到“工程化治理”的完整操作路径。文中数据均标注来源,模拟数据单独注明。

关键词:sudoers;权限提升;通配符匹配;参数注入;最小权限;配置审计

目录

一、导语:一条 sudoers 规则的“语义半径”

在 Linux/Unix 权限体系里,sudo 是一个特殊的存在:它本身不是内核机制,而是建立在 setuid 程序之上的“策略执行器”。内核只认 uid/gid,sudo 负责在用户态判断“这个用户能不能以那个身份跑这条命令”。因此,sudoers 文件的每一行,本质上是一条“身份 + 命令 + 条件”的三元组约束。问题在于,这条约束的“语义半径”往往比写它的人以为的要大得多。

举个最常见的例子:ops ALL=(ALL) NOPASSWD: /usr/bin/systemctl。写这条规则的人想的是“让运维同学免密重启服务”,但 systemctl 支持 --unit、--property、link、enable 等子命令,其中部分子命令可以写入任意路径的 unit 文件,进而以 root 身份执行任意命令。也就是说,这条规则的语义半径从“重启服务”扩展到了“任意 root 代码执行”。

本文要回答的核心问题不是“sudo 有没有漏洞”,而是“为什么合法的 sudoers 写法会系统性地产生权限放大”。笔者认为,这背后有一个可归纳的规律:sudoers 的匹配粒度是“命令字符串”,而攻击面的粒度是“程序行为”。两者之间的缝隙,就是权限语义漂移的发生空间。全文将围绕这条主线展开。

二、背景与问题定义:sudo 的授权模型与语义漂移

2.1 sudo 的授权单元拆解

要谈“配置写错”,先要明确“配置到底在约束什么”。sudoers 的一条规则由四部分组成:用户规格(User_Spec)、主机规格(Host_Spec)、运行身份(Runas_Spec)和命令规格(Cmnd_Spec)。其中命令规格又可细分为命令路径、参数匹配(含通配符)、标签(如 NOPASSWD、SETENV、NOEXEC)等。sudo 官方手册(sudo.ws/man/current/sudoers.man.html)对匹配规则有明确定义:命令参数采用“glob 风格”的模式匹配,且匹配的是 sudo 收到的参数字符串,而不是程序内部解析后的语义。

这就引出一个关键区分:“命令级授权”与“行为级授权”不是一回事。sudo 只能做到前者。当被授权程序本身具备“执行其他程序”“写任意文件”“加载任意模块”的能力时,命令级授权就会退化为行为级授权的超集。本文评述:把 sudo 当作“细粒度 RBAC”来用,是一种常见的认知错位;它更接近“带身份切换的命令白名单”,而不是能力沙箱。

2.2 什么是“权限语义漂移”

本文把“权限语义漂移”定义为:配置文本在语法上表达的是权限集合 A,但由于匹配机制、程序行为或环境继承的作用,实际授予的权限集合 B 严格包含 A,且 B 中存在可导致身份越权的元素。漂移的方向几乎总是“放大”,因为攻击者会主动寻找 A 与 B 的差集。

漂移的来源可以归为三类:其一,匹配层漂移——通配符、正则、参数前缀匹配导致“本不该匹配的命令”被匹配;其二,程序层漂移——被授权程序具有超出预期的副作用(写文件、起子进程、加载配置);其三,环境层漂移——环境变量、PATH、动态库、配置文件被低权限用户控制,从而劫持 root 进程的行为。这三类来源分别对应后文第三章的五种写法。

2.3 威胁模型与边界条件

需要明确本文讨论的威胁模型:攻击者已获得目标主机上的一个普通本地账户(非 root),能够执行任意用户态代码、读写自己有权限的文件、设置自己的环境变量。攻击者不能直接读 sudoers(通常 0440),不能修改 /etc 下 root 拥有的文件。在这个模型下,sudo 配置缺陷是“本地提权(LPE)”的典型入口。

边界条件同样重要:如果目标启用了 SELinux/AppArmor 强制模式、启用了 sudo 的 use_pty 与 log_output、限制了 env_reset 且 env_check 严格,那么部分漂移路径会被削弱甚至阻断。本文在分析每种写法时,都会标注其“生效前提”,避免把条件性结论说成普遍结论。

三、原理拆解:五类“看似方便”的写法及其失效机理

本章是全文的技术核心。笔者把高频危险写法归纳为五类,每一类都对应一种“便利动机”,也对应一条可验证的漂移路径。为便于对照,先给出总览表。

写法类别 便利动机 漂移层 典型后果
通配符放行少写几条规则匹配层匹配到任意参数/任意路径
参数全放行避免“参数不匹配”报错程序层利用程序子命令/选项执行代码
脚本/解释器授权一条规则覆盖多种任务程序层解释器执行任意脚本
NOPASSWD 滥用自动化免交互认证层凭据失守即静默提权
环境继承不设限让命令“照常工作”环境层PATH/库/配置劫持

3.1 通配符放行:匹配的是字符串,不是意图

sudoers 中 * 匹配任意字符序列(包括空格与斜杠),? 匹配单字符,[...] 匹配字符集。很多管理员用 /usr/bin/systemctl * 或 /bin/cat /var/log/* 来“图省事”。问题在于,* 的匹配对象是 sudo 命令行参数拼接后的字符串,攻击者完全可以通过参数构造让匹配成立、同时让程序行为偏离预期。

以 /bin/cat /var/log/* 为例,看似只能读日志,但 cat 支持多个文件参数,攻击者可构造 sudo cat /var/log/../../etc/shadow——路径穿越后仍以 /var/log/ 开头,通配符匹配通过,实际读取的是 shadow。本文评述:这类问题的根因不是 cat 有漏洞,而是“路径前缀匹配”被误当成“目录约束”。sudo 没有路径规范化后再匹配的语义,.. 不会被折叠。

更危险的是把通配符用在“可执行文件路径”上,例如 /usr/local/bin/*。若该目录对普通用户可写(现实中并不罕见,尤其是部署脚本创建的目录),攻击者放入同名或任意脚本即可获得 root 执行。验证方法很简单:sudo -l 列出规则后,逐条检查通配符覆盖的目录权限,find /usr/local/bin -maxdepth 0 -perm -o+w 即可确认。

加固要点:能用精确参数就不用通配符;必须用通配符时,把可变部分限制在“不含 / 与 ..”的字符类中,例如 [a-zA-Z0-9_-]*,并确保被匹配目录 root 拥有且不可写。

3.2 参数全放行:把“命令”当成“能力”

第二类写法是不写参数约束,直接 ALL=(ALL) /usr/bin/xxx。sudo 的语义是“该命令的任意参数都允许”。于是任何“能执行子进程、能写文件、能加载配置”的程序都会成为提权跳板。GTFOBins(gtfobins.github.io)系统整理了这类“合法二进制被滥用”的清单,截至 2024 年收录的 Unix 二进制超过 400 个,其中相当比例在 sudo 场景下可直接获得 shell。

典型例子包括:find 的 -exec、vi/vim 的 :!sh、less 的 !command、awk 的 system()、tar 的 --checkpoint-action=exec、git 的 -c core.pager 等。这些都不是漏洞,而是程序的设计功能。sudo 授权了程序,就等于授权了它的全部功能面。

笔者认为,判断一条规则是否“参数全放行危险”,可以用一个简单的启发式:问自己“这个程序能不能在不开新终端的情况下执行另一条命令、写一个我能指定的路径、或读取一个我能指定的文件”。三者任一为“是”,就应视为高危,必须加参数白名单或改用专用包装脚本。

3.3 脚本与解释器授权:一条规则等于一把万能钥匙

比参数全放行更彻底的是直接授权解释器:ALL=(ALL) /usr/bin/python3、/bin/bash、/usr/bin/perl。这等价于直接给 root shell,几乎没有讨论余地。但现实中更隐蔽的是“授权一个脚本”,例如 ALL=(ALL) /opt/ops/restart.sh。看起来约束到了具体文件,实际上有两个坑:其一,脚本若对普通用户可写,攻击者直接改脚本内容;其二,脚本内部调用的命令若未使用绝对路径,会受 PATH 影响(见 3.5)。

还有一种常被忽略的情形:脚本通过 sudo 授权后,其“解释器行”与“文件权限”共同决定安全性。若脚本是 #!/bin/bash 且属主为 root、权限 0755,攻击者不能改内容,但若脚本内部有 source 或 . 引入用户可写配置文件,仍可注入。本文评述:脚本授权的安全前提不是“文件不可写”这一条,而是“文件及其所有依赖(配置、被调命令、临时目录)都在 root 信任域内”。

# 反面示例:脚本内部使用相对命令,受 PATH 影响
#!/bin/bash
systemctl restart nginx   # 若 PATH 被劫持,可能执行攻击者的 systemctl
# 加固写法:绝对路径 + 固定 PATH
#!/bin/bash
export PATH=/usr/sbin:/usr/bin:/sbin:/bin
/usr/bin/systemctl restart nginx

3.4 NOPASSWD 滥用:认证层的“静默放大”

NOPASSWD 本身不是漏洞,它的设计目的是支持自动化。但它改变了攻击模型:有密码时,攻击者需要先拿到该用户的密码或会话;无密码时,只要拿到该用户的任意代码执行能力(例如通过一个 Web 应用 RCE、一个被投毒的 crontab),就能直接调用 sudo 完成提权,且不留下“密码尝试”的日志特征。

更微妙的是 NOPASSWD 与“命令参数可控”的叠加。若规则是 NOPASSWD: /usr/bin/tee /etc/sudoers.d/ops,本意是让运维写一个固定文件,但 tee 的参数若可被通配符覆盖,攻击者可写入任意内容,直接给自己加一条 ALL ALL=(ALL) NOPASSWD: ALL。这类“配置写配置”的链式放大,是 NOPASSWD 场景下最值得警惕的模式。

从审计角度,建议把 NOPASSWD 规则单独导出并逐条复核:grep -rn "NOPASSWD" /etc/sudoers /etc/sudoers.d/。对每条规则回答三个问题:谁可以触发?触发需要什么前置条件?触发后能写哪些路径、起哪些进程?答不上来的,一律降级为需要密码或改为专用命令。

3.5 环境继承不设限:被忽视的“第三输入”

sudo 默认启用 env_reset,会清理大部分环境变量,但仍会保留一部分(如 TERM、LANG 等,具体由 env_keep 决定)。若管理员为了“让命令正常工作”而扩大 env_keep,例如保留 PATH、LD_PRELOAD、PYTHONPATH、PERL5LIB,就等于把 root 进程的部分行为控制权交给了普通用户。

其中 LD_PRELOAD 与 LD_LIBRARY_PATH 最为典型:前者可让 root 进程加载攻击者指定的共享库,后者可让动态链接器优先从攻击者目录找库。sudo 对这两个变量有专门防护(默认在 env_reset 下不保留),但一旦被 env_keep 显式放行,防护即失效。本文评述:环境层的危险在于“它不在 sudoers 的命令列表里”,很多审计工具只检查命令路径,不检查 env_keep,导致这类问题长期潜伏。

此外,secure_path 是 sudo 提供的一道重要防线:它在执行命令时把 PATH 固定为受信任目录。若配置中未启用 secure_path,或 secure_path 包含了用户可写目录(如 /usr/local/bin 且该目录 0777),则 3.3 中的相对命令问题会被放大。验证命令:sudo -V | grep -i secure_path。

四、关键案例与数据:从 CVE 到真实配置审计

4.1 公开漏洞折射的同类问题

sudo 自身历史上出现过若干严重漏洞,它们与本文讨论的“配置漂移”形成互补视角。CVE-2021-3156(Baron Samedit)是 sudo 在处理命令行参数时的堆溢出,影响 sudo 1.8.2 至 1.9.5p1,攻击者无需在 sudoers 中即可触发,Qualys 在 2021 年 1 月的分析报告中给出了完整利用链(Qualys Security Advisory, "sudo: Heap-Based Buffer Overflow", 2021)。CVE-2019-14287 则允许在特定 Runas 配置下通过 -u#-1 绕过用户限制,本质是“身份规格解析”的边界问题。

本文评述:这两个漏洞提醒我们,sudo 的攻击面有两层——程序实现层与配置语义层。补丁能解决前者,但后者需要持续的配置治理。把安全投入全部押在“打补丁”上,会系统性忽略配置层这个更大的、长期存在的暴露面。

4.2 配置审计的量化观察

为量化“危险写法”的普遍程度,笔者参考了近年公开的配置审计类研究与社区统计。需要说明:以下数字中,标注“模拟”的为笔者基于公开规则样本做的整合估算,用于说明量级,不作为精确统计。

观察项 量级/比例 数据性质与来源说明
含通配符的 sudo 规则占比约三成模拟整合估算,基于公开配置样本归纳
授权解释器/脚本的规则占比约一成模拟整合估算
启用 NOPASSWD 的主机比例较高,常见于自动化场景定性观察,来源为社区运维实践讨论
GTFOBins 收录的可滥用二进制数400+(持续增长)gtfobins.github.io 公开清单

需要强调,上述比例只用于说明“这不是个别现象”,不用于推断总体分布。真实环境中,规则数量、业务复杂度、运维习惯差异极大,任何单一比例都不具备普适性。笔者认为,比“比例”更有价值的是“模式”:只要存在“通配符 + 高能力程序”或“NOPASSWD + 可写路径”的组合,风险就是确定的,与统计无关。

4.3 一条可复现的验证链

下面给出一条在实验环境中可复现的验证链,用于说明“看似无害的规则如何被放大”。实验环境为 Ubuntu 22.04、sudo 1.9.9,配置为 test ALL=(ALL) NOPASSWD: /usr/bin/find。该配置在语法上完全合法,意图是“让 test 用户查找文件”。

# 以 test 身份执行,利用 find 的 -exec 获得 root shell
sudo find /tmp -name x -exec /bin/sh -p \; -quit
# 结果:获得 euid=0 的 shell(实验环境验证,仅用于授权测试)

这条链的关键不在 find,而在于“授权了 find 的全部功能面”。若规则改为 /usr/bin/find /var/log -name "*.log" -type f 并配合严格的参数白名单,则 -exec 无法被注入。本文评述:加固的本质不是“禁用 find”,而是“把授权从程序级收缩到参数级”,这正是后文操作路径的核心思想。

五、对比与局限:加固方案的能力边界

5.1 常见加固手段的对比

面对上述风险,业界常见的手段包括:精确参数白名单、专用包装脚本、sudo 插件(如 sudo_pair、sudo 的 Python 插件)、强制访问控制(SELinux/AppArmor)、以及把高危操作从 sudo 迁移到受控的编排系统(如通过 CI/CD 或堡垒机执行)。下表从“阻断能力、运维成本、可审计性”三个维度做定性对比。

手段 阻断能力 运维成本 主要局限
精确参数白名单中高中参数组合爆炸,难穷举
专用包装脚本高中高脚本自身需审计,易引入新坑
SELinux/AppArmor高高策略复杂,误报与兼容成本高
sudo 插件中中依赖版本,维护者少
迁移到编排系统高高改造周期长,需组织配合

5.2 为什么没有“一劳永逸”

上述手段各有边界。精确参数白名单的问题是组合爆炸:一个命令若有 20 个选项,两两组合就有数百种,管理员很难穷举“安全子集”。专用包装脚本的问题是把风险转移:脚本本身若写得不好(相对路径、未校验输入、临时文件竞态),反而制造新的提权点。SELinux 的问题是可运维性:策略一旦过严,业务中断,团队往往选择 permissive,防护形同虚设。

本文评述:安全的本质是“把攻击面收缩到可审计的范围内”,而不是“消灭所有可能性”。因此,合理的策略是分层:用精确参数白名单处理高频、低复杂度的命令;用包装脚本处理复杂业务;用强制访问控制兜底;用日志与告警做检测。任何单点方案都不应被当作终点。

5.3 检测侧的局限

检测同样有边界。基于日志的检测依赖 sudo 的日志完整性:若未启用 log_output 与集中式日志,攻击者可在提权后清理本地日志。基于配置扫描的检测依赖规则库的覆盖面:新出现的“可滥用二进制”需要持续更新。笔者认为,检测的价值不在于“抓住每一次”,而在于“提高攻击成本、缩短驻留时间”,这与配置加固是互补而非替代关系。

六、操作路径:从写法纠偏到工程化治理

本章给出可落地的操作路径,分为“立即纠偏”“规则重构”“持续治理”三个阶段。每一步都给出具体命令或检查项,便于直接执行。

6.1 第一阶段:立即纠偏(1–2 天)

目标是把“确定高危”的规则先处理掉。操作步骤:其一,导出全部规则并分类,命令为 sudo -l -U <user> 逐用户查看,或直接 grep -rnE "NOPASSWD|ALL|\*" /etc/sudoers /etc/sudoers.d/;其二,标记三类高危:授权解释器(bash/python/perl/sh)、授权高能力程序且无参数约束(find/vi/tar/git/awk)、通配符覆盖可写目录;其三,对每条高危规则,先改为“需要密码 + 精确参数”,观察一周业务影响,再决定是否保留。

操作提醒:修改 sudoers 必须用 visudo 或 visudo -f /etc/sudoers.d/xxx,它会在保存前做语法检查,避免“改错一行导致所有人无法 sudo”的灾难。切勿用编辑器直接改。

6.2 第二阶段:规则重构(1–2 周)

重构的核心思想是“把授权从程序级收缩到参数级,把复杂逻辑封装到受控脚本”。具体做法:对每个业务场景,先问“最小必要动作是什么”,再写规则。例如“重启 nginx”不应授权 systemctl 全量,而应写一个 root 拥有的脚本 /usr/local/sbin/restart-nginx.sh,内部固定命令与路径,sudoers 只授权该脚本且不允许参数:ops ALL=(root) /usr/local/sbin/restart-nginx.sh ""。注意末尾的 "" 表示“不接受任何参数”,这是 sudoers 中限制参数为空串的写法。

同时启用几项基础防护:Defaults env_reset、Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"、Defaults use_pty、Defaults log_output。其中 use_pty 可缓解部分 TTY 注入类攻击,log_output 把会话输出写入日志,便于事后取证。本文评述:这些 Defaults 不是“可选项”,而是现代 sudo 配置的基线,缺失它们会让后续所有加固打折。

# /etc/sudoers.d/00-baseline 基线示例
Defaults env_reset
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Defaults use_pty
Defaults log_output
Defaults timestamp_timeout=5
# 业务规则:只允许执行固定脚本,且不接受参数
ops ALL=(root) /usr/local/sbin/restart-nginx.sh ""

6.3 第三阶段:持续治理(长期)

治理的关键是“把配置纳入版本管理与自动化检查”。建议做法:其一,把 /etc/sudoers.d/ 纳入 Git 或配置管理(Ansible/Puppet),所有变更走评审;其二,在 CI 中加入静态检查,规则可参考 sudo 官方手册与 GTFOBins 清单,检测“解释器授权”“无参数约束的高能力程序”“通配符覆盖可写目录”三类模式;其三,定期做“规则有效性复核”,删除长期未触发的规则(可通过日志统计),减少攻击面。

检测规则示例(伪代码,便于移植到自建扫描器):对每条 Cmnd_Spec,若命令 basename 属于高危集合且参数部分为空或为 *,则告警;若参数含 * 且命令路径所在目录 o+w,则告警;若存在 env_keep 包含 LD_*、PYTHONPATH、PATH,则告警。本文评述:自动化检查的价值在于“把专家经验固化成规则”,让配置评审不再依赖个人记忆。

延伸阅读与工具:sudo 官方手册(sudo.ws/docs/man)、GTFOBins(gtfobins.github.io)、Linux 权限提升方法论(HackTricks: Linux Privilege Escalation)、以及 sudo 项目公告页(sudo.ws/security/advisories)用于跟踪最新漏洞。

七、结论与展望

回到开头的问题:visudo 里哪些写法“看似方便实则把 root 权限拱手让人”?本文的答案是五类——通配符放行、参数全放行、脚本/解释器授权、NOPASSWD 滥用、环境继承不设限。它们的共同机理是“权限语义漂移”:sudo 匹配的是命令字符串,而攻击面是程序行为,两者之间的缝隙被便利性不断放大。笔者认为,理解这条主线,比记住具体规则更重要,因为具体的高危程序会变,而“程序级授权 ≠ 行为级授权”这个判断标准是稳定的。

展望未来,两个方向值得关注。其一,sudo 生态正在向“可插拔策略”演进,官方与社区插件可以在命令执行前做更细粒度的检查(如参数语义解析、路径规范化),这有望把部分漂移在运行时拦住。其二,随着基础设施即代码的普及,sudoers 的“配置即代码”治理会成为主流,静态检查与策略测试(policy-as-code)将取代人工评审。本文评述:技术手段在进步,但“最小权限”的原则不会变;任何便利性设计,都应当先回答“它把哪些权限悄悄放大了”。

主要参考文献

  1. sudo 项目组. sudoers 手册(sudoers.man),sudo.ws,持续更新.
  2. Qualys Security Advisory. CVE-2021-3156: Heap-Based Buffer Overflow in sudo(Baron Samedit), 2021.
  3. NIST. NIST SP 800-53 Rev.5: Security and Privacy Controls(AC-6 最小权限相关条目), 2020.
  4. MITRE. CWE-269: Improper Privilege Management;CWE-78: OS Command Injection.
  5. GTFOBins 社区. GTFOBins: Unix binaries exploitable in restricted environments, gtfobins.github.io.
  6. Red Hat. Security Guide: Managing sudo access(RHEL 文档),2023.
  7. Ubuntu 文档团队. Ubuntu Server Guide: User Management and sudo, 2023.
  8. HackTricks. Linux Privilege Escalation: Sudo(社区维护),2024.
  9. 本文模拟数据说明:第四章表格中“规则占比”为基于公开配置样本的整合估算,非精确统计,仅用于说明量级;实验验证链在 Ubuntu 22.04 + sudo 1.9.9 环境完成,仅用于授权测试。

文章声明:本文内容仅为作者学习、思考、经验、笔记的总结,仅供技术交流与参考。文中观点仅代表笔者个人思辨,不构成任何学术建议、商业建议或专业建议。所有数据来源已标注,引用时请以原始文献为准。

内容仅供学习参考。如需引用,请以原始文献为准。 全文约 7800 字 | 参考文献 60+ 篇(主要列出 9 篇)。

🔒 复制本站文章内容需登录并达到 L3。当前:未登录

分享到

💬
微信
📷
朋友圈
🐧
QQ好友
🌐
QQ空间
👁
微博
📌
钉钉
🔗
复制链接
📑
复制图文

微信扫一扫分享

打开微信「扫一扫」,扫描二维码后在微信中分享给好友或朋友圈。

💬 评论 (0)

评论功能已关闭

⏸️ 本站暂未开放评论功能,不能进行评论,此为规划的后续开发预留
首页| 关于本网| 网站声明| 联系我们| 网站纠错| 服务| 网站地图
黔ICP备19010680号-1  |  邮箱:six528528@163.com
贵公网安备 52010302001819号
Copyright 2019-2026 http://www.databrush.com/ All rights reserved.
QQ
QQ扫一扫
Logo
DBN数据刷