SSH Persistence Techniques
After gaining access via SSH, these techniques keep that access alive beyond the current session. Each method trades off stealth against reliability. Start with authorized keys for guaranteed SSH re-entry, then layer in profile or cron callbacks for redundancy.
Authorized Keys Backdoor
The most direct and reliable method. Add an attacker-controlled public key to the target user's authorized_keys file. The key survives password resets, SSH session terminations, and most system updates.
Generate a key pair on the attacker machine:
This produces /tmp/backdoor (private) and /tmp/backdoor.pub (public). Copy the public key content:
On the target, append the public key to the target user's authorized_keys:
Fix permissions — SSH will refuse to use authorized_keys if the directory or file permissions are too open:
For root persistence:
Connect back using the private key:
Notice
OPSEC: authorized_keys is visible to any user who can read ~/.ssh/. Defenders routinely audit this file. For longer engagements, append rather than replace — removing an entry is harder to detect than seeing an unexpected single entry.
Shell Profile Persistence
Append a callback to a shell initialization file. The payload fires on the next interactive SSH login or shell spawn. This blends into legitimate dotfiles and survives reboots without needing root.
Per-user targets (runs as the current user on next login):
The trailing & backgrounds the reverse shell so the interactive SSH session continues normally and does not alert the user.
System-wide target (runs for all users on login, requires root):
On the attacker machine, listen before the next SSH session is opened by the target:
Zsh Equivalents
If the target user's shell is zsh:
Check the target user's shell first:
Cron Persistence via SSH User
A crontab entry provides timed callbacks independent of SSH sessions. It survives shell exits and reboots. Install as the target user or as root depending on the privilege level held.
Add a crontab entry as the current user:
This fires every minute. Adjust the schedule to reduce noise — every 5 minutes is less aggressive:
With root access, write directly to /etc/cron.d/ using a filename that resembles a system job:
Cron does not expand shell variables like $LHOST and $LPORT at runtime unless they are set in the cron environment. Use literal values in the actual entry, or wrap the command in a script:
SSHD Config Manipulation
Requires root. If the sshd_config is modified incorrectly the daemon may fail to restart, locking out all SSH access including your own. Test changes carefully.
Add a custom AuthorizedKeysFile directive pointing to an attacker-controlled path:
ncluding %h/.ssh/authorized_keys in the directive keeps existing keys functional — removing it breaks authentication for all legitimate users.
Restart the daemon to apply changes:
Test the backdoor key before ending the current session:
Notice
OPSEC: Restarting sshd generates a log entry and any monitoring on the config file will detect the modification. This is the noisiest method here. Use only when other persistence methods are unavailable or when root access needs to survive key rotation.
PermitRootLogin Backdoor
If root login is disabled, re-enable it via the config:
Then add a root-level authorized key as above.
SSH RC File
~/.ssh/rc is executed by sshd on each SSH login for the user, before the shell or ForceCommand runs. It is less commonly audited than authorized_keys or dotfiles, making it a lower-profile persistence option.
The file executes only when there is no ForceCommand set in sshd_config. Verify this is not restricted before relying on it:
If no ForceCommand is present, write the callback:
The script requires execute permissions. SSH runs it with the user's shell, so a bash shebang is sufficient on most Linux systems.
Notice
OPSEC: ~/.ssh/rc is checked on every SSH login. It fires before the interactive prompt, so the connection appears normal to the user. It does not appear in crontab -l output or ps history, making it less likely to surface in basic audits. Combined with a backgrounded reverse shell, it is one of the stealthier options here.
References
-
sshd_config(5)man.openbsd.org/sshd_config.5 (opens in new tab)
OpenBSD manual | Full reference for sshd_config directives including AuthorizedKeysFile, ForceCommand, and PermitRootLogin.
-
OpenBSD manual | Documents ~/.ssh/rc execution conditions and per-user login behavior.
Was this helpful?
Your feedback helps improve this page.