CVE-2023-42942:xpcroleaccountd Root 权限升级
CVE-2023-42942:xpcroleaccountd Root 权限升级
Ots安全 2024-03-03 17:21
大约两周前,苹果
在
安全通报中发布了CVE-2023-42942
。
这是系统服务xpcroleaccountd
中存在的竞争条件问题,可利用该问题进行 root 权限提升。
今天,我将分享详细信息。
关于 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权限启动)
-
如果不是第一次启动特殊XPC服务,则相应的XPC包已经复制到SIP保护位置/private/var/db/com.apple.xpc.roleaccountd.staging/exec/bundleID.size.blocks[-relaxed].xpc
,则回复成功。
(从受信任的缓存位置以 root 权限启动) -
否则,就是第一次启动。
它将首先
将特殊的 XPC 包复制到受信任的临时位置
/private/var/db/com.apple.xpc.roleaccountd.staging/tmp/uuid
接下来,它将从受信任的临时位置检查特殊 XPC 包的签名:
特殊的 XPC 服务包必须经过Apple 签名
并具有权利com.apple.private.xpc.role-account
。
如果无法验证签名,则会回复错误,因此 XPC 捆绑包将不会启动。
一旦通过验证,它将 XPC 包从tmp
位置移动/重命名到exec
位置,并成功回复。
因此,特殊的 XPC 服务将从受信任的执行
位置以 root 权限启动。
问题与利用
代码签名验证过程似乎很完美:它首先将 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
。
-
向服务包发送空 XPC 消息以触发该问题。
-
在xpcroleaccountd
调用 API
之前copyfile
,替换/tmp/com.apple.dt.Xcode.XcodeSelectXPCService.xpc
为符号链接,并让符号链接指向原始 Apple 签名的 XPC 包(可写位置
)。 -
通过签名验证后,使用恶意负载修改XPC包。
-
我的恶意 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, ©file_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
退出并回复错误。
感谢您抽出
.
.
来阅读本文
点它,分享点赞在看都在这里