diff --git a/src/ssh_audit/ssh_audit.py b/src/ssh_audit/ssh_audit.py index 9dc04c0..485c3b8 100755 --- a/src/ssh_audit/ssh_audit.py +++ b/src/ssh_audit/ssh_audit.py @@ -250,6 +250,9 @@ def output_security(out: OutputBuffer, banner: Optional[Banner], client_audit: b software = Software.parse(banner) output_security_sub(out, 'cve', software, client_audit, padlen) output_security_sub(out, 'txt', software, client_audit, padlen) + if banner.protocol[0] == 1: + p = '' if out.batch else ' ' * (padlen - 14) + out.fail('(sec) SSH v1 enabled{} -- SSH v1 can be exploited to recover plaintext passwords'.format(p)) if not out.is_section_empty() and not is_json_output: out.head('# security') out.flush_section() @@ -408,12 +411,17 @@ def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header if len(header) > 0: out.info('(gen) header: ' + '\n'.join(header)) if banner is not None: - out.good('(gen) banner: {}'.format(banner)) + banner_line = '(gen) banner: {}'.format(banner) + if sshv == 1 or banner.protocol[0] == 1: + out.fail(banner_line) + out.fail('(gen) protocol SSH1 enabled') + else: + out.good(banner_line) + if not banner.valid_ascii: # NOTE: RFC 4253, Section 4.2 out.warn('(gen) banner contains non-printable ASCII') - if sshv == 1 or banner.protocol[0] == 1: - out.fail('(gen) protocol SSH1 enabled') + software = Software.parse(banner) if software is not None: out.good('(gen) software: {}'.format(software)) diff --git a/test/docker/expected_results/openssh_4.0p1_test1.txt b/test/docker/expected_results/openssh_4.0p1_test1.txt index 54ba817..419105a 100644 --- a/test/docker/expected_results/openssh_4.0p1_test1.txt +++ b/test/docker/expected_results/openssh_4.0p1_test1.txt @@ -1,5 +1,5 @@ # general -(gen) banner: SSH-1.99-OpenSSH_4.0 +(gen) banner: SSH-1.99-OpenSSH_4.0 (gen) protocol SSH1 enabled (gen) software: OpenSSH 4.0 (gen) compatibility: OpenSSH 3.9-6.6, Dropbear SSH 0.53+ (some functionality from 0.52) @@ -25,6 +25,7 @@ (cve) CVE-2006-4924 -- (CVSSv2: 7.8) cause DoS via crafted packet (CPU consumption) (cve) CVE-2006-0225 -- (CVSSv2: 4.6) execute arbitrary code (cve) CVE-2005-2798 -- (CVSSv2: 5.0) leak data about authentication credentials +(sec) SSH v1 enabled -- SSH v1 can be exploited to recover plaintext passwords # key exchange algorithms (kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus diff --git a/test/test_errors.py b/test/test_errors.py index 0e06d05..90cfd1c 100644 --- a/test/test_errors.py +++ b/test/test_errors.py @@ -167,6 +167,6 @@ class TestErrors: conf = self._conf() conf.ssh1, conf.ssh2 = True, False lines = self._audit(output_spy, conf) - assert len(lines) == 3 + assert len(lines) == 4 assert 'error reading packet' in lines[-1] assert 'major versions differ' in lines[-1] diff --git a/test/test_ssh1.py b/test/test_ssh1.py index 1ccbb7c..918bf49 100644 --- a/test/test_ssh1.py +++ b/test/test_ssh1.py @@ -138,7 +138,7 @@ class TestSSH1: self.audit(out, self._conf()) out.write() lines = output_spy.flush() - assert len(lines) == 15 + assert len(lines) == 16 def test_ssh1_server_invalid_first_packet(self, output_spy, virtual_socket): vsocket = virtual_socket @@ -153,7 +153,7 @@ class TestSSH1: out.write() assert ret != 0 lines = output_spy.flush() - assert len(lines) == 9 + assert len(lines) == 10 assert 'unknown message' in lines[-1] def test_ssh1_server_invalid_checksum(self, output_spy, virtual_socket):