MACOS FORENSICS
Defensive / DFIR quick reference for macOS (Intel and Apple Silicon). Blue-team only: what to collect, where artifacts live, how to triage. Collect in order of volatility; work on a copy, hash everything. Many of these files are gated by Full Disk Access (TCC) - grant Terminal FDA, or read them from a mounted image. Paths shown for recent macOS (Monterey 12 - Tahoe 26); some move between versions (untested on 26).
ORDER OF VOLATILITY#
1. Memory (RAM) - hardest on Apple Silicon; grab first if feasible 2. Running processes, open files, network state 3. System/user caches, unified log ring buffer 4. Disk: filesystem, databases, plists, logs 5. Backups (Time Machine), external/archival media
LIVE TRIAGE: SYSTEM + PROCESSES#
sw_vers # product name, version, build system_profiler SPSoftwareDataType # OS, uptime, boot mode, SIP note uname -a ; hostname # kernel / host csrutil status # System Integrity Protection on/off sysctl hw.model machdep.cpu.brand_string # hardware / CPU (Intel vs ARM) date -u ; uptime ps auxwww # all processes, args ps -axo pid,ppid,user,lstart,command # with start time + parent lsof -nP # open files (needs root for all) lsof -i -nP # network-connected processes
USERS + LOGIN HISTORY#
dscl . -list /Users UniqueID | awk '$2>=500' # real users (UID>=500) dscl . -list /Users # ALL accounts incl _service ones dscl . -read /Users/<user> # one account (UID, home, shell) dscl . -read /Groups/admin GroupMembership # who is an admin # dslocal plists (offline on an image): # /var/db/dslocal/nodes/Default/users/<user>.plist last # login history (utmpx records) who ; w # current sessions log show --predicate 'process == "loginwindow"' --last 7d # GUI logins # FileVault-unlock + console logins also show in the unified log.
UNIFIED LOG (primary macOS log store)#
# Live stream + historical query (binary .tracev3, not text files): log stream --info --predicate 'eventMessage CONTAINS "fail"' log show --last 1h --info --debug # recent, incl info/debug events log show --predicate 'process == "sudo"' --last 1d log show --predicate 'subsystem == "com.apple.securityd"' --last 1d # Collect the whole store for offline analysis: log collect --output /evidence/logs.logarchive log show /evidence/logs.logarchive --predicate '...' # On-disk store (parse offline with mac_apt / UnifiedLogReader): # /var/db/diagnostics/ (+ /var/db/uuidtext/ for string lookups) # Note: default store is only days of history - collect early.
PERSISTENCE#
# Launchd jobs (plists). Check Contents, ProgramArguments, RunAtLoad:
~/Library/LaunchAgents/ # per-user agents
/Library/LaunchAgents/ # all users, agents
/Library/LaunchDaemons/ # system daemons (run as root)
# Apple's own (SIP-protected, normally trusted):
/System/Library/Launch{Agents,Daemons}/
launchctl list # loaded jobs (scope = who runs it;
# root -> system, user -> that GUI)
launchctl print gui/$(id -u) # detailed per-user domain
launchctl print system # system domain
# Login / background items (Ventura 13+ Background Task Mgmt):
sfltool dumpbtm # all BTM login + launchd items
# store: /private/var/db/com.apple.backgroundtaskmanagement/
# (BackgroundItems-v*.btm, a binary plist; dumpbtm decodes it)
# Managed configuration profiles (MDM or rogue):
sudo profiles list # installed profiles (run as root)
# /Library/Managed Preferences/ , /var/db/ConfigurationProfiles/
# Login/logout hooks (legacy but still honoured):
defaults read com.apple.loginwindow LoginHook LogoutHook 2>/dev/null
# Shell startup files (per user + system):
cat ~/.zshrc ~/.zprofile /etc/zshrc /etc/zprofile 2>/dev/null
# System extensions / kexts:
systemextensionsctl list ; kextstat -l
# Older / legacy mechanisms:
crontab -l # per-user cron (/usr/lib/cron/tabs/)
ls -la /etc/periodic/ /etc/periodic/*/ # periodic scripts
ls -l /etc/rc.common /etc/rc.local 2>/dev/null # rc.local not run by launchd
ls -la /Library/StartupItems/ 2>/dev/null # deprecated startup items
# emond was removed in Ventura; /etc/emond.d/ only on older systems.
GATEKEEPER / QUARANTINE / XPROTECT#
spctl --status # Gatekeeper assessment on/off spctl -a -vvv /path/to/App.app # assess a bundle's signature xattr -l <file> # show com.apple.quarantine + source # Quarantine events (download provenance) - SQLite LSQuarantineEvent # table; cols LSQuarantineTimeStamp (Mac absolute time, secs since # 2001-01-01), LSQuarantineAgentName, LSQuarantineDataURLString, # LSQuarantineOriginURLString. Per user: ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2 # XProtect (Gatekeeper yara data) + XProtect Remediator (XProtect.app): /Library/Apple/System/Library/CoreServices/XProtect.bundle # signatures /Library/Apple/System/Library/CoreServices/XProtect.app # Remediator # Sequoia 15.2+: active bundle copy also at /var/protected/xprotect/. system_profiler SPInstallHistoryDataType # XProtect/MRT version history codesign -dvvv --entitlements :- /path/App.app # signature + entitlements
TCC (privacy permissions - who got mic/camera/FDA/etc)#
# SQLite 'access' table cols: service, client, client_type (0=bundle # id, 1=absolute path), auth_value, last_modified (Unix epoch). ~/Library/Application Support/com.apple.TCC/TCC.db # per-user grants /Library/Application Support/com.apple.TCC/TCC.db # system grants # Read needs Full Disk Access (TCC), or read it from a mounted image. # auth_value: 0=denied 1=unknown 2=allowed 3=limited (newer schema). # kTCCServiceSystemPolicyAllFiles = Full Disk Access.
SPOTLIGHT + FSEVENTS (file activity)#
mdls <file> # all Spotlight metadata of a file mdls -name kMDItemWhereFroms <file> # download source URL(s) mdfind -onlyin /path "query" # search the Spotlight index # FSEvents (dir-level change log) - parse offline (FSEventsParser). # Catalina+ the data lives on the Data volume: /System/Volumes/Data/.fseventsd/ # (/.fseventsd via firmlink on live) # Spotlight store (offline): /System/Volumes/Data/.Spotlight-V100/
ACTIVITY DATABASES (user behaviour timeline)#
# knowledgeC - app usage, focus, device lock/unlock (parse w/ APOLLO): ~/Library/Application Support/Knowledge/knowledgeC.db # per-user /private/var/db/CoreDuet/Knowledge/knowledgeC.db # system # macOS 13+ (Ventura): much of this activity moved to the Biome store # ~/Library/Biome/ and /private/var/db/biome/ - check both. # Power log (process/app activity, APOLLO-parseable) - a .PLSQL SQLite # DB; its exact path varies by version, so locate it on the image: sudo find /private/var -iname '*powerlog*' 2>/dev/null # Recent / opened items (SharedFileList, binary plists): ~/Library/Application Support/com.apple.sharedfilelist/
USER + BROWSER ARTIFACTS#
cat ~/.zsh_history ~/.bash_history 2>/dev/null # shell history ls -la@ ~/Downloads # -@ shows xattrs (quarantine) # Safari (SQLite / plist): ~/Library/Safari/History.db ~/Library/Safari/Downloads.plist # Chrome / Edge (SQLite): .../Google/Chrome/Default/History # Mail, Messages (chat.db), Notes live under ~/Library/ too. plutil -p <file>.plist # pretty-print any (binary) plist defaults read <domain> # read a preference domain
INSTALL + SYSTEM HISTORY#
# Package install receipts (what was installed, when, by whom): /Library/Receipts/InstallHistory.plist ls -la /var/db/receipts/ # .bom + .plist per installed pkg pkgutil --pkgs # installed package IDs system_profiler SPApplicationsDataType # installed apps + signed-by
NETWORK STATE#
lsof -i -nP # sockets with owning process netstat -anv # all connections (BSD netstat) nettop -P -l 1 # per-process traffic snapshot arp -an # ARP cache scutil --dns # resolver config networksetup -listallnetworkservices # configured services ifconfig -a # Config state (offline on image): # /Library/Preferences/SystemConfiguration/
KEYCHAIN + AUDIT#
security list-keychains # keychain search list # ~/Library/Keychains/login.keychain-db (user secrets - needs pwd) # /Library/Keychains/System.keychain # OpenBSM audit trail (if auditing enabled; deprecated but present): ls -la /var/audit/ # binary audit logs (BSM) praudit -l /var/audit/<trailfile> # decode one trail, one line/record cat /etc/security/audit_control # audit policy / flags
ACQUISITION (APFS, FileVault)#
diskutil list # volumes / APFS containers diskutil apfs list # APFS detail (encryption state) fdesetup status # FileVault on? (need key to decrypt) # T2 + Apple Silicon encrypt internal storage in hardware, so a raw dd # of the PHYSICAL disk yields ciphertext. Image the UNLOCKED synthesized # APFS data volume device instead (find it in `diskutil list`), e.g.: dd if=/dev/rdisk3s1 of=/evidence/disk.raw bs=4m conv=noerror,sync shasum -a 256 /evidence/disk.raw | tee /evidence/disk.raw.sha256 # hdiutil makes a COMPRESSED logical image (not bit-for-bit) of a volume: hdiutil create -srcdevice /dev/diskXsY -format UDZO /evidence/img # Live triage / logical collection (preferred on modern Macs): # mac_apt (-> SQLite), a Velociraptor agent, or `sysdiagnose`. # RAM: no public tool on Apple Silicon; osxpmem is legacy (kext, <= 10.x).
TIMELINE + TOOLS#
# Build a super-timeline from a triage image or live host: # mac_apt - artifact parser -> SQLite/CSV (many of the above) # APOLLO - knowledgeC / powerlog pattern-of-life timeline # FSEventsParser - .fseventsd into readable events # log show --style json - unified log slices into your timeline # File times incl. APFS birth time (%SB) via BSD stat: stat -f '%N B=%SB m=%Sm c=%Sc a=%Sa' <file> # birth/mod/change/access
REFERENCES#
# Apple Platform Security guide (SIP, Gatekeeper, FileVault, keychain) # Apple man pages: log(1), spctl(8), fs_usage(1), launchctl(1) # SANS FOR518 macOS/iOS Forensic Analysis # mac_apt: github.com/ydkhatri/mac_apt # APOLLO: github.com/mac4n6/APOLLO # FSEventsParser: github.com/dlcowen/FSEventsParser # MITRE ATT&CK macOS: T1543.001/.004 (launchd agent/daemon), # T1547.015 (login items), T1553.001 (Gatekeeper bypass), # T1555.001 (keychain)
MACOS FORENSICS CHEAT SHEET
===========================
Source: https://cyberramen.com
Defensive / DFIR quick reference for macOS (Intel and Apple Silicon).
Blue-team only: what to collect, where artifacts live, how to triage.
Collect in order of volatility; work on a copy, hash everything. Many
of these files are gated by Full Disk Access (TCC) - grant Terminal
FDA, or read them from a mounted image. Paths shown for recent macOS
(Monterey 12 - Tahoe 26); some move between versions (untested on 26).
ORDER OF VOLATILITY
-------------------
1. Memory (RAM) - hardest on Apple Silicon; grab first if feasible
2. Running processes, open files, network state
3. System/user caches, unified log ring buffer
4. Disk: filesystem, databases, plists, logs
5. Backups (Time Machine), external/archival media
LIVE TRIAGE: SYSTEM + PROCESSES
-------------------------------
sw_vers # product name, version, build
system_profiler SPSoftwareDataType # OS, uptime, boot mode, SIP note
uname -a ; hostname # kernel / host
csrutil status # System Integrity Protection on/off
sysctl hw.model machdep.cpu.brand_string # hardware / CPU (Intel vs ARM)
date -u ; uptime
ps auxwww # all processes, args
ps -axo pid,ppid,user,lstart,command # with start time + parent
lsof -nP # open files (needs root for all)
lsof -i -nP # network-connected processes
USERS + LOGIN HISTORY
---------------------
dscl . -list /Users UniqueID | awk '$2>=500' # real users (UID>=500)
dscl . -list /Users # ALL accounts incl _service ones
dscl . -read /Users/<user> # one account (UID, home, shell)
dscl . -read /Groups/admin GroupMembership # who is an admin
# dslocal plists (offline on an image):
# /var/db/dslocal/nodes/Default/users/<user>.plist
last # login history (utmpx records)
who ; w # current sessions
log show --predicate 'process == "loginwindow"' --last 7d # GUI logins
# FileVault-unlock + console logins also show in the unified log.
UNIFIED LOG (primary macOS log store)
-------------------------------------
# Live stream + historical query (binary .tracev3, not text files):
log stream --info --predicate 'eventMessage CONTAINS "fail"'
log show --last 1h --info --debug # recent, incl info/debug events
log show --predicate 'process == "sudo"' --last 1d
log show --predicate 'subsystem == "com.apple.securityd"' --last 1d
# Collect the whole store for offline analysis:
log collect --output /evidence/logs.logarchive
log show /evidence/logs.logarchive --predicate '...'
# On-disk store (parse offline with mac_apt / UnifiedLogReader):
# /var/db/diagnostics/ (+ /var/db/uuidtext/ for string lookups)
# Note: default store is only days of history - collect early.
PERSISTENCE
-----------
# Launchd jobs (plists). Check Contents, ProgramArguments, RunAtLoad:
~/Library/LaunchAgents/ # per-user agents
/Library/LaunchAgents/ # all users, agents
/Library/LaunchDaemons/ # system daemons (run as root)
# Apple's own (SIP-protected, normally trusted):
/System/Library/Launch{Agents,Daemons}/
launchctl list # loaded jobs (scope = who runs it;
# root -> system, user -> that GUI)
launchctl print gui/$(id -u) # detailed per-user domain
launchctl print system # system domain
# Login / background items (Ventura 13+ Background Task Mgmt):
sfltool dumpbtm # all BTM login + launchd items
# store: /private/var/db/com.apple.backgroundtaskmanagement/
# (BackgroundItems-v*.btm, a binary plist; dumpbtm decodes it)
# Managed configuration profiles (MDM or rogue):
sudo profiles list # installed profiles (run as root)
# /Library/Managed Preferences/ , /var/db/ConfigurationProfiles/
# Login/logout hooks (legacy but still honoured):
defaults read com.apple.loginwindow LoginHook LogoutHook 2>/dev/null
# Shell startup files (per user + system):
cat ~/.zshrc ~/.zprofile /etc/zshrc /etc/zprofile 2>/dev/null
# System extensions / kexts:
systemextensionsctl list ; kextstat -l
# Older / legacy mechanisms:
crontab -l # per-user cron (/usr/lib/cron/tabs/)
ls -la /etc/periodic/ /etc/periodic/*/ # periodic scripts
ls -l /etc/rc.common /etc/rc.local 2>/dev/null # rc.local not run by launchd
ls -la /Library/StartupItems/ 2>/dev/null # deprecated startup items
# emond was removed in Ventura; /etc/emond.d/ only on older systems.
GATEKEEPER / QUARANTINE / XPROTECT
----------------------------------
spctl --status # Gatekeeper assessment on/off
spctl -a -vvv /path/to/App.app # assess a bundle's signature
xattr -l <file> # show com.apple.quarantine + source
# Quarantine events (download provenance) - SQLite LSQuarantineEvent
# table; cols LSQuarantineTimeStamp (Mac absolute time, secs since
# 2001-01-01), LSQuarantineAgentName, LSQuarantineDataURLString,
# LSQuarantineOriginURLString. Per user:
~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2
# XProtect (Gatekeeper yara data) + XProtect Remediator (XProtect.app):
/Library/Apple/System/Library/CoreServices/XProtect.bundle # signatures
/Library/Apple/System/Library/CoreServices/XProtect.app # Remediator
# Sequoia 15.2+: active bundle copy also at /var/protected/xprotect/.
system_profiler SPInstallHistoryDataType # XProtect/MRT version history
codesign -dvvv --entitlements :- /path/App.app # signature + entitlements
TCC (privacy permissions - who got mic/camera/FDA/etc)
------------------------------------------------------
# SQLite 'access' table cols: service, client, client_type (0=bundle
# id, 1=absolute path), auth_value, last_modified (Unix epoch).
~/Library/Application Support/com.apple.TCC/TCC.db # per-user grants
/Library/Application Support/com.apple.TCC/TCC.db # system grants
# Read needs Full Disk Access (TCC), or read it from a mounted image.
# auth_value: 0=denied 1=unknown 2=allowed 3=limited (newer schema).
# kTCCServiceSystemPolicyAllFiles = Full Disk Access.
SPOTLIGHT + FSEVENTS (file activity)
------------------------------------
mdls <file> # all Spotlight metadata of a file
mdls -name kMDItemWhereFroms <file> # download source URL(s)
mdfind -onlyin /path "query" # search the Spotlight index
# FSEvents (dir-level change log) - parse offline (FSEventsParser).
# Catalina+ the data lives on the Data volume:
/System/Volumes/Data/.fseventsd/ # (/.fseventsd via firmlink on live)
# Spotlight store (offline): /System/Volumes/Data/.Spotlight-V100/
ACTIVITY DATABASES (user behaviour timeline)
--------------------------------------------
# knowledgeC - app usage, focus, device lock/unlock (parse w/ APOLLO):
~/Library/Application Support/Knowledge/knowledgeC.db # per-user
/private/var/db/CoreDuet/Knowledge/knowledgeC.db # system
# macOS 13+ (Ventura): much of this activity moved to the Biome store
# ~/Library/Biome/ and /private/var/db/biome/ - check both.
# Power log (process/app activity, APOLLO-parseable) - a .PLSQL SQLite
# DB; its exact path varies by version, so locate it on the image:
sudo find /private/var -iname '*powerlog*' 2>/dev/null
# Recent / opened items (SharedFileList, binary plists):
~/Library/Application Support/com.apple.sharedfilelist/
USER + BROWSER ARTIFACTS
------------------------
cat ~/.zsh_history ~/.bash_history 2>/dev/null # shell history
ls -la@ ~/Downloads # -@ shows xattrs (quarantine)
# Safari (SQLite / plist):
~/Library/Safari/History.db
~/Library/Safari/Downloads.plist
# Chrome / Edge (SQLite): .../Google/Chrome/Default/History
# Mail, Messages (chat.db), Notes live under ~/Library/ too.
plutil -p <file>.plist # pretty-print any (binary) plist
defaults read <domain> # read a preference domain
INSTALL + SYSTEM HISTORY
------------------------
# Package install receipts (what was installed, when, by whom):
/Library/Receipts/InstallHistory.plist
ls -la /var/db/receipts/ # .bom + .plist per installed pkg
pkgutil --pkgs # installed package IDs
system_profiler SPApplicationsDataType # installed apps + signed-by
NETWORK STATE
-------------
lsof -i -nP # sockets with owning process
netstat -anv # all connections (BSD netstat)
nettop -P -l 1 # per-process traffic snapshot
arp -an # ARP cache
scutil --dns # resolver config
networksetup -listallnetworkservices # configured services
ifconfig -a
# Config state (offline on image):
# /Library/Preferences/SystemConfiguration/
KEYCHAIN + AUDIT
----------------
security list-keychains # keychain search list
# ~/Library/Keychains/login.keychain-db (user secrets - needs pwd)
# /Library/Keychains/System.keychain
# OpenBSM audit trail (if auditing enabled; deprecated but present):
ls -la /var/audit/ # binary audit logs (BSM)
praudit -l /var/audit/<trailfile> # decode one trail, one line/record
cat /etc/security/audit_control # audit policy / flags
ACQUISITION (APFS, FileVault)
-----------------------------
diskutil list # volumes / APFS containers
diskutil apfs list # APFS detail (encryption state)
fdesetup status # FileVault on? (need key to decrypt)
# T2 + Apple Silicon encrypt internal storage in hardware, so a raw dd
# of the PHYSICAL disk yields ciphertext. Image the UNLOCKED synthesized
# APFS data volume device instead (find it in `diskutil list`), e.g.:
dd if=/dev/rdisk3s1 of=/evidence/disk.raw bs=4m conv=noerror,sync
shasum -a 256 /evidence/disk.raw | tee /evidence/disk.raw.sha256
# hdiutil makes a COMPRESSED logical image (not bit-for-bit) of a volume:
hdiutil create -srcdevice /dev/diskXsY -format UDZO /evidence/img
# Live triage / logical collection (preferred on modern Macs):
# mac_apt (-> SQLite), a Velociraptor agent, or `sysdiagnose`.
# RAM: no public tool on Apple Silicon; osxpmem is legacy (kext, <= 10.x).
TIMELINE + TOOLS
----------------
# Build a super-timeline from a triage image or live host:
# mac_apt - artifact parser -> SQLite/CSV (many of the above)
# APOLLO - knowledgeC / powerlog pattern-of-life timeline
# FSEventsParser - .fseventsd into readable events
# log show --style json - unified log slices into your timeline
# File times incl. APFS birth time (%SB) via BSD stat:
stat -f '%N B=%SB m=%Sm c=%Sc a=%Sa' <file> # birth/mod/change/access
REFERENCES
----------
# Apple Platform Security guide (SIP, Gatekeeper, FileVault, keychain)
# Apple man pages: log(1), spctl(8), fs_usage(1), launchctl(1)
# SANS FOR518 macOS/iOS Forensic Analysis
# mac_apt: github.com/ydkhatri/mac_apt
# APOLLO: github.com/mac4n6/APOLLO
# FSEventsParser: github.com/dlcowen/FSEventsParser
# MITRE ATT&CK macOS: T1543.001/.004 (launchd agent/daemon),
# T1547.015 (login items), T1553.001 (Gatekeeper bypass),
# T1555.001 (keychain)
Defensive reference on CyberRamen. Offensive / red-team sheets live on OffensiveRamen.com.