LaunchAgents et LaunchDaemons : persistance macOS
Les plists launchd des dossiers LaunchAgents et LaunchDaemons définissent ce que macOS lance au démarrage, à la connexion ou selon un planning.
- Emplacement
- ~/Library/LaunchAgents, /Library/LaunchAgents, /Library/LaunchDaemons
- Prouve
- Quel code est configuré pour démarrer automatiquement, sous quel utilisateur, sur quel déclencheur, et depuis quand
- Horodatages
- Aucun horodatage interne ; dates de fichier APFS (nanosecondes, UTC)
- Accès
- Agents utilisateur : utilisateur propriétaire ; /Library : root ; accès complet au disque recommandé pour l'outil de collecte
- Rétention
- Jusqu'à la suppression du plist ; les overrides et les enregistrements BTM peuvent lui survivre
- Collecte
- Aftermath, mac_apt, UAC, Velociraptor
Outils
Comparer tous les outils- mac_aptCLI · open source
- PlasoCLI · open source
- KnockKnockGUI · open source
- plutilCLI · intégré à macOS
Ce que c'est
launchd est le PID 1 de macOS. Il démarre les démons système au boot et les agents par utilisateur à la connexion, à partir de définitions de tâches stockées sous forme de property lists. Un plist de tâche indique un Label, le programme à exécuter et les déclencheurs (au chargement, maintien en vie, intervalle, calendrier, modification de chemins). Les logiciels légitimes et la plupart des malwares macOS utilisent exactement le même mécanisme : c'est pourquoi ces dossiers sont le premier arrêt de toute revue de persistance.
Les démons s'exécutent dans le contexte système (root sauf si UserName en dispose autrement) sans utilisateur connecté. Les agents s'exécutent dans la session d'un utilisateur.
Où il se trouve
| Chemin | Type | Écrit par | macOS / protection |
|---|---|---|---|
~/Library/LaunchAgents | Agent par utilisateur | L'utilisateur, sans droits admin | Toutes versions |
/Library/LaunchAgents | Agent pour tous les utilisateurs | Administrateur (root) | Toutes versions |
/Library/LaunchDaemons | Démon système | Administrateur (root) | Toutes versions |
/System/Library/LaunchAgents, /System/Library/LaunchDaemons | Tâches Apple | Apple | Volume système scellé à partir de 11 Big Sur |
/Library/Apple/System/Library/LaunchAgents, .../LaunchDaemons | Tâches Apple sur le volume Data | Apple | Protégé par SIP |
<App>.app/Contents/Library/LaunchAgents, .../LaunchDaemons | Tâches embarquées dans l'application, enregistrées via SMAppService | Développeur | 13 Ventura et ultérieur |
/private/var/db/com.apple.xpc.launchd/disabled.plist, disabled.<UID>.plist | Overrides d'activation/désactivation launchd | launchctl enable/disable | root |
/private/var/db/com.apple.xpc.launchd/loginitems.<UID>.plist | Éléments de connexion Service Management | SMLoginItemSetEnabled | root |
/Library/StartupItems | Éléments de démarrage historiques | Administrateur | Mécanisme obsolète |
Vérifiez aussi /var/root/Library/LaunchAgents et chaque répertoire personnel sous /Users.
Ce qu'il prouve
- Qu'un programme a été configuré pour démarrer au boot, à la connexion, à intervalle régulier, selon un calendrier, sur modification de fichiers ou au montage d'un volume.
- Le compte sous lequel s'exécute la tâche (un démon sans
UserNamesignifie root). - Qu'écrire dans
/Library/LaunchDaemonsnécessitait root : un démon malveillant implique donc une élévation de privilèges. - Avec l'état d'exécution (
launchctl print), si la tâche est chargée, son PID, son nombre d'exécutions et son dernier code de sortie.
Un plist seul ne prouve pas que la tâche s'est exécutée : elle peut être désactivée par un override, échouer au chargement ou pointer vers un binaire absent. Corroborez avec les journaux et les traces de processus.
Champs clés
D'après launchd.plist(5) :
| Clé | Signification |
|---|---|
Label | Nom unique de la tâche (obligatoire) |
Program / ProgramArguments | Exécutable et vecteur d'arguments |
BundleProgram | Exécutable relatif à l'application, plists SMAppService uniquement |
RunAtLoad | Démarrage au chargement (boot ou connexion) |
KeepAlive | Redémarrage à la sortie, ou dictionnaire conditionnel |
StartInterval / StartCalendarInterval | Démarrage périodique ou planifié |
WatchPaths / QueueDirectories / StartOnMount | Déclencheurs liés au système de fichiers |
UserName / GroupName | Identité d'exécution |
EnvironmentVariables | Environnement (surveillez DYLD_INSERT_LIBRARIES) |
StandardOutPath / StandardErrorPath | Fichiers de sortie, souvent des preuves utiles |
LimitLoadToSessionType | Types de session pour les agents (par exemple Aqua) |
AssociatedBundleIdentifiers | Application affichée pour cette tâche dans les réglages Ouverture |
Disabled | État par défaut ; l'état launchctl enable/disable est conservé ailleurs |
Horodatages
Les plists ne portent aucune date de création propre. Utilisez le système de fichiers : APFS stocke les dates de naissance, de modification, de changement et d'accès avec une précision à la nanoseconde, en UTC.
stat -f '%SB | %Sm | %N' -t '%Y-%m-%d %H:%M:%S' ~/Library/LaunchAgents/*.plist
La date de naissance est en général le meilleur repère de la date d'installation, mais elle peut être modifiée avec touch ou par des outils de copie. Vérifiez les dates du binaire référencé, FSEvents pour le dossier et l'enregistrement Background Task Management.
Rétention
Une tâche persiste jusqu'à la suppression de son plist. La suppression n'efface pas tout : les overrides disabled*.plist, les enregistrements Background Task Management, les entrées du unified log, FSEvents, les snapshots APFS locaux et les sauvegardes Time Machine peuvent conserver des traces.
Collecte
# Dead-box or live (root, Full Disk Access)
sudo ditto /Library/LaunchAgents ./case/la_system
sudo ditto /Library/LaunchDaemons ./case/ld_system
sudo ditto /private/var/db/com.apple.xpc.launchd ./case/launchd_db
for u in /Users/*; do [ -d "$u/Library/LaunchAgents" ] && \
sudo ditto "$u/Library/LaunchAgents" "./case/la_$(basename "$u")"; done
# Live state (read-only)
sudo launchctl print system > ./case/launchctl_system.txt
launchctl print gui/501 > ./case/launchctl_gui501.txt
sudo launchctl print-disabled system > ./case/disabled_system.txt
- UAC
files/system/startup_items.yamlcollecte les dossiers standard d'agents et de démons (par utilisateur,/Library,/System/Libraryet/Library/Apple/System/Library, mais pas/var/rootni les tâches intégrées aux applications),/Library/StartupItemsetloginitems.*.plist;live_response/system/launchctl.yamlexécutelaunchctl list. - Aftermath collecte les agents et démons parmi ses éléments de persistance.
- N'exécutez jamais
launchctl bootout,unloadoudisableavant d'avoir tout documenté.
Analyse
- plutil :
plutil -p <file>affiche les plists XML ou binaires ;plutil -lintsignale les plists malformés. - Plugin
AUTOSTARTde mac_apt :python mac_apt.py -o out E01 mac.E01 AUTOSTART. - Plugin
launchd_plistde Plaso :log2timeline.py --parsers 'plist/launchd_plist' --storage-file ld.plaso ./case. - KnockKnock (objective-see/KnockKnock) énumère les éléments persistants d'un Mac live avec leur statut de signature.
Tri rapide du programme de chaque tâche :
for f in /Library/Launch*/*.plist ~/Library/LaunchAgents/*.plist; do
printf '%s\t' "$f"; plutil -extract ProgramArguments json -o - "$f" 2>/dev/null \
|| plutil -extract Program raw -o - "$f"; echo
done
Conseils d'investigation
- Un label
com.apple.*en dehors de/Systemet/Library/Appleest un signal d'alerte : les tâches Apple ne se trouvent pas dans/Library/LaunchDaemons. - Quand
ProgramArgumentscommence par/bin/sh,/bin/bash,/usr/bin/python3ou/usr/bin/osascript, l'interpréteur est signé par Apple ; la charge utile est l'argument de script. - Calculez l'empreinte de chaque cible et vérifiez-la :
codesign -dv --verbose=4,spctl --assess -vv,xattr -lpour la quarantaine. - Les cibles situées dans des dossiers cachés,
/tmp,/Users/Sharedou portant des noms d'éditeur plausibles sous~/Library/Application Supportsont prioritaires. - Une tâche que
launchctl printmontre chargée mais sans plist sur disque signifie que le fichier a été supprimé après le chargement. - Comparez avec le master standard de l'organisation : outils de mise à jour, VPN, MDM et agents de sauvegarde constituent un bruit normal.
- Examinez aussi cron et periodic et consultez le guide de la persistance launchd.