diff --git a/ssh-audit.py b/ssh-audit.py index a43b1dc..37007a9 100755 --- a/ssh-audit.py +++ b/ssh-audit.py @@ -567,7 +567,7 @@ class SSH(object): return self.display() def __repr__(self): - out = 'vendor={0} '.format(self.vendor) if self.vendor else '' + out = 'vendor={0}'.format(self.vendor) if self.vendor else '' if self.product: if self.vendor: out += ', ' @@ -582,7 +582,7 @@ class SSH(object): @staticmethod def _fix_patch(patch): - return re.sub(r'^[-_\.]+', '', patch) + return re.sub(r'^[-_\.]+', '', patch) or None @staticmethod def _fix_date(d): diff --git a/test/test_software.py b/test/test_software.py new file mode 100644 index 0000000..20eca18 --- /dev/null +++ b/test/test_software.py @@ -0,0 +1,285 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import pytest + + +class TestSoftware(object): + @pytest.fixture(autouse=True) + def init(self, ssh_audit): + self.ssh = ssh_audit.SSH + + def test_unknown_software(self): + ps = lambda x: self.ssh.Software.parse(self.ssh.Banner.parse(x)) + assert ps('SSH-1.5') is None + assert ps('SSH-1.99-AlfaMegaServer') is None + assert ps('SSH-2.0-BetaMegaServer 0.0.1') is None + + def test_openssh_software(self): + ps = lambda x: self.ssh.Software.parse(self.ssh.Banner.parse(x)) + # common + s = ps('SSH-2.0-OpenSSH_7.3') + assert s.vendor is None + assert s.product == 'OpenSSH' + assert s.version == '7.3' + assert s.patch is None + assert s.os is None + assert str(s) == 'OpenSSH 7.3' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == str(s) + assert repr(s) == '' + # common, portable + s = ps('SSH-2.0-OpenSSH_7.2p1') + assert s.vendor is None + assert s.product == 'OpenSSH' + assert s.version == '7.2' + assert s.patch == 'p1' + assert s.os is None + assert str(s) == 'OpenSSH 7.2p1' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == 'OpenSSH 7.2' + assert repr(s) == '' + # dot instead of underline + s = ps('SSH-2.0-OpenSSH.6.6') + assert s.vendor is None + assert s.product == 'OpenSSH' + assert s.version == '6.6' + assert s.patch is None + assert s.os is None + assert str(s) == 'OpenSSH 6.6' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == str(s) + assert repr(s) == '' + # dash instead of underline + s = ps('SSH-2.0-OpenSSH-3.9p1') + assert s.vendor is None + assert s.product == 'OpenSSH' + assert s.version == '3.9' + assert s.patch == 'p1' + assert s.os is None + assert str(s) == 'OpenSSH 3.9p1' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == 'OpenSSH 3.9' + assert repr(s) == '' + # patch prefix with dash + s = ps('SSH-2.0-OpenSSH_7.2-hpn14v5') + assert s.vendor is None + assert s.product == 'OpenSSH' + assert s.version == '7.2' + assert s.patch == 'hpn14v5' + assert s.os is None + assert str(s) == 'OpenSSH 7.2 (hpn14v5)' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == 'OpenSSH 7.2' + assert repr(s) == '' + # patch prefix with underline + s = ps('SSH-1.5-OpenSSH_6.6.1_hpn13v11') + assert s.vendor is None + assert s.product == 'OpenSSH' + assert s.version == '6.6.1' + assert s.patch == 'hpn13v11' + assert s.os is None + assert str(s) == 'OpenSSH 6.6.1 (hpn13v11)' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == 'OpenSSH 6.6.1' + assert repr(s) == '' + # patch prefix with dot + s = ps('SSH-2.0-OpenSSH_5.9.CASPUR') + assert s.vendor is None + assert s.product == 'OpenSSH' + assert s.version == '5.9' + assert s.patch == 'CASPUR' + assert s.os is None + assert str(s) == 'OpenSSH 5.9 (CASPUR)' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == 'OpenSSH 5.9' + assert repr(s) == '' + + def test_dropbear_software(self): + ps = lambda x: self.ssh.Software.parse(self.ssh.Banner.parse(x)) + # common + s = ps('SSH-2.0-dropbear_2016.74') + assert s.vendor is None + assert s.product == 'Dropbear SSH' + assert s.version == '2016.74' + assert s.patch is None + assert s.os is None + assert str(s) == 'Dropbear SSH 2016.74' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == str(s) + assert repr(s) == '' + # common, patch + s = ps('SSH-2.0-dropbear_0.44test4') + assert s.vendor is None + assert s.product == 'Dropbear SSH' + assert s.version == '0.44' + assert s.patch == 'test4' + assert s.os is None + assert str(s) == 'Dropbear SSH 0.44 (test4)' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == 'Dropbear SSH 0.44' + assert repr(s) == '' + # patch prefix with dash + s = ps('SSH-2.0-dropbear_0.44-Freesco-p49') + assert s.vendor is None + assert s.product == 'Dropbear SSH' + assert s.version == '0.44' + assert s.patch == 'Freesco-p49' + assert s.os is None + assert str(s) == 'Dropbear SSH 0.44 (Freesco-p49)' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == 'Dropbear SSH 0.44' + assert repr(s) == '' + # patch prefix with underline + s = ps('SSH-2.0-dropbear_2014.66_agbn_1') + assert s.vendor is None + assert s.product == 'Dropbear SSH' + assert s.version == '2014.66' + assert s.patch == 'agbn_1' + assert s.os is None + assert str(s) == 'Dropbear SSH 2014.66 (agbn_1)' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == 'Dropbear SSH 2014.66' + assert repr(s) == '' + + def test_libssh_software(self): + ps = lambda x: self.ssh.Software.parse(self.ssh.Banner.parse(x)) + # common + s = ps('SSH-2.0-libssh-0.2') + assert s.vendor is None + assert s.product == 'libssh' + assert s.version == '0.2' + assert s.patch is None + assert s.os is None + assert str(s) == 'libssh 0.2' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == str(s) + assert repr(s) == '' + s = ps('SSH-2.0-libssh-0.7.3') + assert s.vendor is None + assert s.product == 'libssh' + assert s.version == '0.7.3' + assert s.patch is None + assert s.os is None + assert str(s) == 'libssh 0.7.3' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == str(s) + assert repr(s) == '' + + def test_romsshell_software(self): + ps = lambda x: self.ssh.Software.parse(self.ssh.Banner.parse(x)) + # common + s = ps('SSH-2.0-RomSShell_5.40') + assert s.vendor == 'Allegro Software' + assert s.product == 'RomSShell' + assert s.version == '5.40' + assert s.patch is None + assert s.os is None + assert str(s) == 'Allegro Software RomSShell 5.40' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == str(s) + assert repr(s) == '' + + def test_hp_ilo_software(self): + ps = lambda x: self.ssh.Software.parse(self.ssh.Banner.parse(x)) + # common + s = ps('SSH-2.0-mpSSH_0.2.1') + assert s.vendor == 'HP' + assert s.product == 'iLO (Integrated Lights-Out) sshd' + assert s.version == '0.2.1' + assert s.patch is None + assert s.os is None + assert str(s) == 'HP iLO (Integrated Lights-Out) sshd 0.2.1' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == str(s) + assert repr(s) == '' + + def test_cisco_software(self): + ps = lambda x: self.ssh.Software.parse(self.ssh.Banner.parse(x)) + # common + s = ps('SSH-1.5-Cisco-1.25') + assert s.vendor == 'Cisco' + assert s.product == 'IOS/PIX sshd' + assert s.version == '1.25' + assert s.patch is None + assert s.os is None + assert str(s) == 'Cisco IOS/PIX sshd 1.25' + assert str(s) == s.display() + assert s.display(True) == str(s) + assert s.display(False) == str(s) + assert repr(s) == '' + + def test_sofware_os(self): + ps = lambda x: self.ssh.Software.parse(self.ssh.Banner.parse(x)) + # unknown + s = ps('SSH-2.0-OpenSSH_3.7.1 MegaOperatingSystem 123') + assert s.os is None + # NetBSD + s = ps('SSH-1.99-OpenSSH_2.5.1 NetBSD_Secure_Shell-20010614') + assert s.os == 'NetBSD (2001-06-14)' + assert str(s) == 'OpenSSH 2.5.1 running on NetBSD (2001-06-14)' + assert repr(s) == '' + s = ps('SSH-1.99-OpenSSH_5.0 NetBSD_Secure_Shell-20080403+-hpn13v1') + assert s.os == 'NetBSD (2008-04-03)' + assert str(s) == 'OpenSSH 5.0 running on NetBSD (2008-04-03)' + assert repr(s) == '' + s = ps('SSH-2.0-OpenSSH_6.6.1_hpn13v11 NetBSD-20100308') + assert s.os == 'NetBSD (2010-03-08)' + assert str(s) == 'OpenSSH 6.6.1 (hpn13v11) running on NetBSD (2010-03-08)' + assert repr(s) == '' + s = ps('SSH-2.0-OpenSSH_4.4 NetBSD') + assert s.os == 'NetBSD' + assert str(s) == 'OpenSSH 4.4 running on NetBSD' + assert repr(s) == '' + s = ps('SSH-2.0-OpenSSH_3.0.2 NetBSD Secure Shell') + assert s.os == 'NetBSD' + assert str(s) == 'OpenSSH 3.0.2 running on NetBSD' + assert repr(s) == '' + # FreeBSD + s = ps('SSH-2.0-OpenSSH_7.2 FreeBSD-20160310') + assert s.os == 'FreeBSD (2016-03-10)' + assert str(s) == 'OpenSSH 7.2 running on FreeBSD (2016-03-10)' + assert repr(s) == '' + s = ps('SSH-1.99-OpenSSH_2.9 FreeBSD localisations 20020307') + assert s.os == 'FreeBSD (2002-03-07)' + assert str(s) == 'OpenSSH 2.9 running on FreeBSD (2002-03-07)' + assert repr(s) == '' + s = ps('SSH-2.0-OpenSSH_2.3.0 green@FreeBSD.org 20010321') + assert s.os == 'FreeBSD (2001-03-21)' + assert str(s) == 'OpenSSH 2.3.0 running on FreeBSD (2001-03-21)' + assert repr(s) == '' + s = ps('SSH-1.99-OpenSSH_4.4p1 FreeBSD-openssh-portable-overwrite-base-4.4.p1_1,1') + assert s.os == 'FreeBSD' + assert str(s) == 'OpenSSH 4.4p1 running on FreeBSD' + assert repr(s) == '' + s = ps('SSH-2.0-OpenSSH_7.2-OVH-rescue FreeBSD') + assert s.os == 'FreeBSD' + assert str(s) == 'OpenSSH 7.2 (OVH-rescue) running on FreeBSD' + assert repr(s) == '' + # Windows + s = ps('SSH-2.0-OpenSSH_3.7.1 in RemotelyAnywhere 5.21.422') + assert s.os == 'Microsoft Windows (RemotelyAnywhere 5.21.422)' + assert str(s) == 'OpenSSH 3.7.1 running on Microsoft Windows (RemotelyAnywhere 5.21.422)' + assert repr(s) == '' + s = ps('SSH-2.0-OpenSSH_3.8 in DesktopAuthority 7.1.091') + assert s.os == 'Microsoft Windows (DesktopAuthority 7.1.091)' + assert str(s) == 'OpenSSH 3.8 running on Microsoft Windows (DesktopAuthority 7.1.091)' + assert repr(s) == '' + s = ps('SSH-2.0-OpenSSH_3.8 in RemoteSupportManager 1.0.023') + assert s.os == 'Microsoft Windows (RemoteSupportManager 1.0.023)' + assert str(s) == 'OpenSSH 3.8 running on Microsoft Windows (RemoteSupportManager 1.0.023)' + assert repr(s) == ''