macOS Endpoint Security (im_maces)

This module collects logs from Apple’s Endpoint Security auditing system on MacOS 10.15 and later. Endpoint Security is an audit subsystem for monitoring system events for potentially malicious activity.

To examine the supported platforms, see the list of installer packages in the Available Modules chapter.
It is recommended that FlowControl be disabled for im_maces module instances. If the im_maces module instance is suspended, some events can be lost.

macOS Security & Privacy settings

Due to the nature of security auditing, most auditing systems require special privileges to function properly. To prepare macOS for use with this module, the nxlog application requires Full Disk Access. If NXLog is running, stop the nxlog process.

Stop nxlog
sudo launchctl unload /Library/LaunchDaemons/com.nxlog.plist

Navigate to System Preferences > Security & Privacy and select Full Disk Access from the list on the left. After unlocking the settings as an Administrator and checking nxlog, the nxlog process can be restarted:

Start nxlog
sudo launchctl load /Library/LaunchDaemons/com.nxlog.plist

The module will then have sufficient privileges to capture events from Apple’s Endpoint Security auditing system.

Configuration

The im_maces module accepts the following directives in addition to the common module directives.

MutedPathLiteral

This optional directive specifies a path literal to mute. The client stops receiving events from executable whose paths exactly matches this literal.

MutedPathPrefix

This optional directive specifies a prefix string to mute. The client stops receiving events from executables whose paths begin with this string.

NotifyEvents

This optional directive specifies a list of Apple Endpoint Security notify events to subscribe to. The value All can be used to subscribe to all supported notify events. By default, only the following events are enabled: chroot, close, create, exec, exit, fork, kextload, kextunload, open, unlink. The following notify events are supported:

  • File-System Events: access, clone, close, create, dup, exchangedata, fcntl, lookup, open, rename, truncate, write;

  • File Metadata Events: deleteextattr, fsgetpath, getattrlist, getextattr, listextattr, readdir, setacl, setattrlist, setextattr, setflags, setmode, setowner, stat, utimes;

  • File Provider Events: file_provider_materialize, file_provider_update;

  • Symbolic Link Events: link, readlink, unlink;

  • File-System Mounting Events: mount, unmount;

  • Memory Mapping Events: mmap, mprotect;

  • Process Events: chdir, chroot, exec, exit, fork, get_task, proc_check, signal;

  • Socket Events: uipc_bind, uipc_connect;

  • Clock Events: settime;

  • Kernel Events: iokit_open, kextload, kextunload;

  • Pseudoterminal Events: pty_grant, pty_close.

    Some of these event types are not available on older versions of macOS. While NotifyEvents allows all of the event types to be specified, event types that aren’t supported by the operating system will be silently ignored by im_maces. I.e., no configuration errors will be reported about enabled event which aren’t supported by the operating system, nor will these events be generated.

    For detailed descriptions of each event (including the minimum required macOS version for each event type), please see Apple’s developer documentation page.

Procedures

The following procedures are exported by im_maces.

mute_path_literal(string path_literal);

Suppresses events from executables matching the given path literal.

mute_path_prefix(string path_prefix);

Suppresses events from executables matching the given path prefix.

subscribe(string event);

Subscribes to the specified event.

subscribe_all();

Subscribes to all supported events.

unmute_all_paths();

Unmutes all previously muted executable paths.

unsubscribe(string event);

Unsubscribes from the specified event.

unsubscribe_all();

Unsubscribes from all events.

Fields

The following fields are used by im_maces.

$raw_event (type: string)

A list of event fields in key-value pairs.

$AccessMode (type: integer)

The file-access flags that were used to acces the file (if applicable).

$AccessTime (type: datetime)

The time when the file was last accessed.

$ACL (type: string)

The ACL used for the file (if applicable). Field available only if $MessageVersion is greater than 2.

$ACLAction (type: string)

The operation that was performed on the file’s ACL (set or cear).

$AvailableBlocks (type: integer)

Free blocks in filesystem that are available to non-superusers (if applicable).

$BlockSize (type: integer)

Fundamental filesystem block size (if applicable).

$ClientClass (type: string)

Meta class name of the user client instance for I/O Kit device events.

$ClientType (type: string)

User client type for I/O Kit device events.

$Command (type: integer)

The cmd argument given to fcntl(2).

$CommonAttributes (type: integer)

Common attributes (if applicable).

$CreateMode (type: integer)

The file-creation flags with which the file was created (if applicable).

$DeviceVersion (type: integer)

Major and minor version of the pseudoterminal device.

$Directory (type: string)

Target directory (if applicable).

$DirectoryAttributes (type: integer)

Directory attributes (if applicable).

$Domain (type: integer)

The communications domain of the socket (see socket(2)).

$EventTime (type: datetime)

The date and time of the event.

$EventType (type: string)

The type of Endpoint Security event.

$ExistingFile (type: boolean)

Field which set to true if the file was already present in the system (if applicable).

$ExitCode (type: integer)

The exit code that was passed to the exit(2) system call.

$ExtendedAttributes (type: string)

The extended attributes of the file (if applicable).

$ExtendedFlags (type: integer)

Extended flags for the mount(2)/unmount(2) system calls.

$File (type: string)

Path to the main file that the event reffers to (if applicable).

$FileAttributes (type: integer)

File attributes (if applicable).

$FileFlags (type: integer)

The file flags that were applied to the file.

$FileMode (type: integer)

The new file mode of the file.

$Filename (type: string)

Target filename, relative to the $Directory path (if applicable).

$FilesystemID (type: integer)

The filesystem ID (if applicable).

$FilesystemSubType (type: integer)

The filesystem sub-type (flavor) (if applicable).

$FilesystemType (type: integer)

The filesystem type (if applicable).

$FilesystemTypeName (type: string)

The filesystem type name (if applicable).

$FirstFile (type: string)

The first file to be exchanged.

$ForkAttributes (type: integer)

Fork attributes (if applicable).

$FreeBlocks (type: integer)

Free blocks in filesystem (if applicable).

$FreeFileNodes (type: integer)

Free file nodes in filesystem (if applicable).

$GID (type: integer)

The new GID of the file.

$KernelExtension (type: string)

A string identifying the kernel extension.

$MachTimestamp (type: string)

The number of Mach system clock ticks, which is effectively elapsed nanoseconds.

$MemoryAddress (type: integer)

The base memory address.

$MemoryMapFilePosition (type: integer)

The file offset of the memory map.

$MemoryMapFlags (type: integer)

The type and attributes of the mapped file.

$MemoryMapMaxProtection (type: integer)

The maximum allowed protection value the operating system will respect.

$MemoryMapProtection (type: integer)

The protection (region accessibility) value.

$MemorySize (type: integer)

The size of the memory region.

$MessageSequence (type: integer)

Per-client, per-event-type sequence number that can be inspected to detect whether the kernel had to drop events for this client. Field available only if $MessageVersion is greater than 2.

$MessageVersion (type: integer)

The event message version.

$Modified (type: boolean)

true if the file was modified before the close(2) system call.

$ModifiedTime (type: datetime)

The time when the file was last modified.

$MountedFrom (type: string)

Mounted filesystem for the mount(2)/unmount(2) system calls.

$MountedOn (type: string)

Directory on which the filesystem is mounted (if applicable).

$MountFlags (type: integer)

The filesystem mount flags (if applicable).

$OpenFlags (type: integer)

The file-open kernel flags that were used to open the file (if applicable).

$OwnerUID (type: integer)

The UID of the user that mounted the filesystem (if applicable).

$ProcessCheckFlavor (type: string)

A representation of the process information that was requested, based on the $ProcessCheckType (if applicable).

$ProcessCheckType (type: string)

The type of call number used to check the access on the target process (if applicable).

$ProcessCodeDirectoryHash (type: string)

The code directory hash value of the source process.

$ProcessCodesigningFlags (type: string)

Formatted string containing the hexadecimal representation of the codesigning flags of the source process, as well as the logical expression used to obtain these flags.

$ProcessEffectiveGID (type: integer)

The effective GID of the source process.

$ProcessEffectiveUID (type: integer)

The effective UID of the source process.

$ProcessESClient (type: boolean)

Set to true if the source process is an Endpoint Security client.

$ProcessExecutable (type: string)

The path to the executable of the source process.

$ProcessOriginalParentPID (type: integer)

The PID of the source process' original parent. This field remains constant even when the process is reparented.

$ProcessParentPID (type: integer)

The PID of the source process' parent.

$ProcessPID (type: integer)

The PID of the source process.

$ProcessPIDVersion (type: integer)

The PID version of the source process.

$ProcessPlatformBinary (type: boolean)

Set to true if the source process is a platform binary (signed with Apple certificates).

$ProcessRealGID (type: integer)

The real GID of the source process.

$ProcessRealUID (type: integer)

The real UID of the source process.

$ProcessSessionID (type: integer)

The session ID of the source process.

$ProcessSigningID (type: string)

The identifier used to sign the source process.

$ProcessTeamID (type: string)

The team identifier used to sign the source process.

$ProcessTty (type: string)

The tty from which the source process was invoked. Note: this field is only available if $MessageVersion is greater than 2.

$ProcessUID (type: integer)

The audit UID of the source process.

$Protection (type: integer)

The new memory protection flags.

$Protocol (type: integer)

The protocol of the socket (see socket(2)).

$SecondFile (type: string)

The second file to be exchanged.

$Signal (type: string)

Signal name and number, as passed to the kill(2) system call.

$SocketMode (type: integer)

The mode of the socket file.

$SocketType (type: integer)

The type of the socket.

$TargetFile (type: string)

Full path to the target file (if applicable).

$TargetProcessArgs (type: string)

Formatted list of command-line arguments that were passed to the target process via the exec(2) system call.

$TargetProcessCodeDirectoryHash (type: string)

The code directory hash value of the target process.

$TargetProcessCodesigningFlags (type: string)

Formatted string containing the hexadecimal representation of the codesigning flags of the target process, as well as the logical expression used to obtain these flags.

$TargetProcessEffectiveGID (type: integer)

The effective GID of the target process.

$TargetProcessEffectiveUID (type: integer)

The effective UID of the target process.

$TargetProcessESClient (type: boolean)

Set to true if the target process is an Endpoint Security client.

$TargetProcessExecutable (type: string)

The path to the executable of the target process.

$TargetProcessOriginalParentPID (type: integer)

The PID of the target process' original parent. This field remains constant even when the process is reparented.

$TargetProcessParentPID (type: integer)

The PID of the target process' parent.

$TargetProcessPID (type: integer)

The PID of the target process.

$TargetProcessPIDVersion (type: integer)

The PID version of the target process.

$TargetProcessPlatformBinary (type: boolean)

Set to true if the target process is a platform binary (signed with Apple certificates).

$TargetProcessRealGID (type: integer)

The real GID of the target process.

$TargetProcessRealUID (type: integer)

The real UID of the target process.

$TargetProcessSessionID (type: integer)

The session ID of the target process.

$TargetProcessSigningID (type: string)

The identifier used to sign the target process.

$TargetProcessTeamID (type: string)

The team identifier used to sign the target process.

$TargetProcessTty (type: string)

The tty from which the target process was invoked. Note: this field is only available if $MessageVersion is greater than 2.

$TargetProcessUID (type: integer)

The audit UID of the target process.

$TotalDataBlocks (type: integer)

Total data blocks in filesystem (if applicable).

$TotalFileNodes (type: integer)

Total file nodes in filesystem (if applicable).

$TransferBlockSize (type: integer)

Optimal transfer block size (if applicable).

$UID (type: integer)

The new UID of the file.

$VolumeAttributes (type: integer)

Volume attributes (if applicable).

Examples

Example 1. Collecting Apple endpoint security events

With this configuration, NXLog will collect the events listed in the Events directive.

nxlog.conf
<Input in>
    Module              im_maces
    NotifyEvents        get_task, proc_check, write
</Input>
Example 2. Using procedures to dynamically change the list of collected events

With this configuration, NXLog will only collect up to MAX_WRITE_EVENTS write events.

nxlog.conf
define MAX_WRITE_EVENTS 100

<Input in>
    Module      im_maces
    <Exec>
        create_stat("nwrites", "COUNT");
        if ( get_stat("nwrites") == 0 )
        {
            subscribe("write");
        }
        if ( get_stat("nwrites") == %MAX_WRITE_EVENTS% )
        {
            unsubscribe("write");
        }
        if ( $EventType == "write" )
        {
            add_stat("nwrites", 1);
        }
    </Exec>
</Input>
Example 3. Using directives to mute "spam" processes

With this configuration, NXLog will collect write events from all processes, except for events generated by /usr/bin/tail, /usr/bin/less and all executables under /usr/local/bin/.

nxlog.conf
<Input in>
    Module              im_maces
    NotifyEvents        write
    MutedPathLiteral    '/usr/bin/tail'
    MutedPathLiteral    '/usr/bin/less'
    MutedPathPrefix     '/usr/local/bin'
</Input>
Example 4. Using procedures to dynamically mute "spam" processes

With this configuration, NXLog will collect write events generated by /usr/bin/tail, /usr/bin/less and all executables under /usr/local/bin/. When more than MAX_TAIL_EVENTS, MAX_LESS_EVENTS or MAX_LOCAL_EVENTS events have been generated for each process respectively, the corresponding executable path(s) are muted, meaning that no further events will be generated for any processes located under these paths.

nxlog.conf
define MAX_TAIL_EVENTS  50
define MAX_LESS_EVENTS  100
define MAX_LOCAL_EVENTS 1000

<Input in>
    Module              im_maces
    NotifyEvents        write
    <Exec>
        create_stat("ntail", "COUNT");
        create_stat("nless", "COUNT");
        create_stat("nlocal", "COUNT");
        if ( $Executable == "/usr/bin/tail" )
        {
            add_stat("ntail", 1);
        }
        if ( $Executable == "/usr/bin/less" )
        {
            add_stat("nless", 1);
        }
        if ( $Executable =~ /^(\/usr\/local\/bin\/)(.*)$/ )
        {
            add_stat("nlocal", 1);
        }
        if ( get_stat("ntail") == %MAX_TAIL_EVENTS% )
        {
            mute_path_literal("/usr/bin/tail");
        }
        if ( get_stat("nless") == %MAX_LESS_EVENTS% )
        {
            mute_path_literal("/usr/bin/less");
        }
        if ( get_stat("nlocal") == %MAX_LOCAL_EVENTS% )
        {
            # Mute all processes from /usr/local/bin
            mute_path_prefix("/usr/local/bin");
        }
    </Exec>
</Input>