梦幻的彼岸 发表于 2021-1-28 13:47:01

CVE-2021-3156:Sudo中基于堆的缓冲区溢出 (Baron Samedit)

本帖最后由 梦幻的彼岸 于 2021-1-28 15:05 编辑

简述
原文:
https://blog.qualys.com/vulnerabilities-research/2021/01/26/cve-2021-3156-heap-based-buffer-overflow-in-sudo-baron-samedit

[*]作者:Animesh Jain

[*]2021年1月26日发布


static/image/hrline/1.gif


Qualys研究小组在sudo中发现了一个堆溢出漏洞,sudo是一个几乎无处不在的实用程序,可用于主要的类Unix操作系统。通过利用此漏洞,任何未经授权的用户都可以使用默认sudo配置在易受攻击的主机上获得root权限。


Sudo是一个强大的实用程序,它包含在大多数基于Unix和Linux的操作系统中。它允许用户以另一个用户的安全权限运行程序。近10年来,这个漏洞本身一直隐藏在人们的视线中。它于2011年7月引入(commit 8255ed69),在默认配置中影响从1.8.2到1.8.31p2的所有旧版本和从1.9.0到1.9.5p1的所有稳定版本。


成功利用此漏洞可使任何未经授权的用户在易受攻击的主机上获得根用户权限。Qualys安全研究人员已经能够独立验证该漏洞,开发多种漏洞变体,并在Ubuntu 20.04(Sudo 1.8.31)、Debian 10(Sudo 1.8.27)和Fedora 33(Sudo 1.9.2)上获得完整的root权限。其他操作系统和发行版也可能被利用。


Qualys研究团队确认该漏洞后,Qualys立即进行了负责任的漏洞披露,并协调sudo的作者和开源发行版公布该漏洞。

披露时间表
2021-01-13: 预警发送至Todd.Miller@sudo
2021-01-19: 向distros@openwall发送预警和补丁
2021-01-26: 协调发布日期(世界协调时下午6:00)
漏洞验证视频在线视频
https://www.bilibili.com/video/BV19y4y1173K/

本地保存

技术细节
如果在“shell”模式下执行 Sudo 以运行命令(shell-c 命令)
通过-s选项,设置Sudo的MODE_SHELL标志
通过-i 选项设置 Sudo 的 MODE shell 和 MODE login shell 标志; 然后,在 Sudo 的 main ()的开头,parse args ()通过串联所有命令行参数(第587-595行)和用反斜杠转义所有元字符(第590-591行)来重写 argv

------------------------------------------------------------
571   if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) {
572         char **av, *cmnd = NULL;
573         int ac = 1;
...
581             cmnd = dst = reallocarray(NULL, cmnd_size, 2);
...
587             for (av = argv; *av != NULL; av++) {
588               for (src = *av; *src != '\0'; src++) {
589                     /* quote potential meta characters */
590                     if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$')
591                         *dst++ = '\\';
592                     *dst++ = *src;
593               }
594               *dst++ = ' ';
595             }
...
600             ac += 2; /* -c cmnd */
...
603         av = reallocarray(NULL, ac + 1, sizeof(char *));
...
609         av = (char *)user_details.shell; /* plugin may override shell */
610         if (cmnd != NULL) {
611             av = "-c";
612             av = cmnd;
613         }
614         av = NULL;
615
616         argv = av;
617         argc = ac;
618   }
------------------------------------------------------------
稍后,在sudoers\u policy\u main()中,set\cmnd()将命令行参数连接到基于堆的缓冲区“user\u args”(第864-871行)中,并取消对元字符(第866-867行)的scape,“用于sudoers匹配和日志记录目的”:

------------------------------------------------------------
819   if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
...
852             for (size = 0, av = NewArgv + 1; *av; av++)
853               size += strlen(*av) + 1;
854             if (size == 0 || (user_args = malloc(size)) == NULL) {
...
857             }
858             if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
...
864               for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
865                     while (*from) {
866                         if (from == '\\' && !isspace((unsigned char)from))
867                           from++;
868                         *to++ = *from++;
869                     }
870                     *to++ = ' ';
871               }
...
884             }
...
886   }
------------------------------------------------------------
不幸的是,如果命令行参数以单个反斜杠字符结尾,则:

在第866行,“ from ”是反斜杠字符,“ from ”是参数的 null 结束符(即,不是空格字符) ;
在第867行,“ from”递增,并指向null 结束符;
在第868行,null 结束符被复制到“ user _ args”缓冲区,“ from”再次递增并指向 null 结束符之后的第一个字符(即超出参数的边界) ;
第865-869行的“ while”循环读取超出界限的字符并将其复制到“ user _ args”缓冲区。
换句话说,set cmnd ()容易受到基于堆的缓冲区溢出的影响,因为复制到“ user args”缓冲区的界外字符没有包含在其大小中(计算在 lines852-853)。


然而,理论上,任何命令行参数都不能以单个反斜杠字符结束: 如果设置了 MODE shell 或 MODE login shell (第858行,这是到达易受攻击代码的必要条件) ,那么设置了 MODE shell (第571行) ,并且 parse _ args ()已经转义了所有元字符,包括反斜杠(即,它用第二个反斜杠对每个反斜杠进行转义)。
但实际上,set_cmnd()中的弱势代码和parse_args()中的转义代码周围的条件略有不同:


------------------------------------------------------------
819   if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
...
858             if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
------------------------------------------------------------
对比:

------------------------------------------------------------
571   if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) {
------------------------------------------------------------
我们的问题是: 我们是否可以设置 MODE shell 和 MODE edit 或 MODE check (以达到易受攻击的代码) ,而不设置默认的 MODE run (以避免转义代码) ?


答案似乎是否定的: 如果我们设置 MODE edit (- e 选项,第361行)或 MODE check (- l 选项,第423和519行) ,然后 parse args ()从“ valid flags”(第363和424行)中删除 MODE shell,如果我们指定无效的标志如 MODE shell (第532-533行) ,则退出时将出现错误:


------------------------------------------------------------
358               case 'e':
...
361                     mode = MODE_EDIT;
362                     sudo_settings.value = "true";
363                     valid_flags = MODE_NONINTERACTIVE;
364                     break;
...
416               case 'l':
...
423                     mode = MODE_LIST;
424                     valid_flags = MODE_NONINTERACTIVE|MODE_LONG_LIST;
425                     break;
...
518   if (argc > 0 && mode == MODE_LIST)
519         mode = MODE_CHECK;
...
532   if ((flags & valid_flags) != flags)
533         usage(1);
------------------------------------------------------------
但我们发现了一个漏洞:如果我们以 "sudoedit "而不是 "sudo "的方式执行Sudo,那么parse_args()会自动设置MODE_EDIT(第270行),但不会重置 "valid_flags",而且 "valid_flags "默认包括MODE_SHELL(第127行和249行)

------------------------------------------------------------
127 #define DEFAULT_VALID_FLAGS   (MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_SHELL)
...
249   int valid_flags = DEFAULT_VALID_FLAGS;
...
267   proglen = strlen(progname);
268   if (proglen > 4 && strcmp(progname + proglen - 4, "edit") == 0) {
269         progname = "sudoedit";
270         mode = MODE_EDIT;
271         sudo_settings.value = "true";
272   }
------------------------------------------------------------
因此,如果我们执行“ sudoedit-s”,然后我们同时设置 MODE edit 和 MODE shell (但不设置 MODE run) ,我们就避免了转义代码,达到了易受攻击的代码,并且通过一个以一个反斜杠字符结尾的命令行参数溢出了基于堆的缓冲区“ user args”:


------------------------------------------------------------
sudoedit -s '\' `perl -e 'print "A" x 65536'`
malloc(): corrupted top size
Aborted (core dumped)
------------------------------------------------------------
从攻击者的角度来看,这种缓冲区溢出是理想的,原因如下:


1)攻击者控制可以溢出的“ user _ args”缓冲区的大小(串联的命令行参数的大小,在第852-854行) ;


2)攻击者独立控制溢出本身的大小和内容(我们最后的命令行参数后面跟着我们的第一个环境变量,这些变量不包括在第852-853行的大小计算中) ;


3)攻击者甚至可以向溢出的缓冲区写入空字节(每个命令行参数或者以一个反斜杠结尾的环境变量向“ user _ args”写入一个空字节,第866-868行)。


例如,在 amd64 Linux 上,下面的命令分配一个24字节的“ user _ args”缓冲区(一个32字节的堆块) ,并用“ a = a 0B = b0”(0x00623d4200613d41)覆盖下一个块的大小字段,用“ c = c 0D = d 0”(0x00643d4400633d43)覆盖其 fd 字段及其 bk 字段“ e = e0f = f0”(0x00663d4600653d45) :


------------------------------------------------------------
env -i 'AA=a\' 'B=b\' 'C=c\' 'D=d\' 'E=e\' 'F=f' sudoedit -s '1234567890123456789012\'
------------------------------------------------------------

--|--------+--------+--------+--------|--------+--------+--------+--------+--
|      |      |12345678|90123456|789012.A|A=a.B=b.|C=c.D=d.|E=e.F=f.|
--|--------+--------+--------+--------|--------+--------+--------+--------+--

            size<---- user_args buffer ---->size      fd       bk
解决方案
鉴于该漏洞的攻击面很广,Qualys建议用户立即应用该漏洞的补丁。
Qualys客户可以在漏洞知识库中搜索CVE-2021-3156,以确定所有易受此漏洞影响的QID和资产。
如果您不是客户,请开始您的免费Qualys VMDR试用版,以获得对CVE-2021-3156的QIDs(检测)的完整访问权限,这样您就可以识别您的易受攻击的资产。
Qualys 覆盖范围
QID 374891: Sudo Heap-based Buffer Overflow 漏洞。


该QID在vulnsigs版本VULNSIGS-2.5.90-4和Linux Cloud Agent manififest版本lx_manifest-2.5.90.4-3中可用。

仪表版
通过 VMDR Dashboard,您可以实时跟踪这个漏洞、它们所影响的主机、它们的状态和总体管理。通过为仪表板小部件启用趋势,您可以使用“ Baron Samedit | Heap-based buffer overflow Sudo”仪表板跟踪环境中的这些漏洞趋势。


查看和下载 Baron Samedit 仪表板。


供应商参考资料

[*]Baron Samedit 安全建议(所有 Qualys 安全建议)
[*]Baron Samedit 的 Sudo 警报(所有 Sudo 安全警报)
常见问题解答 (FAQs)
哪些版本容易受到攻击?
以下版本的 sudo 易受攻击:

[*]从1.8.2到1.8.31p2的所有旧版本
[*]从1.9.0到1.9.5p1的所有稳定版本

如何测试我是否有易受攻击的版本?

[*]要测试系统是否易受攻击,请以非 root 用户登录系统。
[*]运行命令“sudoedit -s /”
[*]如果系统易受攻击,它将响应以“sudoedit:”开头的错误
[*]如果系统打了补丁,它将以一个以“usage:”开头的错误响应

1.8.2之前的版本容易受到攻击吗?
没有。见上文解释。
是否需要一个本地用户来利用这个漏洞?
是的,但是这个用户不需要是特权用户或成为sudoers列表的一部分。例如,即使是账户 "nobody "也可以利用这个问题。
为什么把这个漏洞命名为 “Baron Samedit”?
这是对Baron Samedi和sudoedit的戏称。
Qualys 研究团队是否会发布此漏洞的利用代码?
不会。
补充
[*]检测脚本
来源:https://access.redhat.com/security/vulnerabilities/RHSB-2021-002
下载:https://access.redhat.com/sites/default/files/cve-2021-3156--2021-01-26-1453.sh


页: [1]
查看完整版本: CVE-2021-3156:Sudo中基于堆的缓冲区溢出 (Baron Samedit)