Lab 1 was persistence in the boot chain. This is the version that actually runs on the machine in front of you. An implant that survives a reboot has to register somewhere the OS will read on the way up or on login — and macOS has a fixed, well-known set of those places. That's the defender's advantage: the hiding spots are enumerable. You list them, check each item's signature and path against what belongs, and diff against a baseline. New, unsigned, and in the wrong place is the whole game.
To survive, persistence registers with one of a handful of OS mechanisms. Each is a place you can enumerate:
~/Library/LaunchAgents (per-user), /Library/LaunchAgents + /Library/LaunchDaemons (system), run by launchd with RunAtLoad / KeepAlive. Most macOS malware lands here.SMAppService and are tracked in the Background Task Management database (macOS 13+). sfltool dumpbtm lists them; a new ad-hoc-signed helper here is a classic dropper tail.com.apple.loginwindow LoginHook running a shell script. Deprecated, still works, and rarely legitimate today — a strong signal when present.crontab entry or a script dropped into /etc/periodic is low-tech persistence that EDR sometimes overlooks..mobileconfig can install payloads and settings with authority. An unexpected profile (profiles list) is persistence and policy control at once.DYLD_INSERT_LIBRARIES in a plist's environment, or a hijackable @rpath, loads attacker code into a legit process on launch — ties straight to Lab 6 & 9.A snapshot of the persistence locations on a sample Mac. Run the sweep — each item is judged by who signed it (Apple / valid Developer ID / unsigned-or-ad-hoc), where its program lives (a system path vs. /tmp or a hidden dir), and whether it masquerades as something Apple. Apple system agents and known vendors pass; the odd ones out light up.
The sweep above is a point-in-time list. The real detection is continuous: enumerate the locations, establish a baseline of what's normal for this host, and alert on anything that appears — the same baseline-then-diff from Labs 1 and 3, pointed at launchd.
# osquery — the persistence locations as tables, queryable and diffable SELECT name,path,program,run_at_load FROM launchd WHERE run_at_load=1; # agents/daemons SELECT * FROM startup_items; SELECT * FROM crontab; SELECT * FROM launchd_overrides; # disabled→enabled flips # eslogger — watch the locations change in real time (Endpoint Security) eslogger btm_launch_item_add create # new login item / plist write # signing & profiles codesign -dv --verbose=4 <program> · spctl --assess · profiles list # reference tools (Objective-See) KnockKnock # enumerate every persistence point, check signatures BlockBlock # alert the moment something persists
A new item becomes a Vertical case (Lab 7): the plist, its signature verdict, the writing process and its lineage, captured as evidence.
launchd, Service Management (SMAppService / BTM), Endpoint Security framework.launchd, startup_items, crontab, launchd_overrides tables.T1543.001 / Launch Daemon T1543.004; Boot/Logon Autostart: plist mod T1547.011; Boot/Logon Init Scripts T1037; Event-Triggered Execution T1546.Next: Lab 12 — DNS / DGA: expanding Lab 4's tunnel detector into domain-generation-algorithm scoring and fast-flux.