原理
背景知识:sudoedit 和命令参数解析
-
sudo是 Linux 上的权限提升工具,普通用户可以用它执行需要 root 权限的命令。 -
sudoedit是sudo的一个子命令,用来以 root 权限编辑文件。 -
当我们在命令里加
-s或-i选项时,sudo 会尝试进入 shell 模式。 -
在解析命令行参数时,sudo 需要对特殊字符(如空格、引号、反斜杠
\)做转义处理。
漏洞出在: sudo 在处理参数转义时,有一处内存复制(
heap buffer copy)写入越界,导致堆缓冲区溢出。
漏洞触发点
当以如下方式调用 sudoedit:
sudoedit -s '\' `perl -e 'print "A"x65536'`
-
-s选项要求 sudo 启动 shell。 -
参数中第一个反斜杠
'\'被当作转义字符处理。 -
sudo 在处理时错误地以为还需要再加一个字符,于是多分配了一个字节。
-
后面跟着巨长的
A(65536 个),于是触发堆缓冲区溢出。
背景:
sudoedit -s与参数处理
sudoedit -s表示让sudo启动一个 shell。
sudoedit会对传入的参数进行 shell escape / 转义处理,比如把\当作转义符处理。在处理参数字符串时,sudo 会计算 最终字符串长度,然后分配缓冲区。
反斜杠
\的处理
你传入的参数是:
'\' `perl -e 'print "A"x65536'`
第一个字符是
\。在 C 或 sudo 内部,
\是 转义字符,意思是“下一个字符被转义”。sudo 的逻辑:
if (c == '\\') {
// 预期后面跟一个字符需要转义
length += 2;
// 或者多分配一个字节?
}
问题出在 sudo 的长度计算:
它遇到
\,认为后面还需要一个字符进行转义。但是这里
\后面什么都没有(或者是被单引号包住),sudo 依然多分配了 1 个额外字节,以“容纳被转义的字符”。也就是说,sudo 的算法是:
分配长度 = strlen(原始参数) + 1(额外字节,用于转义处理)
这个“额外字节”在普通情况不会出问题,但遇到非常长的参数(65536 个 A)时,就可能触发 堆缓冲区溢出。
结合巨长参数
你用
perl -e 'print "A"x65536'生成了 65536 个字符。【sudo 内部缓冲区大小sudo 对参数做拷贝时,会在堆上分配一个缓冲区。这个缓冲区在代码里可能定义为 16 位整数来存长度,最大值就是 2^16 = 65536。】sudo 在计算缓冲区时:
需要分配的长度 = 65536 + 1(多分配的字节) = 65537
某些系统 malloc/堆管理器在这种边界长度上处理不当,可能导致 堆溢出。
为什么“多分配一个字节”会导致溢出?
sudo 内部有一个 固定长度缓冲区,比如 65536(2^16)字节。
多分配一个字节(65537)就超出了原有缓冲区的容量。
当 sudo 把参数复制进去时,最后多出来的 1 字节写入堆中 紧邻的内存,就触发了 堆缓冲区溢出。
具体成因
-
在
sudoers_policy.c和parse_args.c中,sudo 有一个函数用来解析参数并处理转义:while (*src) { if (*src == '\\') { *dst++ = *src++; } *dst++ = *src++; } -
正常情况下,
\用来保护后面的字符,不被当作特殊字符。 -
但
sudoedit -s的逻辑在处理参数列表时,没有正确计算需要拷贝到堆缓冲区的空间大小。 -
攻击者可以精心构造参数(含转义符+超长字符串),使得拷贝到堆中的内容超过预分配的内存块 → 覆盖堆上的相邻结构体数据(如函数指针)。
这就相当于:
你准备了一个小杯子(缓冲区),
结果被人往里灌了一桶水(超长参数),
水溢出来覆盖了桌上的其他物品(堆上相邻的数据)。
利用方式
-
因为 sudo 是 setuid root 程序(以 root 权限运行),
-
攻击者只要能控制溢出的数据,就有机会覆盖堆上的控制结构,例如:
-
service_user结构体的指针 -
函数返回地址
-
-
这样当 sudo 继续运行时,就会跳转到攻击者提供的 payload,
-
直接获得 root shell,无需知道任何密码。
环境准备
建议在虚拟机中测试,避免影响日常使用系统。
受影响的环境包括:
-
Ubuntu 20.04 / 19.04
-
Debian 10
-
CentOS 8
-
sudo版本在:-
1.8.2 – 1.8.31p2
-
1.9.0 – 1.9.5p1
-
查看 sudo 版本:
sudo --version
如果显示类似:
Sudo version 1.8.31
说明处于漏洞范围内。
漏洞验证命令
执行下面的命令(会触发 sudo 参数解析):
sudoedit -s '\' `perl -e 'print "A"x65536'`
命令解释
-
sudoedit -s
进入sudoedit模式,并尝试调用 shell。 -
'\''
构造转义字符,触发参数解析错误。 -
`perl -e 'print "A"x65536'`
使用 Perl 打印 65536 个A,构造超长参数,触发堆溢出。
结果观察
-
易受攻击系统:
会出现 Segmentation fault(进程崩溃),类似:Segmentation fault (core dumped) -
已修复系统:
会报参数错误:sudoedit: invalid option -- '\'
后续操作
-
如果验证出系统存在漏洞,可以进一步尝试利用公开的 Exploit 获取 root
修复方式
更新 sudo 到安全版本:
# Debian / Ubuntu sudo apt-get update && sudo apt-get install sudo
# CentOS / RHEL sudo yum update sudo
确认修复后,重新执行漏洞验证命令,应该不会再触发崩溃。


提权漏洞复现&spm=1001.2101.3001.5002&articleId=152178337&d=1&t=3&u=24916b8a20d444098a4dd901decf9aa9)
3731

被折叠的 条评论
为什么被折叠?



