Announcing osquery 5: Now with EndpointSecurity on macOS

Sharvil Shah
Senior Software Engineer
Oct 6, 2021

TL;DR: Version 5.0.1 of osquery, a cross-platform, open-source endpoint visibility agent, is now available. This release is an exciting milestone for the project, as it introduces an EndpointSecurity-based process events table for macOS. Read on to learn how we integrated EndpointSecurity into osquery and how you can begin using it in your organization.

Apple’s New Rules for macOS Security

Over the years, Apple has been gradually taking pages from its iOS playbook to spruce up macOS security, beginning five years ago with the introduction of System Integrity Protection (SIP) to contain the root user in OS X 10.11 El Capitan. Since then, Apple has accelerated its efforts to improve macOS security by introducing stricter requirements for GateKeeper and the enforcement of code signing and of notarizing application binaries and packages.

Entitlements are another feature strengthening macOS security. Granted by Apple and baked in with a corresponding code signature, an entitlement allows an application or binary to use restricted APIs or frameworks. These new locked-down APIs replace the APIs that were formerly available only in kernel-mode “kernel extensions.” As a user-mode-only executable, following the same out-from-the-kernel OS integrity trends that many platforms are adopting, the osquery project was already well positioned to adopt these new APIs.

What Is EndpointSecurity?

Apple has gradually deprecated kernel extensions with its recent releases of macOS. To replace kernel extensions, Apple developed the EndpointSecurity framework and API. When combined with the required entitlements, the EndpointSecurity framework enables user-mode processes to subscribe to events of interest from the macOS kernel in real time. EndpointSecurity replaces kauth, the kernel-mode authorization framework, and OpenBSM, the legacy framework used to grab the audit trail from the kernel.

Compared to OpenBSM, EndpointSecurity is more reliable, is more performant, and anecdotally captures more process events. For a more in-depth review of EndpointSecurity, check out our Sinter blog post, our team’s first demonstration of EndpointSecurity.

These security features are a great boon to end users. We were on a steep learning curve as we retrofitted osquery—which has always been deployed as a basic, standalone CLI executable—with new signing and packaging procedures, but we believe it was well worth the effort.

How to Use osquery with EndpointSecurity: A Mini Tutorial

With the 5.0.1 release of osquery, we have implemented the es_process_events table. Check the schema for this table before following along with the tutorial.

Following along in osqueryi

The simplest way to get started with osquery is by using osqueryi, the interactive osquery shell. Download the official macOS installer package from osquery.io and install it as you would any other application.

With the release of version 5.0.1, osquery is now installed as an app bundle in /opt/osquery/lib/osquery.app, and osqueryi is a symlink in /usr/local/bin.

Next up, grant your terminal emulator application—whether it be Terminal.app, iTerm2.app, or any other terminal emulator—Full Disk Access permissions in System Preferences. Full Disk Access is part of Apple’s Transparency Consent and Control (TCC) framework, another macOS security feature, and is required to enable EndpointSecurity. In the next section, we explain how to grant this permission automatically for Macs that are enrolled in a mobile device management (MDM) solution.

Finally, run osqueryi with root permissions and provide the --disable_events=false and --disable_endpointsecurity=false flags to launch osquery interactively, with ephemeral events and the EndpointSecurity-based es_process_events table enabled.

Below is an example of osqueryi capturing recent process events that have occurred since the last time osqueryi was launched.

➜  ~ sudo osqueryi --disable_events=false --disable_endpointsecurity=false
Using a virtual database. Need help, type '.help'
osquery> .mode line
osquery> select * from es_process_events;
 
        version = 4
        seq_num = 178
 global_seq_num = 574
            pid = 8522
           path = /Applications/Xcode.app/Contents/Developer/usr/share/xcs/Nginx/sbin/nginx
         parent = 1
original_parent = 1
        cmdline = /Library/Developer/XcodeServer/CurrentXcodeSymlink/Contents/Developer/usr/share/xcs/Nginx/sbin/nginx -c /Library/Developer/XcodeServer/CurrentXcodeSymlink/Contents/Developer/usr/share/xcs/xcsnginx/xcsnginx.conf
  cmdline_count = 3
            env = XPC_SERVICE_NAME=com.apple.xcsnginx PATH=/usr/bin:/bin:/usr/sbin:/sbin XPC_FLAGS=1 LOGNAME=_xcsnginx USER=_xcsnginx HOME=/var/_xcsnginx SHELL=/bin/false TMPDIR=/var/folders/xl/xl5_qxqd1095w75dfmq92c4w0000f3/T/
      env_count = 8
            cwd = /Applications/Xcode.app/Contents/Developer/usr/share/xcs/Nginx
            uid = 451
           euid = 450
            gid = 450
           egid = 450
       username = _xcsnginx
     signing_id = com.apple.nginx
        team_id =
         cdhash = 7fde0ccc9dcdb7d994e82a880d684c5418368460
platform_binary = 1
      exit_code =
      child_pid =
           time = 1631617834
     event_type = exec
 
 
        version = 4
        seq_num = 193
 global_seq_num = 552
            pid = 8077
           path = /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/Metadata.framework/Versions/A/Support/mdworker_shared
         parent = 1
original_parent = 1
        cmdline =
  cmdline_count = 0
            env =
      env_count = 0
            cwd =
            uid = 501
           euid = 20
            gid = 20
           egid = 20
       username = sharvil
     signing_id = com.apple.mdworker_shared
        team_id =
         cdhash = 993abbb7ffcd0d3216808513f8212f4fa1fa07d7
platform_binary = 1
      exit_code = 9
      child_pid =
           time = 1631617820
     event_type = exit

Deploying a PPPC Profile for an MDM-Managed Mac

While osqueryi is a great tool for interactively introspecting, monitoring, and developing queries suitable to your environment, most deployments of osquery are in daemon mode with a configuration file. 

For a Mac host that is enrolled in MDM, you can grant Full Disk Access permissions automatically and silently by pushing a Privacy Preferences Policy Control (PPPC) configuration profile. For this profile, you need both the systemPolicyAllFiles key, which grants Full Disk Access, and a CodeRequirement key. 

Use the codesign tool to output CodeRequirement and copy everything in the output after
designated =>.

> codesign  -dr - /opt/osquery/lib/osquery.app/Contents/MacOS/osqueryd
Executable=/opt/osquery/lib/osquery.app/Contents/MacOS/osqueryd
designated => identifier "io.osquery.agent" and anchor apple generic and 
certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate 
leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate 
leaf[subject.OU] = "3522FA9PXF"

To complete systemPolicyAllFiles, the Identifier should be io.osquery.agent and IdentifierType should be bundleID

Pulling it all together, below is an example of a complete PPPC profile granting Full Disk Access to osquery. Please note that you will need to update the PayloadOrganization and other relevant fields, shown here in bold.

<?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>PayloadContent</key> <array> <dict> <key>PayloadDescription</key> <string>osqueryd</string> <key>PayloadDisplayName</key> <string>osqueryd</string> <key>PayloadIdentifier</key> <string>
BDBD19F2-A35A-4AEC-9E96-3CA7E2994666
</string> <key>PayloadOrganization</key> <string>Trail of Bits</string> <key>PayloadType</key> <string>com.apple.TCC.configuration-profile-policy</string> <key>PayloadUUID</key> <string>89121197-3B5F-4502-BB8C-4331261D3B8C</string> <key>PayloadVersion</key> <integer>1</integer> <key>Services</key> <dict> <key>SystemPolicyAllFiles</key> <array> <dict> <key>Allowed</key> <true/> <key>CodeRequirement</key> <string>identifier "io.osquery.agent" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = "3522FA9PXF"</string> <key>Comment</key> <string></string> <key>Identifier</key> <string>io.osquery.agent</string> <key>IdentifierType</key> <string>bundleID</string> </dict> </array> </dict> </dict> </array> <key>PayloadDescription</key> <string>osqueryd</string> <key>PayloadDisplayName</key> <string>osqueryd</string> <key>PayloadIdentifier</key> <string>BDBD19F2-A35A-4AEC-9E96-3CA7E2994666</string> <key>PayloadOrganization</key> <string>Trail of Bits</string> <key>PayloadScope</key> <string>System</string> <key>PayloadType</key> <string>Configuration</string> <key>PayloadUUID</key> <string>28A8A2B7-A91E-4C26-BAEC-00F6F542742E</string> <key>PayloadVersion</key> <integer>1</integer> </dict> </plist>

You may need to consult the documentation of your MDM provider for more information on PPPC profiles.

Migrating from osquery 4.x to 5.x

With the release of version 5.0.1, osquery now installs on macOS as an app bundle in /opt/osquery/lib/osquery.app, and the new package identifier is io.osquery.agent. If you are upgrading osquery from version 4.9, you need to stop the osquery launchd service and restart it after version 5.0.1 is installed, since osquery itself doesn’t provide a mechanism to clean up artifacts, binaries, and configuration files for older versions. Also of note is that the package installer does not install a LaunchDaemon to start osqueryd. You may use the provided osqueryctl start script to copy the sample LaunchDaemon plist and associated configuration to start the osqueryd daemon.

Similar changes apply to Linux and Windows hosts. Please consult the installation guide on the osquery wiki to learn more. 

A Stronger Foundation

We developed a working proof-of-concept of osquery with an EndpointSecurity integration rather quickly; in fact, we merged the feature into osquery months before the version 5.0.1 release. But to actually “switch on” the EndpointSecurity functionality, we had to conquer a mountain of technical debt:

And finally, we had to socialize all these breaking changes and navigate all the community’s feedback. Indeed, the number of changes we needed to make warranted a new major version of osquery, from version 4.9 to 5.0.1.

In June 2019, Facebook and the Linux Foundation formed the osquery Foundation, a new community entity intended to accelerate the development and open participation around the osquery project. A multi-stakeholder Technical Steering Committee (which includes Trail of Bits) has been updating and maintaining osquery ever since. Throughout the project’s development, one of the biggest technical obstacles to the project’s independence was the lack of an automated packaging and code-signing pipeline. Thanks to the community’s efforts this year to integrate EndpointSecurity into osquery, this pipeline is finally in place. Facebook’s original osquery developers can now fully hand over the keys (literally and figuratively) to the community.

The osquery project is undoubtedly only made possible by the continuing involvement and support of its open-source community. We especially want to thank our client sponsor, Atlassian, and our fellow contributors to the osquery community, past and present.

Future Directions

Now that we have integrated EndpointSecurity into osquery, the tool comes with a variety of new detection capabilities on macOS. It should now be much easier to add a file event monitor, kernel extension loading events, and even memory mapping events. The automated code-signing and packaging groundwork that we’ve laid for EndpointSecurity could pave the way for other permissioned/entitled macOS event monitoring frameworks, like NetworkExtension, to be integrated into osquery.

Trail of Bits has been at the forefront of osquery development for years. Where do you want us to take the project next? Drop us a line to chat about how we can help implement your idea!