Suzu macOS Playground

M14 · 階梯 5 · L4

偵測、監控與 DFIR

把前面每一道信任邊界翻過來看——攻擊者過閘時在 Endpoint Security、Unified Log、OpenBSM、FSEvents、Spotlight/KnowledgeC 留下什麼訊號,怎麼用 eslogger 訂閱事件、重建 timeline、做 Time Machine 取證,並認清 ES mute/event-flooding 與 `<private>` 遮蔽造成的 telemetry 盲區。

●● 前置:M03、M04、M05、M06、M07、M08、M09 eslogger · log · praudit · auditreduce · fs_usage · mdfind · mdls · tmutil · mount_apfs · launchctl · sfltool · systemextensionsctl · sqlite3

把每一道閘倒過來看

前面九個模組教的是攻擊者要通過哪些閘:簽章(M03)、Gatekeeper(M04)、SIP(M05)、TCC(M06)、Sandbox(M07)、XPC(M08)、權限分層(M09)。這一章把同一套機制倒過來問:攻擊者過閘的那一刻,作業系統在哪裡記了什麼?

這就是 DFIR(Digital Forensics & Incident Response)與 EDR(Endpoint Detection & Response)的核心心智模型——telemetry 是攻擊面的鏡像。每一個信任決策,理論上都有一個對應的可觀測訊號:

攻擊面(前面模組)主要 telemetry 來源看什麼
程序執行 / 父子關係(M09)Endpoint Security ES_EVENT_TYPE_*_EXECexec 鏈、is_platform_binary、簽署 team/signing_id
Gatekeeper / quarantine(M04)Unified Log(syspolicyd)、com.apple.quarantine xattr首次執行評估、下載來源
TCC 授權(M06)Unified Log(tccd)、TCC.db哪個 client 對哪個資源請求/被准
持久化(M10 概念)LaunchAgents/Daemons、BTM、ES BTM_LAUNCH_ITEM_ADD新增的開機/登入項
檔案落地 / 改名FSEvents、ES WRITE/RENAME/CREATEdropper 寫了什麼到哪
XPC / 提權(M08)OpenBSM 稽核(AUE_* 認證/授權記錄,如 AUE_ssauthorize、登入事件)認證、授權、敏感操作
互動式登入 / SSHES ES_EVENT_TYPE_NOTIFY_LOGIN_LOGIN、ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGIN(macOS 14 起)誰在何時登入、來源

⚠ 重點:偵測不是「裝個工具就好」。每一種來源都有它看得到與看不到的邊界。本章的真正目標不是「列出所有 log 指令」,而是讓你能對任一攻擊面,說出它的偵測面與盲區在哪——這正是階梯 5「為每類攻擊面設計一條偵測規則」的能力。

Endpoint Security Framework:核心級的事件總線

Endpoint Security(ES)是 macOS 上做 EDR 的權威來源。它不是抓 log 字串,而是 kernel 在關鍵動作發生時,主動把結構化事件(es_message_t)推給已註冊的 ES client。相較於 dtrace/fs_usage 這類取樣或字串 trace,ES 的事件是有型別、有 audit token、與動作同步的。

AUTH 事件 vs NOTIFY 事件——這是整個框架的關鍵分野

ES 的事件分兩大類,混淆這兩者會誤判一個產品「能不能阻擋」:

類別時機client 能做什麼例
AUTH(ES_EVENT_TYPE_AUTH_*)動作發生前,kernel 阻塞等你裁決回 ES_AUTH_RESULT_ALLOW / DENY,可阻擋AUTH_EXEC、AUTH_OPEN、AUTH_MOUNT
NOTIFY(ES_EVENT_TYPE_NOTIFY_*)動作發生後(非同步)只能觀察記錄,無法回頭阻擋NOTIFY_EXEC、NOTIFY_FORK、NOTIFY_WRITE

直覺:AUTH 是門禁、NOTIFY 是監視器。AUTH client 必須在 deadline 內回應,否則 kernel 視為逾時並依預設處置——這就是為什麼寫得爛的 AUTH client 會拖垮系統(每個 exec/open 都在等它)。EDR 設計上的取捨在此:要阻擋能力(AUTH)就得吃延遲與穩定性風險;只做偵測(NOTIFY)則攻擊者的動作已經發生了,你只是事後知道。

⚠ errata / 防禦視角:許多「行為偵測」產品其實只訂 NOTIFY。理解這點才知道它的處置邊界——它能告訴你「發生了惡意 exec」,但那支程序已經跑起來。把 NOTIFY 偵測誤當成阻擋,是事件回應裡常見的錯誤假設。

一條 es_message 裡有什麼

不論用內建 eslogger 還是自製 client,每條事件大致都帶:事件型別、發生時間、觸發的 process(含 audit token、pid、ppid、簽署資訊 is_platform_binary / signing_id / team_id / cdhash)、以及該事件型別專屬的 payload(exec 的 target 與 args、open 的 file、rename 的 source/dest…)。

簽署欄位之所以關鍵,是因為它接回 M03/M09:一條 is_platform_binary=false、父程序是 Terminal、target 落在 /tmp 的 exec,三個特徵疊起來就是經典的可疑落地執行訊號。單一欄位不足以判定,特徵的組合才是規則。

下面的實驗室餵一條合成 es_message 流,讓你寫簡化 predicate 即時看命中,並用 mute 開關示範偵測盲區:

ES 事件流 + 偵測規則

#typekindprocpathplat
1execAUTHTerminal/bin/zsh✓
2execAUTHzsh/tmp/.x/helper✗
3openNOTIFYhelper~/Library/LaunchAgents/com.x.plist✗
4btm_addNOTIFYhelpercom.x.agent✗
5mmapNOTIFYSafari/usr/lib/dyld✓
6execAUTHlaunchd/tmp/.x/helper✗
7openNOTIFYSpotlight~/Documents/a.pdf✓
命中 2 筆

AUTH(黃)事件可即時放行/拒絕(同步、有背壓);NOTIFY 只是事後通知。predicate 太鬆 → 雜訊(FP),太緊 → 漏報(FN)。mute / event-flooding 是真實盲區:被 mute 的程序事件根本不送達 client。純教學合成流。

eslogger:系統內建、不用付費帳號的 ES 訂閱器

自寫 ES client 需要 com.apple.developer.endpoint-security.client entitlement——這要向 Apple 申請、且 system extension 要付費開發者帳號簽署。對學習者這是門檻。好消息:macOS 內建的 eslogger(/usr/bin/eslogger,自 macOS 13 Ventura 起,驗證於版本)就是 Apple 簽的 ES client,root 即可訂閱大多數事件型別並輸出 JSON,不需要自己的 entitlement。

sudo eslogger --list-events                 # 列出此版本支援訂閱的所有 ES 事件型別
sudo eslogger exec | head                   # 訂閱 exec 事件(JSON,一行一事件)

⚠ errata(必記):eslogger(與所有 ES client 一樣)強制要求 root,且要對「responsible process」——即執行它的終端機/父程序——授予 Full Disk Access。man eslogger 寫的是 “requires”,不是「實務上建議」。缺 FDA 時 es_new_client() 會直接以 ERR_NOT_PERMITTED 連線失敗、根本起不來(不是跑出殘缺資料)。沒授權卻看到它跑不動,是「缺 TCC 授權」而非「工具壞了」。這正呼應 M06:連偵測工具自己都受 TCC 管。另外 eslogger 是研究/除錯導向工具,Apple 文件明言它不適合當生產 EDR 的長期資料平面(無背壓保證、可能丟事件);正式產品要走自己的 ES client。

實務節奏(呼應 DESIGN.md §3.1 的黃色可達性註):hands-on 主路徑用 eslogger,自製 ES client 降為概念/選修,避免對沒有付費帳號的學習者形成隱性門檻。

Unified Logging 與 <private>:為什麼你常看到一片馬賽克

macOS 的系統日誌是 Unified Logging:記憶體 + 磁碟上的 .tracev3 二進位環形緩衝(在 /var/db/diagnostics/,配合 /var/db/uuidtext/ 還原字串),用 log 工具讀。

log stream --predicate 'subsystem == "com.apple.TCC"' --info   # 即時看 tccd 的授權決策
log show --last 1h --predicate 'process == "syspolicyd"'        # 回看 Gatekeeper/notarization 評估

但你很快會撞到這個:

default  tccd  Service kTCCServiceCamera, client <private>, ...

⚠ errata(核心觀念):<private> 不是壞掉,是設計上的隱私遮蔽。Unified Logging 預設把被標為 private 的格式化欄位(常是路徑、識別碼、使用者輸入這類敏感資料)遮成 <private>。這對 DFIR 是雙面刃——它保護隱私,但也代表你能看到「發生了什麼類別的事」,卻看不到具體的哪個檔/哪個 client 字串。

要在自己研究的機器上揭露 private 欄位,需要安裝 Apple 簽署的 logging configuration profile(Enable-Private-Data / system_logging)或在 recoveryOS 調整,且這會降低該機隱私——屬授權研究環境的操作,不是預設狀態。把 <private> 當成結構性盲區來規劃偵測,而不是假設你總能拿到明文。

⚠ 保存性盲區:tracev3 是環形緩衝,舊事件會被覆蓋(保留時間視音量與磁碟而定)。事件調查要趁早 log collect 把 .logarchive 收下來,不能假設一週前的 exec 還在。

OpenBSM 稽核:另一條獨立的、可控保存的軌

ES 是現代主力,但 macOS 還保留(正在淘汰中的)OpenBSM(Basic Security Module)稽核子系統——auditd 依 /etc/security/audit_control 的 flags 把事件寫成 BSM 二進位 trail(/var/audit/),用 praudit / auditreduce 解讀。

⚠ 重要前提:OpenBSM 預設是關的(macOS 14+)。 man auditd 明載:audit(4) 子系統「since macOS 11.0 deprecated、since macOS 14.0 disabled、未來版本將移除」。預設機器上 auditd 不跑、/etc/security/ 只有 audit_control.example、/var/audit/current 不存在。下面的 praudit 命令卡需先手動啟用才有資料(copy audit_control.example→audit_control、launchctl enable system/com.apple.auditd、重開機)。所以把 OpenBSM 當「ES 被 mute 時的交叉佐證」只在該機曾啟用 BSM 時成立,別假設預設可用。

# ⚠ 以下需先啟用 auditd(預設停用);否則 /var/audit/current 不存在
sudo praudit -l /var/audit/current | tail              # 解讀最新稽核軌(每行一筆 token 串)

OpenBSM 啟用後的價值在於它與 ES 互補且獨立:它有自己的持久化 trail、能稽核認證/授權這類面向。缺點是事件模型古老、欄位粗,且已被官方標為淘汰。DFIR 上頂多當選修/歷史軌,不能當預設可用的依靠。

FSEvents、Spotlight 與 KnowledgeC:被動留下的時間線素材

不是所有訊號都來自即時監控;很多是系統為了別的目的順手記下、事後可挖的取證寶庫:

  • FSEvents:每個 APFS 卷根的 .fseventsd/ 目錄級變更日誌(粒度到目錄、非每檔每動作)。現代 System/Data 分割下,使用者資料的日誌在 Data 卷(/System/Volumes/Data/.fseventsd,唯讀 sealed 系統卷上沒有 /.fseventsd)。它本是給備份/Spotlight 用的,但能回答「這個目錄曾經有過變更」——對重建「dropper 寫過哪裡」很有用,即使檔案已被刪。
  • Spotlight metadata:mdls 看單檔 metadata,其中 kMDItemDateAdded、kMDItemDownloadedDate、kMDItemWhereFroms(下載來源 URL,接回 M04 quarantine)等是強力 timeline 錨點。mdfind 可全機查詢。
  • KnowledgeC / biome:~/Library/Application Support/Knowledge/knowledgeC.db 等 SQLite 記了 app 使用、裝置活動等行為。注意這些是私有、未文件化的 schema,欄位語意可能隨版本變(驗證於版本)——當佐證可以,當鐵證要謹慎。
mdls /path/to/suspicious_file                          # 看 DateAdded / WhereFroms / DownloadedDate
mdls -name kMDItemWhereFroms /path/to/file             # 只看下載來源 URL(接 M04)
sudo fs_usage -w -f filesys | grep -i write            # 即時看檔案系統寫入(取樣式,會漏)

持久化盤點與 timeline 重建

承 M10 的全景:DFIR 的「找立足點」就是系統化盤點所有能讓程式在重開機/登入後再跑的位置——LaunchAgents/Daemons、login items、BTM(Background Task Management)、cron、Configuration Profile/MDM。現代 macOS 把這些核可集中到 BTM,所以 ES 的 NOTIFY_BTM_LAUNCH_ITEM_ADD 事件是新增持久化的高價值偵測點。

timeline 重建的本質:把多來源事件(ES exec、FSEvents 寫入、Spotlight DateAdded、quarantine 時戳、Unified Log 的 syspolicy 評估)按時間軸對齊成一條故事線,找出「初始落地 → 執行 → 持久化 → 外連」的順序。本章的關卡會用去識別化的合成 es_message 流讓你練這件事,不必在真機上製造惡意行為。

log show --last 24h --predicate 'subsystem == "com.apple.syspolicy"' --info  # 評估事件
launchctl list                                          # 目前載入的 launchd 服務(盤點起點)
sudo sfltool dumpbtm 2>/dev/null | head                 # 檢視 BTM 註冊項(持久化全景)

Time Machine 取證:被忽略的「過去快照」

Time Machine 在 APFS 上是 local snapshot + 備份卷。對 DFIR 的意義:即使攻擊者刪檔、清 log,較舊的 APFS 本機快照可能還保留著被刪的 dropper、被改前的 LaunchAgent plist、甚至更完整的 .tracev3。

tmutil listlocalsnapshots /                             # 列出本機 APFS 快照(含時戳)
tmutil listbackups 2>/dev/null                          # 列出備份(若有外接/網路備份卷)

⚠ 取證原則:要從快照取資料,掛載成唯讀(mount_apfs -s <snapshot> -o ro …)再複製出來,絕不在原始證據上改動。任何寫入、解封、或關 SIP 的操作屬授權鑑識流程,需 recoveryOS/明確授權與證物鏈紀錄,不在本章唯讀範圍內。

Network Extension 偵測面

承 M15 會深入的 Network Extension:content filter / DNS proxy / packet tunnel 這類 NE 既是防禦工具(你可以用它做網路偵測),也是攻擊面(惡意 NE 可攔截/重導流量)。偵測角度看兩件事:(1) 誰註冊了 NE——systemextensionsctl list 列出已啟用的 system extension,未預期的 content filter 就是訊號;(2) NE 的存在本身會改變網路 telemetry 的可信度(流量可能被它改寫)。

systemextensionsctl list                                # 列出已啟用的 system extension(含 NE)

⚠ 安裝/卸載 system extension 需使用者核可與對應 entitlement;systemextensionsctl developer 等開發模式操作會降低系統限制,屬授權研究環境,不在唯讀盤點範圍。

ES 的盲區:mute 與 event-flooding

這是本章最重要的防禦現實,也是 lvl2 關卡的核心。ES 不是全知的。

  • mute(靜音):ES client 可對特定 process / path 設 mute,讓 kernel 不再為它送某些事件。這原本是效能優化(不想被 /usr/bin 的正常活動淹沒)。但mute inversion(只觀察白名單、其餘全靜音)若設計不當,會在白名單外開一個完全看不見的洞——攻擊者只要落在被 mute 的路徑/程序,事件根本不產生。這不是「規則沒命中」,是事件壓根沒來。
  • event-flooding(事件洪泛):大量良性事件(密集 fork/exec、大量 open)會把 AUTH client 的處理拖到 deadline、或把 NOTIFY 緩衝壓爆導致 kernel 丟事件,惡意事件就可能落在被丟掉的那批裡。AUTH client 逾時後,kernel 會套用該 client 的逾時處置策略——許多 EDR 為避免凍結系統而選 fail-open(放行),這正是理解「為何高負載下偵測會失真」的關鍵(屬機制理解,非繞過步驟)。

⚠ errata / 防禦設計重點:把 mute 與 flooding 當成結構性盲區而非「bug」。一條好的偵測規則不只要會命中惡意事件(TP),還要對「我這條規則的可見範圍被 mute 排除了嗎?」「flooding 下我會不會先丟事件再漏報?」有自覺。本章 lvl2 關卡會讓你在合成事件流上調整 mute-inversion 與 flooding 的條件,觀察惡意事件如何「從事件流裡消失」——藉此建立「telemetry 有邊界」的直覺,把這當成偵測面的已知未知列入規則的覆蓋假設。

🟢/🟡 真機操作卡

以下皆為唯讀觀察,在你自己的機器上安全執行(macOS 26 適用)。需要 root 的會標 sudo。

# ── Endpoint Security(🟡 強制需 root + 對終端機/父程序的 Full Disk Access;缺 FDA 直接連線失敗。研究用,非生產 EDR)──
sudo eslogger --list-events                 # 此版本支援的 ES 事件型別清單(看偵測面有多廣)
sudo eslogger exec | head                   # 訂閱 exec:看 target/args 與簽署欄位(is_platform_binary)

# ── Unified Logging(看決策訊號;注意 <private> 是設計上的遮蔽)──
log stream --predicate 'subsystem == "com.apple.TCC"' --info   # tccd 授權決策(接 M06)
log show --last 1h --predicate 'process == "syspolicyd"'        # Gatekeeper/notarization 評估(接 M04)
log show --last 30m --predicate 'process == "sandboxd"' --info  # sandbox 拒絕訊號(接 M07)

# ── OpenBSM 稽核(macOS 14+ 預設停用;需先啟用 auditd 才有資料)──
sudo praudit -l /var/audit/current | tail   # 預設機器上 /var/audit/current 不存在,須先啟用 auditd

# ── FSEvents / Spotlight / KnowledgeC(被動 timeline 素材)──
mdls -name kMDItemWhereFroms ~/Downloads/* 2>/dev/null  # 下載來源 URL(quarantine 的另一面)
mdls -name kMDItemDateAdded -name kMDItemDownloadedDate ~/Downloads/* 2>/dev/null

# ── 持久化盤點 + Time Machine 取證(找立足點與過去狀態)──
launchctl list | head                       # 已載入的 launchd 服務(盤點起點)
sudo sfltool dumpbtm 2>/dev/null | head     # BTM 持久化全景(接 M10)
tmutil listlocalsnapshots /                 # 本機 APFS 快照時戳(可能保有被刪證據)

# ── Network Extension 偵測面 ──
systemextensionsctl list                    # 已啟用的 system extension / NE(未預期者即訊號)

⚠ 危險/授權邊界:揭露 Unified Log 的 <private> 欄位需安裝 Apple 簽署的 logging profile 或 recoveryOS 操作,降低該機隱私;從 APFS 快照取證需唯讀掛載並保全原證;eslogger 雖 root 可用,但對全系統行為的訂閱應只在你有權限的研究機上進行,且其輸出可能含他人敏感資料。任何停用 SIP、開 system extension 開發模式、或寫入證據卷的操作,皆屬授權鑑識流程,需 recoveryOS/明確授權(DESIGN.md §10)。


下一步:M15 橫向專題 — 把 DFIR 學到的偵測視角分流到各專題深水區:Network Extension 攻防、Rosetta 2 安全意涵、虛擬化/VM 研究限制、SEP/firmware 深入、Keychain/資料保護、網路信任(Trust Store / ATS / 憑證釘選)。