Tuesday, April 28, 2020

Mac Sandbox Escape via TextEdit

Jeff Johnson (tweet):

Normally, when a sandboxed app writes to a file, the file is quarantined. If the file is a shell script, then the quarantine extended attribute would prevent the script from running. However, when an app such as TextEdit with the “com.apple.security.files.user-selected.executable” entitlement saves a file, it removes the quarantine extended attribute!

My sample app opens a shell script in TextEdit, and then it uses the Apple Events permission to tell TextEdit to save the file, thus removing the quarantine and allowing the script to be executed outside the app’s sandbox.

This should appear very innocuous to the user, because nobody thinks that TextEdit is dangerous, so one would think it’s not much of a risk to allow TextEdit to be controlled.

I tried the sample project, and this seems to be legit. The app can save an arbitrary shell script, launder it through TextEdit, and then tell the system to open it, which will make it run outside of the sandbox.

I don’t understand why Apple thinks there are no “actual security implications” (and thus won’t pay the bug bounty). This comes on the heels of the iOS Mail vulnerabilities—which Apple said could not be exploited even though the reporter, ZecOps, claims it has seen them in the wild—and Johnson’s own report about Safari running disabled extensions, where Apple initially didn’t see a problem but later fixed it and credited him.

Jeff Johnson:

Note that Transmit is another sandboxed app, along with BBEdit and TextEdit, that possesses the special “executable” entitlement. These apps can all escape their own sandboxes.

The “user-selected” part of the “com.apple.security.files.user-selected.executable” entitlement is extremely misleading. No user action is required to use that entitlement.

It seems to me that the core issue is not the entitlement but that if a shell script has executable permission, macOS will run it when it’s opened. Why not restrict code execution to .app bundles? I’m not even sure it’s a useful feature. I always run scripts via a helper app or from within Terminal.


Update (2020-05-18): Daniel Jalkut:

I just reproduced @lapcatsoftware’s sandbox escape. Incredible find, I can’t believe Apple doesn’t deem this a legitimate security issue that warranted a bounty payment?

Update (2020-06-05): Jeff Johnson:

So I’m writing now to clarify a number of points that I feel have not been broadly understood.

See also: Hacker News and this Twitter thread.

4 Comments RSS · Twitter

This seems like an exploit vector that Apple should fix. I don’t think any app should be allowed to run arbitrary scripts outside its sandbox using that user-selected.executable entitlement. That seems to be the real problem here, as you said Michael. An app should not be allowed to circumvent its own sandboxing restrictions.

The use of Apple Events to exploit this entitlement is problematic too, but much less so. Granting one app control over another using Apple Events is already a big show of trust. You never know what kind of access or data might be finagled out.

One final (but less important) thought: I would be very suspicious if an app triggered an alert to control TextEdit using Apple Events. I can’t think of any good reason an app would ever need to do that. I'd like to imagine that I would decline permission, though I can see how regular Mac users might just click to allow it.

Wouldn’t the same exploit still work if the script was inside an app bundle?

Peter, I'm not sure which app bundle you mean, but Michael suggested to me that it's the sandbox app's own bundle, so I'll address this point. The answer is yes, but if you were trying to ship malware in the Mac App Store (which is the only reason you'd even sandbox malware), you wouldn't leave a malicious executable in "plain sight" inside the app bundle. Hopefully Apple would catch that (but who knows LOL). In fact I included my shell script inside the app bundle of my sample app, but this was merely for ease of demonstration of the exploit. Instead of copying an executable from the bundle into the app's container, a sandboxed app can just directly create a file in its container and make it executable with NSFileManager setAttributes NSFilePosixPermissions. But whenever a normal sandboxed app copies or creates a file, the file is quarantined, which prevents execution. That's why you still need the "com.apple.security.files.user-selected.executable" entitlement to remove the quarantine.

It's also important to note that this exploit works with Mach-O executables, not just with shell scripts. Again, I only used a shell script for ease of demonstration. You can actually get TextEdit to open and save a Mach-O executable file. It's at least partially text!

Indeed, a malware sandboxed app could download an evil executable from the internet instead of including it in the app, to better avoid detection from Apple. But again, the download would be quarantined.

Leave a Comment