Le blog sécurité de FireAI

Par FireAI Security & Research Team · Publié

Chasse à la persistance sur macOS : LaunchAgents, éléments de connexion et tâches en arrière-plan

Chasse à la persistance sur macOS : LaunchAgents, éléments de connexion et tâches en arrière-plan

« Persistance » est le terme de sécurité désignant un problème spécifique : comment un code exécuté une fois s'organise-t-il pour s'exécuter à nouveau, automatiquement, après un redémarrage ou une connexion, sans que personne ne le relance manuellement ? macOS offre aux logiciels légitimes de nombreuses façons approuvées de faire exactement cela – un vérificateur de mise à jour, un client de synchronisation de la barre de menus, un assistant de pilote d'imprimante – et chacun de ces mécanismes est également disponible pour quelque chose que vous préféreriez ne pas exécuter du tout. Il s'agit d'une visite des endroits réels à rechercher, avec les vraies commandes, et d'un compte rendu honnête de la place qu'occupe et n'occupe pas un outil axé sur le réseau comme FireAI dans cette image.

LaunchAgents et LaunchDaemons : les deux grands

macOS démarre presque tout via launchd, piloté par des fichiers de liste de propriétés (.plist) dans un petit nombre de répertoires connus. La technique T1543.001 de MITRE ATT&CK décrit clairement le mécanisme : lors de la connexion, un processus launchd par utilisateur charge les plists à partir des répertoires LaunchAgents de l'utilisateur et du système, et un plist avec RunAtLoad défini sur true s'exécute automatiquement au moment où il est chargé - aucune autre action n'est nécessaire de la part de celui qui l'y a mis. La technique répertorie les trois emplacements importants : /System/Library/LaunchAgents, /Library/LaunchAgents et ~/Library/LaunchAgents. MITRE note quelque chose qui mérite d'être rappelé lorsque vous faites défiler une liste de ces fichiers : les agents installés pour la persistance sont souvent "déguisés[d]... en utilisant des noms ressemblant à des composants légitimes du système d'exploitation ou du logiciel" - le fichier qui ressemble à com.apple.something.plist mérite un second regard précisément parce qu'il essaie de ne pas en obtenir un.

Les LaunchDaemons, couverts par la technique associée T1543.004, sont la version à l'échelle du système, sans connexion requise : ils s'exécutent en tant que root, dès le démarrage, à partir de /System/Library/LaunchDaemons/ ou /Library/LaunchDaemons/. Parce que l'installation d'un là nécessite des privilèges administratifs pour commencer, MITRE encadre la route du démon comme un moyen de convertir un point d'accès privilégié initial en quelque chose qui survit à un redémarrage, s'exécutant avec un accès au niveau racine à partir de ce moment-là - c'est aussi pourquoi un nouveau fichier inconnu apparaissant dans /Library/LaunchDaemons est un signal plus lourd que celui apparaissant dans le dossier LaunchAgents d'un utilisateur.

Terminal – répertoriant ce qui est réellement enregistré
ls -la ~/Library/LaunchAgents /Library/LaunchAgents /Library/LaunchDaemons
# compare this list against what you remember installing; anything you don't
# recognise is worth reading with: plutil -p /path/to/the.plist

Un fichier existant sur le disque et un travail en cours de chargement sont deux questions différentes, et launchctl print répond à la seconde. Sa page de manuel le décrit comme imprimant "des informations sur le service ou le domaine spécifié" - pointant vers un domaine comme system/ ou gui/501/ (501 étant l'UID d'un utilisateur), elle répertorie tous les services et points de terminaison actuellement chargés dans ce contexte, ainsi que l'état de chacun :

Terminal – ce qui est réellement chargé en ce moment
launchctl print gui/$(id -u)
# example output, trimmed — a real run lists every loaded agent for your session
	"com.apple.someAgent" => {
		active count = 1
		path = /Library/LaunchAgents/com.apple.someAgent.plist
		state = running
	}

Éléments de connexion et gestion des tâches en arrière-plan

La surface destinée à l'utilisateur pour une grande partie de cela est le volet Éléments de connexion des paramètres système, et cela vaut la peine de vérifier de vos propres yeux, pas seulement la ligne de commande. Le guide d'assistance d'Apple le décrit directement : vous pouvez "choisir les éléments de connexion qui s'ouvrent automatiquement lorsque vous vous connectez", les ajouter ou les supprimer, et autoriser ou refuser séparément les applications qui "effectuent des tâches lorsque l'application n'est pas ouverte, comme la vérification des mises à jour logicielles ou la synchronisation des données" - cette deuxième catégorie couvre les aides en arrière-plan qui ne sont pas des éléments de connexion complets mais qui fonctionnent toujours sans surveillance.

Depuis macOS Ventura, le système situé sous ce volet de paramètres est communément appelé Gestion des tâches en arrière-plan (BTM) dans la communauté de sécurité : un service qui suit chaque agent de lancement, démon de lancement et élément de connexion au fur et à mesure de son enregistrement, ce qui permet aux paramètres système de vous montrer une liste en direct et centralisée au lieu de devoir parcourir trois répertoires plist à la main. Il existe un outil de ligne de commande non documenté, sfltool, que certains chercheurs utilisent pour interroger cette base de données plus directement avec sfltool dumpbtm — Apple ne fournit aucune page de manuel pour celui-ci et son format de sortie n'est pas garanti pour rester stable, alors traitez-le comme une curiosité de recherche à essayer sur votre propre machine plutôt que comme quelque chose autour duquel créer un flux de travail. Le moyen stable et pris en charge pour afficher les mêmes informations reste le volet Éléments de connexion dans les paramètres système, ou launchctl print pour l'état actif d'une tâche spécifique.

cron : plus vieux, plus silencieux, toujours là

launchd est le planificateur préféré d'Apple depuis longtemps, mais l'ancien démon Unix cron est toujours livré et exécute toujours tout ce qui y est programmé. La page de manuel crontab décrit directement le format de fichier : chaque ligne comporte cinq champs heure/date – minute, heure, jour du mois, mois, jour de la semaine – suivis de la commande à exécuter, avec @reboot et des chaînes abrégées similaires disponibles à la place des cinq champs sur certains systèmes. crontab -l, selon la page de manuel crontab(1), "Affichera la crontab actuelle sur la sortie standard" pour l'utilisateur actuel :

Terminal - vérification de votre propre crontab et de celle de root
crontab -l
sudo crontab -l -u root

Un résultat vide pour les deux est normal sur la plupart des Mac aujourd’hui – c’est exactement pourquoi tout ce qui s’y trouve mérite attention. cron n'est pas glamour et est rarement vérifié, c'est précisément pourquoi il apparaît toujours comme un emplacement de persistance de secours dans les rapports d'incidents.

Profils de configuration : persistance avec une trace écrite

Un profil de configuration peut installer un LaunchDaemon, accorder des autorisations de confidentialité ou appliquer des paramètres sur une flotte de Mac – c'est légitimement ainsi que fonctionne le MDM (gestion des appareils mobiles). Illégitimement, un profil est un moyen documenté de faire en sorte que les modifications soient appliquées sans toucher directement à un fichier plist. L'outil de ligne de commande profiles répertorie ce qui est installé : profiles list affiche les profils installés et, comme le note sa page de manuel, l'exécuter en tant que root avec -all "listera tous les profils de configuration sur le système" plutôt que uniquement ceux de l'utilisateur actuel.

Terminal – tous les profils de configuration sur Mac
sudo profiles list -all
sudo profiles show -all

Un Mac personnel sans inscription MDM ne devrait généralement pas en avoir, ou seulement ceux que vous avez installés délibérément (une configuration VPN, un profil professionnel). Un profil dont vous ne vous souvenez pas avoir installé mérite d'être étudié avant de le supprimer, car profiles prend également en charge la suppression avec protection par mot de passe pour cette étape précise.

Plugins d'autorisation et longue traîne

Au-delà des quatre grands ci-dessus, il existe une longue liste de mécanismes plus petits et plus anciens : plugins de service d'annuaire et d'autorisation, importateurs Spotlight, générateurs QuickLook, plugins de tuiles Dock et fichiers de démarrage du shell qui s'exécutent à chaque fois qu'une nouvelle session de terminal s'ouvre. C’est là qu’un outil spécialement conçu gagne sa place par rapport à la vérification manuelle. KnockKnock d'Objective-See, par exemple, énumère plus de vingt catégories d'emplacements de persistance en un seul passage - y compris les agents de lancement et les démons, les éléments de connexion, les extensions de navigateur, les tâches cron, les extensions du noyau et du système, ainsi que les plugins de service d'autorisation et d'annuaire - et affiche l'état de signature de code de ce qu'il trouve dans chacun d'eux. Son compagnon, BlockBlock, prend la même liste d'emplacements et les surveille en permanence, alertant dès que quelque chose de nouveau s'enregistre ; selon sa propre description, il « surveille les emplacements de persistance courants et alerte chaque fois qu'un nouveau composant persistant est ajouté », indiquant le processus responsable, son statut de signature et vous permettant d'autoriser ou de bloquer sur place.

Fichiers de démarrage Shell : le fourre-tout silencieux

Un emplacement de plus qui mérite un coup d'œil direct, car il ne nécessite aucun plist ni aucune installation privilégiée : les fichiers de configuration du shell. ~/.zshrc, ~/.zprofile et ~/.bash_profile s'exécutent à chaque fois qu'une nouvelle session de terminal correspondante s'ouvre, et une seule ligne ajoutée (direction vers un script, exportation d'un PATH piraté, lancement d'un processus en arrière-plan) suffit à reprendre pied à chaque fois que vous ouvrez le terminal, sans rien à charger dans launchd et rien à afficher pour launchctl print. KnockKnock d'Objective-See inclut exactement cette catégorie dans son analyse, répertoriée aux côtés des agents de lancement et des éléments de connexion en tant que fichiers de configuration du shell, pour la même raison qu'elle appartient à cet article : c'est assez courant et assez peu glamour pour mériter d'être vérifié plutôt que de supposer.

Terminal - une lecture rapide, ne remplace pas la lecture réelle
cat -A ~/.zshrc ~/.zprofile ~/.bash_profile 2>/dev/null | less
# -A shows non-printing characters, which surfaces anything hidden with
# trailing whitespace or a carriage return trying to push it off-screen

Où FireAI s’intègre et où il ne le fait délibérément pas

Pour être direct à ce sujet : FireAI n'analyse pas /Library/LaunchDaemons, ne lit pas les fichiers plist et ne tente pas de détecter un nouvel élément de connexion ou un nouvel profil de configuration. Il s’agit d’une discipline distincte de ce que fait FireAI, et les outils spécialement conçus pour cela – parmi eux KnockKnock et BlockBlock – font déjà bien ce travail. Ce que FireAI surveille, c'est l'étape qui vient après la persistance, et dont chacun de ces mécanismes a finalement besoin s'il veut être utile à celui qui l'a installé : une connexion réseau. Un LaunchAgent qui s’exécute silencieusement à chaque connexion mais ne communique jamais avec le réseau est, du point de vue d’un pare-feu réseau, invisible – et aussi, en pratique, beaucoup moins utile pour un attaquant. Dès qu’il ouvre un socket, les règles par application de FireAI s’y appliquent comme n’importe quel autre processus : un binaire inconnu signé ou non signé établissant sa première connexion déclenche une invite, avec le raisonnement du modèle sur l’appareil affiché en langage clair, et chaque décision est visible, annulable et exportable sous forme de règle de texte par la suite.

La manière honnête de combiner les deux disciplines : vérifiez les emplacements dans cet article selon un calendrier qui correspond à votre tolérance au risque (une fois par mois est raisonnable pour la plupart des gens, une fois par semaine si vous installez de nombreux logiciels tiers) et laissez un outil réseau porter la charge entre les deux, en partant du principe que tout ce qui a persisté tranquillement devra éventuellement parler pour atteindre celui à qui il répond.

Le rôle de FireAI et de HisnLabs

FireAI does not scan for persistence — that is a different job, and tools like KnockKnock and BlockBlock already do it well; what FireAI watches is what that persisted code does the moment it opens a socket, which is the step every one of these mechanisms eventually has to take to be useful to whoever installed it.

FireAI est le produit de HisnLabs : un pare-feu IA embarqué pour Mac. Il montre en langage clair chaque connexion faite par vos applications et vous laisse décider ce qui sort de votre Mac — son IA fonctionne en local, votre trafic ne nous est jamais envoyé, ni à personne d’autre. L’équipe de recherche en sécurité de HisnLabs est celle qui garde ces décisions fiables : elle recense les domaines de simple télémétrie face à ceux d’un vrai service, suit le pays et le réseau derrière une connexion, et entraîne le modèle embarqué (la fonction Autopilot) sur du trafic réel, sans que rien ne quitte votre Mac.

Vous pouvez lire les choix techniques qui s’y trouvent, ou essayer FireAI pendant 17 jours, sur FireAI, par HisnLabs.

Sources