macOS 10.14.1 Privacy: What's fixed and what's not

November 2, 2018

By Jeff Johnson

This is a follow-up to my earlier blog post Another hole in Mojave privacy protection. Three days ago macOS 10.14.1 was released, the first software update to Mojave. Apple published a support document about the security content of macOS 10.14.1 on the same day. As of today, the support document does not mention the privacy protection bypass that I discovered and alluded to in my blog post. Nonetheless, macOS 10.14.1 does appear to fix the main issue, although there remain other avenues for bypassing Mojave's privacy protections under certain conditions. I'll discuss everything I know here.

The privacy protection bypass that I discovered is quite simple. It's obvious that Apple exempted some of its own code from Mojave's privacy protections; for example, you're able to navigate protected folders in Finder without triggering permission dialogs. The key to finding a bypass, therefore, is to think of something that Apple forgot. It helps if you have many years of experience with Macs, as I do, and know where the bodies are buried, so to speak. The body in this case was Automator. Or more accurately, /usr/bin/automator. You can use /usr/bin/automator to run an Automator workflow from the command line. You can also use it to run an Automator workflow from a Cocoa app, as follows:

NSString *workflow = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"workflow"];
NSTask *task = [NSTask launchedTaskWithLaunchPath:@"/usr/bin/automator" arguments:@[workflow]];

Only a non-sandboxed app is allowed to do this, but Mojave privacy protections are supposed to apply regardless of sandboxing. Now we just need to produce a "maliciously crafted" Automator workflow. This is trivial:

  1. Create a new workflow in Automator
  2. Get Specified Finder Items
  3. Add ~/Library/Application Support/AddressBook
  4. Copy Finder Items
  5. To: ~/Desktop
  6. Save

The Desktop is not protected by Mojave, and it's accessible to a non-sandboxed app, so if this workflow works, then the Contacts protection is completely bypassed. On macOS 10.14.0 and earlier, it does work. A newly downloaded and opened app with no special permissions is able to run the workflow successfully without triggering any permission dialog. Game over. On macOS 10.14.1, in contrast, running the workflow triggers a permission dialog for the app, as expected. Thus, as far as I can tell, this particular hole has been filled.

Privacy Reset

Speaking of command-line tools, another interesting one on Mojave is /usr/bin/tccutil. You can use this tool to reset the privacy permissions for a single app, for a whole service, or nuke everything from orbit. After reset, the permissions that were already granted or declined by clicking dialogs are revoked, and a new dialog will be presented the next time an app needs permission. It turns out that you can also call /usr/bin/tccutil from a Cocoa app using NSTask, as above. An app can reset its own permissions, and this still works on macOS 10.14.1.

A malicious app could exploit the ability to reset privacy permissions by continually presenting permission dialogs to a user until the user loses patience and gives in, granting permission. In other words, the app tries to access a protected resource, Mojave presents a dialog, the user declines, the app checks whether it has access to the resource, and if not, reset the privacy database, try again, as many times as necessary. (Note also that an app can easily disable the Quit menu item, preventing a user from quitting an app to stop the stream of dialogs.

Terminal Illness

Another possible way to bypass Mojave privacy protections is to "piggyback" on another app. Even if a malicious app is unable to obtain special permission itself, the app can use another app that has already been granted permission, such as Terminal app. Suppose for example that the user has granted Terminal permission to access ~/Library/Application Support/AddressBook. Then a maliciously crafted app can make Terminal run a shell script to do the dirty work for it:

NSString *workflow = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"workflow"];
NSArray<NSString *> *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *applicationSupport = [paths[0] stringByAppendingPathComponent:@"BadApp"];
if (![[NSFileManager defaultManager] fileExistsAtPath:applicationSupport])
  [[NSFileManager defaultManager] createDirectoryAtPath:applicationSupport withIntermediateDirectories:YES attributes:nil error:NULL];
NSString *script = [NSString stringWithFormat:@"/usr/bin/automator \"%@\"", workflow];
NSString *scriptPath = [applicationSupport stringByAppendingPathComponent:@"test.sh"];
[script writeToFile:scriptPath atomically:NO encoding:NSUTF8StringEncoding error:NULL];
[[NSFileManager defaultManager] setAttributes:@{NSFilePosixPermissions: @(493)} ofItemAtPath:scriptPath error:NULL];
[[NSWorkspace sharedWorkspace] openFile:scriptPath withApplication:@"Terminal"];

This still works on macOS 10.14.1, though of course it all depends on the user having already granted permission to Terminal.

Don't Panic

I'll repeat the message from my previous blog post: Don't panic. Mojave privacy protection is a new feature in macOS 10.14. Any weakness in the privacy protection is simply a flaw in the new feature. You're as safe on Mojave as you were on High Sierra, which did not have this feature at all. You just might not be safer on Mojave than you were on High Sierra.