Leveraging Emond on macOS For Persistence

NOTE: This binary was described in the recently released, “*OS Internals, Volume I, User Space” textbook by Jonathan Levin. This book has already proven to be a great resource and I would highly recommend it if you have an interest in macOS security research.

The event monitor daemon (emond), according to Apple, “accepts events from various services, runs them through a simple rules engine, and takes action. The actions can run commands; send email, or SMS messages”. Sounds interesting right? Emond has been available since OS X 10.7, so the details discussed in this post are applicable to the most recent version of macOS (10.13.2).

This binary functions as a normal daemon and is executed by launchd every time the OS starts up. There are a few on-disk components to emond as well. The launchd config file is located where other system daemons reside: /System/Library/LaunchDaemons/com.apple.emond.plist. This determines when the emond binary is executed along with any desired options that are regularly used with LaunchDaemons. The emond.plist config file is located in the /etc/emond.d/ directory. This file defines the locations for rules paths, UID/GID filters, error and event log paths, and a few other options.

Figure 1: emond.plist contents

emond plist contents

For rules, they’re stored in the /etc/emond.d/rules/ directory and they should be in plist format. There is an example rules file already present in this directory (SampleRules.plist). The example defines the name, eventType, and the action once the event triggers. There are several event types (startup, periodic, auth.success, auth.failure, etc.) but for this demonstration we will only use startup. The startup event type will trigger the rule once it has been loaded by emond. The periodic event type will only trigger once the defined ‘startTime’ has elapsed. The auth.success event type will only trigger once a user successfully authenticates, and auth.failure will trigger on authentication failure events. There are references to other event types here, but I have not found any additional documentation at this time. Actions define what emond will do once the event has fired. Also note that multiple actions can be defined within a rule. There are only a few interesting actions that could be abused for nefarious purposes, like run command and send email. As you might have guessed, run command allows you to execute any arbitrary system command. The send email action is self-explanatory. For this walkthrough, we’ll focus on the run command action.

Now, we can demonstrate how to leverage the event monitor daemon to establish persistence. The mechanics of emond are similar to any other LaunchDaemon. Launchd is responsible for executing all LaunchDaemons and LaunchAgents during the boot process. Since emond is started during the boot process, when using the run command action, you should be conscious of what command you’re executing and at which point during the boot process your command is going to be executed. This is important because while testing various commands, it became apparent that networking may not be available at the time an event fires and triggers an action. Thus, any commands that require network access will not work. Next, we will show how to create a rules file.

To craft a rule file, we will utilize the SampleRule.plist file that already exists and modify it as necessary.

Figure 2: SampleRules.plist


The sample contains some of the values that we need for our rules file. Specifically, we can remove the “allowPartialCriterionMatch” key and change the name if desired. The defined actions need to be modified for the *run command *action type. A complete example is shown below and also available as a gist.

Figure 3: Example persistence rule

persistence rulepersistence rule 2

Notice that the first action is to sleep for 10 seconds in order to wait with the hope that network access will become available. The amount of time is just a rough estimate and may vary across hosts. The second action will just curl a hosted Empire stager and pipe it to Python. The ampersand symbol is an xml entity and needs to be escaped appropriately. There is one last oddity with this persistence mechanism: launchd will execute emond during the boot process, but the service will remain inactive until there is a file present within the QueueDirectories path. This is specified in the LaunchDaemon configuration file, /System/Library/LaunchDaemons/com.apple.emond.plist. The file that is placed in the QueueDirectories path does not need to follow a particular naming scheme and can be empty.

Figure 4: QueueDirectories path in com.apple.emond.plist

Queue Directory

Once you place your rule plist file in the rules directory, the emond error log will show that the service is started. You won’t see any entries about your rule file specifically but emond will stop complaining about not finding any rules.

Figure 5: emond error log after starting the service

starting emond

Once the service has started, if you have defined a startup event type, your event will immediately fire and trigger any actions. Now, we should see the request for an Empire stager and then a new agent.

Figure 6: Hosted stager and web request from emond

Hosted Stager

Figure 7: New agent

image alt text

Emond is not a novel mechanism for event monitoring on OSX, but it is in terms of offensive use cases. To my recollection, this persistence method has not been mentioned in any macOS threat reports that I’ve read at the time of writing. It’s certainly possible that this is being used in the wild and just not being reported for a lack of notoriety.


This method of persistence is predicated on several changes to the file system. Fortunately, macOS offers the fsevents API to capture file system events. In essence, fsevents records all events for the file system in each volume. Initially, events are stored in memory and then written to disk once the memory buffer becomes full or before the volume is unmounted. FSEvent log files are stored in a gzip compressed format and follow a hexadecimal naming scheme. All log files are stored in a hidden directory: /.fseventsd/. Root privileges are required to access this directory. Another caveat for fsevents are that timestamps are not included with entries in the log file. With access to the API, we can use Python or Objective-C to sift through all received events and alert once an event for file creation/modification occurs in the rules directory or the QueueDirectory.

For a simple example, we can use the fswatch open-source project to monitor for changes. It offers support for multiple platforms, thorough documentation, and the project is actively maintained. You can review the project here. So, after installing the application via homebrew, we can setup a monitor for the emond rules directory.

Figure 8:Example fswatch rule for emond rules directory

Example Fswatch Rule

This rule specifies the output format for an event. You’ll notice that fswatch has the ability to provide timestamps when an event is triggered. Additionally, you can pipe the output to any other command line to you desire for further processing. You can also specify multiple directories to monitor. Figure 9 shows that once we drop a plist file in the rules the directory, fswatch will display the event details in a nicely formatted JSON string.

Figure 9:Output When Event Fires

Output When Event Fires

This is a very rudimentary example and may not be the best solution in a large macOS environment with multiple deployments. A more applicable alternative would be osquery. Osquery offers File Integrity Monitoring which uses the fsevents api to log file system changes to specific directories and/or files. Additional information can be found here. After installing osquery, you will need to provide a configuration file to monitor file system events. You can see a simple example to monitor all file system events within the rules directory below. All events will be queried at 60 second intervals.

Figure 10: Example osquery config

osquery config

For the sake of brevity, we’ll start the osquery daemon from the command line and specify our config file with the –config_path flag. Once we create our plist file and place it in the rules directory, after 60 seconds has elapsed, there should be an entry in the osquery log file. Results are logged to /var/log/osquery/osqueryd.results.log by default. The output will include the path, host identifier, timestamp, type of file event, and the MD5 hash amongst other fields.

Figure 11: Log file contents for osquery

osquery log file

The log entry shown above is also available here. These methods of detection are not meant to be a silver bullet for malicious use of emond, but they should suffice as an adequate starting point.


Levin, J. (2017) OS Internals, Volume I: User Space. North Castle, NY: Technologeeks.com

Reynolds, J. (2016, April). What is emond?. Retrieved from: http://www.magnusviri.com/Mac/what-is-emond.html

Written by Chris Ross on 17 January 2018