2021年1月,一个编号CVE-2021-3156的漏洞让全球服务器管理员集体失眠。攻击者只需输入一条带反斜杠的命令,就能从普通用户秒变root。但安全研究员在挖这个洞时,意外发现了另一件事——Sudo的程序员用了一种堪称"玄学"的方式判断自己是谁。
这个判断逻辑离谱到:你把Sudo改名叫"anythinglongerthan4edit",它立刻觉得自己是sudoedit。
更魔幻的是,这个bug存在了至少10年,直到CVE-1-3156的补丁发布3天后,才被顺手修掉。
一个"偷懒"的判断,成了权限绕过的后门
Sudo和sudoedit其实是同一个二进制文件。sudoedit只是指向sudo的符号链接(Symbolic Link),sudo启动时会检查自己的名字,决定该以哪种模式运行。
这是2011年就写死的逻辑:
代码先获取程序名progname,然后计算长度proglen。如果长度大于4,且最后4个字符是"edit",就认定自己是sudoedit。
换句话说,"myfancyedit"能通过检测,"sudoedit"当然也能。但"edit"不行——长度不够4,被拦在外面。
研究员的第一反应很直接:如果我把二进制拷贝成"hackedit"或者"notsudoedit"呢?
答案是可以。系统会把它当sudoedit用,但某些安全检查可能没跟上。这种"身份错乱"在权限系统里通常是灾难性的。
补丁来得悄无声息,几乎没人注意到
CVE-2021-3156的官方补丁在2021年1月26日发布。3天后,一个看似"顺带"的提交改了程序名判断逻辑:
新代码直接用strcmp比对,必须是完整的"sudoedit"才算数。同时加了一行valid_flags = EDIT_VALID_FLAGS,把编辑模式下的合法标志位锁死。
提交注释写得很平淡:"The program name may now only be 'sudo' or 'sudoedit'."
没有CVE编号,没有安全通告,没有媒体报导。大多数管理员升级Sudo时,根本不知道这个补丁堵上了另一条路。
老代码的注释说"The plugin API includes the program name (either sudo or sudoedit)",实际代码却是"是sudoedit,或其他任何东西"。
这种注释和实现脱节的现象,在 legacy 代码(遗留代码)里并不少见。但出现在权限管理的核心组件上,就值得玩味了。
为什么"大于4且以edit结尾"能活10年?
推测原因有几个层面。Sudo项目始于1980年,代码库里到处是历史包袱。那个字符串判断很可能来自某个早期版本,当时sudoedit还没从sudo分离,或者分离方式不同。
"大于4"这个条件本身就很谜。edit正好4个字符,所以"edit"本身不会触发,但"cedit""redit"都会。这可能是为了防止某些极端短的程序名导致越界,但写法极其粗糙。
更深层的问题是:这种"模糊匹配"在Unix传统里其实有先例。很多工具会通过argv[0](程序调用名)判断运行模式,比如busybox。但busybox的匹配通常是精确列表,而不是"后缀包含"。
Sudo的选择更像是"能跑就行"的妥协。在2011年那个提交之前,可能根本没人想过会有人故意利用这个特性。
研究员的Windows+WSL实测
作者在Windows 11的WSL(Windows Subsystem for Linux,Windows子系统 for Linux)环境里做了验证。Ubuntu默认安装的Sudo版本已经打过补丁,但旧版本的行为可以复现。
输入sudoedit --version,系统报错:"Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified"。
这个报错本身说明程序确实进入了sudoedit的分支逻辑。如果改名叫其他"xxedit",同样的命令行可能触发不同的权限检查路径。
具体能做什么?原文作者没深入,因为CVE-1-3156的主漏洞更紧急。但权限系统的"身份混淆"从来都是高危区——程序以为自己处于安全模式A,实际运行在模式B,中间的落差就是攻击面。
10年没人发现,3天就被修掉
时间线对比很有意思。CVE-2021-3156的堆溢出漏洞存在于Sudo 1.8.2到1.9.5p1,跨越近10年。程序名判断的bug同样古老,但直到主漏洞被公开,才有人顺手看了眼相关代码。
这符合安全研究的常态:高光漏洞会带动周边代码审查,很多"陈年暗病"因此被治愈。但也说明,没有CVE压力时,没人愿意碰legacy代码里的"怪味道"。
补丁发布后的版本里,程序名被严格限定为两个白名单值。这种"从模糊到精确"的修复模式,在权限系统里应该是默认做法,但历史代码的惯性太强。
Sudo维护者Todd C. Miller在这个项目里维护了超过30年。2021年的补丁风暴里,他一周内处理了多个相关提交。程序名限制那个补丁的提交信息简短到近乎敷衍,但改动本身干净利落。
现在的问题是:还有多少核心工具在用类似的"字符串魔术"判断运行模式?grep -r "strlen.*strcmp" /usr/bin 可能会给你惊喜。
热门跟贴