飘云阁安全论坛

 找回密码
 快速注册

QQ登录

只需一步,快速开始

查看: 514|回复: 0

[漏洞相关] CVE-2021-3156:Sudo中基于堆的缓冲区溢出 (Baron Samedit)

[复制链接]
  • TA的每日心情
    开心
    2019-3-15 11:00
  • 签到天数: 262 天

    [LV.8]以坛为家I

    发表于 2021-1-28 13:47:01 | 显示全部楼层 |阅读模式
    本帖最后由 梦幻的彼岸 于 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
      767964_MBD6QPSD9KHY8JC.png
    • 2021年1月26日发布





    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/

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

    [AppleScript] 纯文本查看 复制代码
    ------------------------------------------------------------
    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\u policy\u main()中,set\cmnd()将命令行参数连接到基于堆的缓冲区“user\u args”(第864-871行)中,并取消对元字符(第866-867行)的scape,“用于sudoers匹配和日志记录目的”:

    [AppleScript] 纯文本查看 复制代码
    ------------------------------------------------------------
    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]”是参数的 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()中的转义代码周围的条件略有不同:


    [AppleScript] 纯文本查看 复制代码
    ------------------------------------------------------------
    819     if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
    ...
    858             if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
    ------------------------------------------------------------

    对比:

    [AppleScript] 纯文本查看 复制代码
    ------------------------------------------------------------
    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行) ,则退出时将出现错误:


    [AppleScript] 纯文本查看 复制代码
    ------------------------------------------------------------
    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行)

    [AppleScript] 纯文本查看 复制代码
    ------------------------------------------------------------
    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”:


    [AppleScript] 纯文本查看 复制代码
    ------------------------------------------------------------
    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) :


    [AppleScript] 纯文本查看 复制代码
    ------------------------------------------------------------
    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 仪表板
    767964_MBD6QPSD9KHY8JC.png

    供应商参考资料
    常见问题解答 (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 研究团队是否会发布此漏洞的利用代码?
    不会。
    补充

    评分

    参与人数 1威望 +5 飘云币 +5 收起 理由
    Jongan + 5 + 5 PYG有你更精彩!

    查看全部评分

    您需要登录后才可以回帖 登录 | 快速注册

    本版积分规则

    快速回复 返回顶部 返回列表