Skip to content

PersistenceNetworkLogs

SSH Artifacts: authorized_keys, known_hosts and sshd Logs

OpenSSH artifacts on Linux (authorized_keys, known_hosts, configs, host keys, sshd logs) that prove remote access, key persistence and lateral movement.

Location
~/.ssh/authorized_keys
Proves
Which keys can log in to an account, where a user connected to, and who logged in over SSH from where
Timestamps
Key files: file system times only; logs: syslog local time or journal usec since Unix epoch (UTC)
Access
root (or the account owner for its own ~/.ssh); adm/systemd-journal group for logs
Retention
Key files until deleted; log lines follow syslog rotation and journal limits
Collection
UAC, Velociraptor, cp -a, journalctl

What it is

OpenSSH leaves evidence on both ends of a connection. On the server side, authorized_keys decides which public keys may log in to an account, sshd_config sets the rules, and sshd logs every accepted and failed attempt. On the client side, known_hosts records the servers a user has connected to and ~/.ssh/config often names them. Together they answer the two core questions of most Linux intrusions: how did the attacker get in, and where did they go next.

Adding a key to authorized_keys is one of the most common Linux persistence techniques (MITRE ATT&CK T1098.004) because it survives password resets.

Where it lives

ArtifactPathNotes
Authorized keys~/.ssh/authorized_keys, ~/.ssh/authorized_keys2Default AuthorizedKeysFile; check every home including /root and service accounts
Known hosts~/.ssh/known_hosts, /etc/ssh/ssh_known_hostsClient-side record of servers
Hash backup~/.ssh/known_hosts.oldLeft by ssh-keygen -H when a file is hashed
Client config~/.ssh/config, /etc/ssh/ssh_config, /etc/ssh/ssh_config.d/Host aliases, users, jump hosts, keys
User keys~/.ssh/id_*, ~/.ssh/id_*.pubNote presence and fingerprints only
Per-login scripts~/.ssh/rc, /etc/ssh/sshrcRun by sshd before the user's shell
User environment~/.ssh/environmentOnly read if PermitUserEnvironment allows it
Server config/etc/ssh/sshd_config, /etc/ssh/sshd_config.d/*.confDrop-ins via Include in current Debian, Ubuntu and Fedora/RHEL 9 packaging
Host keys/etc/ssh/ssh_host_{rsa,ecdsa,ed25519}_key(.pub)Identify the server; regenerated keys change client fingerprints
Logs/var/log/auth.log (Debian/Ubuntu), /var/log/secure (RHEL family), systemd journalFacility AUTH by default; RHEL-family configs set AUTHPRIV

What it proves

  • Access capability: any key in authorized_keys can log in as that account, subject to its options and sshd_config.
  • Actual logins: Accepted publickey or Accepted password lines prove a successful authentication, with source IP, port and (for keys) the key fingerprint.
  • Attempts: Failed password, Invalid user and similar lines show brute force and username guessing.
  • Outbound movement: known_hosts and ~/.ssh/config show that the account connected to other hosts, even with no shell history.
  • Not proven: a key comment (user@host) is free text written by whoever created the key. known_hosts entries do not carry dates or show that a login succeeded, only that a host key was accepted.

Key fields

authorized_keys options (comma-separated, before the key type):

OptionMeaning
command="..."Forces a command for this key; original request in SSH_ORIGINAL_COMMAND
from="pattern"Restricts source hosts/addresses (CIDR allowed)
environment="NAME=value"Sets variables if PermitUserEnvironment is enabled
no-pty, no-port-forwarding, no-agent-forwarding, no-X11-forwarding, no-user-rcRestrictions
restrictAll restrictions at once; can be relaxed with pty, port-forwarding etc.
permitopen=, permitlisten=, tunnel=Forwarding and tunnel controls
expiry-time="YYYYMMDD[HHMM[SS]][Z]"Key stops working after this time
cert-authority, principals=Trust a CA instead of a single key

known_hosts: [marker] hostnames keytype base64key [comment]. Hashed entries start with |1| (salt and HMAC), so hostnames cannot be read directly. Debian and Ubuntu ship HashKnownHosts yes in /etc/ssh/ssh_config; upstream default is no.

sshd_config directives: AuthorizedKeysFile, AuthorizedKeysCommand, AuthorizedPrincipalsFile, TrustedUserCAKeys, PermitRootLogin (default prohibit-password), PasswordAuthentication, PermitUserEnvironment (default no), ForceCommand, Match blocks, LogLevel (default INFO), SyslogFacility.

Log lines (process sshd, and on OpenSSH 9.8+ also sshd-session; on 10.0+ some messages may also come from sshd-auth):

Accepted publickey for deploy from 198.51.100.7 port 51522 ssh2: ED25519 SHA256:<fingerprint>
Accepted password for deploy from 203.0.113.50 port 40318 ssh2
Failed password for invalid user admin from 203.0.113.50 port 40022 ssh2
Invalid user admin from 203.0.113.50 port 40022

Timestamps

Key and config files have only file system times: mtime of authorized_keys changes whenever a key is added or removed, and ctime cannot be set with touch. Syslog files (auth.log, secure) use the local time zone and, in the classic format, no year; the journal stores __REALTIME_TIMESTAMP in microseconds since 1970-01-01 UTC. expiry-time values without Z are interpreted in the system time zone.

Retention

Key files and configs remain until changed. Log retention depends on logrotate (weekly with four rotations is a common Debian default for auth.log) and journal size limits; see syslog and auth.log and systemd journal. known_hosts only grows unless a user runs ssh-keygen -R or edits it.

Collection

UAC has dedicated artifacts for authorized_keys*, known_hosts, public keys and ~/.ssh/rc, and collects /etc/ssh with /etc. Velociraptor provides Linux.Ssh.AuthorizedKeys, Linux.Ssh.KnownHosts and Linux.Syslog.SSHLogin.

R=/mnt/evidence
tar -C "$R" -czf ssh.tgz etc/ssh root/.ssh home/*/.ssh 2>/dev/null   # includes private keys: handle as sensitive
journalctl -D "$R"/var/log/journal _COMM=sshd -o short-iso        # add _COMM=sshd-session on newer OpenSSH

Treat private host and user keys as sensitive evidence: record fingerprints, restrict access, never reuse them.

Parsing

# fingerprint every authorized key, then match against "Accepted publickey" lines
for f in /mnt/evidence/root/.ssh/authorized_keys* /mnt/evidence/home/*/.ssh/authorized_keys*; do
  echo "== $f"; ssh-keygen -l -f "$f"; done
grep -hE 'sshd(-session|-auth)?\[[0-9]+\]: (Accepted|Failed|Invalid user)' /mnt/evidence/var/log/auth.log* /mnt/evidence/var/log/secure*
zgrep -h 'Accepted' /mnt/evidence/var/log/auth.log.*.gz
# test a candidate hostname against a hashed known_hosts
ssh-keygen -F 10.0.0.12 -f /mnt/evidence/home/alice/.ssh/known_hosts

Linux Log Parser reads auth.log / secure, syslog, journal files, audit.log and wtmp / btmp / lastlog in the browser and merges them into one timeline with rebuilt login sessions; nothing is uploaded.

Investigator tips

  • Match the SHA256: fingerprint in each Accepted publickey line to a specific key line; this identifies which key an attacker used even when comments are fake.
  • Look for AuthorizedKeysFile pointing to an unusual path, or an AuthorizedKeysCommand, in sshd_config and every drop-in: keys may live outside ~/.ssh.
  • command= keys and ~/.ssh/rc run code at each login; a from= option can reveal attacker infrastructure.
  • Parsers or SIEM rules that match only sshd[ miss lines tagged sshd-session or sshd-auth on recent OpenSSH (Velociraptor's Linux.Syslog.SSHLogin filters on program sshd).
  • Hashed known_hosts can still be tested against candidate IPs from your case with ssh-keygen -F.
  • Changed host keys (new ctime on /etc/ssh/ssh_host_*) can indicate a rebuilt or cloned server.
  • Correlate accepted logins with wtmp/lastlog and the user's shell history.

See also