At the Worldwide Developer Conference (WWDC) in 2019, Apple announced the release of macOS Catalina and along with it, system extensions and, something they referred to as the Endpoint Security Framework, or ESF.
The following year, at WWDC2020, they discussed building endpoint security tools (or applications) by leveraging ESF.
A discussion about Endpoint Security from WWDC2019
Now before we dive in too deep, it's important to note that at some point since its release, ESF has been renamed, or at the very least, there has been a call to be more specific. Because of that, I will do my best to refer to it as either Endpoint Security or ES, although I must admit, old habits die hard.
Just a PSA on behalf of the engineering folks who work on it: There is no single "Endpoint Security Framework" or "ESF", it's just "Endpoint Security" or "ES" for short, optionally combined with "API" if you want to be extra-fancy 👍— Pepijn Bruienne 🐶🌲🧀💴 (@bruienne) October 6, 2022
Endpoint Security is quite a complex, in-depth topic. It would take hours (days?) to cover everything ES can do, but I want to cover it in a few aspects—a high-level overview, a deeper dive into how it works and how detection engineers can potentially leverage some of the information ES provides.
Let’s start with a high-level, not overly technical run-through before we dive into the deep end of the pool here. Endpoint Security is available to those on macOS Catalina, which is 10.15, or higher. If you’re not running this operating system or higher, you should be (unless your device literally can’t run anything more recent). One of the most important things to do to keep yourself—and your Mac—secure is to keep your software and operating system up to date. Flaws are often fixed with supplemental or security updates, so running an outdated OS can make you or your users more susceptible to exploits.
To the end user, ES probably doesn’t mean much, but to the software that runs on their Mac, it means much more. Let’s start with what ES allows. Its primary function is to allow applications to look for malicious activity by providing visibility into certain parts of their system. The activity that ES subsequently returns can be analyzed, whether by a human or automated service. It can be reviewed, and as such, the activity can be blocked. This is how your more traditional macOS antiviruses (AVs) operate—by leveraging Endpoint Security.
Juxtaposed to offering applications deeper visibility and insight through ES is Apple's expansion of what I call, 'end user transparency', allowing the end user acknowledgment into what applications are doing on the system. Although this means more alerts to the user, and could potentially lead to alert fatigue, it is a purposeful design by Apple to give users more knowledge behind what applications have access and visibility to their system. This means that when installing any type of system extension (which ES is typically bundled into) on your system, and whether it leverages ES or not is moot, it requires explicit approval from the end user (although this does not necessarily apply to users enrolled in an MDM—but that’s a story for another blog post).
Not only will the user need to approve the system extension, but they will need to allow Full Disk Access (FDA) permissions to the ES application as well. Fortunately, if this application is using a system extension, upon install, the FDA request is pre-populated with the System Settings, making it a little easier for the user or admin to accept this FDA request.
If we start to explore a little deeper, Endpoint Security is a C API, which is part of the System Extension framework. The idea was that ES would replace a few different functions of macOS - the KAuth KPI, Kernel Extensions (
kexts), and OpenBSM audit trail. System Extensions are entitlements granted by Apple to have access to some of these lower level system events. If you’re a developer, you would be required to hold a
An additional security mechanism that is utilized by this process is code signing. In order to request and subsequently use this entitlement, you must possess a developer’s license, or Developer/Team ID. This 10-digit, alphanumeric string ties your software back to the developer. Although there is such a thing as a malicious team ID (someone who uses their Team ID for nefarious purposes), it provides an extra layer of security to the process.
When creating an ES system extension, you first create your ES client.
Once you have your client, you pick which event types you want to subscribe to via an event stream -
ES_EVENT_TYPE_NOTIFY_EXEC, ES_EVENT_TYPE_AUTH_MOUNT, etc., etc.
There are two types of events,
NOTIFY events and
AUTH events (you can see the
NOTIFY event in the above screenshot). Notify events are just as their name alludes to - they notify you that an event occurred. Auth events are different in that your application has a chance to take action against it first - meaning you could potentially block a process from executing if you are subscribing to the
When your application receives the messages from the client you created, if it is an auth event, you can then handle those cases. This is accomplished by your application queuing up the messages, then handling them based on the conditions set by the application.
Because all of this is handled without leaving the kernel, if your application is set up to block that process, it can be halted before executing its commands.
System Extensions, in general, also persist, so when the system boots, these system extensions are immediately executed and started. They don’t need to be manually started or triggered once the machine boots, which can help make your application somewhat of a ‘set it and forget it’ item.
It is possible to use rules from Sigma or writing predicates with NSPredicate that can be backed by data from ES. These can be ingested into a SIEM to capture and iterate over that data. These rules will allow you to look at events, or potentially in the case of
AUTH events, take action against the processes based on your logic within your application.
The output is a robust json blob with a pile of information that can be parsed and analyzed. Below, we have an
ES_EVENT_TYPE_NOTIFY_EXEC, or ‘exec event’, event that occurred when we simply open the Calculator application.
Information provided from this object like the
event::exec::target::executable::path gives you the path of the executable, whereas the
event::exec::args shows the arguments, as an array, that were executed. We could look at these fields, and based on their contents, make an informed decision according to what was observed. That can include what the path is, or use some regex to check for very specific cases.
Some of the different event types that may be useful when looking to detect threats are:
For me, the
ES_EVENT_TYPE_NOTIFY_EXEC gives me the most immediate benefit when looking at macOS malware. If we look at the sample below, we can see the Shlayer malware running some commands from the command line. We can see all of the arguments, in an array, that Shlayer is running here. The actual command is
openssl enc -base64 -d -aes-256-cbc -nosalt -pass pass:10595727573, which we can see on line 135 of this ES output.
It's worth noting that although the information these events give visibility into are valuable, some of these events can also be very noisy, especially if you have lots of noise on your system (an MDM that is constantly running
In addition, there are some constants that detection engineers may find useful.
The entire list of events is available in es_event_type_t, and obviously, they can be used in whichever way you find valuable.
Endpoint Security, although still relatively infantile in comparison to other macOS features, is arguably one of the biggest game-changers to the macOS security stack. It gives invaluable information and context around the processes and files that are executing and changing on your system. Under the hood, it is complex, but with many different tools, it is possible to get a good understanding of what is happening on your system and protect yourself against malicious activity.
ES is designed to give security applications more detailed access to system events, all while being able to ignore direct interaction with the kernel. In the end, this reiterates Apple’s stance on protecting their end users.