/analyzing-linux-persistence
Systematically identify and analyze persistence mechanisms on Linux systems during DFIR investigations -- sweep systemd units, cron jobs, shell initialization, SSH config, kernel modules, LD_PRELOAD, package manager hooks, udev rules, container entrypoints, and XDG autostart
$ npx -y skills add trilwu/secskills --skill analyzing-linux-persistence --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/analyzing-linux-persistence
Context preview
The summary Claude sees to decide when to auto-load this skill.
Systematically identify and analyze persistence mechanisms on Linux systems during DFIR investigations -- sweep systemd units, cron jobs, shell initialization, SSH config, kernel modules, LD_PRELOAD, package manager hooks, udev rules, container entrypoints, and XDG autostart
SKILL.md
analyzing-linux-persistence.SKILL.mdname: analyzing-linux-persistence
description: Systematically identify and analyze persistence mechanisms on Linux systems during DFIR investigations -- sweep systemd units, cron jobs, shell initialization, SSH config, kernel modules, LD_PRELOAD, package manager hooks, udev rules, container entrypoints, and XDG autostart entries. Use when investigating a compromised Linux host, performing forensic analysis of a Linux disk image, looking for backdoors or unauthorized access mechanisms, or determining how an attacker maintained access.
verified: 2026-07-27
Analyzing Linux Persistence
Linux persistence mechanisms are spread across dozens of locations that no single tool checks comprehensively. The attacker needs only one you miss. The work is a systematic sweep of every initialization path the kernel and userspace honor, in a sequence that catches the common before the exotic.
When to Use
- Investigating a compromised Linux host to find how the attacker kept access
- Forensic analysis of a Linux disk image or live system
- Looking for backdoors, unauthorized services, or rogue scheduled tasks
- Determining the full scope of attacker modifications during IR
- Validating that eradication removed every persistence mechanism
When NOT to Use
- **Running a full incident response** -- use `responding-to-incidents`
- **Establishing persistence offensively** -- use `establishing-persistence`
- **Actively escalating privileges** -- use `escalating-linux-privileges`
- **The host is Windows** -- use `investigating-windows-endpoints`
- **You have an acquired disk image, not a live host** -- use `analyzing-disk-images`
- **Analyzing a recovered malware sample** -- use `analyzing-malware`
Systemd Units
Systemd is the most common persistence vector on modern Linux. Check every search path, not just `/etc/systemd/system`.
**Search paths (evaluated in priority order):**
/etc/systemd/system/ # admin-installed, highest priority
/run/systemd/system/ # runtime units, survive until reboot
/usr/lib/systemd/system/ # package-installed defaults
/usr/local/lib/systemd/system/
~/.config/systemd/user/ # per-user units (no root needed)
**Enumeration:**
# All enabled units -- compare against a known-good baseline
systemctl list-unit-files --state=enabled --type=service
systemctl list-unit-files --state=enabled --type=timer
# Recently modified service files
find /etc/systemd /run/systemd /usr/lib/systemd ~/.config/systemd \
-name '*.service' -o -name '*.timer' -o -name '*.socket' \
2>/dev/null | xargs ls -lt | head -30
# Show the full contents of a suspect unit
systemctl cat suspicious.service
# Check for drop-in overrides that modify legitimate units
find /etc/systemd/system/*.d /run/systemd/system/*.d \
-name '*.conf' 2>/dev/null
# Masked units -- attacker may mask a security service
systemctl list-unit-files --state=masked
# Systemd generators -- scripts that dynamically create units at boot.
# Four directories, in ascending precedence. Checking only the first two
# misses generators dropped in the others.
ls -la /etc/systemd/system-generators/
ls -la /run/systemd/system-generators/ # tmpfs: runtime-injected
ls -la /usr/local/lib/systemd/system-generators/
ls -la /usr/lib/systemd/system-generators/
A generator under `/run` does not survive reboot, so it is not persistence in the strict sense — but it is a live execution primitive, and its absence from a post-reboot image does not mean it was never there. Note it on a running host before you collect.
**What to look for:** `ExecStart` pointing to `/tmp`, `/dev/shm`, or writable paths. `Restart=always` units. Timers with unusual schedules. Drop-ins that change `ExecStart` on legitimate services. Generators not from any package.
Cron and At Jobs
# System crontab
cat /etc/crontab
# System cron directories
ls -la /etc/cron.d/
ls -la /etc/cron.daily/ /etc/cron.hourly/ /etc/cron.weekly/ /etc/cron.monthly/
# Per-user crontabs -- enumerate every user
for user in $(cut -d: -f1 /etc/passwd); do
echo "=== $user ==="; crontab -l -u "$user" 2>/dev/null
done
# Anacron
cat /etc/anacrontab
# At queue -- one-shot scheduled commands
atq
for job in $(atq | awk '{print $1}'); do at -c "$job"; done
# Systemd timers (modern cron replacement)
systemctl list-timers --all
# Recently modified cron files
find /etc/cron* /var/spool/cron -type f -newer /etc/hostname 2>/dev/null**What to look for:** Entries appended to existing files. Jobs running as root from unusual paths. Cron scripts with modification times not matching package install dates. One-shot `at` jobs that download and execute.
Shell Initialization Files
# System-wide
cat /etc/profile
ls -la /etc/profile.d/
cat /etc/bash.bashrc # Debian/Ubuntu
cat /etc/bashrc # RHEL/CentOS
cat /etc/environment
ls -la /etc/environment.d/
# Per-user -- check every user with a login shell
for home in $(awk -F: '$7 !~ /(nologin|false)/ {print $6}' /etc/passwd); do
echo "=== $home ==="
for f in .bashrc .bash_profile .bash_login .profile .zshrc .zprofile \
.zlogin .zshenv .config/fish/config.fish; do
[ -f "$home/$f" ] && echo "--- $f ---" && tail -5 "$home/$f"
done
done
# Check for sourced external files
grep -rn 'source \|^\. ' /etc/profile.d/ /root/.bashrc /root/.profile 2>/dev/null**What to look for:** Lines appended to rc files that launch background processes or modify PATH. Sourced files in unusual locations. Environment variables setting `LD_PRELOAD`, `LD_LIBRARY_PATH`, or prepending attacker directories to `PATH`.
SSH Persistence
# Authorized keys -- check every user
find / -name authorized_keys -o -name authorized_keys2 2>/dev/null | \
while read f; do echo "=== $f ==="; cat "$f"; done
# Look for command= and from= restrictions (or lack thereof)
grep -n 'command=\|from=\|environment=\|no-pty\|permitopen' \
/root/.ssh/authorized_keys /home/*/.s
Read more
name: analyzing-linux-persistence description: Systematically identify and analyze persistence mechanisms on Linux systems during DFIR investigations -- sweep systemd units, cron jobs, shell initialization, SSH config, kernel modules, LD_PRELOAD, package manager hooks, udev rules, container entrypoints, and XDG autostart entries. Use when investigating a compromised Linux host, performing forensic analysis of a Linux disk image, looking for backdoors or unauthorized access mechanisms, or determining how an attacker maintained access. verified: 2026-07-27
Analyzing Linux Persistence
Linux persistence mechanisms are spread across dozens of locations that no single tool checks comprehensively. The attacker needs only one you miss. The work is a systematic sweep of every initialization path the kernel and userspace honor, in a sequence that catches the common before the exotic.
When to Use
- Investigating a compromised Linux host to find how the attacker kept access
- Forensic analysis of a Linux disk image or live system
- Looking for backdoors, unauthorized services, or rogue scheduled tasks
- Determining the full scope of attacker modifications during IR
- Validating that eradication removed every persistence mechanism
When NOT to Use
- **Running a full incident response** -- use `responding-to-incidents`
- **Establishing persistence offensively** -- use `establishing-persistence`
- **Actively escalating privileges** -- use `escalating-linux-privileges`
- **The host is Windows** -- use `investigating-windows-endpoints`
- **You have an acquired disk image, not a live host** -- use `analyzing-disk-images`
- **Analyzing a recovered malware sample** -- use `analyzing-malware`
Systemd Units
Systemd is the most common persistence vector on modern Linux. Check every search path, not just `/etc/systemd/system`.
**Search paths (evaluated in priority order):**
/etc/systemd/system/ # admin-installed, highest priority /run/systemd/system/ # runtime units, survive until reboot /usr/lib/systemd/system/ # package-installed defaults /usr/local/lib/systemd/system/ ~/.config/systemd/user/ # per-user units (no root needed)
**Enumeration:**
# All enabled units -- compare against a known-good baseline systemctl list-unit-files --state=enabled --type=service systemctl list-unit-files --state=enabled --type=timer # Recently modified service files find /etc/systemd /run/systemd /usr/lib/systemd ~/.config/systemd \ -name '*.service' -o -name '*.timer' -o -name '*.socket' \ 2>/dev/null | xargs ls -lt | head -30 # Show the full contents of a suspect unit systemctl cat suspicious.service # Check for drop-in overrides that modify legitimate units find /etc/systemd/system/*.d /run/systemd/system/*.d \ -name '*.conf' 2>/dev/null # Masked units -- attacker may mask a security service systemctl list-unit-files --state=masked # Systemd generators -- scripts that dynamically create units at boot. # Four directories, in ascending precedence. Checking only the first two # misses generators dropped in the others. ls -la /etc/systemd/system-generators/ ls -la /run/systemd/system-generators/ # tmpfs: runtime-injected ls -la /usr/local/lib/systemd/system-generators/ ls -la /usr/lib/systemd/system-generators/
A generator under `/run` does not survive reboot, so it is not persistence in the strict sense — but it is a live execution primitive, and its absence from a post-reboot image does not mean it was never there. Note it on a running host before you collect.
**What to look for:** `ExecStart` pointing to `/tmp`, `/dev/shm`, or writable paths. `Restart=always` units. Timers with unusual schedules. Drop-ins that change `ExecStart` on legitimate services. Generators not from any package.
Cron and At Jobs
# System crontab
cat /etc/crontab
# System cron directories
ls -la /etc/cron.d/
ls -la /etc/cron.daily/ /etc/cron.hourly/ /etc/cron.weekly/ /etc/cron.monthly/
# Per-user crontabs -- enumerate every user
for user in $(cut -d: -f1 /etc/passwd); do
echo "=== $user ==="; crontab -l -u "$user" 2>/dev/null
done
# Anacron
cat /etc/anacrontab
# At queue -- one-shot scheduled commands
atq
for job in $(atq | awk '{print $1}'); do at -c "$job"; done
# Systemd timers (modern cron replacement)
systemctl list-timers --all
# Recently modified cron files
find /etc/cron* /var/spool/cron -type f -newer /etc/hostname 2>/dev/null**What to look for:** Entries appended to existing files. Jobs running as root from unusual paths. Cron scripts with modification times not matching package install dates. One-shot `at` jobs that download and execute.
Shell Initialization Files
# System-wide
cat /etc/profile
ls -la /etc/profile.d/
cat /etc/bash.bashrc # Debian/Ubuntu
cat /etc/bashrc # RHEL/CentOS
cat /etc/environment
ls -la /etc/environment.d/
# Per-user -- check every user with a login shell
for home in $(awk -F: '$7 !~ /(nologin|false)/ {print $6}' /etc/passwd); do
echo "=== $home ==="
for f in .bashrc .bash_profile .bash_login .profile .zshrc .zprofile \
.zlogin .zshenv .config/fish/config.fish; do
[ -f "$home/$f" ] && echo "--- $f ---" && tail -5 "$home/$f"
done
done
# Check for sourced external files
grep -rn 'source \|^\. ' /etc/profile.d/ /root/.bashrc /root/.profile 2>/dev/null**What to look for:** Lines appended to rc files that launch background processes or modify PATH. Sourced files in unusual locations. Environment variables setting `LD_PRELOAD`, `LD_LIBRARY_PATH`, or prepending attacker directories to `PATH`.
SSH Persistence
# Authorized keys -- check every user find / -name authorized_keys -o -name authorized_keys2 2>/dev/null | \ while read f; do echo "=== $f ==="; cat "$f"; done # Look for command= and from= restrictions (or lack thereof) grep -n 'command=\|from=\|environment=\|no-pty\|permitopen' \ /root/.ssh/authorized_keys /home/*/.s
**Security skills for Claude Code that encode the judgment professionals bring, not another wrapper around a scanner.** Offense, defense, and the reverse-engineering and code-audit core both sides share. Every skill is fact-checked against primary sources.

