【漏洞预警】Sudo 堆缓冲区溢出漏洞(CVE-2021-3156)

还未收到关于该漏洞补丁的消息,已经被证实该漏洞存在极大的安全隐患

原始帖子:Qualys研究团队已经在sudo中发现了一个堆溢出漏洞,该漏洞在类似Unix的主要操作系统上都可以使用。通过利用此漏洞,任何没有特权的用户都可以使用默认的sudo配置在易受攻击的主机上获得root特权。

Sudo是一个功能强大的实用程序,大多数(如果不是全部)基于Unix和Linux的操作系统都包含Sudo。它允许用户使用其他用户的安全特权运行程序。该漏洞本身已经隐藏了将近十年。它于2011年7月引入(提交8255ed69),在默认配置下会影响从1.8.2到1.8.31p2的所有旧版本以及从1.9.0到1.9.5p1的所有稳定版本。

成功利用此漏洞,任何没有特权的用户都可以在易受攻击的主机上获得root特权。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:协调发布日期(UTC下午6:00)

技术细节

如果执行了Sudo以在“ shell”模式下运行命令(shell -c命令):

  • 通过-s选项设置Sudo的MODE_SHELL标志;或者 要么
  • 通过-i选项,该选项设置Sudo的MODE_SHELL和MODE_LOGIN_SHELL标志;然后,在Sudo main()的开头,parse_args()通过连接所有命令行参数(第587-595行)并用反斜杠转义所有元字符(第590-591行)来重写argv(第609-617行) ):
-------------------------------------------------------------------- 
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[0] = (char *)user_details.shell; /* plugin may override shell */ 
610         if (cmnd != NULL) { 
611             av[1] = "-c"; 
612             av[2] = cmnd; 
613         } 
614         av[ac] = NULL; 
615  
616         argv = av; 
617         argc = ac; 
618     } 
--------------------------------------------------------------------- 

稍后,在sudoers_policy_main()中,set_cmnd()将命令行参数连接到基于堆的缓冲区“ user_args”(行864-871)中,并取消转义元字符(行866-867),“用于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[0] == '\\' && !isspace((unsigned char)from[1])) 
867                             from++; 
868                         *to++ = *from++; 
869                     } 
870                     *to++ = ' '; 
871                 } 
... 
884             } 
... 
886     } 
--------------------------------------------------------------------- 

不幸的是,如果命令行参数以单个反斜杠字符结尾,则:

  • 在866行,“ from [0]”是反斜杠字符,“ from [1]”是参数的空终止符(即,不是空格字符);
  • 在第867行,“ from”递增,并指向空终止符;
  • 在第868行,将空终止符复制到“ user_args”缓冲区,并再次从“ from”开始递增,并指向空终止符之后的第一个字符(即,超出参数的范围);
  • 第865-869行的“ while”循环读取越界字符并将其复制到“ user_args”缓冲区。

换句话说,set_cmnd()容易受到基于堆的缓冲区溢出的影响,因为复制到“ user_args”缓冲区的越界字符不包括在其大小中(在第852-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[ARG_SUDOEDIT].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[ARG_SUDOEDIT].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)攻击者甚至可以将空字节写入溢出的缓冲区(每个命令行参数或以单个反斜杠结尾的环境变量在866-868行将空字节写入“ user_args”)。

例如,在amd64 Linux上,以下命令分配一个24字节的“ user_args”缓冲区(一个32字节的堆块),并用“ A = a \ 0B = b \ 0”(0x00623d4200613d41)覆盖下一个块的大小字段。 ,其fd字段为“ C = c \ 0D = d \ 0”(0x00643d4400633d43),其bk字段为“ E = e \ 0F = f \ 0”(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覆盖范围

Qualys将在下表中发布QID,这些QID从vulnsigs版本VULNSIGS-2.5.90-4和Linux Cloud Agent清单版本lx_manifest-2.5.90.4-3开始可用。

QID标题操作系统咨询版*
352207 适用于sudo的Amazon Linux安全通报:ALAS2-2021-1590(Samedit先生)亚马逊Linux ALAS2-2021-1590VULNSIGS-2.5.94-2 / 2.5.94.4-3
352208适用于sudo的Amazon Linux安全建议:ALAS-2021-1478(Samedit男爵)亚马逊Linux ALAS-2021-1478VULNSIGS-2.5.94-2 / 2.5.94.4-3
174570sudo的SUSE Enterprise Linux安全更新(SUSE-SU-2021:0226-1)(Samedit男爵)SUSE Enterprise LinuxSUSE-SU-2021:0226-1VULNSIGS-2.5.94-2 / 2.5.94.4-3
174571sudo的SUSE Enterprise Linux安全更新(SUSE-SU-2021:0227-1)(男爵Samedit)SUSE Enterprise LinuxSUSE-SU-2021:0227-1VULNSIGS-2.5.94-2 / 2.5.94.4-3
174572sudo的SUSE Enterprise Linux安全更新(SUSE-SU-2021:0225-1)(Baredit Samedit)SUSE Enterprise LinuxSUSE-SU-2021:0225-1VULNSIGS-2.5.94-2 / 2.5.94.4-3
178379Debian的sudo安全更新(DSA 4839-1)(男爵Samedit)德比安DSA 4839-1VULNSIGS-2.5.94-2 / 2.5.94.4-3
198231Ubuntu的Sudo漏洞安全通知:USN-4705-1(Baron Samedit)的UbuntuUSN-4705-1VULNSIGS-2.5.94-2 / 2.5.94.4-3
374915Gentoo Linux Sudo多个漏洞(GLSA 202101-33)(Baron Samedit)GentooGLSA 202101-33VULNSIGS-2.5.94-2 / 2.5.94.4-3
158992适用于sudo的Oracle Enterprise Linux安全更新(ELSA-2021-0221)(男爵Samedit)Oracle企业LinuxELSA-2021-0221VULNSIGS-2.5.94-4 / 2.5.94.4-3
158993适用于sudo的Oracle Enterprise Linux安全更新(ELSA-2021-0218)(Baron Samedit)Oracle企业LinuxELSA-2021-0218VULNSIGS-2.5.94-4 / 2.5.94.4-3
158994适用于sudo的Oracle Enterprise Linux安全更新(ELSA-2021-9019)(男爵Samedit)Oracle企业LinuxELSA-2021-9019VULNSIGS-2.5.94-4 / 2.5.94.4-3
178383Debian的sudo安全更新(DLA 2534-1)(男爵Samedit)德比安DLA 2534-1VULNSIGS-2.5.94-4 / 2.5.94.4-3
239026sudo的Red Hat更新(RHSA-2021:0218)(男爵Samedit)红帽RHSA-2021:0218VULNSIGS-2.5.94-4 / 2.5.94.4-3
239027sudo的Red Hat更新(RHSA-2021:0219)(男爵Samedit)红帽RHSA-2021:0219VULNSIGS-2.5.94-4 / 2.5.94.4-3
239028sudo的Red Hat更新(RHSA-2021:0220)(男爵Samedit)红帽RHSA-2021:0220VULNSIGS-2.5.94-4 / 2.5.94.4-3
239029sudo的Red Hat更新(RHSA-2021:0221)(男爵Samedit)红帽RHSA-2021:0221VULNSIGS-2.5.94-4 / 2.5.94.4-3
239030sudo的Red Hat更新(RHSA-2021:0222)(男爵Samedit)红帽RHSA-2021:0222VULNSIGS-2.5.94-4 / 2.5.94.4-3
239031sudo的Red Hat更新(RHSA-2021:0223)(男爵Samedit)红帽RHSA-2021:0223VULNSIGS-2.5.94-4 / 2.5.94.4-3
239032sudo的Red Hat更新(RHSA-2021:0227)(男爵Samedit)红帽RHSA-2021:0227VULNSIGS-2.5.94-4 / 2.5.94.4-3
257056用于sudo安全更新的CentOS安全更新(CESA-2021:0221)(男爵Samedit)CentOS的CESA-2021:0221VULNSIGS-2.5.94-4 / 2.5.94.4-3
280866sudo的Fedora安全更新(FEDORA-2021-8840cbdccd)(男爵Samedit)软呢帽菲多拉-2021-8840cbdccdVULNSIGS-2.5.94-4 / 2.5.94.4-3
280868sudo的Fedora安全更新(FEDORA-2021-2cb63d912a)(Samedit男爵)软呢帽费多拉-2021-2cb63d912aVULNSIGS-2.5.94-4 / 2.5.94.4-3
352217适用于sudo的Amazon Linux安全通报:AL2012-2021-335(Samedit男爵)亚马逊LinuxAL2012-2021-335VULNSIGS-2.5.95-2 / 2.5.95.2-1
374891基于Sudo堆的缓冲区溢出漏洞(Baron Samedit)本地Sudo安全警报VULNSIGS-2.5.90-4 / 2.5.90.4-3

*版本是签名版本,后跟Linux清单版本。

常见问题(FAQ)

哪些版本易受攻击?

以下版本的sudo容易受到攻击:

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

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

要测试系统是否易受攻击,请以非root用户身份登录系统。

运行命令“ sudoedit -s /”

如果系统容易受到攻击,它将以“ sudoedit:”开头的错误作为响应。

如果对系统进行了修补,它将以“ usage:”开头的错误作为响应。

1.8.2之前的版本容易受到攻击吗?

否。请参见上面的说明。

我正在从上述列表中运行sudo的易受攻击版本。为什么测试显示我的主机不容易受到攻击?

操作系统供应商在向软件引入补丁程序后,并不总是更新软件的版本号,尤其是在向后移植补丁程序时。例如,Ubuntu发布了针对Ubuntu 20.04的补丁(USN-4705-1),但安装补丁后,补丁版本仍为1.8.31。

为什么在同一主机上看到同一CVE-2021-3156的多个QID?

Qualys在发布时发布了通用QID,该QID根据命令的输出检测到漏洞sudoedit。后来,随着OS供应商发布补丁,我们也基于软件包版本发布了QID。因此,有漏洞的资产可能会报告QID 374891的漏洞以及稍后发布的特定于操作系统的检查。

QID 374891不触发易受攻击的系统的可能原因是什么?

QID 374891与vulnsigs版本VULNSIGS-2.5.90-4和Linux Cloud Agent清单版本lx_manifest-2.5.90.4-3一起发布。为了报告这些漏洞,必须在平台上提供这些签名和清单版本(部署时间表有所不同),并且代理已使用签名的最新版本完成了扫描。

同样,Qualys根据各种Linux发行版发布的安全公告和补丁发布了更多的QID。因此,某些Linux发行版在其余版本之前就已经涉及了。例如,首先发布了Amazon Linux安全公告,并在几天后发布了CentOS公告和补丁。对CentOS linux的支持已添加到更高版本的vulnsigs和清单中。有关详细信息,请参见上表。

对于CVE-2021-3156,QID 374891与其余QID之间的检测逻辑有何区别?

QID 374891尝试根据命令输出确认漏洞sudoedit。其余QID根据基于OS供应商在其各自的安全公告中公开的版本的版本比较来确认该漏洞。

是否需要本地用户才能利用此漏洞?

是。但是,该用户不必是特权用户或sudoers列表的一部分。例如,即使帐户“没人”也可以利用此问题。

为什么将漏洞命名为“ Baron Samedit”?

这是萨米迪男爵和sudoedit的戏。

Qualys Research Team是否会发布此漏洞的利用代码? 

没有 

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
大佬不来一句? 抢沙发

请登录后发表评论