Unidades systemd: persistencia de servicios en Linux
Servicios, timers y drop-ins de systemd, symlinks de activación, generadores y lingering: dónde se definen los servicios de Linux y cómo delatan persistencia.
- Ubicación
- /etc/systemd/system/
- Prueba
- Qué servicios y timers están configurados para arrancar, qué ejecutan y cuándo se instaló o modificó la unidad
- Marcas de tiempo
- mtime/ctime/crtime de los archivos; entradas del journal en microsegundos desde la época Unix (UTC)
- Acceso
- root para las unidades del sistema; cualquier usuario para su propio ~/.config/systemd/user
- Retención
- Hasta su borrado; las unidades de /run se pierden al reiniciar; los eventos de arranque/parada siguen los límites del journal
- Adquisición
- UAC, Velociraptor, cp -a, journalctl
Herramientas
Comparar todas las herramientas- systemctlCLI · incluido en Linux
- systemd-analyzeCLI · incluido en Linux
- VelociraptorPlataforma · código abierto
- UACCLI · código abierto
Qué es
systemd arranca y supervisa casi todo en un host Linux moderno. Cada servicio, timer, socket, montaje o vigilante de rutas es un archivo de unidad en formato INI, y systemd combina las unidades de una lista de directorios de búsqueda, archivos drop-in de anulación y unidades generadas en el arranque. Un atacante que escribe un pequeño archivo .service y un enlace simbólico obtiene ejecución de código en cada arranque, a menudo como root (MITRE ATT&CK T1543.002).
Como systemd aplica un orden de precedencia estricto, la unidad que realmente se ejecuta puede no ser la primera que encuentre. Recoger todas las rutas de búsqueda es el único enfoque fiable.
Dónde se encuentra
Rutas de búsqueda del gestor del sistema, de mayor a menor precedencia (según systemd.unit(5)):
| Ruta | Función |
|---|---|
/etc/systemd/system.control/, /run/systemd/system.control/ | Ajustes realizados con systemctl set-property |
/run/systemd/transient/ | Unidades transitorias (por ejemplo, systemd-run) |
/run/systemd/generator.early/ | Salida de generadores, prioridad alta |
/etc/systemd/system/ | Unidades del administrador, anulaciones y enlaces simbólicos *.wants/ |
/run/systemd/system/ | Unidades en tiempo de ejecución, desaparecen tras el reinicio |
/run/systemd/generator/ | Salida de generadores, prioridad media |
/usr/local/lib/systemd/system/ | Unidades instaladas localmente |
/usr/lib/systemd/system/ | Unidades de paquetes (RHEL/Fedora; Debian/Ubuntu recientes) |
/lib/systemd/system/ | Unidades de paquetes en versiones antiguas de Debian y Ubuntu |
/run/systemd/generator.late/ | Salida de generadores, prioridad baja |
Las rutas del gestor de usuario incluyen ~/.config/systemd/user/, ~/.local/share/systemd/user/, /etc/systemd/user/, /etc/xdg/systemd/user/, /usr/local/lib/systemd/user/ y /usr/lib/systemd/user/.
Otras ubicaciones importantes:
| Ruta | Motivo |
|---|---|
<unit>.d/*.conf, service.d/*.conf | Drop-ins que se combinan tras el archivo principal; un service.d de nivel superior se aplica a todos los servicios |
<target>.wants/, <target>.requires/ | Enlaces simbólicos creados por systemctl enable |
/etc/systemd/system-generators/, /usr/local/lib/systemd/system-generators/, /usr/lib/systemd/system-generators/ (y user-generators) | Ejecutables que se lanzan en cada arranque y en cada daemon-reload |
/var/lib/systemd/linger/<user> | Archivo vacío: el gestor de ese usuario arranca con el sistema |
/var/lib/systemd/timers/stamp-*.timer | Último disparo de los timers persistentes |
Qué prueba
- Qué servicios, timers y sockets están definidos y activados, y qué ejecutan exactamente.
- Que una unidad de un paquete se modificó o se anuló (drop-in, o copia con el mismo nombre en
/etc/systemd/system). - Cuándo arrancó, se detuvo o falló una unidad, mediante los eventos del journal.
- Que un usuario tenía servicios en ejecución sin haber iniciado sesión (lingering).
- Lo que no prueba: un archivo de unidad en disco puede no haberse cargado nunca. Busque eventos de arranque en el journal, y tenga en cuenta que las unidades desactivadas solo se ejecutan si otra cosa las arrastra.
Campos clave
| Directiva | Sección | Interés forense |
|---|---|---|
ExecStart=, ExecStartPre=, ExecStartPost=, ExecStop=, ExecReload= | [Service] | Comandos ejecutados; el prefijo - ignora los fallos |
User=, Group=, DynamicUser= | [Service] | Identidad de ejecución (root por defecto en las unidades del sistema) |
Environment=, EnvironmentFile= | [Service] | Pueden inyectar LD_PRELOAD o ajustes de proxy |
Restart=, RestartSec= | [Service] | Resiliencia de una puerta trasera |
Type= | [Service] | oneshot o forking sugieren scripts y demonios |
WantedBy=, RequiredBy=, Alias= | [Install] | Dónde coloca enable el enlace simbólico |
Description=, Documentation= | [Unit] | Texto libre; los atacantes copian descripciones reales |
OnCalendar=, OnBootSec=, Unit= | [Timer] | Activación programada (ver cron y timers) |
Campos del journal para los eventos de unidades: UNIT= (o USER_UNIT=), MESSAGE_ID=, _PID=, INVOCATION_ID=. IDs de catálogo útiles: 7d4958e842da4a758f6c1cdc7b36dcc5 (inicio del trabajo de arranque), 39f53479d3a045ac8e11786248231fbf (arranque terminado), be02cf6855d2428ba40df7e9d022f03d (arranque fallido), 98e322203f7a4ed290d09fe03c09fe15 (salida del proceso de la unidad).
Marcas de tiempo
Los archivos de unidad no contienen marcas de tiempo internas; use las del sistema de archivos. Una unidad procedente de un paquete suele tener un mtime que coincide con la compilación del paquete y un ctime cercano a la instalación; una unidad escrita a mano tiene mtime y ctime muy próximos. ext4 y XFS v5 registran además una hora de creación (ver marcas de tiempo de ext4). El enlace simbólico de *.wants/ tiene sus propias marcas de tiempo, que fechan el enable. Los eventos del journal usan microsegundos desde 1970-01-01 UTC.
journalctl -D /mnt/evidence/var/log/journal -u suspicious.service -o short-iso-precise
Retención
Los archivos de unidad persisten hasta que se eliminan; el contenido de /run y las unidades transitorias desaparecen al reiniciar. Desinstalar un paquete borra sus unidades, pero no los archivos creados por un administrador o un atacante. Los mensajes del ciclo de vida de las unidades solo sobreviven mientras el journal (o syslog) los conserve.
Adquisición
El artefacto de systemd de UAC recoge /etc/systemd, /lib/systemd/system, /usr/lib/systemd, /usr/local/lib/systemd, /run/systemd/system, las unidades transitorias y los ~/.config/systemd y ~/.local/share/systemd de cada usuario. En un host en vivo también guarda systemctl list-units, list-unit-files, list-timers --all y el estado de los timers. El artefacto Linux.Sys.Services de Velociraptor analiza systemctl list-units --type=service en el endpoint.
# 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
Análisis
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> señala las directivas desconocidas y los binarios de ExecStart= que no existen. Compruebe a qué paquete pertenece cada archivo con dpkg -S o rpm -qf (ver logs del gestor de paquetes).
Consejos para la investigación
- Los atacantes prefieren nombres que imitan servicios reales (
dbus-org.freedesktop.helper.service). Juzgue la ruta deExecStart=, no el nombre. - Revise cada
*.d/override.conf: un drop-in que vacía y redefineExecStart=en una unidad de confianza se esconde muy bien. - Busque en
*.wants/enlaces simbólicos que apunten a archivos fuera de las rutas de unidades, o a unidades que no pertenecen a ningún paquete. - Un generador en
/etc/systemd/system-generators/se ejecuta antes de que se carguen las unidades en cada arranque, algo poco habitual en servidores. - Las unidades de usuario junto con
/var/lib/systemd/linger/<user>proporcionan una persistencia sin root que sobrevive al cierre de sesión; es habitual en los criptomineros. Environment=LD_PRELOAD=en una unidad es una forma dirigida de secuestro del enlazador dinámico.- systemd registra un mensaje de recarga en cada
daemon-reload; uno poco antes del primer arranque de una unidad nueva ayuda a fechar la instalación.