HackBlue

Tools · Linux command line for security · 25 / 28

Auditing systemd services and timers for persistence

List enabled units and timers, find unit files outside package control, inspect user-level units, and read what a unit actually runs.

10 min read · practice only with authorization

List what starts

systemctl list-unit-files --state=enabled shows every unit set to start. systemctl list-timers --all shows timers and their next run. Unit files live in /usr/lib/systemd/system for packages, /etc/systemd/system for local administrators, and ~/.config/systemd/user for per-user services that start when the user logs in or lingers.

Attackers favor /etc/systemd/system and user directories because they look like ordinary local customization.

Snippet
systemctl list-unit-files --state=enabled --type=service
systemctl list-timers --all
ls -la /etc/systemd/system /etc/systemd/system/*.wants
loginctl list-users; ls /var/lib/systemd/linger 2>/dev/null

Read what a unit runs

systemctl cat name shows the unit file and all drop-ins. Look at ExecStart, ExecStartPre, User, and Restart. A unit named like a system component, such as dbus-helper.service, that runs a binary from /var/tmp is suspicious. So is Restart=always on a script that opens a network connection.

Compare local units against package ownership with dpkg -S or rpm -qf. A unit file no package owns was created by an administrator or someone else.

Snippet
systemctl cat suspicious.service
for f in /etc/systemd/system/*.service; do dpkg -S "$f" >/dev/null 2>&1 || echo "unowned: $f"; done

Lab: create, find, and remove a fake unit

Create a service in /etc/systemd/system named network-sync.service that runs /usr/bin/sleep from a copy in /opt/.cache, enable it, and reboot. Then hunt for it: list enabled units, look for unowned files, and check modification times. Disable it, delete it, and run systemctl daemon-reload.

Also create a user-level unit for a test account with loginctl enable-linger, since those run without the user logged in and are easy to overlook.

Snippet
sudo find /etc/systemd/system /home/*/.config/systemd -name "*.service" -newer /etc/hostname -ls 2>/dev/null
sudo systemctl disable --now network-sync.service
sudo rm /etc/systemd/system/network-sync.service && sudo systemctl daemon-reload

Defensive controls

Watch /etc/systemd/system and user unit directories with auditd or AIDE. Log systemctl enable events through the journal. Baseline enabled units per server role and diff regularly.

Use unit hardening options such as ProtectSystem=strict and NoNewPrivileges=yes for your own services, which limits what a compromised service can do.

Diagram

Hunting a persistent unit

  1. List

    Enabled services and all timers.

    Command
    systemctl list-unit-files --state=enabled
  2. Attribute

    Find unit files no package owns.

  3. Read

    systemctl cat to see ExecStart and User.

  4. Include users

    Check lingering users’ ~/.config/systemd/user.

Check yourself

1. Which command shows every timer and its next run?

2. Where do administrators and attackers usually add custom units?

3. Why check users with lingering enabled?