macOS XPC Authorization
XPC授权
苹果还提出了另一种验证连接进程是否具有调用公开XPC方法的权限的方法。
当应用程序需要以特权用户身份执行操作时,通常不会将应用程序作为特权用户运行,而是将HelperTool作为XPC服务以root身份安装,应用程序可以调用该服务执行这些操作。但是,调用服务的应用程序应具有足够的授权。
ShouldAcceptNewConnection始终为YES
可以在EvenBetterAuthorizationSample中找到一个示例。在App/AppDelegate.m中,它尝试连接到HelperTool。在HelperTool/HelperTool.m中,函数**shouldAcceptNewConnection** 不会检查之前指定的任何要求。它将始终返回YES:
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
// Called by our XPC listener when a new connection comes in. We configure the connection
// with our protocol and ourselves as the main object.
{
assert(listener == self.listener);
#pragma unused(listener)
assert(newConnection != nil);
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(HelperToolProtocol)];
newConnection.exportedObject = self;
[newConnection resume];
return YES;
}有关如何正确配置此检查的更多信息:
macOS XPC Connecting Process Check应用程序权限
然而,当调用 HelperTool 中的方法时,会进行一些授权。
App/AppDelegate.m 中的 applicationDidFinishLaunching 函数将在应用程序启动后创建一个空的授权引用。这应该始终有效。
然后,它将尝试通过调用 setupAuthorizationRights 为该授权引用添加一些权限:
Common/Common.m 中的 setupAuthorizationRights 函数将存储应用程序的权限到授权数据库 /var/db/auth.db。请注意,它只会添加尚未在数据库中的权限:
函数enumerateRightsUsingBlock是用来获取应用程序权限的函数,这些权限在commandInfo中定义:
这意味着在此过程结束时,commandInfo 中声明的权限将存储在 /var/db/auth.db 中。请注意,在那里,您可以找到对于每个需要身份验证的方法,权限名称和**kCommandKeyAuthRightDefault。后者指示谁可以获得此权限**。
有不同的范围来指示谁可以访问权限。其中一些在AuthorizationDB.h中定义(您可以在这里找到所有这些),但总结如下:
kAuthorizationRuleClassAllow
allow
任何人
kAuthorizationRuleClassDeny
deny
无人
kAuthorizationRuleIsAdmin
is-admin
当前用户需要是管理员(在管理员组内)
kAuthorizationRuleAuthenticateAsSessionUser
authenticate-session-owner
要求用户进行身份验证。
kAuthorizationRuleAuthenticateAsAdmin
authenticate-admin
要求用户进行身份验证。他需要是管理员(在管理员组内)
kAuthorizationRightRule
rule
指定规则
kAuthorizationComment
comment
在权限上指定一些额外的注释
权限验证
在 HelperTool/HelperTool.m 中,函数**readLicenseKeyAuthorization** 检查调用者是否被授权执行此方法,调用函数**checkAuthorization。此函数将检查由调用进程发送的authData是否具有正确的格式**,然后将检查调用特定方法所需的权限。如果一切顺利,返回的error将为nil:
请注意,要检查调用该方法的权限,函数authorizationRightForCommand将仅检查先前注释的对象commandInfo。然后,它将调用AuthorizationCopyRights来检查是否有权调用该函数(请注意,标志允许与用户交互)。
在这种情况下,要调用函数readLicenseKeyAuthorization,kCommandKeyAuthRightDefault被定义为@kAuthorizationRuleClassAllow。因此,任何人都可以调用它。
数据库信息
提到这些信息存储在/var/db/auth.db中。您可以使用以下命令列出所有存储的规则:
然后,您可以阅读谁可以访问权限:
宽松的权限
您可以在这里找到所有权限配置,但不需要用户交互的组合将是:
'authenticate-user': 'false'
这是最直接的键。如果设置为
false,则指定用户无需提供身份验证即可获得此权限。这与下面的两个之一结合使用,或指示用户必须属于的组。
'allow-root': 'true'
如果用户作为具有提升权限的根用户运行,并且此键设置为
true,则根用户可能无需进一步身份验证即可获得此权限。但是,通常,已经需要身份验证才能获得根用户状态,因此对于大多数用户来说,这不是“无需身份验证”的情况。
'session-owner': 'true'
如果设置为
true,会话所有者(当前登录的用户)将自动获得此权限。如果用户已经登录,则这可能会绕过额外的身份验证。
'shared': 'true'
此键不会在没有身份验证的情况下授予权限。相反,如果设置为
true,这意味着一旦权限得到验证,它可以在多个进程之间共享,而无需每个进程重新进行身份验证。但是,除非与其他键(如'authenticate-user': 'false')结合使用,否则仍需要身份验证来最初授予权限。
您可以使用此脚本获取有趣的权限:
反向授权
检查是否使用EvenBetterAuthorization
如果找到函数:[HelperTool checkAuthorization:command:],那么该进程可能正在使用先前提到的授权模式:

如果此函数调用诸如AuthorizationCreateFromExternalForm、authorizationRightForCommand、AuthorizationCopyRights、AuhtorizationFree等函数,则正在使用EvenBetterAuthorizationSample。
检查**/var/db/auth.db**以查看是否可能在无需用户交互的情况下获得调用某些特权操作的权限。
协议通信
然后,您需要找到协议模式,以便能够与XPC服务建立通信。
函数**shouldAcceptNewConnection**指示正在导出的协议:

在这种情况下,我们与EvenBetterAuthorizationSample中的情况相同,检查此行。
知道所使用协议的名称后,可以使用以下命令转储其头文件定义:
最后,我们只需要知道暴露的 Mach 服务的名称,以便与其建立通信。有几种方法可以找到这个名称:
在**
[HelperTool init]**中,您可以看到正在使用的 Mach 服务:

在 launchd plist 中:
漏洞利用示例
在这个示例中创建了:
具有函数的协议定义
一个空的授权用于请求访问
与XPC服务的连接
如果连接成功,则调用该函数
参考
最后更新于