CVE-2023-42942:xpcroleaccountd Root 权限升级

CVE-2023-42942:xpcroleaccountd Root 权限升级

Ots安全 2024-03-03 17:21

大约两周前,苹果

安全通报中发布了CVE-2023-42942

这是系统服务xpcroleaccountd
中存在的竞争条件问题,可利用该问题进行 root 权限提升。
今天,我将分享详细信息。

CVE-2023-42942:xpcroleaccountd Root 权限升级 -2

关于 xpcroleaccountd

系统服务/usr/libexec/xpcroleaccountd
以 root 身份运行,并具有以下权限:

[Key] com.apple.private.xpc.launchd.ios-system-session
  [Value]
    [Bool] true
  [Key] com.apple.rootless.storage.RoleAccountStaging
  [Value]
    [Bool] true
  [Key] com.apple.security.exception.files.absolute-path.read-only
  [Value]
    [Array]
      [String] /private/var/preferences/com.apple.security.xpc.plist
  [Key] com.apple.security.exception.files.absolute-path.read-write
  [Value]
    [Array]
      [String] /private/var/db/com.apple.xpc.roleaccountd.staging/
      [String] /private/var/MobileSoftwareUpdate/com.apple.xpc.roleaccountd.staging/
  [Key] platform-application
  [Value]
    [Bool] true
  [Key] seatbelt-profiles
  [Value]
    [Array]
      [String] temporary-sandbox

请注意,它能够访问SIP 保护的
目录/private/var/db/com.apple.xpc.roleaccountd.staging

/private/var/db/com.apple.xpc.roleaccountd.stagin

有一些特殊的Apple 签名的
XPC 服务,它们 在Info.plist
文件中定义“_RoleAccount”=>“root”


/Applications/Xcode.app/Contents/Frameworks/IDEKit.framework/Versions/A/XPCServices/com.apple.dt.Xcode.XcodeSelectXPCService.xpc/Contents/Info.plist:
...
  "XPCService" => {
    "_AllowedClients" => [
      0 => " identifier = com.apple.dt.Xcode and (anchor apple or (anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.9]) or (anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.9.1]))"
    ]
    "_RoleAccount" => "root"
    "ServiceType" => "Application"
  }
...

当我们尝试与此类 XPC 服务进行通信时,xpcroleaccountd
将帮助将
XPC 服务包复制/暂存到受
SIP 保护的
位置,然后
从受信任的位置以 root 权限安全地启动 XPC 服务包。

通过逆向,我发现xpcroleaccountd
的逻辑
很简单:
1. 如果特殊的 XPC 服务捆绑来自系统本身,并且捆绑路径受 SIP 保护/可信,则它会成功回复。
(直接用root权限启动)

  1. 如果不是第一次启动特殊XPC服务,则相应的XPC包已经复制到SIP保护位置/private/var/db/com.apple.xpc.roleaccountd.staging/exec/bundleID.size.blocks[-relaxed].xpc
    ,则回复成功。
    (从受信任的缓存位置以 root 权限启动)

  2. 否则,就是第一次启动。
    它将首先
    将特殊的 XPC 包复制到受信任的临时位置
    /private/var/db/com.apple.xpc.roleaccountd.staging/tmp/uuid

CVE-2023-42942:xpcroleaccountd Root 权限升级 -3

接下来,它将从受信任的临时位置检查特殊 XPC 包的签名:

CVE-2023-42942:xpcroleaccountd Root 权限升级 -4

特殊的 XPC 服务包必须经过Apple 签名
并具有权利com.apple.private.xpc.role-account

如果无法验证签名,则会回复错误,因此 XPC 捆绑包将不会启动。

一旦通过验证,它将 XPC 包从tmp
位置移动/重命名到exec
位置,并成功回复。
因此,特殊的 XPC 服务将从受信任的执行
位置以 root 权限启动。

CVE-2023-42942:xpcroleaccountd Root 权限升级 -5

问题与利用

代码签名验证过程似乎很完美:它首先将 XPC 服务包复制到受信任的临时位置,然后检查那里的签名(使用权利com.apple.private.xpc.role-account
)。
只有通过签名验证后,XPC服务才会以root权限启动。


从一开始就阻止了我的TOCTOU攻击,因为我无法从 SIP 保护的位置修改 XPC 服务包。

然而,我发现我可以通过符号链接绕过它!

在第 372 行,在将特殊 XPC 捆绑包复制到受信任的临时位置之前,我可以用符号链接替换 XPC 捆绑包源路径。
接下来,符号链接已成功复制到受信任位置。
结果,它检查签名并通过解析我的符号链接来
启动 XPC 包。

以下是我利用这个问题的方法:
1. 将 Apple 签名的 XPC 服务包放在位置/tmp/com.apple.dt.Xcode.XcodeSelectXPCService.xpc

  1. 向服务包发送空 XPC 消息以触发该问题。

  2. 在xpcroleaccountd
    调用 API
    之前copyfile
    ,替换/tmp/com.apple.dt.Xcode.XcodeSelectXPCService.xpc
    为符号链接,并让符号链接指向原始 Apple 签名的 XPC 包(可写位置
    )。

  3. 通过签名验证后,使用恶意负载修改XPC包。

  4. 我的恶意 XPC 包将以 root 权限启动。

顺便说一句,为了赢得竞争条件,日志字符串可能是执行某些操作的提示。
例如,日志内容“stagingareaforbundle:”
表明它将调用API copyfile
,现在是替换为符号链接的正确时机。

漏洞代码上传至
GitHub
仅用于研究目的。

苹果的补丁

该问题已在macOS 14.1
中修复:

void handle_xpc_message(void *, void *msg) {
...
  v70 = copyfile_state_alloc();
    copyfile_state_set(v70, 6u, &copyfile_callback); // COPYFILE_STATE_STATUS_CB
    v71 = copyfile(from, to, v70, 0xC800Fu);
    copyfile_state_free(v70);
    if ( v71 ) {
       // "pid[%d]: copyfile(3) failed on service: %d, (errno %{errno}d)"
       goto EXIT;
    }
...
}

在该copyfile_callback
函数中,它将检查目标路径

int copyfile_callback(int what, int stage, copyfile_state_t state, const char *src, const char *dst, void *ctx)
{
  memset(&v11, 170, sizeof(v11));
  result = 0LL;
  if ( stage == COPYFILE_FINISH )
  {
    if ( lchown(dst, 0, 0) )
    {
      v7 = sub_100003DF5();
      v8 = (os_log_s *)objc_retainAutoreleasedReturnValue(v7);
      if ( os_log_type_enabled(v8, OS_LOG_TYPE_ERROR) )
        sub_1000067AF(v8);//"chown(2) failed during copyfile(3): %{errno}d"
    }
    else if ( lstat_INODE64(dst, &v11) )
    {
      v9 = sub_100003DF5();
      v8 = (os_log_s *)objc_retainAutoreleasedReturnValue(v9);
      if ( os_log_type_enabled(v8, OS_LOG_TYPE_ERROR) )
        sub_100006746(v8);//"lstat(2) failed during copy: %{errno}d"
    }
    else
    {
      result = 0LL;
      if ( (v11.st_mode & 0xF000) != 0xA000 )//dst is a symbolic link?
        return result;
      v10 = sub_100003DF5();
      v8 = (os_log_s *)objc_retainAutoreleasedReturnValue(v10);
      if ( os_log_type_enabled(v8, OS_LOG_TYPE_ERROR) )
        sub_100006712(v8);//"encountered symbolic link during copy"
    }
    objc_release(v8);
    return 2LL;//COPYFILE_QUIT, the entire copy is aborted at this stage.  Any filesystem objects created up to this point will remain.  copyfile() will return -1, but errno will be unmodified.
  }
  return result;
}

如果目标路径是符号链接,copyfile_callback
将返回2 (COPYFILE_QUIT)
,整个复制将在此阶段中止。
接下来,copyfile
将返回-1
,但 errno 将保持不变。
最后,xpcroleaccountd
退出并回复错误。

感谢您抽出

CVE-2023-42942:xpcroleaccountd Root 权限升级 -6

.

.

CVE-2023-42942:xpcroleaccountd Root 权限升级 -8

来阅读本文

点它,分享点赞在看都在这里