This note documents detection patterns related to SSH Key Persistence on Linux systems.
Direct Indicators
| Source | Grep Pattern / Artifact | Meaning | Forensic Value | Notes |
|---|---|---|---|---|
~/.ssh/authorized_keys | New key entry | SSH key-based access granted | Critical | Primary persistence artifact. |
/root/.ssh/authorized_keys | Root key insertion | Direct privileged persistence | Critical | Extremely high-value finding. |
~/.ssh/authorized_keys | Multiple unknown keys | Additional hidden access paths | Critical | Common attacker redundancy. |
~/.ssh/authorized_keys | Key comment anomaly | Suspicious operator/tool comments | High | Comments may reveal hostnames, emails, tooling. |
~/.ssh/authorized_keys | Forced command entry | Restricted but persistent access | High | May hide backdoor behavior. |
~/.ssh/authorized_keys | from= restriction | Controlled source IP persistence | High | Suggests deliberate stealth. |
~/.ssh/authorized_keys | command= prefix | Auto-executed command upon login | Critical | Can embed stealth persistence logic. |
auth.log / secure | Accepted publickey | Successful key authentication | Critical | Confirms key usage. |
auth.log / secure | userauth_pubkey | Public key auth flow | High | Useful precursor and validation signal. |
journalctl | key auth acceptance | Journald SSH key usage evidence | Critical | Required where flat logs absent. |
| File timestamps | recent mtime on authorized_keys | Key file modified | Critical | Strong insertion timing pivot. |
| File ownership anomalies | incorrect owner/group | Tampered key file | High | Common attacker mistake. |
auditd | write to authorized_keys | Process-level persistence evidence | Critical | Best process attribution if enabled. |
| Shell history | echo >> authorized_keys | Interactive key insertion | Critical | High-confidence attacker action. |
Indirect Indicators
| Indicator | What To Look For | Forensic Value | Notes |
|---|---|---|---|
| Key login appears after password login | Password foothold followed by key auth | Critical | Classic stabilization sequence. |
| New account immediately has key | Fresh user paired with SSH persistence | Critical | Strong malicious persistence pattern. |
| Root key appears without admin ticket | Unexplained root access path | Critical | High severity. |
| Multiple identical keys across hosts | Lateral persistence reuse | Critical | Cross-host compromise signal. |
| Key comment references external machine | Foreign hostname/email | High | Often reveals operator environment. |
| Old account suddenly gains new key | Dormant account reused | High | Common stealth technique. |
| Key file timestamp mismatches home activity | Silent insertion | High | Timeline anomaly. |
| Authorized keys created where absent before | Persistence introduced | Critical | Especially suspicious on service users. |
| Key auth from new IP | Unexpected source begins key login | High | Investigate source trust. |
| Forced command present unexpectedly | Hidden restricted backdoor | Critical | Often missed in casual review. |
Common Tools
| Tool | Usage |
|---|---|
ssh-copy-id | Legitimate or malicious key insertion helper. |
echo >> ~/.ssh/authorized_keys | Crude manual persistence. |
cat key.pub >> authorized_keys | Common attacker insertion method. |
scp / sftp | Key transfer before insertion. |
| Stolen private key | Enables later re-entry without passwords. |
| Automation scripts | Used by attackers after first foothold. |
Relevant Artifacts
| Artifact | Path / Command | Forensic Value | Notes |
|---|---|---|---|
| Authorized keys | ~/.ssh/authorized_keys | Critical | Primary persistence file. |
| Root authorized keys | /root/.ssh/authorized_keys | Critical | Highest severity key persistence artifact. |
| SSH directory metadata | ~/.ssh/ | High | Ownership, mode, timestamps. |
| File timestamps | stat authorized_keys | Critical | Modification timing. |
| SSH auth logs | /var/log/auth.log, /var/log/secure | Critical | Key usage evidence. |
| Journald | journalctl -u ssh, journalctl -u sshd | Critical | Modern systems primary source. |
| Shell history | .bash_history, .zsh_history | Critical | Key insertion commands. |
| Audit logs | /var/log/audit/audit.log | Critical | Write attribution if enabled. |
| Home directory | /home/<user> | High | Related persistence artifacts. |
| SSH daemon config | /etc/ssh/sshd_config | High | Determines accepted auth methods. |
MITRE ATT&CK References
- T1098 Account Manipulation
- T1098.004 SSH Authorized Keys
- T1078 Valid Accounts
- T1021.004 SSH
Decision Tree
-
Does an authorized_keys file exist?
- Enumerate all users and root.
-
Is key content expected?
- Compare against baseline, deployment tooling, known admin keys.
-
When was key inserted?
- Check mtime, ctime, nearby auth events.
-
Was key used?
- Search
Accepted publickey.
- Search
-
Which account owns the key?
- Determine privilege level and business role.
-
Pivot
- Key comment → operator clues.
- Source IP → login history.
- Adjacent shell history → insertion path.
-
Confirm persistence
- Unknown key + suspicious login + privilege path = malicious persistence.
Example Detection Templates
Grep
find /home /root -name authorized_keys -type f 2>/dev/null
grep -R "ssh-rsa\|ssh-ed25519\|ecdsa" /home /root/.ssh 2>/dev/null
grep "Accepted publickey" /var/log/auth.log /var/log/secure 2>/dev/null
grep -R "authorized_keys" /home/*/.bash_history /root/.bash_history 2>/dev/null
Journalctl
journalctl -u ssh | grep "Accepted publickey"
journalctl -u sshd | grep "userauth_pubkey"
File Inspection
stat /root/.ssh/authorized_keys
find /home -name authorized_keys -exec stat {} \;
Sigma
title: Linux SSH Key Persistence
id: linux-ssh-key-persistence
status: experimental
description: Detects SSH key-based persistence indicators and public key authentication activity
logsource:
product: linux
service: auth
detection:
selection:
message|contains:
- 'Accepted publickey'
- 'userauth_pubkey'
condition: selection
fields:
- message
- hostname
- source_ip
falsepositives:
- Legitimate administrator SSH key usage
level: high
tags:
- attack.persistence
- attack.t1098.004
- attack.t1021.004
Mitigation & Hardening
| Control Area | Mitigation | Effectiveness | Notes |
|---|---|---|---|
| Key governance | Baseline all authorized keys | Critical | Unknown keys should stand out immediately. |
| Root SSH | Disable root key login where possible | Critical | Removes highest-value persistence target. |
| Key rotation | Periodic review and rotation | High | Reduces stale persistence risk. |
| File integrity monitoring | Watch .ssh/authorized_keys | Critical | Excellent invariant detection. |
| Source restrictions | Use from= intentionally or monitor unexpected ones | High | Limits key misuse. |
| Logging | Preserve public key auth logs | High | Needed to prove use. |
| Centralized access | Prefer managed SSH access systems | High | Reduces unmanaged local key sprawl. |
Fast Triage Checks
| Question | Command / Artifact | Why It Matters |
|---|---|---|
| Which users have authorized keys? | find /home /root -name authorized_keys | Establish persistence surface. |
| Which key changed recently? | stat authorized_keys | Timeline anchor. |
| Was key used? | grep Accepted publickey | Confirms operational access. |
| Does root have unknown key? | inspect root key file | Highest severity check. |
| Was key inserted interactively? | shell history grep | Attribution clue. |
| Are key comments suspicious? | inspect raw key line | Often reveals operator hints. |
High Value Grep Strings
| Pattern | Why It Matters |
|---|---|
Accepted publickey | Successful key auth. |
userauth_pubkey | SSH key auth process evidence. |
authorized_keys | Direct persistence artifact reference. |
ssh-rsa | Common key type. |
ssh-ed25519 | Common modern key type. |
command= | Forced command persistence clue. |
from= | Restricted-source persistence clue. |
Analyst Notes
| Scenario | Interpretation |
|---|---|
| Password login then publickey login later | Strong attacker stabilization pattern. |
| Root authorized_keys modified recently | Critical privileged persistence lead. |
| Unknown key on dormant account | Silent foothold likely. |
| Key comment references laptop/email | Valuable operator clue. |
| Publickey success with no recent key change | Possible older persistence or stolen pre-existing key. |
| Forced command inside key | Hidden execution logic may exist. |