Persistence Mechanisms: Cron, systemd, Shell Profiles & SSH Keys
An attacker who has gained access to a Linux host wants to keep that access even after a reboot, a password reset, or a service restart. On Linux this almost always means abusing one of a handful of well-known startup or scheduling mechanisms. This chapter covers where to look for each one.
Cron Persistence
Cron is the classic Linux scheduling mechanism, and it is one of the most common places an attacker plants a recurring command. A new job among dozens of legitimate ones is easy to miss unless someone is looking specifically for it.
| Location | Notes |
|---|---|
| Per-user crontab | crontab -l shows the current user's jobs; each user on the system can have their own crontab |
/etc/crontab | The system-wide crontab, readable by anyone but writable only by root |
/etc/cron.d/ | Drop-in system cron jobs, often used by installed packages, which also makes it easy for a malicious entry to blend in |
/etc/cron.daily/, /etc/cron.hourly/, etc | Directories of periodic system maintenance scripts, run on a fixed schedule by cron itself |
Cron is a common persistence vector because it is simple, ubiquitous, and already trusted. A single extra line in a crontab or a single extra script in a drop-in directory rarely draws attention next to dozens of legitimate entries doing the same thing.
systemd Persistence
systemd service and timer units offer the same recurring or on-boot execution that cron does, but they look like ordinary system infrastructure to anyone who isn't specifically checking. A malicious unit file next to legitimate ones rarely stands out on its own.
| Location | Scope |
|---|---|
/etc/systemd/system/ | System-wide unit files, applied regardless of which user is logged in |
~/.config/systemd/user/ | Per-user unit files, tied to a specific account |
A service unit can be set to start on boot or restart automatically if it stops, giving an attacker resilience beyond a single reboot. A timer unit pairs with a service unit to trigger it on a schedule, achieving the same recurring-execution effect as a cron job while sitting among the system's normal service definitions.
Shell Profile Persistence
Shell profile files run automatically whenever a matching shell starts, which means code planted in one of them executes without needing to trick the user into running anything themselves.
| File | Triggers On |
|---|---|
~/.bashrc | Interactive non-login shell, such as opening a new terminal window |
~/.bash_profile or ~/.profile | Login shell, such as an SSH session or a fresh console login |
/etc/profile.d/ | System-wide scripts sourced for all users at login |
Because these files execute silently on ordinary, everyday actions like opening a terminal or logging in over SSH, a single planted line can re-establish an attacker's foothold every time the legitimate user simply works normally.
SSH Key Persistence
~/.ssh/authorized_keys lists the public keys allowed to log in as that user without a password. An attacker who can write to this file adds their own public key, and that access does not depend on the account's password at all.
That independence from the password is what makes this mechanism durable: resetting the user's password, or even forcing a full credential rotation elsewhere, does nothing to remove a key an attacker already planted in authorized_keys.
Persistence Hunting Checklist
Each mechanism in this chapter is easy to check individually, but attackers often rely on defenders checking only one. Working through all of them, in order, is what turns a spot check into a real sweep.
Once these mechanisms have been checked, the next step is looking at what they may have already launched, which is where chapter 5 picks up with live process and network state.
Key Takeaways
- Cron persistence can live in per-user crontabs, /etc/crontab, /etc/cron.d/, or the periodic cron.daily/cron.hourly directories.
- systemd service units and timer units can start on boot or run on a schedule, giving the same effect as cron while looking like ordinary system infrastructure.
- Shell profile files (.bashrc, .bash_profile, .profile, /etc/profile.d/) execute automatically on normal actions like opening a terminal or logging in.
- .bashrc triggers on interactive non-login shells, while .bash_profile and .profile trigger on login shells.
- A planted key in ~/.ssh/authorized_keys survives a password reset, because it doesn't rely on the password at all.
- Hunting persistence means checking cron, systemd, shell profiles, and authorized_keys together, then comparing all of it against a known-good baseline.
Knowledge Check
Click an answer to reveal the explanation.
What is /etc/cron.d/ typically used for?
Why does a planted key in ~/.ssh/authorized_keys survive a password reset?
When does ~/.bashrc trigger, as opposed to ~/.bash_profile?