From 2cd96f1785c598983b1fa295adc0c6ae2fc96d6d Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Wed, 25 Sep 2024 17:05:17 -0400 Subject: [PATCH] Ensure ECDSA and DSS fingerprints are only output in verbose mode. Clean up Docker tests from merge of #286. --- README.md | 1 + src/ssh_audit/hostkeytest.py | 4 ++-- src/ssh_audit/ssh_audit.py | 12 +++++++++-- .../dropbear_2019.78_test1.json | 20 +++++++++++++++++++ .../expected_results/openssh_4.0p1_test1.json | 10 ++++++++++ .../expected_results/openssh_5.6p1_test1.json | 10 ++++++++++ .../expected_results/openssh_8.0p1_test1.json | 10 ++++++++++ 7 files changed, 63 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 52ba6b5..a8a7009 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,7 @@ For convenience, a web front-end on top of the command-line tool is available at - Fixed DHEat connection rate testing on MacOS X and BSD platforms; credit [Drew Noel](https://github.com/drewmnoel) and [Michael Osipov](https://github.com/michael-o). - Fixed invalid JSON output when a socket error occurs while performing a client audit. - When scanning multiple targets (using `-T`/`--targets`), the `-p`/`--port` option will now be used as the default port (set to 22 if `-p`/`--port` is not given). Hosts specified in the file can override this default with an explicit port number (i.e.: "host1:1234"). For example, when using `-T targets.txt -p 222`, all hosts in `targets.txt` that do not explicitly include a port number will default to 222; when using `-T targets.txt` (without `-p`), all hosts will use a default of 22. + - Now reports ECDSA and DSS fingerprints when in verbose mode; partial credit [Daniel Lenski](https://github.com/dlenskiSB). - Added 1 new cipher: `grasshopper-ctr128`. - Added 2 new key exchanges: `mlkem768x25519-sha256`, `sntrup761x25519-sha512`. diff --git a/src/ssh_audit/hostkeytest.py b/src/ssh_audit/hostkeytest.py index 22f5870..f9129bc 100644 --- a/src/ssh_audit/hostkeytest.py +++ b/src/ssh_audit/hostkeytest.py @@ -1,7 +1,7 @@ """ The MIT License (MIT) - Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com) + Copyright (C) 2017-2024 Joe Testa (jtesta@positronsecurity.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -202,7 +202,7 @@ class HostKeyTest: cakey_warn_str = HostKeyTest.SMALL_ECC_MODULUS_WARNING # Keys smaller than 2048 result in a failure. Keys smaller 3072 result in a warning. Update the database accordingly. - if (cert is False) and (hostkey_modulus_size < hostkey_min_good): + if (cert is False) and (hostkey_modulus_size < hostkey_min_good) and (host_key_type != 'ssh-dss'): # Skip ssh-dss, otherwise we get duplicate failure messages (SSH2_KexDB will always flag it). # If the key is under 2048, add to the failure list. if hostkey_modulus_size < hostkey_min_warn: diff --git a/src/ssh_audit/ssh_audit.py b/src/ssh_audit/ssh_audit.py index f163c5f..e60cce9 100755 --- a/src/ssh_audit/ssh_audit.py +++ b/src/ssh_audit/ssh_audit.py @@ -360,11 +360,19 @@ def output_fingerprints(out: OutputBuffer, algs: Algorithms, is_json_output: boo fp_types = sorted(fps.keys()) for fp_type in fp_types: fp = fps[fp_type] - out.good('(fin) {}: {}'.format(fp_type, fp.sha256)) + + # Don't output any ECDSA or DSS fingerprints unless verbose mode is enabled. + if fp_type.startswith("ecdsa-") or (fp_type == "ssh-dss"): + if out.verbose: + out.warn('(fin) {}: {} -- [info] this fingerprint type is insecure and should not be relied upon'.format(fp_type, fp.sha256)) + else: + continue # If verbose mode is not enabled, skip this type entirely. + else: + out.good('(fin) {}: {}'.format(fp_type, fp.sha256)) # Output the MD5 hash too if verbose mode is enabled. if out.verbose: - out.info('(fin) {}: {} -- [info] do not rely on MD5 fingerprints for server identification; it is insecure for this use case'.format(fp_type, fp.md5)) + out.warn('(fin) {}: {} -- [info] do not rely on MD5 fingerprints for server identification; it is insecure for this use case'.format(fp_type, fp.md5)) if not out.is_section_empty() and not is_json_output: out.head('# fingerprints') diff --git a/test/docker/expected_results/dropbear_2019.78_test1.json b/test/docker/expected_results/dropbear_2019.78_test1.json index 884ea8e..8204eb7 100644 --- a/test/docker/expected_results/dropbear_2019.78_test1.json +++ b/test/docker/expected_results/dropbear_2019.78_test1.json @@ -78,6 +78,26 @@ } ], "fingerprints": [ + { + "hash": "jdUfqoGCDOY1drQcoqIJm/pEix2r09hqwOs9E9GimZQ", + "hash_alg": "SHA256", + "hostkey": "ecdsa-sha2-nistp256" + }, + { + "hash": "98:27:f3:12:20:f6:23:6d:1a:00:2a:6c:71:7c:1e:6b", + "hash_alg": "MD5", + "hostkey": "ecdsa-sha2-nistp256" + }, + { + "hash": "NBzry0uMAX8BRsn4mv9CHpeivMOdwzGFEKrf6Hg7tIQ", + "hash_alg": "SHA256", + "hostkey": "ssh-dss" + }, + { + "hash": "16:60:9e:54:d7:1e:b3:0d:97:60:12:ad:fe:83:a2:40", + "hash_alg": "MD5", + "hostkey": "ssh-dss" + }, { "hash": "CDfAU12pjQS7/91kg7gYacza0U/6PDbE04Ic3IpYxkM", "hash_alg": "SHA256", diff --git a/test/docker/expected_results/openssh_4.0p1_test1.json b/test/docker/expected_results/openssh_4.0p1_test1.json index e344739..aaa7267 100644 --- a/test/docker/expected_results/openssh_4.0p1_test1.json +++ b/test/docker/expected_results/openssh_4.0p1_test1.json @@ -253,6 +253,16 @@ } ], "fingerprints": [ + { + "hash": "sqDDYhzYz7YIQeFDc0WF8SeXtrEz+iwsV7d/FdIgztM", + "hash_alg": "SHA256", + "hostkey": "ssh-dss" + }, + { + "hash": "5c:de:62:f0:60:c8:93:13:87:71:78:95:56:3f:61:51", + "hash_alg": "MD5", + "hostkey": "ssh-dss" + }, { "hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4", "hash_alg": "SHA256", diff --git a/test/docker/expected_results/openssh_5.6p1_test1.json b/test/docker/expected_results/openssh_5.6p1_test1.json index 82ab274..d0082da 100644 --- a/test/docker/expected_results/openssh_5.6p1_test1.json +++ b/test/docker/expected_results/openssh_5.6p1_test1.json @@ -240,6 +240,16 @@ } ], "fingerprints": [ + { + "hash": "sqDDYhzYz7YIQeFDc0WF8SeXtrEz+iwsV7d/FdIgztM", + "hash_alg": "SHA256", + "hostkey": "ssh-dss" + }, + { + "hash": "5c:de:62:f0:60:c8:93:13:87:71:78:95:56:3f:61:51", + "hash_alg": "MD5", + "hostkey": "ssh-dss" + }, { "hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4", "hash_alg": "SHA256", diff --git a/test/docker/expected_results/openssh_8.0p1_test1.json b/test/docker/expected_results/openssh_8.0p1_test1.json index 8f75e3c..2f950c1 100644 --- a/test/docker/expected_results/openssh_8.0p1_test1.json +++ b/test/docker/expected_results/openssh_8.0p1_test1.json @@ -87,6 +87,16 @@ } ], "fingerprints": [ + { + "hash": "Q6Llm0o4TrcUen4tnT2h4BDf2f+ina6dIJmVH8c40bg", + "hash_alg": "SHA256", + "hostkey": "ecdsa-sha2-nistp256" + }, + { + "hash": "cc:e0:80:84:5b:05:98:64:24:43:52:3b:17:c8:94:89", + "hash_alg": "MD5", + "hostkey": "ecdsa-sha2-nistp256" + }, { "hash": "UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU", "hash_alg": "SHA256",