← Back to Resources

Threat Hunting for macOS, Part Two

Matt Bromiley, Lead Solutions Engineer at LimaCharlie

The macOS Unified Log promises total visibility, and that promise is exactly the problem. The log captures everything: user applications, system processes, kernel events, down to the noise a window throws off when you resize it. The instinct an analyst carries over from Windows, where "turn on all the logs" really means a handful of channels, falls apart on a Mac. A default Windows install ships with over 150 event logs enabled, and the speaker is blunt that the Unified Log can eclipse even that tenfold. So the real tension of this session is not how to see more on macOS. It is how to see less, on purpose, and how to turn that restraint into detections you can run across a fleet of customer endpoints.

Privacy is part of the threat model

The harder lesson is that Apple is an active participant in what you can and cannot see, and not always on your side. Apple owns the whole stack and keeps optimizing for user privacy and resource use, often on its own silicon. The practical consequence is that an OS update can change how a subsystem behaves and break security tooling overnight. The speaker treats LimaCharlie surviving the macOS 15 (Sequoia) update intact as a genuine win rather than a given, and notes that plenty of other tools did not. The warning generalizes: confirm your macOS coverage survives a major release before you depend on it.

Privacy also masks the evidence directly. Querying the mdnsresponder process for DNS activity should be a softball, just show which process IDs make requests and where they go. It half works. You see which process is issuing requests, including a crowd of LimaCharlie sensors, but the DNS service query record comes back with the Q name replaced by a hash. The speaker dumped far more DNS logs than would fit on a slide and found not a single domain represented. That is a structural limit, not a misconfiguration, and it changes the hunt. You stop trusting the masked field and start reducing the population: filter out the endpoint agents, config services, and system daemons, and what remains, a non-standard process making requests, is the thing worth investigating. That is data-reduction work, which is why the speaker keeps this one in the query console rather than promoting it to a real-time rule.

The good queries are the narrow ones

The session's strongest argument is implicit in which findings the speaker would promote to a detection and which he would not. The DNS query stays in the console. The high-fidelity ones move forward, and they are high fidelity because they are narrow.

A predicate of process == "ChatGPT" surfaced the ChatGPT desktop app the moment it ran. The discipline matters more than the example. The speaker draws a sharp line: he is not dumping a process list and grepping it for bad names. A targeted predicate fires only when the specific thing happens, so the instant it trips it is a near-certain policy indicator with no triage required. Swap in TeamViewer or LogMeIn and you have a small set of high-signal detections for remote-access tooling. On macOS, specificity is what buys fidelity, and fidelity is what makes a detection safe to run across many tenants at once.

The same instinct points him at the subsystems that behave like hubs. Querying securityd (shown as secd in the console) for messages containing "keychain" returned hundreds of results, including evidence of an ExpressVPN install writing to the keychain as it tried to run. Because the same authentication machinery that stores passwords also handles saved Wi-Fi credentials, securityd concentrates security activity the way the Windows security log does. Authentication logging proved similarly rich. Closing a laptop lid with an Apple Watch and external monitor attached produced a readable sequence: a lid-closed message, a cascade of authentication checks, and an error hunting for the Apple Watch configured as an auth mechanism. Those logs land in coreauthd and the local authentication module, and they expose how a user actually configured a workstation, which is often a policy question before it is a security one.

Even the noisier subsystems earn a place once you accept they need filtering. TCC (com.apple.tccd) shows the system deciding whether a user may reach resources like Contacts. The network extension subsystem catches configuration changes but leaks badly, logging connection attempts from apps installed only on a phone sharing the same Wi-Fi, so a message filter is mandatory before any of it becomes a rule. Running Board, Apple's process and error monitoring layer, throws off accidental metadata like a user's home directory, shell, and login name, which makes it a candidate for alerting on unexpected accounts on a device. The subsystem-versus-process distinction is a live hazard: Running Board's process is runningboard while its subsystem is com.apple.runningboardd, and confusing the two yields either nothing or a firehose.

Restraint as a workflow

What turns these scattered queries into an operating posture is the loop LimaCharlie wraps around them. A macOS sensor taps the Unified Log through artifact collection and ships events up as parsed JSON, sitting in the same timeline as the rest of the EDR telemetry. Those events are indexed for post-ingestion search, and the past 30 days are free to query in the console. That free window is the part an MSSP or MDR should notice. Detections look forward, but incidents already happened, so you need backward search to scope anything real, and the console becomes the natural place to test a hypothesis before committing to it.

The worked example shows the shape of the discipline. Build the query line by line to stay logically honest, pull events from the background task management daemon, then use projections to count and summarize what it has done over the past 24 hours. The output is not a list of events, it is a picture of what is normal, which is the only baseline against which an anomaly means anything. From there the console converts in both directions: promote a proven query into a detection and response rule, or run an existing detection backward over history to see what it would have caught.

That is the real argument. The Unified Log will give you everything if you ask, and everything is useless. The value comes from deciding in advance what is worth seeing, proving it against real telemetry, and only then automating it. For a provider standing up macOS coverage across customers, the work is not collecting more. It is collecting deliberately, and building the loop that turns a sharp query today into a fleet-wide detection tomorrow.

See what agentic SecOps looks like in your environment

LimaCharlie gives MSSPs and MDRs a fully programmable SecOps Cloud Platform, with transparent usage-based pricing, API-first integration across every telemetry source, and the infrastructure to run multi-tenant operations at scale.