Abusing MacOS Entitlements for code execution
Recently I disclosed some vulnerabilities to Dropbox and PortSwigger via H1 and Microsoft via MSRC pertaining to Application entitlements on MacOS. Weβll be exploring what entitlements are, what exactly you can do with them, and how they can be used to bypass security products.
These are all unpatched as of publish.
Whatβs an Entitlement?
On MacOS, an entitlement is a string that grants an Application specific permissions to perform specific tasks that may have an impact on the integrity of the system or user privacy. Entitlements can be viewed with the comand codesign -d --entitlements - $file
.
For the above image, we can see the key entitlements com.apple.security.cs.allow-unsigned-executable-memory
and com.apple.security.cs.disable-library-validation
- they allow exactly what they say on the tin. Weβll explore Dropbox first, as itβs the more involved of the two to exploit.
Dropbox
Just as Windows has PE and Linux has ELF, MacOS has its own executable format, Mach-O (short for Mach-Object). Mach-O files are used on all Apple products, ranging from iOS, to tvOS, to MacOS. In fact, all these operating systems share a common heritage stemming from NeXTStep, though thatβs beyond the scope of this article.
MacOS has a variety of security protections in place, including Gatekeeper, AMFI (AppleMobileFileIntegrity), SIP (System Integrity Protection, a form of mandatory access control), code signing, etc. Gatekeeper is akin to Windows SmartScreen in that it fingerprints files, checks them against a list on Appleβs servers, and returns the value to determine if the file is safe to run. `
This is vastly simplified.
There are three configurable options, though the third is hidden by default - App Store only, App Store and identified developers, and βanywhereβ, the third presumably hidden to minimize accidental compromise. Gatekeeper can also be managed by the command line tool, spctl(8)
, for more granular control of the system. One can even disable Gatekeeper entirely through spctl --master-disable
, though this requires superuser access. Itβs to be noted that this does not invalidate rules already in the System Policy database (/var/db/SystemPolicy
), but allows anything not in the database, regardless of notarization, etc, to run unimpeded.
Now, back to Dropbox. Dropbox is compiled using the hardened runtime, meaning that without specific entitlements, JIT code cannot be executed, DYLD environment variables are automatically ignored, and unsigned libraries are not loaded (often resulting in a SIGKILL of the binary.) We can see that Dropbox allows unsigned executable memory, allowing shellcode injection, and has library validation disabled - meaning that any library can be inserted into the process. But how?
Using LIEF, we can easily add a new LoadCommand to Dropbox. In the following picture, you can see my tool, Coronzon
, which is based off of yololib, doing the same.
import lief
file = lief.parse('Dropbox')
file.add_library('inject.dylib')
file.write('Dropbox')
Using code similar to the following, one can execute code within the context of the Dropbox process (albeit via voiding the code signature - youβre best off stripping the code signature, or it wonβt run from /Applications/
). Youβll either have to strip the code signature or ad-hoc sign it to get it to run from /Applications/
, though the application will lose any entitlements and TCC rights previously granted. Youβll have to use a technique known as dylib proxying
- which is to say, replacing a library that is part of the application bundle with one of the same name that re-exports the library itβs replacing. (Using the link-time flags `-Xlinker -reexport_library $(PATH_TO_LIBRARY)).
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
__attribute__((constructor))
static void customConstructor(int argc, const char **argv)
{
printf("Hello from dylib!\n");
syslog(LOG_ERR, "Dylib injection successful in %s\n", argv[0]);
system("open -a Calculator");
}
This is a simple example, but combined with something like frida-gum
the impact becomes much more severe - allowing application introspection and runtime modification without the userβs knowledge. This makes for a great, persistent usermode implant, as Dropbox is added as a LaunchItem.
Visual Studio
Microsoft releases a cut-down version of their premier IDE for MacOS, mainly for C# development with Xamarin, .NET Core, and Mono. Though βcut-downβ, it still supports many features of the original, including NuGet, IntelliSense, and more.
It also has some interesting entitlements.
Of course, MacOS users are treated as second class citizens in Microsoftβs ecosystem and Microsoft could not give a damn about the impact this has on the end user - which is similar in impact to the above, albeit more severe. We can see that basically every single feature of the hardened runtime is disabled - enabling the simplest of code injection methods, via the DYLD_INSERT_LIBRARIES
environment variable. The following video is a proof of concept of just how easily code can be executed within the context of Visual Studio.
Keep in mind: code executing in this context will inherit the entitlements and TCC values of the parent. Itβs not hard to imagine a scenario in which IP (intellectual property) theft could result from Microsoftβs attempts at βhardeningβ Visual Studio for Mac. As with Dropbox, all the security implications are the same, yet itβs about 30x easier to pull off as DYLD environment variables are allowed.
Burp Suite
Iβm sure most reading this article are familiar with Burp Suite. If not - itβs a web exploitation Swiss army knife that aids in recon, pre, and post-exploitation. So why donβt we exploit it?
This time, weβll be exploiting the Burp Suite installer. As youβll probably guess by now, it has someβ¦ interesting entitlements.
Aside from the output lacking newlines, exploitation in this case is different. There are no shell scripts in the install (nor is the entitlement for allowing DYLD environment variables present), and if weβre going to create a malicious installer, we need to use whatβs already packaged. So, weβll tamper with the included JRE (jre.tar.gz) thatβs included with the installer.
Thereβs actually two approaches to this - replacing a dylib outright or dylib hijacking. Dylib hijacking is similar to itβs partner, DLL hijacking, on Windows, in that it abuses the executable searching for a library that may or may not be there, usually specified by @rpath
or sometimes a βweakrefβ. A weakref is a library that doesnβt need to be loaded, but can be loaded. For more information on dylib hijacking, I reccomend this excellent presentation by Patrick Wardle of Objective-See. For brevity, however, weβll just be replacing a .dylib in the JRE.
The way the installer executes is that it extracts the JRE to a temporary location during install, which is used for the rest of the install. This temporary location is randomized and actually adds a layer of obfuscation to our attack, as no two executions will have the JRE extracted into the same place. Once the JRE is extraced, itβs loaded and attempts to install Burp Suite. This allows us to execute unsigned code under the guise and context of Burp Suite, running code in the background unbenknownst to the user. Thankfully Burp Suite doesnβt (currently) require elevated privileges to install on macOS. Nonetheless, this is an issue due to the ease of forging a malicious installer and the fact that Gatekeeper is none the wiser.
A proof of concept can be viewed below.
Conclusions
Entitlements are both a valuable component of MacOSβ security model, but can also be a double edged sword. Youβve seen how trivivally Gatekeeper and existing OS protections can be bypassed by leveraging a weak application as a trampoline - the one with the most impact in this case I argue to be Dropbox, due to inheritance of Dropboxβs TCC permissions and being a LaunchItem, thus gaining persistence. Thus, entitlements provide a valuable addition to the attack surface of MacOS for any red-teamer or bug-bounty hunter. Your mileage may vary, however - Dropbox and Microsoft didnβt seem to care much. (PortSwigger, on the other hand, admitted that due to the design of Burp Suite and inherent language intrinsics itβs extremely hard to prevent such an attack - and I donβt fault them).
Happy hacking.
Disclosure Timelines
Dropbox
- June 11th, initial disclosure.
- June 17th, additional information added
- June 20th, closed as Informative
Visual Studio
- June 19th, initial disclosure
- June 22nd, closed (βUpon investigation, we have determined that this submission does not meet the bar for security servicing. This report does not appear to identify a weakness in a Microsoft product or service that would enable an attacker to compromise the integrity, availability, or confidentiality of a Microsoft offering. β)
Burp Suite
- June 27th, initial disclosure
- June 30th, closed as Informative