LaunchAgents und LaunchDaemons: macOS-Persistenz erkennen

Kurzfassung: LaunchAgents und LaunchDaemons sind der häufigste Persistenzweg unter macOS - das Gegenstück zu den Autostart-Mechanismen und geplanten Aufgaben unter Windows, aber mit eigener Technik. Ein Angreifer legt eine plist-Datei in ein Launch-Verzeichnis, und sein Programm startet beim nächsten Login oder Boot von selbst wieder. Das stabilste Signal ist die plist-Datei selbst; in Echtzeit zeigt das Endpoint Security Framework (ESF) das Anlegen der Datei und den launchctl-Aufruf. Dieser Beitrag baut auf macOS-Sicherheitsmonitoring auf, trennt sauber zwischen ESF, Unified Log, OpenBSM und der reinen Dateisicht und bringt drei sigma-cli-validierte Regeln. Serie "Angriff erkennen".

macOS-Persistenz läuft fast immer über launchd, den zentralen Dienst, der beim Start Programme und Hintergrunddienste hochfährt. Wer dort einen Eintrag hinterlegt, ist bei jedem Login oder Boot wieder da - ganz ohne Exploit. Dieser Beitrag bleibt auf der Erkennungsseite und zeigt, woran sich diese Persistenz erkennen lässt, mit welcher macOS-eigenen Telemetrie das geht und wo sie an Grenzen stößt. Er setzt die Grundlagen aus macOS-Sicherheitsmonitoring voraus und überträgt bewusst keine Windows-Event-Log-Denke auf den Mac: Unter macOS ist nicht eine Event-ID der Anker, sondern die plist-Datei auf der Platte und das ESF-Ereignis, das ihr Entstehen zeigt.

Einordnung in ATT&CK: Es geht um zwei Sub-Techniken von Create or Modify System Process: Launch Agent (T1543.001) und Launch Daemon (T1543.004), beide in ATT&CK v19 unter den Taktiken Persistence und Privilege Escalation; in dieser Serie steht der Beitrag in der Spalte Persistence. Das Aktivieren eines Jobs über launchctl ist Launchctl (T1569.001, Execution). Wird nur der Inhalt einer bestehenden plist manipuliert, ist das zusätzlich Plist File Modification (T1647).

Was der Angreifer tut

launchd liest seine Jobs aus festen Verzeichnissen. Wer dort schreiben darf, bekommt Persistenz. Bewusst auf der Ebene des Prinzips, nicht als Anleitung:

  • LaunchAgent im Benutzerkontext. Eine plist in ~/Library/LaunchAgents startet das Programm bei jedem Login dieses Nutzers, mit dessen Rechten. Dieser Ort braucht keine Administratorrechte und ist deshalb der häufigste.
  • LaunchAgent oder LaunchDaemon systemweit. Eine plist in /Library/LaunchAgents (alle Nutzer) oder /Library/LaunchDaemons (als root, schon vor dem Login) braucht Administratorrechte, liefert dafür aber breitere oder höhere Ausführung - hier verbindet sich Persistenz mit Rechteausweitung.
  • Automatisch und dauerhaft. Die Schlüssel RunAtLoad und KeepAlive in der plist sorgen dafür, dass der Job sofort und nach jedem Beenden erneut startet. Das ist das, was die Persistenz robust macht.
  • Aktivieren. Mit launchctl (load beziehungsweise bootstrap) wird der Job ohne Neustart sofort scharf geschaltet.

Für die Erkennung ist entscheidend: Jeder dieser Wege hinterlässt eine Datei an einem bekannten Ort. Die plist ist das stabilste Artefakt, unabhängig davon, ob zum Zeitpunkt der Tat eine Live-Telemetrie lief.

Welche Telemetrie die Technik zeigt

macOS hat eine eigene Telemetrie, und die Quellen sind nicht gleichwertig. Vier Sichten, von der belastbarsten zur ergänzenden:

  • Endpoint Security Framework (ESF). Die strukturierte Echtzeit-Quelle, auf der die Erkennung aufbaut, zugänglich über eslogger, den Red Canary Mac Monitor oder eine EDR-Lösung. Zwei ESF-Ereignisse tragen hier: das Anlegen oder Ändern der plist-Datei (ein Dateiereignis) und der Start von launchctl (ein Prozessereignis mit Argumenten). Genau diese beiden speisen die Sigma-Regeln unten.
  • Dateisystem- und Artefaktsicht. Die plist-Dateien liegen dauerhaft in den Launch-Verzeichnissen. Sie lassen sich auch ohne laufende Telemetrie inventarisieren und mit einem bekannten Soll-Zustand vergleichen - die forensisch robusteste Grundlage, weil das Artefakt bleibt, auch wenn kein Sensor lief. Dazu gehört auch die Background Task Management-Datenbank (btm), die moderne macOS-Versionen über Hintergrundobjekte führen.
  • Unified Log. Das zentrale Systemprotokoll hält launchd- und xpc-Ereignisse fest und ist für die forensische Rekonstruktion wertvoll (was wann geladen wurde). Für die laufende, regelbasierte Erkennung ist es zu gesprächig und strukturell unhandlich - es ergänzt, es trägt die Regel nicht.
  • OpenBSM/audit. Die ältere BSM-Audit-Spur (/var/audit, Auswertung mit praudit) zeigt Prozessausführung und einige Systemaufrufe. Sie ist der Vorgänger von ESF, wird zunehmend abgelöst und ist hier bestenfalls eine Rückfallebene für den launchctl-Aufruf, nicht die erste Wahl.

Das Muster

Das verlässlichste Signal ist eine neue plist in einem Launch-Verzeichnis, für die es keine passende Software-Installation gibt. Noch deutlicher wird es, wenn nicht ein Installer, sondern eine Shell, ein Skript-Interpreter oder ein Download-Werkzeug die Datei schreibt - das ist das typische Bild einer per Skript eingerichteten Persistenz. Ein drittes Signal ist launchctl, das einen Job aus einem Benutzer- oder Temp-Pfad lädt, statt aus den regulären System- und Programmpfaden. Keines davon ist für sich beweisend, weil auch legitime Software hier schreibt. Belastbar wird der Fall aus der Kombination: eine frisch angelegte plist, ein ungewöhnlicher schreibender Prozess und ein unmittelbar folgendes Laden des Jobs.

Drei Sigma-Regeln

Die Regeln sind mit sigma-cli geprüft und setzen auf der macOS-Logquelle auf, die von ESF gespeist wird (file_event für die plist, process_creation für launchctl). Die erste ist das breite Inventursignal, die zweite zielt auf das Laden aus einem Benutzerpfad, die dritte ist die aussagekräftigste, weil sie den schreibenden Prozess einbezieht.

1. Plist in LaunchAgents oder LaunchDaemons angelegt (T1543.001/.004). Breites Signal auf level: medium, weil auch Installer hier schreiben.

Sigma
title: Plist in LaunchAgents oder LaunchDaemons angelegt oder geaendert
id: ee7e9de9-7127-44b8-8f61-f9566bc86cb4
status: experimental
description: |
  Erkennt das Anlegen oder Aendern einer plist-Datei in einem LaunchAgents- oder
  LaunchDaemons-Verzeichnis. Das ist der haeufigste Persistenzweg unter macOS
  (Launch Agent, Launch Daemon): ein dort hinterlegter Job startet automatisch
  wieder. Legitime Installationen schreiben ebenfalls hierhin, deshalb traegt der
  Treffer erst mit Kontext (Konto, schreibender Prozess, Pfad) Gewicht.
references:
  - https://attack.mitre.org/techniques/T1543/001/
  - https://attack.mitre.org/techniques/T1543/004/
author: blue-team.net
date: 2026-10-07
tags:
  - attack.persistence
  - attack.privilege-escalation
  - attack.t1543.001
  - attack.t1543.004
logsource:
  product: macos
  category: file_event
detection:
  sel:
    TargetFilename|contains:
      - '/Library/LaunchAgents/'
      - '/Library/LaunchDaemons/'
    TargetFilename|endswith: '.plist'
  condition: sel
falsepositives:
  - Software-Installationen und Updates legen hier legitim plist-Dateien an - bekannte Installer, Pfade und Herausgeber als Baseline ausnehmen
level: medium

2. launchctl lädt einen Job aus einem benutzerschreibbaren Pfad (T1569.001). Das Aktivieren aus einem Benutzer- oder Temp-Pfad, auf level: medium.

Sigma
title: launchctl laedt einen Job aus einem benutzerschreibbaren Pfad
id: a9c3fcf2-8bd2-4240-8257-96555e7f9f6e
status: experimental
description: |
  Erkennt launchctl beim Laden oder Bootstrappen eines Jobs, dessen plist in einem
  benutzerschreibbaren oder temporaeren Pfad liegt. Angreifer aktivieren so eine
  frisch abgelegte Launch-Agent- oder Launch-Daemon-Persistenz (Launchctl). launchctl
  ist ein haeufig genutztes Bordwerkzeug, erst der Benutzer- oder Temp-Pfad macht den
  Aufruf auffaellig.
references:
  - https://attack.mitre.org/techniques/T1569/001/
author: blue-team.net
date: 2026-10-07
tags:
  - attack.execution
  - attack.t1569.001
logsource:
  product: macos
  category: process_creation
detection:
  sel_img:
    Image|endswith: '/launchctl'
  sel_cmd:
    CommandLine|contains:
      - 'bootstrap'
      - 'load'
      - 'submit'
  sel_path:
    CommandLine|contains:
      - '/Users/'
      - '/tmp/'
      - '/private/tmp/'
      - '/var/tmp/'
      - '/private/var/folders/'
  condition: sel_img and sel_cmd and sel_path
falsepositives:
  - Entwickler- und Build-Werkzeuge laden Jobs aus dem Benutzerprofil - bekannte Faelle als Baseline ausnehmen
level: medium

3. Launch-plist von einer Shell oder einem Downloader geschrieben (T1543.001/.004). Der schreibende Prozess verrät die skriptgesteuerte Persistenz, auf level: high.

Sigma
title: LaunchAgent- oder LaunchDaemon-plist von einer Shell oder einem Downloader geschrieben
id: 0c69d9fe-6282-4ee8-8ce0-bcdbd5b4bd78
status: experimental
description: |
  Erkennt das Schreiben einer plist in ein LaunchAgents- oder LaunchDaemons-Verzeichnis
  durch eine Shell, einen Skript-Interpreter oder ein Download-Werkzeug. Legitime
  Persistenz wird von Installern angelegt, nicht von bash, curl oder osascript. Das ist
  das typische Bild einer per Skript eingerichteten macOS-Persistenz (Launch Agent,
  Launch Daemon) und deutlich hoeher einzustufen als ein reiner Dateitreffer.
references:
  - https://attack.mitre.org/techniques/T1543/001/
  - https://attack.mitre.org/techniques/T1543/004/
author: blue-team.net
date: 2026-10-07
tags:
  - attack.persistence
  - attack.privilege-escalation
  - attack.t1543.001
  - attack.t1543.004
logsource:
  product: macos
  category: file_event
detection:
  sel_file:
    TargetFilename|contains:
      - '/Library/LaunchAgents/'
      - '/Library/LaunchDaemons/'
    TargetFilename|endswith: '.plist'
  sel_writer:
    Image|endswith:
      - '/bash'
      - '/sh'
      - '/zsh'
      - '/curl'
      - '/osascript'
      - '/python3'
      - '/python'
  condition: sel_file and sel_writer
falsepositives:
  - Eigene Verwaltungs- oder Provisionierungsskripte, die Jobs per Shell einrichten - bekannte Skripte und Hosts als Baseline ausnehmen
level: high

Grenzen der Erkennung

  • Der plist-Inhalt steht nicht im Dateiereignis. Ob eine plist RunAtLoad oder KeepAlive setzt oder auf welches Programm sie zeigt, verrät der Dateiname nicht. Diese Auswertung braucht das Lesen der Datei selbst (Artefaktsicht) oder eine EDR, die den Inhalt mitliefert - die Regeln hier erkennen das Entstehen, nicht die Bösartigkeit des Inhalts.
  • Andere Autostart-Wege. Persistenz über Login Items beziehungsweise Background Task Management (T1547.015), über Konfigurationsprofile oder über periodische Skripte läuft nicht über diese Verzeichnisse und wird von diesen Regeln nicht erfasst.
  • Sichtbarkeit ist produktabhängig. Ohne ESF-Quelle (eslogger, Red Canary Mac Monitor oder EDR) gibt es kein Echtzeitsignal - dann bleibt nur die Artefaktsicht bei der nächsten Untersuchung. Die Felder der Regeln setzen voraus, dass die Quelle Datei- und Prozessereignisse mit Pfad und schreibendem Prozess liefert.

Fehlalarme und Tuning

  • Installer sind der Normalfall. Jede zweite App legt beim Einrichten einen LaunchAgent an. Ohne Baseline der bekannten, legitimen Jobs ist Regel 1 laut - bekannte Herausgeber, Pfade und Dateinamen zuerst ausnehmen.
  • Nach Konto und Ort gewichten. Eine plist in /Library/LaunchDaemons (root) wiegt schwerer als eine im eigenen Benutzerprofil. Den Ort in die Bewertung aufnehmen.
  • Entwickler- und Admin-Werkzeuge. Provisionierung und Build-Tools laden Jobs legitim per Shell oder aus dem Benutzerprofil. Diese bekannten Skripte und Hosts als Baseline aufnehmen, damit Regel 3 auf das Ungewöhnliche zeigt.
  • Kette schlägt Einzeltreffer. Eine neue plist, geschrieben von einer Shell, gefolgt vom launchctl-Laden - diese Abfolge ist weit aussagekräftiger als jedes Signal allein.

Analysten-Checkliste

  1. In welchem Verzeichnis liegt die plist - Benutzer (~/Library/LaunchAgents) oder systemweit (/Library/LaunchDaemons als root)? Der Ort bestimmt Rechte und Schwere.
  2. Gibt es eine passende Software-Installation, oder ist die plist ohne erkennbaren legitimen Ursprung entstanden?
  3. Welcher Prozess hat die Datei geschrieben - ein Installer oder eine Shell, curl, osascript, python?
  4. Auf welches Programm zeigt die plist (Program oder ProgramArguments), und liegt dieses in einem Benutzer- oder Temp-Pfad? Dafür die Datei selbst lesen.
  5. Setzt sie RunAtLoad oder KeepAlive, also auf dauerhaften Neustart?
  6. Wurde der Job unmittelbar per launchctl geladen, und passt der Zeitpunkt zu anderen auffälligen Ereignissen auf dem Host?

Härtung

  • Launch-Verzeichnisse als Soll-Zustand führen. Eine Inventarliste der erlaubten LaunchAgents und LaunchDaemons pflegen und regelmäßig dagegen abgleichen - jede Abweichung ist dann ein Signal statt Rauschen.
  • ESF-Quelle bereitstellen. eslogger, Red Canary Mac Monitor oder eine EDR aktivieren und die Datei- und Prozessereignisse zentral ins SIEM bringen, damit sie im Vorfall verfügbar sind.
  • Geräte verwalten. Über eine MDM-Verwaltung Konfigurationsprofile und erlaubte Hintergrundobjekte steuern und die Background Task Management-Benachrichtigungen auswerten, die macOS bei neuen Hintergrundobjekten erzeugt.
  • Rechte begrenzen. Wo Nutzer keine Administratorrechte brauchen, bleiben die systemweiten Launch-Verzeichnisse für sie unbeschreibbar - das schließt den Daemon-Weg mit Rechteausweitung.

Der Test im Lab

Die Erkennung lässt sich auf einem Test-Mac mit aktivem eslogger oder Red Canary Mac Monitor gefahrlos prüfen - den Testjob danach wieder entfernen (launchctl bootout/unload und die plist löschen):

  • Für Regel 1 eine harmlose Test-plist in ~/Library/LaunchAgents ablegen und prüfen, dass das ESF-Dateiereignis sie zeigt und die Regel greift.
  • Für Regel 2 den Testjob mit launchctl load aus einem Pfad im Benutzerprofil laden und den Prozesstreffer kontrollieren.
  • Für Regel 3 die Test-plist per Shell (echo/cp aus bash) statt per Installer schreiben und prüfen, dass der schreibende Prozess im Ereignis auftaucht.
  • Breiter wird der Test mit den macOS-Fällen zu T1543 aus Atomic Red Team, das auch macOS abdeckt.

Fazit

LaunchAgents und LaunchDaemons sind der erste Ort, an dem man unter macOS nach Persistenz sucht. Der Anker ist nicht eine Event-ID, sondern die plist-Datei selbst: Sie bleibt auf der Platte, und das Endpoint Security Framework zeigt in Echtzeit, wie sie entsteht und wie launchctl den Job lädt. Die drei Regeln nehmen genau diese Signale, vom breiten Dateitreffer bis zur skriptgeschriebenen plist. Wichtig bleibt die ehrliche Grenze: Der Dateiname sagt nichts über den Inhalt, und andere Autostart-Wege wie Login Items laufen an diesen Verzeichnissen vorbei. Die wirksamste Härtung ist ein gepflegter Soll-Zustand der Launch-Verzeichnisse plus eine zentral gesammelte ESF-Quelle. Die Grundlagen stehen unter macOS-Sicherheitsmonitoring; die nächsten Beiträge dieser macOS-Reihe behandeln die Gatekeeper- und Quarantine-Umgehung, den AppleScript- und osascript-Missbrauch, den Keychain-Zugriff, die TCC-Manipulation und das Dylib-Hijacking.

NH

$ whoami

Norbert Hofmann

Cyber Defense Analyst im Security Operations Center eines Managed Security Service Providers. Red und Blue Teaming, Malware-Analyse, Incident Response und Security-Awareness-Trainings. Finalist bei „Deutschlands bester Hacker“ 2022, mehrere CVE-Einträge für WordPress-Plugins.