Detect Launch Agent in Google Chronicle
Adversaries may create or modify launch agents to repeatedly execute malicious payloads as part of persistence on macOS. When a user logs in, a per-user launchd process loads parameters for each launch-on-demand user agent from property list (.plist) files in /System/Library/LaunchAgents, /Library/LaunchAgents, and ~/Library/LaunchAgents. Adversaries install Launch Agents by placing a .plist file into these directories with RunAtLoad or KeepAlive keys set to true, ensuring malicious payloads execute at every user login. Launch Agents execute with user-level permissions and are commonly disguised using Apple-like naming conventions (e.g., com.apple.softwareupdate.plist, com.apple.GrowlHelper.plist). This technique is used by Calisto, Proton, MacSpy, CrossRAT, Dok, OceanLotus, ThiefQuest, Dacls, macOS.OSAMiner, InvisibleFerret (Contagious Interview), CoinTicker, and Green Lambert malware families.
MITRE ATT&CK
- Tactic
- Persistence Privilege Escalation
- Technique
- T1543 Create or Modify System Process
- Sub-technique
- T1543.001 Launch Agent
- Canonical reference
- https://attack.mitre.org/techniques/T1543/001/
YARA-L Detection Query
rule macos_launch_agent_persistence_t1543_001 {
meta:
author = "Argus Detection Engineering"
description = "Detects macOS Launch Agent persistence via suspicious plist file creation in LaunchAgent directories or launchctl load/bootstrap execution. Covers Apple name spoofing and shell/interpreter-initiated writes."
mitre_attack_tactic = "Persistence"
mitre_attack_technique = "T1543.001"
mitre_attack_url = "https://attack.mitre.org/techniques/T1543/001/"
severity = "HIGH"
priority = "HIGH"
events:
// Branch 1: Plist file creation in LaunchAgent directories by suspicious processes
(
$file_event.metadata.event_type = "FILE_CREATION" or
$file_event.metadata.event_type = "FILE_MODIFICATION"
)
and $file_event.target.file.full_path = /\/Library\/LaunchAgents\/.+\.plist/
and (
$file_event.principal.process.file.full_path = /\/(bash|sh|zsh|python3|python|ruby|perl|curl|wget|osascript|node|npm|installer|pkgutil|xattr|mktemp)$/
or $file_event.target.file.full_path = /com\.apple\.[a-z]+\.[a-z]+\.plist/
or (
$file_event.target.file.full_path = /com\.[a-z0-9]{4,10}\.[a-z0-9]{4,10}\.plist/
and not $file_event.target.file.full_path = /com\.(apple|microsoft|adobe|google)\./
)
)
match:
$file_event.principal.hostname over 5m
outcome:
$hostname = $file_event.principal.hostname
$user = $file_event.principal.user.userid
$plist_path = $file_event.target.file.full_path
$writer_process = $file_event.principal.process.file.full_path
$writer_cmdline = $file_event.principal.process.command_line
$agent_scope = if(
re.match($file_event.target.file.full_path, "^/System/Library/LaunchAgents/"), "System",
if(re.match($file_event.target.file.full_path, "^/Library/LaunchAgents/"), "Global", "User")
)
$apple_name_spoof = re.match($file_event.target.file.full_path, "com\.apple\.[a-z]+\.[a-z]+\.plist") and
not re.match($file_event.target.file.full_path, "^/System/Library/")
condition:
$file_event
}
rule macos_launchctl_load_bootstrap_t1543_001 {
meta:
author = "Argus Detection Engineering"
description = "Detects launchctl load or bootstrap commands targeting LaunchAgent paths, initiated by shell interpreters or download utilities — a key step in activating a malicious launch agent."
mitre_attack_tactic = "Persistence"
mitre_attack_technique = "T1543.001"
severity = "HIGH"
priority = "HIGH"
events:
$proc.metadata.event_type = "PROCESS_LAUNCH"
and $proc.target.process.file.full_path = /\/launchctl$/
and (
$proc.target.process.command_line = /load/ or
$proc.target.process.command_line = /bootstrap/
)
and (
$proc.target.process.command_line = /LaunchAgents/ or
$proc.target.process.command_line = /\.plist/
)
and $proc.principal.process.file.full_path = /\/(bash|sh|zsh|python3|python|ruby|perl|curl|wget|osascript|node|npm|installer|pkgutil)$/
match:
$proc.principal.hostname over 5m
outcome:
$hostname = $proc.principal.hostname
$user = $proc.principal.user.userid
$parent_process = $proc.principal.process.file.full_path
$parent_cmdline = $proc.principal.process.command_line
$launchctl_cmdline = $proc.target.process.command_line
condition:
$proc
} Two Chronicle YARA-L 2.0 rules detecting macOS Launch Agent persistence. Rule 1 fires on suspicious plist file creation/modification in LaunchAgent directories (by interpreters/download tools or with Apple name-spoofing patterns). Rule 2 fires on launchctl load/bootstrap targeting LaunchAgent paths when initiated by shell or download utilities.
Data Sources
Required Tables
False Positives & Tuning
- Software package managers (Homebrew, MacPorts) write launch agent plists via shell scripts during formula installation, creating high-volume events on developer machines that match the suspicious writer process list
- Legitimate enterprise deployment tools (Munki, Jamf) use installer or scripts to deploy configuration plists into /Library/LaunchAgents as part of managed software pushes
- Security research tooling or red team simulation frameworks (e.g., Atomic Red Team macOS tests) intentionally create synthetic launch agents for detection validation, which will match all indicators in this rule
Other platforms for T1543.001
Testing Methodology
Validate this detection against 4 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.
- Test 1Create Persistent Launch Agent via Bash
Expected signal: DeviceFileEvents: FileCreated action for file 'com.df00tech.atomictest.plist' in '~/Library/LaunchAgents/', InitiatingProcessFileName='bash'. osquery_differential: action='added' in launchd table with label='com.df00tech.atomictest', run_at_load='1', program_arguments='/bin/bash -c date...'.
- Test 2Load Launch Agent with launchctl
Expected signal: DeviceProcessEvents: FileName='launchctl', ProcessCommandLine contains 'load' and 'LaunchAgents/com.df00tech.launchctltest.plist', InitiatingProcessFileName='bash'. DeviceFileEvents: FileCreated for the plist in LaunchAgents directory.
- Test 3Apple Name Spoof Launch Agent (MacMa/Green Lambert Pattern)
Expected signal: DeviceFileEvents: FileCreated for 'com.apple.softwareupdate.helper.plist' in ~/Library/LaunchAgents/, InitiatingProcessFileName='bash'. osquery_differential: action='added', label='com.apple.softwareupdate.helper', run_at_load='1', keep_alive='1', path contains '/Users/<user>/Library/LaunchAgents/'.
- Test 4KeepAlive Launch Agent with Randomly Named Plist (Dok/CoinTicker Pattern)
Expected signal: DeviceFileEvents: FileCreated for 'com.<rand1>.<rand2>.plist' in ~/Library/LaunchAgents/, InitiatingProcessFileName='bash'. osquery_differential: action='added', label='com.<rand1>.<rand2>', run_at_load='1', keep_alive='1'.
References (11)
- https://attack.mitre.org/techniques/T1543/001/
- https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html
- https://www.sentinelone.com/blog/how-malware-persists-on-macos/
- https://objective-see.org/blog/blog_0x25.html
- https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1543.001/T1543.001.md
- https://www.trendmicro.com/en_us/research/20/d/new-macos-dacls-rat-backdoor-show-lazarus-apt-targets-macos.html
- https://securelist.com/calisto-trojan-for-macos/86543/
- https://www.checkpoint.com/research/may-i-download-adware-please-new-macos-malware-spreading-via-bundled-software/
- https://www.welivesecurity.com/2016/07/06/new-osxkeydnap-malware-hungry-credentials/
- https://www.zscaler.com/blogs/security-research/contagiousinterview-invisibleferret
- https://github.com/SigmaHQ/sigma/tree/master/rules/macos
Unlock Pro Content
Get the full detection package for T1543.001 including response playbook, investigation guide, and atomic red team tests.