Hello and welcome to the first installment of Pwnage Per Port! Today we will be discussing the oh-so-important SSH service which runs (most commonly) on TCP port 22.
Back in the early days of computing there was a little something called ARPANET, which was the predecessor of the Internet. Times were simpler then, and ARPANET was a place where you could let your kids walk down the street without fear of bad guys getting them. Kinda like this:
Things have changed since those simpler days, and parents are rightfully afraid to let their children wander the Internet alone. Face it, would you want your kids hanging out in a place like this:
Because it’s a pretty accurate rendition of what happens today on the Internet when your stuff isn’t secured.
Metaphors aside, back in the days of ARPANET there was a different mentality surrounding the design of computing protocols. Networks of computers (outside of a few inter-institution links) were mostly physically secured, meaning that data traversing those networks could be considered reasonably secure as attackers would require physical access. Additionally, hardware of the time had a minute fraction of the power of modern hardware, and cryptography was more of a guarded secret and export-controlled munition.
As networks started to grow, computer operators needed the ability to remotely invoke computer functionality. This birthed the r-suite of BSD tools (rcp, rlogin, rsh, rexec, etc) as well as Telnet, and everyone was happy. These utilities could send commands to remote machines, and it didn’t matter that commands and credentials were sent in plaintext as the network links were physically secured.
Then ARPANET became the Internet, and the Internet began its exponential growth. Connectivity to the Internet was no longer reserved for academic institutes and governmental bodies. Individuals could get access from their homes! Suddenly, all of these protocols which hadn’t taken security into account now posed security risks. Someone on your network no longer needed to be physically present, and physical isolation no longer protected your network links.
Unsurprisingly, the creation of SSH1 in 1995 was motivated by a password sniffing attack at the Helsinki University of Technology in Finland. While I did not find specific details on what the attack entailed, a researcher named Tatu Ylönen responded to the attack by writing SSH1 and the SSH-1 protocol himself. Tatu distributed his program freely until he realized he could privatize it and turn a profit. SSH2 was submitted as an IETF draft in 1997, and as Tatu’s implementation became privatized and proprietary the folks over at OpenBSD built OpenSSH.
Since then, not very much has changed (which is incredible to think about considering how much the computing industry has grown). There are many implementations of SSH2, and OpenSSH continues to champion them all. In the twenty years of SSH’s existence, CVE Details reports that only 42 CVEs have been granted for SSH servers:
Compare that with something like the WordPress CMS platform that sports 199 CVEs in half as much time:
What Is It Used For?
SSH allows users to connect to a program (most commonly a shell) on a remote server in a secure fashion. Once the connection is established, the SSL/TLS tunnel built, and proper authentication provided, the user is dropped into the configured program and can work with the program as if they were physically sitting in front of the machine they’re connect to. SSH is most commonly found on port 22, but is often run on other ports as well as a defensive security control.
SSH not only provides a securely encrypted tunnel that commands can be issued across and varying levels of authentication for users, but also authentication of the servers that users connect to. During the SSH connection establishment, the client and server exchange keys identifying themselves. If a user has not seen a server before, then the user is prompted to verify the server’s key. If a user has seen the server before and the key it provides matches what the user has on file, the connection setup proceeds. If a user has seen the server before and the server’s key does NOT match what the user has on file, the connection is immediately terminated and the user notified (which helps prevent man-in-the-middle attacks).
SSH is most commonly used for remote computer management, administration, and general computing tasks. Typically if it’s a *nix box or a Mac machine in a production environment, it’s going to have an SSH server running on it.
Remember that time that I said SSH has only seen 42 CVEs in 20 years? Yeah, SSH is pretty darn secure out of the box. There may be one-off implementations of SSH that sport memory corruption vulnerabilities and things of that nature, but for the most part the SSH software itself is sound. Because of this, successfully compromising an SSH server relies on misconfiguration and standard human error factors. That being said, though, compromising a single SSH server can provide a nice foothold for pivoting into other parts of a target network. SSH is also a service that is commonly found on both internal and external networks.
Brute forcing is really the only way to directly attack an SSH server. There are a LOT of brute forcing tools out there, such as:
As a Python fan, I like Patator the best, and thus the following instructions are going to be for Patator.
First things first – you need a list of usernames and a list of passwords. I recommend checking out this GitHub repository to acquire both of those. Also, add some usernames and passwords based on the name of your target. Poor passwords commonly incorporate company names, application names, registration dates, and other guessable information.
I pulled Patator down and threw a username and password list into the Patator directory:
You can run the following command to see all of the configuration options that Patator’s ssh_login option comes with:
The syntax for executing Patator commands is a bit funky at first, but once you get the hang of it the syntax makes a lot of sense. You can specify file contents for nearly any argument. As shown below, the user argument is set to FILE0. FILE0 is then defined by the “0=top_shortlist.txt” command line argument. Putting this together, Patator will attempt to login with every username found in top_shortlist.txt. The same thing holds true for FILE1 and 1=rockyou.txt:
python patator.py ssh_login host=127.0.0.1 user=FILE0 password=FILE1 0=top_shortlist.txt 1=rockyou.txt -x ignore:mesg='Authentication failed.'
Executing this command is shown below:
As you can see above, this isn’t a particularly fast process. Not only that, but SSH brute forcing is noisy and is trivially caught by IDS and IPS controls. SSH brute forcing can absolutely work, but you’re going to have to get lucky with this one. I tend to only try a handful of very common username and password combinations across an enterprise’s entire internal network (root/root, root/admin, root/toor, admin/admin, etc), and sometimes I will get a box or two. Those one or two boxes, however, tend to give me a foothold into places where I need to get! Also, antiquated appliances and networking equipment often have default logins enabled and in some cases accept SSH connections based on username alone.
Lastly, SSH brute forcing is a good thing to do once you get your hands on a few pairs of valid credentials. Password re-use is prevalent! Take those accounts you already have and see if they don’t work on other SSH servers!
While there aren’t very many attacks against SSH servers, there are plenty of ways to harden them. Sheerly due to the number of ways SSH servers can be hardened, I’m only going to provide brief descriptions here with links to guides that provide more details.
Disable Password Authentication
Authentication to SSH servers can be done in a lot of ways. Password-based authentication represents the most common poor configuration that I see on SSH servers. While password authentication isn’t inherently bad, it allows regular users to make silly mistakes like setting their password as their username or using passwords like “Password1”. Disabling password authentication entirely prevents users from making these silly mistakes, and requires users to employ stronger authentication methods like key-based authentication.
Disable Root Account Remote Login
Unless you’ve got a specific need for allowing remote root login, it’s not a bad idea to disable logging in as the root account via SSH. Even if an attacker knows the root account password for a box, they will have to compromise another account and then su to root if remote root login is disabled.
Explicitly Allow or Deny SSH Access for Users
In the same vein as disabling remote root login, any other user accounts which do not require remote access should not be provided remote access! Every account that can be prevented from logging in remotely presents one less attack vector to malicious third-parties.
Deploy SSH Server on a Non-standard Port
Ahh security through obscurity, I hate you and you’re ugly. Deploying an SSH server on a port other than 22 increases the difficulty with which attackers can find your server. That being said, the increase in difficulty is not significant. The real benefit that you gain from changing the port on which your SSH server runs is that your SSH logs will likely be a bit cleaner, and ergo forensic efforts can proceed faster. Script kiddies like to fire off SSH brute forcers across the entire IPv4 address space, and if your SSH server is on the open Internet on port 22 you will be end up as a target.
Fail2ban is an awesome utility for preventing brute force attacks. Fail2ban is a daemon that monitors server logs for evidence of intrusion attempts against SSH servers and other common targets. Once Fail2ban identifies malicious activity, it blocks the attacker via firewall and can notify the system administrator. While I haven’t installed and configured Fail2ban myself, colleagues of mine speak quite highly of it and state that it works reasonably well out of the box.
As is the case with darn near anything that requires authentication, requiring multiple factors of authentication increases the authenticator’s security posture. With SSH servers, multi-factor can mean many different things. Users can be required to use key-based authentication as well as password-based authentication. They can be required to use password-based authentication which is followed by a push to the user’s Google authenticator. They can be required to use all three! Implementing multiple factors of authentication requires attackers to compromise more than just a password or a private key, which greatly increases the difficulty of the attack.
If you haven’t heard of port knocking before, you should go read more about it. It’s the digital equivalent of having a secret handshake or door knock. Port knocking is when a daemon listens on a server for a specific sequence of packets, and when it receives that sequence the daemon configures the firewall to allow the knocking user to access the SSH server. Attackers that are not aware of the sequence will have no idea that an SSH server is running on the machine at all, as the port will appear closed to them. As awesome as port knocking is, it is not particularly scalable.
While this won’t directly secure your SSH server, it can alert you when an attacker is attempting to log in to SSH servers on your network. Honey pots are services and applications that appear legitimate, but serve only to attract attackers and alert defenders of the attackers’ presence. If you’ve got a large internal network that you’re defending, having tripwires for attackers to walk through will greatly aid in your ability to detect and react to malicious activity. Throw a few SSH honey pots on your network and configure them to alert security personnel whenever someone attempts to log in to them.
Did you know that the default *nix SSH client has a “hidden” menu? This menu allows you to background the SSH connection and add and remove port forwarding rules without breaking the connection! It’s pretty great, and you can read more here.
- History of SSH
- Wikipedia on SSH
- Brief History of SSH and Remote Access
- AskUbuntu.Com How to Harden an SSH Server
- Setting up 2FA on SSH
- SSH Escape Codes
- SSH CVE Details
- Wikipedia on Comparison of SSH Servers
- Enable SSH Key Logon and Disable Password Logon in CentOS
- AskUbuntu.Com How Do I Disable Remote SSH Login as Root from a Server?
- Ubuntu Forums SSH Server: A More Secure Configuration
- SysConfig’s Blog Two-Factor Authentication with SSH
- Digital Ocean How to Use Port Knocking to Hide Your SSH Daemon from Attackers on Ubuntu
- SSH Escape Sequences
- Wikipedia on Cryptography Export Rules
- Security Lists on GitHub