CVE-2024-34331:Parallels Desktop权限提升漏洞分析

Parallels Desktop是macOS下的一个虚拟机软件,在其打包功能中存在一处安全性问题。本文通过利用 Parallels Desktop 对 macOS 安装程序的信任,进行本地权限提升 [1]。

漏洞详情

  • 受影响产品:Parallels Desktop for macOS [2]
  • 受影响主机:基于x86_64的主机(搭载Intel处理器的Mac)
  • 受影响版本:16.0.0 至 19.3.0
  • 修复版本:19.3.1
  • CVE编号:CVE-2024-34331

漏洞发现

在使用 Parallels 的大规模部署包进行测试时,使用了2018年款的 Intel Mac mini 和一个 macOS 虚拟机。在测试过程中注意到一个奇怪的现象,那就是在创建 macOS 虚拟机时,从未出现过密码提示。这不符合常理,因为Parallels 使用了苹果的 createinstallmedia程序,此程序需要 root 权限。经过进一步检查,通过一个名为 repack_osx_install_app.sh 的脚本确认了这一点,该脚本位于 Parallels Desktop.app/Contents/Resources 下:

CVE-2024-34331:Parallels Desktop权限提升漏洞分析

从以上bash脚本中可以看到,在运行 createinstallmedia 时并没有进行任何校验和验证,这可能是一个非常容易被利用的漏洞。但现在存在另一个疑问,Parallels 是如何在没有管理员凭据的情况下以 root 身份运行 createinstallmedia 程序的呢?

程序SUID位的魔力

在Unix系统中,存在多个权限标识(如Linux定义在cred结构体中):
  • UID (User ID) – 实际用户标识:指启动进程的用户的实际用户ID。例如,如果以用户名alice登录系统,那么该进程的UID就是alice的用户ID。
  • GID (Group ID) – 实际组标识:指启动进程的用户所属的实际组的组ID,表示用户所属的组。例如,如果alice属于组developers,那么该进程的GID就是developers的组ID。
  • EUID (Effective User ID) – 有效用户标识:在程序运行时用于权限检查的用户ID。它可以与UID相同,也可以不同,这取决于程序是否设置了特殊权限位,如Set-User-ID(SUID)。当程序具有SUID权限时,EUID通常会变为程序文件的所有者的用户ID。这允许程序以文件所有者的权限运行,通常用于提供临时的权限提升,例如passwd命令。
  • EGID (Effective Group ID) – 有效组标识:在程序运行时用于权限检查的组ID,程序具有SGID权限时,EGID通常会变为程序文件的所有者的组ID。
  • SUID (Set-User-ID) – 设置用户标识:SUID是一种文件权限,用于可执行文件,当设置了SUID位的可执行程序运行时,它的EUID将变为文件所有者的UID,而不是启动进程的实际UID。典型的例子是passwd程序,它需要以root权限更改密码。
  • SGID (Set-Group-ID) – 设置组标识:SGID是一种文件权限,类似于SUID,但是针对组。例如,某些目录需要以特定组的权限运行,以便其他用户可以访问其中的文件。
  • FSUID (Filesystem User ID) – 文件系统用户标识:在文件系统级别上用于权限检查的用户ID,确保文件系统上的访问权限正确。
  • FSGID (Filesystem Group ID) – 文件系统组标识:在文件系统级别上用于权限检查的组ID。
例如,要查看macOS下/usr/bin/top文件的权限,可以使用:
ls -la /usr/bin/top

# 输出结果为
-r-sr-xr-x  1 root  wheel  273520  6 15  2023 /usr/bin/top
对于上面的输出结果,root为所有者,所有者具有读取权限,s表示设置了 Set-User-ID(SUID)权限,当执行此文件时,进程的有效用户 ID(EUID)将变为文件所有者的用户 ID,而不是启动进程的实际用户 ID。wheel为文件所属的用户组,用户组成员具有可读和可执行权限,没有写权限。其他人(非所有者且非组成员)具有可读和可执行权限,没有写入权限。总之,/usr/bin/top文件是一个具有 SUID 权限的普通文件,它允许以 root 用户的权限运行 top 命令。
总结,这个 S-Bit 所做的是允许可执行文件将其 UID(用户 ID)更改为文件所有者的 UID。如果文件的所有者是 root,那么当前程序就可以以 root 身份运行了。
此外,可以通过以下命令查找到所有具有 S-Bit 的文件:
/usr/bin/find . -perm -u=s

Parallels历史权限提升漏洞

在ZDI发布的《BASH PRIVILEGED-MODE VULNERABILITIES IN PARALLELS DESKTOP AND CDPATH HANDLING IN MACOS》[3] 一文中,详细解释了SUID导致的 Parallels 提权问题。
在ZDI的文章中提到,Parallels Desktop有几个setuid二进制文件:prl_update_helper 和 Parallels Service,这两个二进制文件都以root权限运行,并且通过调用bash脚本来以root权限运行命令:

CVE-2024-34331:Parallels Desktop权限提升漏洞分析

对于在二进制程序中通过调用bash脚本来以root权限运行命令这类用例,bash提供专门的特权模式 [4] ,参数为“-p”。
在使用bash特权模式时,bash shell 会在有效用户标识与实际用户标识不相等时降低权限,有效用户标识被重置为实际用户标识的值。同样,组标识也适用于相同的规则。在特权模式下,bash 不会降低有效权限,并会忽略环境中的敏感变量和 shell 函数。以下是在 bash 的 shell.c 文件中找到的相关源代码:
int
main (argc, argv, env)
     int argc
;
     char **argv, **env;
{
. . .
  running_setuid = uidget ();
. . .
  if (running_setuid && privileged_mode == 0)
    disable_priv_mode ();
. . .
  shell_initialize ();
. . .
  if (locally_skip_execution == 0 && running_setuid == 0)
    {
. . .
      run_startup_files ();
这里的 uidget 函数在从 setuid/setgid 进程启动 bash 时设置 running_setuid。在下面代码中,如果未指定特权模式,则使用 setuid 和 setgid 调用将权限降低为实际标识的权限:
/* Fetch the current set of uids and gids and return 1 if we're running
   setuid or setgid. */

static int
uidget ()
{
  uid_t u;

  u = getuid ();
. . .
  current_user.uid = u;
  current_user.gid = getgid ();
  current_user.euid = geteuid ();
  current_user.egid = getegid ();

  /* See whether or not we are running setuid or setgid. */
  return (current_user.uid != current_user.euid) ||
           (current_user.gid != current_user.egid);
}

void
disable_priv_mode ()
{
  setuid (current_user.uid);
  setgid (current_user.gid);
  current_user.euid = current_user.uid;
  current_user.egid = current_user.gid;
}
通过以上两段bash源码,我们了解了bash特权模式专门针对于这种情景所做的权限控制。而在18.1.0版本之前的Parallels Desktop没有利用bash特权模式,也没有过滤不受信任的环境变量,这就导致本地权限提升。
在 Parallels Desktop 的情况中,二进制文件使用 setuid() 系统调用将真实用户标识设置为有效用户标识。这种实现的问题在于,敏感的环境变量(如 BASH_ENV、ENV、SHELLOPTS、BASHOPTS、CDPATH、GLOBIGNORE 和其他 shell 函数)会被 bash 处理。这是因为 bash 不知道 setuid 或 setgid 执行,并信任其环境。最终,具有对环境变量控制权的本地非特权用户可以利用此漏洞以 root 权限执行代码。
  • CVE-2023-27322(ZDI-23-216)- 通过Parallels服务进行本地权限提升
Parallels Service 会 fork 一个子进程,并使用一个非交互式的 bash shell(以 /bin/bash -s 形式调用)来执行嵌入的脚本。父进程通过管道将嵌入的脚本写入运行 bash shell 的子进程。在调用 bash shell 之前,Parallels Service 调用 setuid(0) 将真实用户标识设置为有效用户标识(root)。以下是 Parallels Desktop 版本 17.1.4 中可执行文件中的相关代码片段:
__text:000000010000603B loc_10000603B:                          ; CODE XREF: child_process+4D↑j
__text:000000010000603B ; child_process+68↑j
__text:000000010000603B call _geteuid
__text:0000000100006040 test eax, eax
__text:0000000100006042 jnz short loc_10000605B
__text:0000000100006044 call _getuid ; when effective uid is 0
__text:0000000100006049 mov ebx, eax
__text:000000010000604B call _geteuid
__text:0000000100006050 cmp ebx, eax ; check real uid == effective uid
__text:0000000100006052 jz short loc_10000605B
__text:0000000100006054 xor edi, edi ; uid_t
__text:0000000100006056 call _setuid ; setuid(0)
__text:000000010000605B
__text:000000010000605B loc_10000605B: ; CODE XREF: child_process+E2↑j
__text:000000010000605B ; child_process+F2↑j
__text:000000010000605B call _getuid
__text:0000000100006060 test eax, eax
__text:0000000100006062 jz short loc_1000060B9
__text:0000000100006064
__text:0000000100006064 loc_100006064: ; CODE XREF: child_process+162↓j
__text:0000000100006064 mov rdi, [r14] ; __path
__text:0000000100006067 mov rsi, r14 ; __argv
__text:000000010000606A call _execv
execv 函数是对 execve 的一个包装,它使用 _NSGetEnviron() 获取环境变量并将其传递给 execve。因此,作为子进程生成的 Bash shell 可以访问由启动 Parallels Service 的用户设置的所有环境变量,该用户可能是一个非特权用户。最终通过使用bash特权模式参数“-p”修复了此漏洞。
  • CVE-2023-27324 (ZDI-23-218)和 CVE-2023-27325(ZDI-23-219),通过Parallels Updater进行本地权限提升。这两处漏洞是在Parallels Updater prl_update_helper 二进制文件中发现的。在CVE-2023-27324中,prl_update_helper 二进制文件调用一个名为 inittool 的bash脚本,而无需设置特权模式:
        snprintf(&script_path, 0x400uLL, "%s/Contents/MacOS/inittool", appbundle_path);
        __argv[0] = &script_path;
        __argv[1] = "install";
        __argv[2] = "-t";
        __argv[3] = target_path;
        __argv[4] = 0LL;
    . . .
            v48 = posix_spawn(&v47.st_dev, &script_path, 0LL, 0LL, __argv, &_envp);

    CVE-2024-34331:Parallels Desktop权限提升漏洞分析

    在调用inittool脚本之前,将真正的用户标识符设置为有效用户标识符,即root。这意味着bash将作为root运行,并将信任其执行环境,这可能会导致本地特权升级:
    __text:0000000100005B90 start           proc near
    . . .
    __text:0000000100005B90
    __text:0000000100005B90 push rbp
    __text:0000000100005B91 mov rbp, rsp
    __text:0000000100005B94 push r15
    __text:0000000100005B96 push r14
    __text:0000000100005B98 push rbx
    __text:0000000100005B99 sub rsp, 0CD8h
    __text:0000000100005BA0 mov rax, cs:___stack_chk_guard_ptr
    __text:0000000100005BA7 mov rax, [rax]
    __text:0000000100005BAA mov [rbp+var_20], rax
    __text:0000000100005BAE cmp edi, 2
    __text:0000000100005BB1 jnz short loc_100005BD9
    __text:0000000100005BB3 mov rbx, rsi
    __text:0000000100005BB6 call _geteuid
    __text:0000000100005BBB test eax, eax
    __text:0000000100005BBD jz short loc_100005BF3 ; if effective uid == 0
    . . .
    __text:0000000100005BF3 loc_100005BF3: ; CODE XREF: start+2D↑j
    __text:0000000100005BF3 xor edi, edi ; uid_t
    __text:0000000100005BF5 call _setuid ; setuid(0)
    可以通过使用BASH_ENV环境变量或导出shell函数dirname来利用此漏洞:

    CVE-2024-34331:Parallels Desktop权限提升漏洞分析

    而 CVE-2023-27325 会影响从inittool脚本调用的inittool2可执行文件。与Parallels Service一样,inittool2 fork 子进程,并使用调用为/bin/bash -s的非交互式bash shell执行嵌入式脚本,漏洞利用方式与CVE-2023-27324相似。修复方案是,在调用posix_spawn时,envp参数没有将environ数组传递给子进程,而是提供了指向NULL数组的指针,并向inittool脚本的解释器以及inittool2中的嵌入式脚本中添加了bash特权模式“-p”。
更多细节可以参考链接 [3] 的文章,其中详细解释了SUID导致的 Parallels 提权问题。

历史总是惊人的相似

回到主题 CVE-2024-34331,在Parallels中找到了具有SUID标志的两个文件:

CVE-2024-34331:Parallels Desktop权限提升漏洞分析

由于在repack_osx_install_app.sh脚本中,运行 createinstallmedia 时并没有进行任何校验和验证,所以可以按照如下流程完成对权限提升的漏洞利用:
  1. 创建一个 macOS 安装程序应用,其中包含位于 Contents/Resources/createinstallmedia 下的恶意载荷;
  2. 让 Parallels Desktop 打开该应用程序,并准备进行安装:
    i. prl_client_app 获取恶意的 macOS 安装程序应用;
    ii. prl_client_app 运行 Parallels Service;
    iii. Parallels Service 运行 setuid,提升为 root 权限;
    iv. Parallels Service 运行 repack_osx_install_app.sh;
    v. repack_osx_install_app.sh 以 root 权限运行 createinstallmedia。
整体的流程如下图:

CVE-2024-34331:Parallels Desktop权限提升漏洞分析

将以上过程自动化,可以在此处 [5] 找到验证程序parallels_exploit.py。执行parallels_exploit.py,可以将本地权限提升为root,验证如下图:

CVE-2024-34331:Parallels Desktop权限提升漏洞分析

总结

通过本文中可以了解到,由于不当的bash权限设置,在执行具有SUID权限的程序时,可能会导致权限提升的问题。那么是否 VMware Fusion 也容易受到恶意createinstallmedia的攻击?
答案是否定的,这是因为VMware团队开发了一个名为Create macOS Installer.tool的脚本,位于VMware Fusion.app/Contents/Library/下,该脚本试图手动创建有效的安装程序,并绕过对createinstallmedia的使用。
这些漏洞都基于createinstallmedia程序,而M系列芯片的macOS Parallels软件中,createinstallmedia实际上并没有在repack_osx_install_app.sh中被调用。相反,它使用hdiutil创建类似于VMware Fusion的磁盘映像。并且Parallels添加了对基于createinstallmedia的虚拟机的支持,同时检查主机是否可以使用它,所以不会在M系列芯片平台的Mac上触发漏洞。以下错误消息是由ParallelsVirtualizationSDK.framework在M芯片Mac上尝试使用macOS安装程序时生成的:

CVE-2024-34331:Parallels Desktop权限提升漏洞分析

Reference

[1]https://khronokernel.com/macos/2024/05/30/CVE-2024-34331.html
[2]https://www.parallels.com/products/desktop/
[3]https://www.zerodayinitiative.com/blog/2023/4/5/bash-privileged-mode-vulnerabilities-in-parallels-desktop-and-cdpath-handling-in-macos
[4]https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
[5]https://khronokernel.com/Binaries/Parallels%20Repack/parallels_exploit.py

原文始发于微信公众号(山石网科安全技术研究院):CVE-2024-34331:Parallels Desktop权限提升漏洞分析

版权声明:admin 发表于 2024年7月11日 上午9:23。
转载请注明:CVE-2024-34331:Parallels Desktop权限提升漏洞分析 | CTF导航

相关文章