edr-collector,经由 MSK Kafka 和富化服务(ENRICH_PLATFORM=macos)路由,最终落入一张专门构建的 ClickHouse 表:endpoint_events。
endpoint_events 是一张宽表,为 macOS 原生设计,以 event_class 和 event_type 分型。每个分类专属的列只会在使用它们的事件上被填充,其余列留空。此表结构中没有 Linux 的 cgroup、容器、pod 或 Kubernetes 之类的杂项——这些概念不适用于端点。
此表最本质的特性——也是 macOS 的差异化所在——在于每一行都把代码签名信任与应用归属作为一等列携带。 一次文件读取、一条网络流以及一次进程 exec,到达时都已盖好”是谁签署了这个二进制文件、我们是否信任该签名、以及哪个面向用户的应用对此负责”。在 Linux 上,内核事件层面根本不存在这些信息。而在 macOS 上,它们随每一行一同传递,从而把诸如*“哪个未签名的应用读取了 ~/.ssh?“*这样的问题变成一条 WHERE 子句。
表结构概览
每一行都是一次观测到的内核事件,包含四层列:
本文将依次介绍每一层,然后列出
event_type 的取值。
公共头部(每个事件)
头部标识何时、何地与何人——无论事件分类如何,每一行都带有相同的行为主体元数据。wall_time_ns 是来自 Endpoint Security 消息的权威事件时间戳。event_time 是派生的 DateTime64 列,你在 ClickHouse 中用它进行过滤和分区。代码签名标识(每个事件)——macOS 差异化
在 macOS 上,内核知道每个运行中二进制文件的签名标识,Apple 的 Endpoint Security 框架会在每条消息中把它交给 ESensor。采集器将该标识提升为专用列,因此信任在每个事件上都可查询——而不仅仅是在 exec 上。code_signature 裁定
code_signature 将 Apple 的签名评估归并为四个信任层级之一:
正是这一列让 macOS 遥测与众不同。因为裁定存在于每一行上——文件、网络与进程皆然——你可以对任何动作提出信任层面的问题:
应用归属(每个事件)——macOS 差异化
现代 macOS 应用并非单个进程。仅 Google Chrome 就会派生出数十个Google Chrome Helper、Google Chrome Helper (GPU) 和 Google Chrome Helper (Renderer) 进程。只看原始的 comm 值,信号会散落在对分析师毫无意义的辅助进程之中。
macOS 采集器利用 Apple Endpoint Security 的”负责进程”概念,把每个事件归拢回其所属应用,从而按照人类的思维方式对活动进行分组。
这意味着单个
WHERE application_id = 'com.google.Chrome' 就能返回 Chrome 的完整足迹——每一次辅助进程 exec、它触及的每个文件、它打开的每条流——无需枚举辅助进程名。session_id 进一步将其收窄到应用的某一次具体启动,而 responsible_pid 让你可以从任意事件转向该负责进程。
responsible_pid 和 application_id 是仪表盘的 Investigate、Files、Networks 和 Users 视图将散落的辅助进程活动归属到用户实际运行的应用的方式。折叠在富化时完成,因此在每一次查询中都保持一致。单事件载荷
除了公共头部和两层始终存在的标识列外,每个事件分类还携带各自的载荷列。较少见的长尾属性会落入attrs 映射。
进程载荷——exec、fork、signal
exec 是进程模型的主干:它在同一行上携带 argv、签名标识、team id 和 cdhash。signal 事件记录 kill 尝试——attrs['target_pid'] 和 attrs['signum'] 揭示谁试图终止谁,从而暴露攻击者的击杀链,以及篡改采集器自身的尝试。
文件载荷——file_open、file_unlink、file_rename、file_chmod、xattr_set、xattr_delete
file_open 主导事件量(约 95%+),这正是 ESensor 在任何数据离开主机之前就施加激进的用户态过滤的原因——参见 Agent 过滤。
xattr_* 事件为 macOS 特有且信号价值高:它们捕获对 com.apple.quarantine 的更改,这是 Gatekeeper 用来标记下载文件的扩展属性。对隔离属性的 xattr_delete 是一种经典的 Gatekeeper 绕过——剥除”从互联网下载”标志,使操作系统在不弹窗提示的情况下运行文件。
网络载荷——net_flow
网络流来自
lsof/socket 轮询器与 NetFilter NetworkExtension 内容过滤系统扩展的组合,后者将每条流的审计令牌解析回负责应用。得益于 NetFilter,一条 net_flow 行已经知道哪个应用打开了该连接——bundle_id 无需单独的进程到 socket 关联步骤即可回答”是什么发起了这个连接”。
net_flow 仅记录连接元数据——目标、端口、字节计数和负责应用。它不捕获数据包载荷,且默认不解析 DNS 名称。持久化载荷——btm_add
btm_add 事件来自 macOS 13+ 的 Background Task Management (BTM),每当注册 launch agent、launch daemon 或 login item 时触发——即当某物将自身安装为跨重启持久化时。这是 macOS 上信号价值最高的单个持久化事件:绝大多数 macOS 恶意软件(以及合法的自启动软件)正是借此在重启后存活。
设备载荷——mount
mount 事件在文件系统被挂载时触发——最值得关注的是可移动介质(USB 驱动器)和磁盘映像(DMG),二者都是数据外泄和软件投递的常见途径。
事件类型
采集器订阅 12 个 Apple Endpoint Security 事件外加一个网络源,并向endpoint_events 发出以下 event_type 取值:
xattr_delete 和 mount 本质上罕见(隔离移除以及 USB/DMG 挂载)——它们已被订阅并发出,但一台安静的主机在短时间窗口内可能一个都不显示。signal、file_unlink 和 file_rename 作为 AUTH 事件订阅,以便 ESensor 还能拒绝对自身的篡改,但它们仍会发出等价的遥测行。标识与归属如何被填充
标识层与归属层并非尽力而为的元数据——它们以很高的填充率被填充,且是大多数查询所依赖的透视列。来自实时数据的已验证填充率:
关于遥测如何从 ESensor 传输到 ClickHouse 的更多内容,参见端到端数据流。关于原始事件量在离开主机之前如何被削减,参见 Agent 过滤。
采集器不会捕获的内容
与 Linux 采集器的设计理念一致,macOS 采集器仅在元数据层面观测活动。它不是内容检查工具。它不会捕获:- 文件内容——仅捕获路径、操作类型、标志,以及(对于重命名)目标路径
- 数据包载荷——仅捕获流的目标、端口、字节计数和负责应用
- DNS 查询内容——
net_flow默认不解析域名 - 键盘输入或屏幕内容
- 内存区域或进程内存
- 环境变量
- 凭据或任何用户数据——超出
ps、lsof或codesign等标准工具本就会暴露的范围之外
