Systemd Service & Timer Persistence
Malware installs a systemd unit or timer so init re-launches its payload at boot or on a schedule, giving durable, often root-level persistence on modern Linux.
Systemd is the init system and service manager on most modern Linux distributions. It starts, stops, and supervises services described by unit files, and can restart them automatically if they exit. Malware abuses systemd by installing its own service unit — often with Restart=always — so the payload both survives reboot and is resurrected the moment it is killed, making it a persistence and watchdog mechanism in one.
Systemd timers are the modern replacement for cron and an equally attractive target. A .timer unit fires an associated .service on a calendar schedule or relative to boot, achieving scheduled execution without ever touching crontab. Units placed in a system directory and enabled with a WantedBy install line are wired into a boot target so they start automatically.
How it works
Unit files live in well-known directories that an analyst should enumerate:
/etc/systemd/system/ admin-defined units (highest precedence)
/usr/lib/systemd/system/ package-provided units
/etc/systemd/user/ + ~/.config/systemd/user/ per-user (no root)A minimal malicious service unit looks like:
[Service]
ExecStart=/usr/lib/.cache/dbus-daemon
Restart=always
[Install]
WantedBy=multi-user.targetAfter dropping the unit the operator runs systemctl daemon-reload && systemctl enable --now <name>, which creates a .wants symlink under the target directory and starts the service. Names mimic legitimate daemons (dbus, networkd-dispatcher, gdm-helper) and the ExecStart path is hidden in a dotted or cache directory. User-level units under ~/.config/systemd/user/ require no root and persist for that account.
Detection & analysis
Static analysis:
- List enabled units and resolve their files:
systemctl list-unit-files --state=enabledplussystemctl list-timers. For anything unfamiliar, read the unit and inspectExecStart— payloads in/tmp,/dev/shm, dotted, or cache directories are high-signal. - Enumerate the unit directories above directly and diff against the distribution's package manifest (
rpm -V/dpkg -V); a unit file owned by no package is suspicious. The.wantssymlinks under*.target.wants/reveal what was enabled and when. - In a captured sample, look for writes to the systemd unit paths, the strings
ExecStart/WantedBy, orexecveofsystemctl enable/daemon-reload.
Dynamic analysis:
- Under auditd or strace, watch for
open/writeto/etc/systemd/systemor the user unit directory and forexecveofsystemctl. Auditd watches on those paths capture the writing process, UID, and the new unit name. - At runtime,
systemd(PID 1) spawning an unexpected long-running child from a temp or cache path, or a brand-new.service/.timerappearing insystemctl status, is the behavioural tell.
Detection rule hint:
Add auditd watches such as -w /etc/systemd/system -p wa -k systemd_persist (and the user unit dir), then alert on unit writes by non-package processes. Flag enabled units whose ExecStart resolves to a world-writable, temp, dotted, or cache directory, units with Restart=always pointing outside /usr/bin-/usr/sbin, and timers created outside a package install.