SSH authorized keys written
An SSH authorized_keys file was CREATED or DELETED.
What it detects
An SSH authorized_keys file was CREATED or DELETED. Installing a public key here grants password-less, MFA-less login as that user and survives reboots and password resets, which is why it is one of the most common Linux footholds — and one of the quietest, since nothing else about the account changes.
Scoped to auditd PATH records whose nametype is CREATE or DELETE. That is the point of the rule, not an implementation detail: sshd READS every user's authorized_keys on each login attempt, so a rule keyed on the path alone fires on ordinary logins forever. nametype is the only write/read signal on the record that names the file — comm/exe live on the sibling SYSCALL record, and the auditd parser is one-line-one-event by design.
MITRE ATT&CK mapping
- T1098.004Account Manipulation: SSH Authorized Keys· Persistence
False positives and triage
Legitimate sources: configuration management (Ansible/Puppet/Chef/cloud-init) provisioning keys, a user running ssh-copy-id, and first-boot images seeding an operator key. Check WHO the key was written for, whether the writing session came from an expected admin host, and whether the key's comment matches a known operator. A key added for a service account, or for a user who has never had one, is the strong case.
Known blind spot — an APPEND to an existing authorized_keys reports nametype=NORMAL, indistinguishable from sshd's read on this record alone, so it does NOT fire here. Closing it needs SYSCALL↔PATH correlation by audit serial, or an audit watch configured write-only (-w <path> -p wa -k ssh_keys), under which reads are never recorded at all. Treated as a stated limit rather than papered over by matching the path and accepting a per-login false positive.
The rule
Declarative YAML read by the detection engine — data, never executed. Confidence 70%. Source: rules/linux/ssh_authorized_keys_persistence.yaml, licensed under the Apache License 2.0.
id: linux.persistence.ssh_authorized_keys_written
version: 1.0.0
status: stable
severity: high
confidence: 0.7
platforms: [linux]
mitre_techniques: [T1098.004]
description: |
An SSH `authorized_keys` file was CREATED or DELETED. Installing a public key
here grants password-less, MFA-less login as that user and survives reboots and
password resets, which is why it is one of the most common Linux footholds — and
one of the quietest, since nothing else about the account changes.
Scoped to auditd PATH records whose `nametype` is CREATE or DELETE. That is the
point of the rule, not an implementation detail: sshd READS every user's
authorized_keys on each login attempt, so a rule keyed on the path alone fires on
ordinary logins forever. `nametype` is the only write/read signal on the record
that names the file — `comm`/`exe` live on the sibling SYSCALL record, and the
auditd parser is one-line-one-event by design.
match:
file_path_regex: '/\.ssh/authorized_keys2?$'
event_action_any:
- file_created
- file_deleted
false_positive_guidance: |
Legitimate sources: configuration management (Ansible/Puppet/Chef/cloud-init)
provisioning keys, a user running `ssh-copy-id`, and first-boot images seeding an
operator key. Check WHO the key was written for, whether the writing session came
from an expected admin host, and whether the key's comment matches a known
operator. A key added for a service account, or for a user who has never had one,
is the strong case.
Known blind spot — an APPEND to an existing authorized_keys reports
`nametype=NORMAL`, indistinguishable from sshd's read on this record alone, so it
does NOT fire here. Closing it needs SYSCALL↔PATH correlation by audit serial, or
an audit watch configured write-only (`-w <path> -p wa -k ssh_keys`), under which
reads are never recorded at all. Treated as a stated limit rather than papered
over by matching the path and accepting a per-login false positive.
Related detections
Run this rule on your own logs — offline
KIROSEC runs this rule and the rest of the library over Windows, Linux, macOS and cloud audit logs on the analyst's own machine. Every alert links to the events that raised it, and nothing leaves the device.
