In this module we will take a look at using Python to list SSH Authentication methods. There is nothing like making your server estate cybersecurity and compliant with your policies. Ensuring that SSH servers on out estate adhere to security guidelines allows peace of mind knowing we can reduce the likelihood of our servers being compromised.
Why is password based authentication so bad? If your SSH Servers can be accessed by a password then pretty much every man and his dog has potential access to the system. There are many tools that can be used by anyone who has access to the system to brute-force accounts. Easily running through password lists attempting to login to the system. On the other hand, using Kerberos or Public key authentication is preferable and much more difficult to compromise.
How can Python Help? With cybersecurity a constant concern you have implemented a security policy to disable all password based authentication on SSH servers. Your job does not end at writing the policy, we have to monitor servers for compliance. Being able to run bespoke scripts written in Python or other languages gives you the ability of running an audit showing which servers do not meet the new criteria. As well as bespoke Python tools that we can create there are standard tools off-the-shelf that also can do the task for us. We will see how we can use tools such as the SSH client and nmap to list the SSH Servers supported authentication methods. Whilst these tools are great, we don’t learn and the more we know about our systems and the operation of protocols like SSH the better we can secure the server estate. Secondly, writing our own tools allow for exact operations that we need and is bespoke to the task we design.
Kali Linux: For the demonstration we use Kali Linux from Offensive Security. Kali is based on Ubuntu, so if you understand Ubuntu you will know how to use Kali. Kali makes a good security desktop as many of the tools that you need to audit your network come preinstalled, such as nmap. Kali also has Python 3 installed which is good along with the Paramiko module that we will use in the script. Using Kali, we are ready to start work.
This is not a Python Primer: We want you to learn more about what you need to know to secure your SSH Servers. We will write a Python script but this is not a Python primer and there are many great guides to get you started with Python. what we do do is give you the complete script in the blog and we explain each step so you can gain a good idea of the what and why we are doing each step.
To understand what we are trying to do we can look at other tools that do the job for us, but not in the way we want. Again the more we look at standard tools, especially the SSH client, the more we understand about the behaviour of the SSH Server itself and the SSH protocol, essential to are true knowledge. Firstly, we will look at how we can use the command line SSH client to list the Servers list of authentication methods.
Using SSH Client to List SSH Authentication Methods
During the initial setup of the SSH session the client and server negotiate a mutually acceptable authentication methods. Using the option PreferredAuthentication we can send what we would like to do, rather than all that we are capable of. Send the type of none will force the server to error and return the list if it’s acceptable methods.
$ ssh -o PreferredAuthentications=none localhost tux@localhost: Permission denied (publickey,password).
From the output, we can see that the server, localhost in this case, supports publickey and password based authentication. The list is the list from the server. Whilst this is okay, the SSH client is probably a bigger program than we need and in itself the command connects to a single server. With a little practice at scripting we could scan many systems, printing a list of servers that had password based authentication enabled. Next, we can look at nmap that can carry out the task easily for us.
Using nmap to List SSH Authentication Methods
The command line tool nmap is pre-installed on Kali Linux. The tool can be used for good and bad, but there is no reason that we shouldn’t use the port scanner to audit our own network. Just make sure that you are allowed to scan the systems. Nmap is a brilliant tool written by Fyodor, Gordon Lyon back in 1997. Of course, it is still developed today. It has also featured in sever movies including The Bourne Identify and The Matrix Reloaded. As part of nmap, it is easy to scan complete networks or network ranges. So it has all you want other than the besoke fot of your own application.
$ nmap -p 22 --script ssh-auth-methods localhost Starting Nmap 7.80 ( https://nmap.org ) at 2020-05-14 14:37 BST Nmap scan report for localhost (127.0.0.1) Host is up (0.000074s latency). Other addresses for localhost (not scanned): ::1 PORT STATE SERVICE 22/tcp open ssh | ssh-auth-methods: | Supported authentication methods: | publickey |_ password Nmap done: 1 IP address (1 host up) scanned in 0.21 seconds
Whilst, this has worked, nmap is overkill for what we want and we still have to find a way to search the output programmatically, allowing us to easily see which servers support the unwanted password authentication. The more that we can learn about how systems work the more we can protect them. Creating are own tools can be written to our needs and will have a generally smaller footprint than generic tools such as ssh or nmap. For more about nmap: click here
Using Python to List SSH Authentication Methods
Yes, at last we are looking at using Python to list SSH authentication methods, using Python and the Paramiko module both of which are standard on Kali Linux. In creating out own script we can be more bespoke about what we report and what we check for. This script, for simplicity in this display version connects to a single Ip and checks that SSH is listening on port 22. If it is a different port then that port can be selected. It would be easy to extend the script to a range of IP Addresses. Having checked that SSH is listening then we request the authentication methods by saying that we support None, just as we did wit the SSH client.
#!/usr/bin/env python3 import argparse import paramiko import socket class Scanner: def __init__(self, server, port): # Global variables used by all functions self.server = server self.port = port def test_ssh_port(self): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: # inner parenthesis create tuple ( one set of multiple arguments ) s.connect((self.server, self.port)) print("connection ok:", self.server, self.port) return True except Exception as err: # say why the connection failed to this server and port print("connection failed:", self.server, self.port, "cause: ", str(err)) return False finally: s.close() def test_ssh_auth(self): t = paramiko.Transport((self.server, self.port)) try: t.connect() except paramiko.ssh_exception.SSHException as err: print("SSH Connection failed 2:", self.server, self.port, "cause: ", str(err)) t.close() exit(1) try: t.auth_none('') except paramiko.BadAuthenticationType as err: print(err.allowed_types) finally: t.close() if __name__ == "__main__": parser = argparse.ArgumentParser(prog="scanner.py") parser.add_argument('--port', '-p', help='Enter a TCP port number', type=int, default=22) parser.add_argument('--server', '-s', help='Target IP or host name', default='127.0.0.1') args = parser.parse_args() scanner = Scanner(args.server, args.port) if scanner.test_ssh_port(): scanner.test_ssh_auth()
The script implements OOP but don’t let that put you off, we define an Object Class Scanner and create a new instance of that in the main code.
- Line 1: We define the script interpreter. This is written and tested with Python 3
- Line 2 -4: We import module that are used
- Line 6: We define the new class that we call Scanner. The class definition end on line 41. Note, that in Python the indent level defines the code blocks instead of using brace brackets { }
- Line 8: This start the definition a of a method, __init__ is a special method used to initial the object instance, to setup the variables needed through the class. This method takes 3 parameters, self (itself), server, and port
- Line 10: Takes the input parameter server to the class and assigns this to the server variable. Line 11 is similar for the port.
- Line 13: Defines the method to test the port is listening
- Line 14: We define the variable s to represent a new socket, a TCP connection
- Line 15: We can test to see what happens when we try to connect
- Line 17: We use the function connect from our instance of the socket to connect to the server and port
- Line 18: A successful connection will print a message of success
- Line 19: To allow us to test the success we return True to the calling routine
- Line 20: Where an error occurs we enter the except block
- Line 21: Print out an error message
- Line 22: And return false
- Line 24-25: In the finally block we run this code for both the success and failure ensuring the connection is closed
- Line 27: Having defined a method to test for SSH we now define a method to test auth methods.
- Line 28: Instead of the socket we now define a Transport higher level connection
- Line 29-30: The try blocks makes the connection to SSH
- Line 31-34: We test that the connect was OK, if it failed we can report on this and leave the code block
- Line 35-36: If we are still in the block at this point we have a TCP connection to SSH and we know it did not fail. We can now use the auth_none function. This will cause an exception!
- Line 37-38: We print the error message which includes the allowed types. We filter to print just the allowed types from the error
- Line 40-41: We close the Transport connection
- Line 44: We test that we are running this as a script program and not an inclusion. This block then becomes out main code of the program
- Line 45: Sets up the variable parser so we can accept command line options
- Line 46: Sets up the –port option so we can set a port number. If we don’t this defaults to port 22
- Line 47: Sets up the –server option which defaults to localhost if unset.
- Line 48: Sets up the variable args which is a list of options and arguments to the script
- Line 50: Creates an instance of the Scanner class we call the instance: scanner. We pass the server and port arguments to the class when it is instantiated
- Line 51: If we have tested that SSH is up then we can test authentication methods
We can save the file as scanner.py on our system We can run as a standard user in Kali Linux. Testing against one of my own servers:
$ ./scanner3.py -s 192.168.0.254 connection ok: 192.168.0.254 22 ['publickey', 'password']
If you need to, and please be respectful, you can run limited testing to Fyodor’s system:
$ ./scanner3.py -s scanme.nmap.org connection ok: scanme.nmap.org 22 ['publickey', 'password']
So now that you know the how and why of Using Python to List SSH Authentication Methods I hope you feel happy 🙂
More Python scripts: Click here