Unités systemd : persistance des services Linux
Fichiers service, timer et drop-in systemd, liens d'activation, générateurs et lingering : où sont définis les services Linux et comment repérer la persistance.
- Emplacement
- /etc/systemd/system/
- Prouve
- Quels services et timers sont configurés pour démarrer, ce qu'ils exécutent, et quand l'unité a été installée ou modifiée
- Horodatages
- mtime/ctime/crtime des fichiers ; entrées du journal en microsecondes depuis l'epoch Unix (UTC)
- Accès
- root pour les unités système ; tout utilisateur pour son propre ~/.config/systemd/user
- Rétention
- Jusqu'à suppression ; les unités de /run sont perdues au redémarrage ; les démarrages/arrêts suivent les limites du journal
- Collecte
- UAC, Velociraptor, cp -a, journalctl
Outils
Comparer tous les outils- systemctlCLI · intégré à Linux
- systemd-analyzeCLI · intégré à Linux
- VelociraptorPlateforme · open source
- UACCLI · open source
Ce que c'est
systemd démarre et supervise presque tout sur un hôte Linux moderne. Chaque service, timer, socket, point de montage ou surveillance de chemin est un fichier d'unité au format INI, et systemd fusionne les unités issues d'une liste de répertoires de recherche, de fichiers drop-in de surcharge et d'unités générées au démarrage. Un attaquant qui écrit un petit fichier .service et un lien symbolique obtient une exécution de code à chaque démarrage, souvent en root (MITRE ATT&CK T1543.002).
Comme systemd applique un ordre de priorité strict, l'unité réellement exécutée n'est pas forcément la première que vous trouvez. Collecter tous les chemins de recherche est la seule approche fiable.
Où il se trouve
Chemins de recherche du gestionnaire système, du plus prioritaire au moins prioritaire (d'après systemd.unit(5)) :
| Chemin | Rôle |
|---|---|
/etc/systemd/system.control/, /run/systemd/system.control/ | Réglages effectués via systemctl set-property |
/run/systemd/transient/ | Unités transitoires (par exemple systemd-run) |
/run/systemd/generator.early/ | Sortie des générateurs, haute priorité |
/etc/systemd/system/ | Unités de l'administrateur, surcharges et liens symboliques *.wants/ |
/run/systemd/system/ | Unités d'exécution, disparaissent au redémarrage |
/run/systemd/generator/ | Sortie des générateurs, priorité moyenne |
/usr/local/lib/systemd/system/ | Unités installées localement |
/usr/lib/systemd/system/ | Unités des paquets (RHEL/Fedora ; Debian/Ubuntu récents) |
/lib/systemd/system/ | Unités des paquets sur les anciennes versions de Debian et Ubuntu |
/run/systemd/generator.late/ | Sortie des générateurs, basse priorité |
Les chemins du gestionnaire utilisateur comprennent ~/.config/systemd/user/, ~/.local/share/systemd/user/, /etc/systemd/user/, /etc/xdg/systemd/user/, /usr/local/lib/systemd/user/ et /usr/lib/systemd/user/.
Autres emplacements importants :
| Chemin | Pourquoi |
|---|---|
<unit>.d/*.conf, service.d/*.conf | Drop-ins fusionnés après le fichier principal ; un service.d de premier niveau s'applique à tous les services |
<target>.wants/, <target>.requires/ | Liens symboliques créés par systemctl enable |
/etc/systemd/system-generators/, /usr/local/lib/systemd/system-generators/, /usr/lib/systemd/system-generators/ (et user-generators) | Exécutables lancés à chaque démarrage et à chaque daemon-reload |
/var/lib/systemd/linger/<user> | Fichier vide : le gestionnaire de cet utilisateur démarre au boot |
/var/lib/systemd/timers/stamp-*.timer | Dernier déclenchement des timers persistants |
Ce qu'il prouve
- Quels services, timers et sockets sont définis et activés, et ce qu'ils exécutent exactement.
- Qu'une unité de paquet a été modifiée ou surchargée (drop-in, ou copie de même nom dans
/etc/systemd/system). - Quand une unité a démarré, s'est arrêtée ou a échoué, grâce aux événements du journal.
- Qu'un utilisateur avait des services actifs sans être connecté (lingering).
- Non prouvé : un fichier d'unité sur disque peut n'avoir jamais été chargé. Cherchez les événements de démarrage dans le journal, et notez que les unités désactivées ne s'exécutent que si une autre les entraîne.
Champs clés
| Directive | Section | Intérêt forensique |
|---|---|---|
ExecStart=, ExecStartPre=, ExecStartPost=, ExecStop=, ExecReload= | [Service] | Commandes exécutées ; un préfixe - ignore les échecs |
User=, Group=, DynamicUser= | [Service] | Identité d'exécution (root par défaut pour les unités système) |
Environment=, EnvironmentFile= | [Service] | Permettent d'injecter LD_PRELOAD ou des réglages de proxy |
Restart=, RestartSec= | [Service] | Résilience d'une porte dérobée |
Type= | [Service] | oneshot ou forking suggèrent des scripts et des démons |
WantedBy=, RequiredBy=, Alias= | [Install] | Où enable place le lien symbolique |
Description=, Documentation= | [Unit] | Texte libre ; les attaquants copient de vraies descriptions |
OnCalendar=, OnBootSec=, Unit= | [Timer] | Activation planifiée (voir cron et timers) |
Champs du journal pour les événements d'unités : UNIT= (ou USER_UNIT=), MESSAGE_ID=, _PID=, INVOCATION_ID=. Identifiants de catalogue utiles : 7d4958e842da4a758f6c1cdc7b36dcc5 (début du job de démarrage), 39f53479d3a045ac8e11786248231fbf (démarrage terminé), be02cf6855d2428ba40df7e9d022f03d (échec du démarrage), 98e322203f7a4ed290d09fe03c09fe15 (fin du processus de l'unité).
Horodatages
Les fichiers d'unité ne contiennent aucun horodatage interne ; utilisez les horodatages du système de fichiers. Une unité issue d'un paquet a normalement un mtime correspondant à la compilation du paquet et un ctime proche de l'installation ; une unité écrite à la main a un mtime et un ctime proches l'un de l'autre. ext4 et XFS v5 enregistrent aussi une date de création (voir horodatages ext4). Le lien symbolique dans *.wants/ a ses propres horodatages, qui datent le enable. Les événements du journal utilisent des microsecondes depuis le 1970-01-01 UTC.
journalctl -D /mnt/evidence/var/log/journal -u suspicious.service -o short-iso-precise
Rétention
Les fichiers d'unité persistent jusqu'à leur suppression ; le contenu de /run et les unités transitoires disparaissent au redémarrage. La désinstallation d'un paquet supprime ses unités, mais pas les fichiers créés par un administrateur ou un attaquant. Les messages de cycle de vie des unités ne survivent que tant que le journal (ou syslog) les conserve.
Collecte
L'artefact systemd d'UAC collecte /etc/systemd, /lib/systemd/system, /usr/lib/systemd, /usr/local/lib/systemd, /run/systemd/system, les unités transitoires et, par utilisateur, ~/.config/systemd et ~/.local/share/systemd. Sur un hôte live, il enregistre aussi systemctl list-units, list-unit-files, list-timers --all et l'état des timers. L'artefact Velociraptor Linux.Sys.Services analyse systemctl list-units --type=service sur le poste.
# live: what systemd actually loaded, including drop-ins
systemctl cat suspicious.service
systemctl list-unit-files --state=enabled
systemctl show suspicious.service -p FragmentPath,DropInPaths,ExecStart
# dead box
tar -C /mnt/evidence -czf systemd.tgz etc/systemd usr/lib/systemd lib/systemd \
usr/local/lib/systemd var/lib/systemd home/*/.config/systemd root/.config/systemd 2>/dev/null
Analyse
R=/mnt/evidence
systemctl --root="$R" list-unit-files # enablement read from disk
find "$R"/etc/systemd "$R"/usr/lib/systemd "$R"/home/*/.config/systemd -xdev \
\( -type f -o -type l \) -printf '%C+ %M %u %p -> %l\n' 2>/dev/null | sort
grep -rhoE '^(ExecStart[A-Za-z]*|Environment(File)?|User)=.*' "$R"/etc/systemd | sort | uniq -c | sort -n
systemd-analyze --root="$R" verify <unit> signale les directives inconnues et les binaires ExecStart= inexistants. Vérifiez le paquet propriétaire avec dpkg -S ou rpm -qf (voir journaux des gestionnaires de paquets).
Conseils d'investigation
- Les attaquants préfèrent des noms qui imitent de vrais services (
dbus-org.freedesktop.helper.service). Jugez le chemin deExecStart=, pas le nom. - Examinez chaque
*.d/override.conf: un drop-in qui vide puis redéfinitExecStart=sur une unité de confiance se cache bien. - Cherchez dans
*.wants/des liens symboliques pointant vers des fichiers hors des chemins d'unités, ou vers des unités qu'aucun paquet ne possède. - Un générateur dans
/etc/systemd/system-generators/s'exécute avant le chargement des unités à chaque démarrage, ce qui est rare sur les serveurs. - Des unités utilisateur associées à
/var/lib/systemd/linger/<user>offrent une persistance sans root qui survit à la déconnexion ; c'est courant chez les cryptomineurs. Environment=LD_PRELOAD=dans une unité est une forme ciblée de détournement de l'éditeur de liens dynamique.- systemd journalise un message de rechargement à chaque
daemon-reload; un rechargement peu avant le premier démarrage d'une nouvelle unité aide à dater l'installation.