1
0
mirror of https://github.com/jtesta/ssh-audit.git synced 2025-07-06 14:02:49 -05:00

97 Commits

Author SHA1 Message Date
f517e03d9f Bumped version to v3.0.0. 2023-09-07 07:45:07 -04:00
6c64257d91 Updated README. 2023-09-06 22:37:06 -04:00
982c0b4c72 Docker: Build multi-arch container images for amd64, arm64 and arm/v7 (#194)
* builds multi-arch container images for linux/{amd64,arm64,arm/v7}

* adds local-build build target for easier local testing
2023-09-06 22:32:18 -04:00
e26597a7aa Marked all NIST K-, B-, and T-curves as unproven since they are so rarely used. Added 12 new host keys: 'ecdsa-sha2-curve25519', 'ecdsa-sha2-nistb233', 'ecdsa-sha2-nistb409', 'ecdsa-sha2-nistk163', 'ecdsa-sha2-nistk233', 'ecdsa-sha2-nistk283', 'ecdsa-sha2-nistk409', 'ecdsa-sha2-nistp224', 'ecdsa-sha2-nistp192', 'ecdsa-sha2-nistt571', 'ssh-dsa', 'x509v3-sign-rsa-sha256'. Added 15 key exchanges: 'curve448-sha512@libssh.org', 'ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org', 'ecdh-nistp384-kyber-768r3-sha384-d00@openquantumsafe.org', 'ecdh-nistp521-kyber-1024r3-sha512-d00@openquantumsafe.org', 'ecdh-sha2-brainpoolp256r1@genua.de', 'ecdh-sha2-brainpoolp384r1@genua.de', 'ecdh-sha2-brainpoolp521r1@genua.de', 'kexAlgoDH14SHA1', 'kexAlgoDH1SHA1', 'kexAlgoECDH256', 'kexAlgoECDH384', 'kexAlgoECDH521', 'sm2kep-sha2-nistp256', 'x25519-kyber-512r3-sha256-d00@amazon.com', 'x25519-kyber512-sha512@aws.amazon.com'. Added 8 new ciphers: 'aes192-gcm@openssh.com', 'cast128-12-cbc', 'cast128-12-cfb', 'cast128-12-ecb', 'cast128-12-ofb', 'des-cfb', 'des-ecb', 'des-ofb'. Added 14 new MACs: 'cbcmac-3des', 'cbcmac-aes', 'cbcmac-blowfish', 'cbcmac-des', 'cbcmac-rijndael', 'cbcmac-twofish', 'hmac-sha256-96', 'md5', 'md5-8', 'ripemd160', 'ripemd160-8', 'sha1', 'sha1-8', 'umac-128'. 2023-09-05 20:10:37 -04:00
f8e29674a3 Refined JSON notes output. Fixed Docker & Tox tests. 2023-09-05 16:36:54 -04:00
d3dd5a9cac Improved JSON output (#185) 2023-09-05 16:16:23 -04:00
79ca4b2d8b Updated README. 2023-09-05 14:22:35 -04:00
884ef645f8 Prioritized certificate host key types for Ubuntu 22.04 client policy. (#193) 2023-09-05 14:01:51 -04:00
953683a762 Fixed most warnings from Shellcheck scans. (#197) 2023-09-05 13:14:21 -04:00
38f9c21760 The color of all notes will be printed in green when the related algorithm is rated good. 2023-09-03 19:14:25 -04:00
4e6169d0cb Added built-in policy for OpenSSH 9.4. 2023-09-03 18:12:16 -04:00
2867c65819 Perform full Docker image update when building. 2023-09-03 18:07:30 -04:00
77cdb969b9 Fixed flake8 tests. 2023-09-03 16:25:26 -04:00
199e75f6cd Refined GEX testing against OpenSSH servers: when the fallback mechanism is suspected of being triggered, perform an additional test to obtain more accurate results. 2023-09-03 16:13:00 -04:00
3f2fdbaa3d Fixed crash during GEX tests. 2023-07-11 11:08:42 -04:00
83e90729e2 Updated README. 2023-06-20 16:12:30 -04:00
83f9e48271 Recommendation output now respects level (#196) 2023-06-20 16:09:37 -04:00
e2fc60cbb4 Updated README and test for resolve function. 2023-06-20 09:26:43 -04:00
a74c3abdde Removed sys.exit from _resolve in ssh_socket.py (#187)
Changed (and documented) _resolve so the application does not quit when a hostname cannot be resolved.

Adapted connect function to expect incoming exceptions from _resolve

This fixes issue #186
2023-06-20 09:21:06 -04:00
e99cb0b579 Now prints the reason why socket listening operations fail. 2023-06-20 08:43:11 -04:00
639f11a5e5 Results from concurrent scans against multiple hosts are no longer improperly combined (#190). 2023-06-19 14:13:32 -04:00
521a50a796 Added 'curve448-sha512@libssh.org' kex. (#195) 2023-06-19 10:35:13 -04:00
2d5a97841f Bumped version to 3.0.0-dev. 2023-04-29 14:46:07 -04:00
54b8c7da02 Updated PyPI and Snap build processes. 2023-04-29 14:42:54 -04:00
3ba28b01e9 Added release date of v2.9.0. 2023-04-29 12:39:04 -04:00
3c1451cfdc Bumped version to v2.9.0. 2023-04-29 12:33:26 -04:00
929652c9b7 Simplified host key test logic. 2023-04-29 11:59:50 -04:00
e172932977 RSA key size comments duplicated for all RSA sig algs (#182)
* RSA key size comments duplicated for all RSA sig algs

* Save results on completion of testing a hostkey

* Revised list names because they operates against all keys now not just rsa.

* ensure all required fields added for non-rsa keys

* Correction to the saving of comments against non-rsa keys
2023-04-29 11:39:29 -04:00
c33e7d9b72 Added built-in policies for OpenSSH 8.8, 8.9, 9.0, 9.1, 9.2, and 9.3. 2023-04-27 21:40:47 -04:00
0074fcc1af Rolled back Windows multithreading crash fix, as upgrading from Python v3.9 to v3.11 may have fixed the root cause. (#152) 2023-04-26 21:55:40 -04:00
1eab4ab0e6 Updated README. 2023-04-26 15:49:45 -04:00
7f8d6b4d5b Fixed built-in policy formatting and filled in missing host key size information. 2023-04-26 15:47:58 -04:00
4c098b7d12 Windows build script now automatically installs/updates package dependencies. 2023-04-25 20:14:49 -04:00
0bfb5d6979 Updated snap base image. Now installing snapcraft tool from snap instead of apt. 2023-04-25 11:54:12 -04:00
a5f5e0dab2 Updated changelog. 2023-04-25 10:25:06 -04:00
05f159a152 Fixed Windows-specific crash when multiple threads are used (#152). 2023-04-25 10:18:45 -04:00
263267c5ad Added support for mixed host key/CA key types (i.e.: RSA host keys signed by ED25519 CAs) (#120). 2023-04-25 09:17:32 -04:00
4f31304b66 Alphabetized algorithm database. 2023-03-28 12:09:25 -04:00
6f05a2c6b5 Updated README. 2023-03-25 14:15:53 -04:00
784d412148 Added Repology table. 2023-03-24 19:22:45 -04:00
dc083de87e Added recommendations and CVE information to JSON output (#122). 2023-03-24 18:48:36 -04:00
7d5eb37a0f Updated colorama initialization. 2023-03-24 16:43:38 -04:00
5c1c447755 Updated testing descriptions. 2023-03-24 14:12:03 -04:00
cbb7d43006 Updated base image. Removed all suid & sgid bits from image. Drop root privileges by default. 2023-03-23 23:43:52 -04:00
cc9e4fbc4a Generic failure/warning messages replaced with more specific reasons. SHA-1 algorithms now cause failures. CBC mode ciphers are now warnings instead of failures. 2023-03-23 21:36:02 -04:00
992aa1b961 Added support for kex GSS wildcards (#143). 2023-03-21 22:17:23 -04:00
413dea60ae Fixed docker tests affected by previous commit. 2023-03-21 14:58:00 -04:00
e2a9896397 Deprecation of ssh-rsa signature algorithm in OpenSSH 8.8 (#171) 2023-03-21 14:52:23 -04:00
71feaa191e Add note regarding OpenSSH's 2048-bit GEX fallback, and suppress the related recommendation since the user cannot control it (partly related to #168). 2023-03-21 11:44:45 -04:00
c02ab8f170 Added --accept option to automatically update failed tests. 2023-03-21 11:28:52 -04:00
cdaee69642 Improved debugging output. 2023-03-21 10:48:58 -04:00
7bbf4cdff0 Fix tox tests. 2023-02-06 18:24:03 -05:00
e4d864c6c1 usage now respects no color (#162)
* usage now respects no color

* Removed superfluous parens after 'not'
2023-02-06 18:20:34 -05:00
1663e5bdcf Fixed setuptools config file. 2023-02-06 16:57:24 -05:00
5ecad8fac9 Bumped copyright year. 2023-02-06 16:49:25 -05:00
38ff225ed8 Updated supported Python versions. 2023-02-06 16:48:53 -05:00
c9dc9a9c10 Now issues a warning when 2048-bit moduli are encountered. 2023-02-06 16:27:30 -05:00
f9e00b6f2d Renamed WARN_CURVES_WEAK to FAIL_CURVES_WEAK. 2023-02-03 17:22:10 -05:00
433c7e779d Added 2 new ciphers: 'rijndael-cbc@ssh.com', 'cast128-12-cbc@ssh.com'. Added 21 new host key types: . 2023-02-02 18:57:53 -05:00
984ea1eee3 Added the following 9 new host key types: 'dsa2048-sha224@libassh.org', 'dsa2048-sha256@libassh.org', 'dsa3072-sha256@libassh.org', 'ecdsa-sha2-1.3.132.0.10-cert-v01@openssh.com', 'eddsa-e382-shake256@libassh.org', 'eddsa-e521-shake256@libassh.org', 'null', 'pgp-sign-dss', 'pgp-sign-rsa'. Added the following 22 new key exchange algorithms: 'diffie-hellman-group-exchange-sha224@ssh.com', 'diffie-hellman-group-exchange-sha384@ssh.com', 'diffie-hellman-group14-sha224@ssh.com', 'diffie-hellman_group17-sha512', 'ecmqv-sha2', 'gss-13.3.132.0.10-sha256-*', 'gss-curve25519-sha256-*', 'gss-curve448-sha512-*', 'gss-gex-sha1-*', 'gss-gex-sha256-*', 'gss-group1-sha1-*', 'gss-group14-sha1-*', 'gss-group14-sha256-*', 'gss-group15-sha512-*', 'gss-group16-sha512-*', 'gss-group17-sha512-*', 'gss-group18-sha512-*', 'gss-nistp256-sha256-*', 'gss-nistp384-sha256-*', 'gss-nistp521-sha512-*', 'm383-sha384@libassh.org', 'm511-sha512@libassh.org'. Added the following 26 new ciphers: '3des-cfb', '3des-ecb', '3des-ofb', 'blowfish-cfb', 'blowfish-ecb', 'blowfish-ofb', 'camellia128-cbc@openssh.org', 'camellia128-ctr@openssh.org', 'camellia192-cbc@openssh.org', 'camellia192-ctr@openssh.org', 'camellia256-cbc@openssh.org', 'camellia256-ctr@openssh.org', 'cast128-cfb', 'cast128-ecb', 'cast128-ofb', 'idea-cfb', 'idea-ecb', 'idea-ofb', 'seed-ctr@ssh.com', 'serpent128-gcm@libassh.org', 'serpent256-gcm@libassh.org', 'twofish-cfb', 'twofish-ecb', 'twofish-ofb', 'twofish128-gcm@libassh.org', 'twofish256-gcm@libassh.org'. Added the following 4 new HMAC algorithms: 'hmac-sha224@ssh.com', 'hmac-sha256-2@ssh.com', 'hmac-sha384@ssh.com', 'hmac-whirlpool'. 2023-02-02 18:30:40 -05:00
0b905a7fdd Added Ubuntu Client 22.04 hardening policy. 2023-02-01 19:29:54 -05:00
6e9283e643 Removed unused CI configs. 2023-02-01 18:00:41 -05:00
32ff04c2cc Added Tox testing for Python 3.11. Fixed flake8 & pylint errors. 2023-02-01 17:56:54 -05:00
e50ac5c84d Gex test usage text (#158)
* Reformatted Usage Text for --gex-test in README.md

* Reformatted Usage Text for --gex-test in ssh_audit.py

Reformatted to adhere to a max line length of 80 characters.
2022-10-27 10:11:05 -04:00
29496b43d5 updated vulnerability database (#157)
* updated vulnerability database

* added info for CVE-2021-36367
2022-10-27 10:10:17 -04:00
3300c60aaa Added 'ssh-xmss@openssh.com' and 'ssh-xmss-cert-v01@openssh.com' experimental host keys (#146). 2022-10-14 23:21:09 -04:00
78a9475a32 Added hmac-sha1-96@openssh.com MAC. (#148) 2022-10-14 22:56:02 -04:00
8d861dcdc6 Removed pytest version pin from Tox. 2022-10-10 21:28:51 -04:00
c50cc040c2 Upgrade all Tox dependencies before running Tox. 2022-10-10 21:06:03 -04:00
93f0692444 Enabled Python 3.10 tests in Tox. 2022-10-10 21:00:05 -04:00
6e9945337e Removed CI tests for Python 3.6. 2022-10-10 20:52:46 -04:00
d429b543d0 Added support for host key 'webauthn-sk-ecdsa-sha2-nistp256@openssh.com' (#149). 2022-10-10 20:51:37 -04:00
b9520cbc25 Fixed pylint & flake8 warnings and errors. 2022-10-10 20:40:29 -04:00
0b8ecf2fb5 Added Ubuntu Server 22.04 LTS hardening policy. 2022-10-10 20:34:28 -04:00
eb4ae65b0a Usage now includes '-g' and '--gex-test' parameters 2022-04-10 12:37:48 -04:00
113d1de443 Removed experimental warning tag from sntrup761x25519-sha512@openssh.com. 2022-04-10 12:16:25 -04:00
4d89f9b30b Updated example. 2022-03-24 10:53:47 -04:00
11905ed44a Fixed pylint errors, consolidated error checking for granular GEX tests, renamed functions for better readability. 2022-03-24 10:53:47 -04:00
19f192d21f Corrected accidental text update and a minor typo. 2022-03-24 10:53:47 -04:00
5ac0ffa8f1 DH GEX Modulus Size Testing 2022-03-24 10:53:47 -04:00
0a6ac5de54 Updated CVE vulnerability flag. 2022-02-21 21:51:35 -05:00
c6b8dc97e1 Fixed tests. 2022-02-21 21:48:10 -05:00
1bdf7029b4 add a bunch of openssh CVEs (#126) 2022-02-21 21:41:44 -05:00
5fbcb1b90f Added 24 new key exchanges: 'ecdh-sha2-1.3.132.0.1', 'ecdh-sha2-1.2.840.10045.3.1.1', 'ecdh-sha2-1.3.132.0.33', 'ecdh-sha2-1.3.132.0.26', 'ecdh-sha2-1.3.132.0.27', 'ecdh-sha2-1.2.840.10045.3.1.7', 'ecdh-sha2-1.3.132.0.16', 'ecdh-sha2-1.3.132.0.34', 'ecdh-sha2-1.3.132.0.36', 'ecdh-sha2-1.3.132.0.37', 'ecdh-sha2-1.3.132.0.35', 'ecdh-sha2-1.3.132.0.38', 'ecdh-sha2-4MHB+NBt3AlaSRQ7MnB4cg==', 'ecdh-sha2-5pPrSUQtIaTjUSt5VZNBjg==', 'ecdh-sha2-VqBg4QRPjxx1EXZdV0GdWQ==', 'ecdh-sha2-zD/b3hu/71952ArpUG4OjQ==', 'ecdh-sha2-qCbG5Cn/jjsZ7nBeR7EnOA==', 'ecdh-sha2-9UzNcgwTlEnSCECZa7V1mw==', 'ecdh-sha2-wiRIU8TKjMZ418sMqlqtvQ==', 'ecdh-sha2-qcFQaMAMGhTziMT0z+Tuzw==', 'ecdh-sha2-m/FtSAmrV4j/Wy6RVUaK7A==', 'ecdh-sha2-D3FefCjYoJ/kfXgAyLddYA==', 'ecdh-sha2-h/SsxnLCtRBh7I9ATyeB3A==', 'ecdh-sha2-mNVwCXAoS1HGmHpLvBC94w=='. 2021-10-20 22:25:20 -04:00
b04acc3737 Updated README. 2021-10-15 00:19:04 -04:00
4ace52a190 Now prints a more user-friendly error message when installed as a Snap package and permission errors are encountered. Updated the Snap build process as well. 2021-10-14 23:56:03 -04:00
22a9559a82 Now supports Python 3.10. 2021-10-14 00:01:23 -04:00
57e6c0246d Updated pylint disable list. 2021-10-13 23:55:49 -04:00
80a718a5af Fixed broken Python 3.10 config. 2021-10-13 23:46:50 -04:00
1f0b3acff2 Complete "target" in the JSON output with the port (#123)
* Complete "target" in JSON output with the port

The JSON output was not showing the port of the target which was scanned. This could be problematic when scanning a host with more than one ssh service running.

* Docker tests completet with the port of the scan target in the JSON output
2021-10-13 23:44:55 -04:00
cdc379d6df Added Python 3.10 to Github Actions testing. 2021-10-07 11:06:32 -04:00
9f87acfc74 Bumped version to v2.6.0-dev. 2021-08-27 11:25:27 -04:00
597b500eba Minor cleanups (#116)
* docker_test.sh: fix shellcheck warnings

* docker_test.sh: unify style

No changes in functionality.

* docker_test.sh: whitespace fixes

* stop mixing tabs and spaces
* remove trailing whitespace

* invoke bash using /usr/bin/env

* build_windows_executable.sh: fix variable assignment

* update_windows_man_page.sh: unify style

No changes in functionality.

* whitespace fixes

* stop mixing tabs and spaces
* remove trailing whitespace

* fix spelling

* remove trailing whitespace
2021-08-27 11:19:18 -04:00
96efb3efb4 Bumped copyright year. 2021-08-26 16:44:06 -04:00
ce5939856c Removed Homebrew from list of pre-built packages. 2021-08-26 16:36:31 -04:00
7f74731351 Bumped version number. 2021-08-26 16:36:06 -04:00
8c4855ffa2 Updated Snap notes. 2021-08-26 16:35:53 -04:00
89 changed files with 7888 additions and 1558 deletions

View File

@ -1,33 +0,0 @@
version: 'v2.2.1-dev.{build}'
build: off
branches:
only:
- master
- develop
environment:
matrix:
- PYTHON: "C:\\Python35"
- PYTHON: "C:\\Python35-x64"
- PYTHON: "C:\\Python36"
- PYTHON: "C:\\Python36-x64"
- PYTHON: "C:\\Python37"
- PYTHON: "C:\\Python37-x64"
- PYTHON: "C:\\Python38"
- PYTHON: "C:\\Python38-x64"
matrix:
fast_finish: true
cache:
- '%LOCALAPPDATA%\pip\Cache'
- .downloads -> .appveyor.yml
install:
- "cmd /c .\\test\\tools\\ci-win.cmd install"
test_script:
- "cmd /c .\\test\\tools\\ci-win.cmd test"
on_failure:
- ps: get-content .tox\*\log\*

View File

@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
python-version: [3.6, 3.7, 3.8, 3.9] python-version: [3.7, 3.8, 3.9, "3.10", 3.11]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -18,7 +18,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install codecov coveralls flake8 mypy pylint tox vulture pip install -U codecov coveralls flake8 mypy pylint pytest tox vulture
- name: Run Tox - name: Run Tox
run: | run: |
tox tox

View File

@ -1,25 +0,0 @@
language: python
arch:
- arm64
- amd64
- ppc64le
python:
- "3.6"
- "3.7"
- "3.8"
- "3.9"
- "3.10"
cache:
- pip
install:
- pip install -U pip tox tox-travis coveralls codecov
script:
- tox
after_success:
- codecov

View File

@ -1,6 +1,6 @@
# Contributing to ssh-audit # Contributing to ssh-audit
We are very much open to receiving patches from the community! To encourage participation, passing Travis tests, unit tests, etc., *is OPTIONAL*. As long as the patch works properly, it can be merged. We are very much open to receiving patches from the community! To encourage participation, passing CI tests, unit tests, etc., *is OPTIONAL*. As long as the patch works properly, it can be merged.
However, if you can submit patches that pass all of our automated tests, then you'll lighten the load for the project maintainer (who already has enough to do!). This document describes what tests are done and what documentation is maintained. However, if you can submit patches that pass all of our automated tests, then you'll lighten the load for the project maintainer (who already has enough to do!). This document describes what tests are done and what documentation is maintained.
@ -9,16 +9,16 @@ However, if you can submit patches that pass all of our automated tests, then yo
## Tox Tests ## Tox Tests
Tox is used to do unit testing, linting with [pylint](http://pylint.pycqa.org/en/latest/) & [flake8](https://flake8.pycqa.org/en/latest/), and static type-checking with [mypy](https://mypy.readthedocs.io/en/stable/). [Tox](https://tox.wiki/) is used to automate testing. Linting is done with [pylint](http://pylint.pycqa.org/en/latest/) & [flake8](https://flake8.pycqa.org/en/latest/), and static type-checking is done with [mypy](https://mypy.readthedocs.io/en/stable/).
For Ubuntu 18.04 or later, install tox with `apt install tox`, then simply run `tox` in the top-level directory. Look for any error messages in the (verbose) output. For Ubuntu systems, install tox with `apt install tox`, then simply run `tox` in the top-level directory. Look for any error messages in the (verbose) output.
## Docker Tests ## Docker Tests
Docker is used to run ssh-audit against various real SSH servers (OpenSSH, Dropbear, and TinySSH). The output is then diff'ed against the expected result. Any differences result in failure. Docker is used to run ssh-audit against various real SSH servers (OpenSSH, Dropbear, and TinySSH). The output is then diff'ed against the expected result. Any differences result in failure.
The docker tests are run with `./docker_test.sh`. The first time it is run, it will download and compile the SSH servers; this may take awhile. Subsequent runs, however, will take only a minute to complete, as the docker image will already be up-to-date. The docker tests are run with `./docker_test.sh`.
## Man Page ## Man Page

View File

@ -1,10 +1,21 @@
FROM python:3.9-slim FROM python:3-slim
WORKDIR / WORKDIR /
# Update the image to remediate any vulnerabilities.
RUN apt clean && apt update && apt -y dist-upgrade && apt clean
# Remove suid & sgid bits from all files.
RUN find / -xdev -perm /6000 -exec chmod ug-s {} \; 2> /dev/null || true
# Copy the ssh-audit code.
COPY ssh-audit.py . COPY ssh-audit.py .
COPY src/ . COPY src/ .
ENTRYPOINT ["python3", "/ssh-audit.py"] # Allow listening on 2222/tcp for client auditing.
EXPOSE 2222 EXPOSE 2222
# Drop root privileges.
USER nobody:nogroup
ENTRYPOINT ["python3", "/ssh-audit.py"]

View File

@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (C) 2017-2020 Joe Testa (jtesta@positronsecurity.com) Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu) Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)

View File

@ -4,10 +4,20 @@ ifeq ($(VERSION),)
endif endif
all: all:
docker buildx build \
--platform linux/amd64,linux/arm64,linux/arm/v7 \
--tag positronsecurity/ssh-audit:${VERSION} \
--tag positronsecurity/ssh-audit:latest \
.
local-build:
docker build -t positronsecurity/ssh-audit:${VERSION} . docker build -t positronsecurity/ssh-audit:${VERSION} .
docker tag positronsecurity/ssh-audit:${VERSION} positronsecurity/ssh-audit:latest
upload: upload:
docker login docker login
docker push positronsecurity/ssh-audit:${VERSION} docker buildx build \
docker push positronsecurity/ssh-audit:latest --platform linux/amd64,linux/arm64,linux/arm/v7 \
--tag positronsecurity/ssh-audit:${VERSION} \
--tag positronsecurity/ssh-audit:latest \
--push \
.

View File

@ -3,10 +3,10 @@ all:
virtualenv -p /usr/bin/python3 /tmp/pypi_upload/ virtualenv -p /usr/bin/python3 /tmp/pypi_upload/
cp -R src /tmp/pypi_upload/ cp -R src /tmp/pypi_upload/
cp setup.py setup.cfg README.md LICENSE /tmp/pypi_upload/ cp setup.py setup.cfg README.md LICENSE /tmp/pypi_upload/
/bin/bash -c "pushd /tmp/pypi_upload/; source bin/activate; pip3 install setuptools twine; python3 setup.py sdist bdist_wheel" /bin/bash -c "pushd /tmp/pypi_upload/; source bin/activate; pip3 install -U setuptools twine build; pip3 install -U requests_toolbelt; python3 -m build"
uploadtest: uploadtest:
/bin/bash -c "pushd /tmp/pypi_upload; source bin/activate; twine upload --repository-url https://test.pypi.org/legacy/ /tmp/pypi_upload/dist/*" /bin/bash -c "pushd /tmp/pypi_upload; source bin/activate; python3 -m twine upload --repository testpypi /tmp/pypi_upload/dist/*"
uploadprod: uploadprod:
/bin/bash -c "pushd /tmp/pypi_upload; source bin/activate; twine upload /tmp/pypi_upload/dist/*" /bin/bash -c "pushd /tmp/pypi_upload; source bin/activate; twine upload /tmp/pypi_upload/dist/*"

View File

@ -1,6 +0,0 @@
all:
echo -e "\n\nDid you remember to bump the version number in snapcraft.yaml?\n\n"
snapcraft --use-lxd
clean:
rm -rf parts/ prime/ snap/ stage/ build/ dist/ src/*.egg-info/ ssh-audit*.snap

View File

@ -2,17 +2,11 @@
An executable can only be made on a Windows host because the PyInstaller tool (https://www.pyinstaller.org/) does not support cross-compilation. An executable can only be made on a Windows host because the PyInstaller tool (https://www.pyinstaller.org/) does not support cross-compilation.
1.) Install Python v3.9.x from https://www.python.org/. To make life easier, check the option to add Python to the PATH environment variable. 1.) Install Python v3.11.x from https://www.python.org/. To make life easier, check the option to add Python to the PATH environment variable.
2.) Using pip, install pyinstaller and colorama: 2.) Install Cygwin (https://www.cygwin.com/).
``` 3.) Install/update package dependencies and create the executable with:
pip install pyinstaller colorama
```
3.) Install Cygwin (https://www.cygwin.com/).
4.) Create the executable with:
``` ```
$ ./build_windows_executable.sh $ ./build_windows_executable.sh
@ -24,7 +18,7 @@ An executable can only be made on a Windows host because the PyInstaller tool (h
To create package and upload to test server: To create package and upload to test server:
``` ```
$ sudo apt install python3-virtualenv $ sudo apt install python3-virtualenv python3.8-venv
$ make -f Makefile.pypi $ make -f Makefile.pypi
$ make -f Makefile.pypi uploadtest $ make -f Makefile.pypi uploadtest
``` ```
@ -51,33 +45,22 @@ To download from production server and verify:
$ pip3 install ssh-audit $ pip3 install ssh-audit
``` ```
# Snap # Snap
To create the snap package, run a fully-updated Ubuntu Server 20.04 VM. To create the snap package, run a fully-updated Ubuntu Server 22.04 VM.
Install pre-requisites with:
Create the snap package with:
``` ```
$ sudo apt install make snapcraft $ ./build_snap.sh
$ sudo snap install review-tools lxd
```
Initialize LXD (leave all options default):
```
$ sudo lxd init
```
Bump the version number in snapcraft.yaml. Then run:
```
$ make -f Makefile.snap
``` ```
Upload the snap with: Upload the snap with:
``` ```
$ snapcraft login $ snapcraft export-login ~/snap_creds.txt
$ export SNAPCRAFT_STORE_CREDENTIALS=$(cat ~/snap_creds.txt)
$ snapcraft upload --release=beta ssh-audit_*.snap
$ snapcraft upload --release=stable ssh-audit_*.snap $ snapcraft upload --release=stable ssh-audit_*.snap
``` ```

View File

@ -32,7 +32,7 @@
- historical information from OpenSSH, Dropbear SSH and libssh; - historical information from OpenSSH, Dropbear SSH and libssh;
- policy scans to ensure adherence to a hardened/standard configuration; - policy scans to ensure adherence to a hardened/standard configuration;
- runs on Linux and Windows; - runs on Linux and Windows;
- supports Python 3.6 - 3.9; - supports Python 3.7 - 3.11;
- no dependencies - no dependencies
## Usage ## Usage
@ -49,6 +49,9 @@ usage: ssh-audit.py [options] <host>
software config (use -p to change port; software config (use -p to change port;
use -t to change timeout) use -t to change timeout)
-d, --debug Enable debug output. -d, --debug Enable debug output.
-g, --gex-test=<x[,y,...]> dh gex modulus size test
<min1:pref1:max1[,min2:pref2:max2,...]>
<x-y[:step]>
-j, --json JSON output (use -jj to enable indents) -j, --json JSON output (use -jj to enable indents)
-l, --level=<level> minimum output level (info|warn|fail) -l, --level=<level> minimum output level (info|warn|fail)
-L, --list-policies list all the official, built-in policies -L, --list-policies list all the official, built-in policies
@ -148,7 +151,7 @@ Below is a screen shot of the client-auditing output when an unhardened OpenSSH
Guides to harden server & client configuration can be found here: [https://www.ssh-audit.com/hardening_guides.html](https://www.ssh-audit.com/hardening_guides.html) Guides to harden server & client configuration can be found here: [https://www.ssh-audit.com/hardening_guides.html](https://www.ssh-audit.com/hardening_guides.html)
## Pre-Built Packages ## Pre-Built Packages
Pre-built packages are available for Windows (see the releases page), on PyPI, Snap, and Homebrew. Pre-built packages are available for Windows (see the releases page), PyPI, Snap, and Docker:
To install from PyPI: To install from PyPI:
``` ```
@ -160,21 +163,59 @@ To install the Snap package:
$ snap install ssh-audit $ snap install ssh-audit
``` ```
To install on Homebrew:
```
$ brew install ssh-audit
```
To install from Dockerhub: To install from Dockerhub:
``` ```
$ docker pull positronsecurity/ssh-audit $ docker pull positronsecurity/ssh-audit
``` ```
(Then run with: `docker run -it -p 2222:2222 positronsecurity/ssh-audit 10.1.1.1`) (Then run with: `docker run -it -p 2222:2222 positronsecurity/ssh-audit 10.1.1.1`)
The status of various other platform packages can be found below (via Repology):
<a href="https://repology.org/project/ssh-audit/versions"><img src="https://repology.org/badge/vertical-allrepos/ssh-audit.svg?columns=4" alt="Packaging status" align="center"></a>
## Web Front-End ## Web Front-End
For convenience, a web front-end on top of the command-line tool is available at [https://www.ssh-audit.com/](https://www.ssh-audit.com/). For convenience, a web front-end on top of the command-line tool is available at [https://www.ssh-audit.com/](https://www.ssh-audit.com/).
## ChangeLog ## ChangeLog
### v3.0.0 (2023-09-07)
- Results from concurrent scans against multiple hosts are no longer improperly combined; bug discovered by [Adam Russell](https://github.com/thecliguy).
- Hostname resolution failure no longer causes scans against multiple hosts to terminate unexpectedly; credit [Dani Cuesta](https://github.com/daniel-cues).
- Algorithm recommendations resulting from warnings are now printed in yellow instead of red; credit [Adam Russell](https://github.com/thecliguy).
- Added failure, warning, and info notes to JSON output (note that this results in a breaking change to the banner protocol, "enc", and "mac" fields); credit [Bareq Al-Azzawi](https://github.com/BareqAZ).
- Docker Makefile now creates multi-arch builds for amd64, arm64, and armv7; credit [Sebastian Cohnen](https://github.com/tisba).
- Fixed crash during GEX tests.
- Refined GEX testing against OpenSSH servers: when the fallback mechanism is suspected of being triggered, perform an additional test to obtain more accurate results.
- The color of all notes will be printed in green when the related algorithm is rated good.
- Prioritized host key certificate algorithms for Ubuntu 22.04 LTS client policy.
- Marked all NIST K-, B-, and T-curves as unproven since they are so rarely used.
- Added built-in policy for OpenSSH 9.4.
- Added 12 new host keys: `ecdsa-sha2-curve25519`, `ecdsa-sha2-nistb233`, `ecdsa-sha2-nistb409`, `ecdsa-sha2-nistk163`, `ecdsa-sha2-nistk233`, `ecdsa-sha2-nistk283`, `ecdsa-sha2-nistk409`, `ecdsa-sha2-nistp224`, `ecdsa-sha2-nistp192`, `ecdsa-sha2-nistt571`, `ssh-dsa`, `x509v3-sign-rsa-sha256`.
- Added 15 new key exchanges: `curve448-sha512@libssh.org`, `ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org`, `ecdh-nistp384-kyber-768r3-sha384-d00@openquantumsafe.org`, `ecdh-nistp521-kyber-1024r3-sha512-d00@openquantumsafe.org`, `ecdh-sha2-brainpoolp256r1@genua.de`, `ecdh-sha2-brainpoolp384r1@genua.de`, `ecdh-sha2-brainpoolp521r1@genua.de`, `kexAlgoDH14SHA1`, `kexAlgoDH1SHA1`, `kexAlgoECDH256`, `kexAlgoECDH384`, `kexAlgoECDH521`, `sm2kep-sha2-nistp256`, `x25519-kyber-512r3-sha256-d00@amazon.com`, `x25519-kyber512-sha512@aws.amazon.com`.
- Added 8 new ciphers: `aes192-gcm@openssh.com`, `cast128-12-cbc`, `cast128-12-cfb`, `cast128-12-ecb`, `cast128-12-ofb`, `des-cfb`, `des-ecb`, `des-ofb`.
- Added 14 new MACs: `cbcmac-3des`, `cbcmac-aes`, `cbcmac-blowfish`, `cbcmac-des`, `cbcmac-rijndael`, `cbcmac-twofish`, `hmac-sha256-96`, `md5`, `md5-8`, `ripemd160`, `ripemd160-8`, `sha1`, `sha1-8`, `umac-128`.
### v2.9.0 (2023-04-29)
- Dropped support for Python 3.6, as it reached EOL at the end of 2021.
- Added Ubuntu Server & Client 22.04 hardening policies.
- Removed experimental warning tag from `sntrup761x25519-sha512@openssh.com`.
- Updated CVE database; credit [Alexandre Zanni](https://github.com/noraj).
- Added `-g` and `--gex-test` for granular GEX modulus size tests; credit [Adam Russell](https://github.com/thecliguy).
- Snap packages now print more user-friendly error messages when permission errors are encountered.
- JSON 'target' field now always includes port number; credit [tomatohater1337](https://github.com/tomatohater1337).
- JSON output now includes recommendations and CVE data.
- Mixed host key/CA key types (i.e.: RSA host keys signed with ED25519 CAs, etc.) are now properly handled.
- Warnings are now printed for 2048-bit moduli; partial credit [Adam Russell](https://github.com/thecliguy).
- SHA-1 algorithms now cause failures.
- CBC mode ciphers are now warnings instead of failures.
- Generic failure/warning messages replaced with more specific reasons (i.e.: 'using weak cipher' => 'using broken RC4 cipher').
- Updated built-in policies to include missing host key size information.
- Added built-in policies for OpenSSH 8.8, 8.9, 9.0, 9.1, 9.2, and 9.3.
- Added 33 new host keys: `dsa2048-sha224@libassh.org`, `dsa2048-sha256@libassh.org`, `dsa3072-sha256@libassh.org`, `ecdsa-sha2-1.3.132.0.10-cert-v01@openssh.com`, `eddsa-e382-shake256@libassh.org`, `eddsa-e521-shake256@libassh.org`, `null`, `pgp-sign-dss`, `pgp-sign-rsa`, `spki-sign-dss`, `spki-sign-rsa`, `ssh-dss-sha224@ssh.com`, `ssh-dss-sha384@ssh.com`, `ssh-dss-sha512@ssh.com`, `ssh-ed448-cert-v01@openssh.com`, `ssh-rsa-sha224@ssh.com`, `ssh-rsa-sha2-256`, `ssh-rsa-sha2-512`, `ssh-rsa-sha384@ssh.com`, `ssh-rsa-sha512@ssh.com`, `ssh-xmss-cert-v01@openssh.com`, `ssh-xmss@openssh.com`, `webauthn-sk-ecdsa-sha2-nistp256@openssh.com`, `x509v3-ecdsa-sha2-1.3.132.0.10`, `x509v3-sign-dss-sha1`, `x509v3-sign-dss-sha224@ssh.com`, `x509v3-sign-dss-sha256@ssh.com`, `x509v3-sign-dss-sha384@ssh.com`, `x509v3-sign-dss-sha512@ssh.com`, `x509v3-sign-rsa-sha1`, `x509v3-sign-rsa-sha224@ssh.com`, `x509v3-sign-rsa-sha384@ssh.com`, `x509v3-sign-rsa-sha512@ssh.com`.
- Added 46 new key exchanges: `diffie-hellman-group14-sha224@ssh.com`, `diffie-hellman_group17-sha512`, `diffie-hellman-group-exchange-sha224@ssh.com`, `diffie-hellman-group-exchange-sha384@ssh.com`, `ecdh-sha2-1.2.840.10045.3.1.1`, `ecdh-sha2-1.2.840.10045.3.1.7`, `ecdh-sha2-1.3.132.0.1`, `ecdh-sha2-1.3.132.0.16`, `ecdh-sha2-1.3.132.0.26`, `ecdh-sha2-1.3.132.0.27`, `ecdh-sha2-1.3.132.0.33`, `ecdh-sha2-1.3.132.0.34`, `ecdh-sha2-1.3.132.0.35`, `ecdh-sha2-1.3.132.0.36`, `ecdh-sha2-1.3.132.0.37`, `ecdh-sha2-1.3.132.0.38`, `ecdh-sha2-4MHB+NBt3AlaSRQ7MnB4cg==`, `ecdh-sha2-5pPrSUQtIaTjUSt5VZNBjg==`, `ecdh-sha2-9UzNcgwTlEnSCECZa7V1mw==`, `ecdh-sha2-D3FefCjYoJ/kfXgAyLddYA==`, `ecdh-sha2-h/SsxnLCtRBh7I9ATyeB3A==`, `ecdh-sha2-m/FtSAmrV4j/Wy6RVUaK7A==`, `ecdh-sha2-mNVwCXAoS1HGmHpLvBC94w==`, `ecdh-sha2-qCbG5Cn/jjsZ7nBeR7EnOA==`, `ecdh-sha2-qcFQaMAMGhTziMT0z+Tuzw==`, `ecdh-sha2-VqBg4QRPjxx1EXZdV0GdWQ==`, `ecdh-sha2-wiRIU8TKjMZ418sMqlqtvQ==`, `ecdh-sha2-zD/b3hu/71952ArpUG4OjQ==`, `ecmqv-sha2`, `gss-13.3.132.0.10-sha256-*`, `gss-curve25519-sha256-*`, `gss-curve448-sha512-*`, `gss-gex-sha1-*`, `gss-gex-sha256-*`, `gss-group14-sha1-*`, `gss-group14-sha256-*`, `gss-group15-sha512-*`, `gss-group16-sha512-*`, `gss-group17-sha512-*`, `gss-group18-sha512-*`, `gss-group1-sha1-*`, `gss-nistp256-sha256-*`, `gss-nistp384-sha256-*`, `gss-nistp521-sha512-*`, `m383-sha384@libassh.org`, `m511-sha512@libassh.org`.
- Added 28 new ciphers: `3des-cfb`, `3des-ecb`, `3des-ofb`, `blowfish-cfb`, `blowfish-ecb`, `blowfish-ofb`, `camellia128-cbc@openssh.org`, `camellia128-ctr@openssh.org`, `camellia192-cbc@openssh.org`, `camellia192-ctr@openssh.org`, `camellia256-cbc@openssh.org`, `camellia256-ctr@openssh.org`, `cast128-cfb`, `cast128-ecb`, `cast128-ofb`, `cast128-12-cbc@ssh.com`, `idea-cfb`, `idea-ecb`, `idea-ofb`, `rijndael-cbc@ssh.com`, `seed-ctr@ssh.com`, `serpent128-gcm@libassh.org`, `serpent256-gcm@libassh.org`, `twofish128-gcm@libassh.org`, `twofish256-gcm@libassh.org`, `twofish-cfb`, `twofish-ecb`, `twofish-ofb`
- Added 5 new MACs: `hmac-sha1-96@openssh.com`, `hmac-sha224@ssh.com`, `hmac-sha256-2@ssh.com`, `hmac-sha384@ssh.com`, `hmac-whirlpool`.
### v2.5.0 (2021-08-26) ### v2.5.0 (2021-08-26)
- Fixed crash when running host key tests. - Fixed crash when running host key tests.
- Handles server connection failures more gracefully. - Handles server connection failures more gracefully.

73
build_snap.sh Executable file
View File

@ -0,0 +1,73 @@
#!/usr/bin/env bash
#
# The MIT License (MIT)
#
# Copyright (C) 2021 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
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
################################################################################
# build_snap.sh
#
# Builds a Snap package.
################################################################################
# Pre-requisites
sudo apt install -y make
sudo snap install snapcraft --classic
sudo snap install review-tools lxd
# Initialize LXD.
sudo lxd init --auto
# Reset the filesystem from any previous runs.
rm -rf parts/ prime/ snap/ stage/ build/ dist/ src/*.egg-info/ ssh-audit*.snap
git checkout snapcraft.yaml 2> /dev/null
git checkout src/ssh_audit/globals.py 2> /dev/null
# Get the version from the globals.py file.
version=$(grep VERSION src/ssh_audit/globals.py | awk 'BEGIN {FS="="} ; {print $2}' | tr -d '[:space:]')
# Strip the quotes around the version (along with the initial 'v' character) and append "-1" to make the default Snap version (i.e.: 'v2.5.0' => '2.5.0-1')
default_snap_version="${version:2:-1}-1"
echo -e -n "\nEnter Snap package version [default: ${default_snap_version}]: "
read -r snap_version
# If no version was specified, use the default version.
if [[ $snap_version == '' ]]; then
snap_version=$default_snap_version
echo -e "Using default snap version: ${snap_version}\n"
fi
# Ensure that the snap version fits the format of X.X.X-X.
if [[ ! $snap_version =~ ^[0-9]\.[0-9]\.[0-9]\-[0-9]$ ]]; then
echo "Error: version string does not match format X.X.X-X!"
exit 1
fi
# Append the version field to the end of the file. Not pretty, but it works.
echo -e "\nversion: '${snap_version}'" >> snapcraft.yaml
# Set the SNAP_PACKAGE variable to True so that file permission errors give more user-friendly
sed -i 's/SNAP_PACKAGE = False/SNAP_PACKAGE = True/' src/ssh_audit/globals.py
snapcraft --use-lxd && echo -e "\nDone.\n"

View File

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
# #
# The MIT License (MIT) # The MIT License (MIT)
@ -34,10 +34,10 @@
PLATFORM="$(uname -s)" PLATFORM="$(uname -s)"
# This script is intended for use on Cygwin only. # This script is intended for use on Cygwin only.
case "$PLATFORM" in case "${PLATFORM}" in
CYGWIN*) ;; CYGWIN*) ;;
*) *)
echo "Platform not supported ($PLATFORM). This must be run in Cygwin only." echo "Platform not supported (${PLATFORM}). This must be run in Cygwin only."
exit 1 exit 1
;; ;;
esac esac
@ -48,15 +48,10 @@ if [[ "$(python -V)" != "Python 3."* ]]; then
exit 1 exit 1
fi fi
# Ensure that pyinstaller is installed. # Install/update package dependencies.
command -v pyinstaller >/dev/null 2>&1 || { echo >&2 "pyinstaller not found. Install with: 'pip install pyinstaller'"; exit 1; } echo "Installing/updating pyinstaller and colorama packages..."
pip install -U pyinstaller colorama
# Ensure that the colorama module is installed. echo
X=`pip show colorama` 2> /dev/null
if [[ $? != 0 ]]; then
echo "Colorama module not found. Install with: 'pip install colorama'"
exit 1
fi
# Prompt for the version to release. # Prompt for the version to release.
echo -n "Enter the version to release, using format 'vX.X.X': " echo -n "Enter the version to release, using format 'vX.X.X': "
@ -83,13 +78,14 @@ git checkout src/ssh_audit/globals.py 2> /dev/null
# Update the man page. # Update the man page.
./update_windows_man_page.sh ./update_windows_man_page.sh
if [[ $? != 0 ]]; then retval=$?
if [[ ${retval} != 0 ]]; then
echo "Failed to run ./update_windows_man_page.sh" echo "Failed to run ./update_windows_man_page.sh"
exit 1 exit 1
fi fi
# Do all operations from this point from the main source directory. # Do all operations from this point from the main source directory.
pushd src/ssh_audit > /dev/null pushd src/ssh_audit || exit > /dev/null
# Delete the existing VERSION variable and add the value that the user entered, above. # Delete the existing VERSION variable and add the value that the user entered, above.
sed -i '/^VERSION/d' globals.py sed -i '/^VERSION/d' globals.py
@ -114,8 +110,9 @@ else
fi fi
# Ensure that the version string doesn't have '-dev' in it. # Ensure that the version string doesn't have '-dev' in it.
X=`dist/ssh-audit.exe | grep -E 'ssh-audit.exe v.+\-dev'` > /dev/null dist/ssh-audit.exe | grep -E 'ssh-audit.exe v.+\-dev' > /dev/null
if [[ $? == 0 ]]; then retval=$?
if [[ ${retval} == 0 ]]; then
echo -e "\nError: executable's version number includes '-dev'." echo -e "\nError: executable's version number includes '-dev'."
exit 1 exit 1
fi fi
@ -126,5 +123,5 @@ rm -rf build/ ssh-audit.spec ssh-audit.py
# Reset the changes we made to globals.py. # Reset the changes we made to globals.py.
git checkout globals.py 2> /dev/null git checkout globals.py 2> /dev/null
popd > /dev/null popd || exit > /dev/null
exit 0 exit 0

View File

@ -4,6 +4,11 @@
# This script will set up a docker image with multiple versions of OpenSSH, then # This script will set up a docker image with multiple versions of OpenSSH, then
# use it to run tests. # use it to run tests.
# #
# Optional arguments:
# --accept: accepts test failures and overwrites expected results with actual results (useful for updating the tests themselves).
# --create: attempts to create a new docker image.
#
#
# For debugging purposes, here is a cheat sheet for manually running the docker image: # For debugging purposes, here is a cheat sheet for manually running the docker image:
# #
# docker run -p 2222:22 -it ssh-audit-test:X /bin/bash # docker run -p 2222:22 -it ssh-audit-test:X /bin/bash
@ -23,51 +28,55 @@ IMAGE_NAME=positronsecurity/ssh-audit-test-framework
# Terminal colors. # Terminal colors.
CLR="\033[0m" CLR="\033[0m"
RED="\033[0;31m" #RED="\033[0;31m"
YELLOW="\033[0;33m" #YELLOW="\033[0;33m"
GREEN="\033[0;32m" GREEN="\033[0;32m"
REDB="\033[1;31m" # Red + bold REDB="\033[1;31m" # Red + bold
YELLOWB="\033[1;33m" # Yellow + bold
GREENB="\033[1;32m" # Green + bold GREENB="\033[1;32m" # Green + bold
# Program return values. # Program return values.
PROGRAM_RETVAL_FAILURE=3 PROGRAM_RETVAL_FAILURE=3
PROGRAM_RETVAL_WARNING=2 PROGRAM_RETVAL_WARNING=2
PROGRAM_RETVAL_CONNECTION_ERROR=1 #PROGRAM_RETVAL_CONNECTION_ERROR=1
PROGRAM_RETVAL_GOOD=0 PROGRAM_RETVAL_GOOD=0
# Counts the number of test failures. # Counts the number of test failures.
num_failures=0 num_failures=0
# When set, if a failure is encountered, overwrite the expected output with the actual value (i.e.: the user validated the failures already and wants to update the tests themselves).
accept=0
# Returns 0 if current docker image exists. # Returns 0 if current docker image exists.
function check_if_docker_image_exists { check_if_docker_image_exists() {
images=`docker image ls | egrep "$IMAGE_NAME[[:space:]]+$IMAGE_VERSION"` images=$(docker image ls | grep -E "$IMAGE_NAME[[:space:]]+$IMAGE_VERSION")
} }
# Uncompresses and compiles the specified version of Dropbear. # Uncompresses and compiles the specified version of Dropbear.
function compile_dropbear { compile_dropbear() {
version=$1 version=$1
compile 'Dropbear' $version compile "Dropbear" "$version"
} }
# Uncompresses and compiles the specified version of OpenSSH. # Uncompresses and compiles the specified version of OpenSSH.
function compile_openssh { compile_openssh() {
version=$1 version=$1
compile 'OpenSSH' $version compile "OpenSSH" "$version"
} }
# Uncompresses and compiles the specified version of TinySSH. # Uncompresses and compiles the specified version of TinySSH.
function compile_tinyssh { compile_tinyssh() {
version=$1 version=$1
compile 'TinySSH' $version compile "TinySSH" "$version"
} }
function compile { compile() {
project=$1 project=$1
version=$2 version=$2
@ -75,31 +84,31 @@ function compile {
uncompress_options= uncompress_options=
source_dir= source_dir=
server_executable= server_executable=
if [[ $project == 'OpenSSH' ]]; then if [[ $project == "OpenSSH" ]]; then
tarball="openssh-${version}.tar.gz" tarball="openssh-${version}.tar.gz"
uncompress_options="xzf" uncompress_options="xzf"
source_dir="openssh-${version}" source_dir="openssh-${version}"
server_executable=sshd server_executable=sshd
elif [[ $project == 'Dropbear' ]]; then elif [[ $project == "Dropbear" ]]; then
tarball="dropbear-${version}.tar.bz2" tarball="dropbear-${version}.tar.bz2"
uncompress_options="xjf" uncompress_options="xjf"
source_dir="dropbear-${version}" source_dir="dropbear-${version}"
server_executable=dropbear server_executable=dropbear
elif [[ $project == 'TinySSH' ]]; then elif [[ $project == "TinySSH" ]]; then
tarball="${version}.tar.gz" tarball="${version}.tar.gz"
uncompress_options="xzf" uncompress_options="xzf"
source_dir="tinyssh-${version}" source_dir="tinyssh-${version}"
server_executable='build/bin/tinysshd' server_executable="build/bin/tinysshd"
fi fi
echo "Uncompressing ${project} ${version}..." echo "Uncompressing ${project} ${version}..."
tar $uncompress_options $tarball tar $uncompress_options "$tarball"
echo "Compiling ${project} ${version}..." echo "Compiling ${project} ${version}..."
pushd $source_dir > /dev/null pushd "$source_dir" || exit > /dev/null
# TinySSH has no configure script... only a Makefile. # TinySSH has no configure script... only a Makefile.
if [[ $project == 'TinySSH' ]]; then if [[ $project == "TinySSH" ]]; then
make -j 10 make -j 10
else else
./configure && make -j 10 ./configure && make -j 10
@ -111,21 +120,21 @@ function compile {
fi fi
echo -e "\n${GREEN}Successfully built ${project} ${version}${CLR}\n" echo -e "\n${GREEN}Successfully built ${project} ${version}${CLR}\n"
popd > /dev/null popd || exit > /dev/null
} }
# Creates a new docker image. # Creates a new docker image.
function create_docker_image { create_docker_image() {
# Create a new temporary directory. # Create a new temporary directory.
TMP_DIR=`mktemp -d /tmp/sshaudit-docker-XXXXXXXXXX` TMP_DIR=$(mktemp -d /tmp/sshaudit-docker-XXXXXXXXXX)
# Copy the Dockerfile and all files in the test/docker/ dir to our new temp directory. # Copy the Dockerfile and all files in the test/docker/ dir to our new temp directory.
find test/docker/ -maxdepth 1 -type f | xargs cp -t $TMP_DIR find test/docker/ -maxdepth 1 -type f -exec cp -t "$TMP_DIR" "{}" +
# Make the temp directory our working directory for the duration of the build # Make the temp directory our working directory for the duration of the build
# process. # process.
pushd $TMP_DIR > /dev/null pushd "$TMP_DIR" || exit > /dev/null
# Get the release keys. # Get the release keys.
get_dropbear_release_key get_dropbear_release_key
@ -134,22 +143,22 @@ function create_docker_image {
# Aside from checking the GPG signatures, we also compare against this known-good # Aside from checking the GPG signatures, we also compare against this known-good
# SHA-256 hash just in case. # SHA-256 hash just in case.
get_openssh '4.0p1' '5adb9b2c2002650e15216bf94ed9db9541d9a17c96fcd876784861a8890bc92b' get_openssh "4.0p1" "5adb9b2c2002650e15216bf94ed9db9541d9a17c96fcd876784861a8890bc92b"
get_openssh '5.6p1' '538af53b2b8162c21a293bb004ae2bdb141abd250f61b4cea55244749f3c6c2b' get_openssh "5.6p1" "538af53b2b8162c21a293bb004ae2bdb141abd250f61b4cea55244749f3c6c2b"
get_openssh '8.0p1' 'bd943879e69498e8031eb6b7f44d08cdc37d59a7ab689aa0b437320c3481fd68' get_openssh "8.0p1" "bd943879e69498e8031eb6b7f44d08cdc37d59a7ab689aa0b437320c3481fd68"
get_dropbear '2019.78' '525965971272270995364a0eb01f35180d793182e63dd0b0c3eb0292291644a4' get_dropbear "2019.78" "525965971272270995364a0eb01f35180d793182e63dd0b0c3eb0292291644a4"
get_tinyssh '20190101' '554a9a94e53b370f0cd0c5fbbd322c34d1f695cbcea6a6a32dcb8c9f595b3fea' get_tinyssh "20190101" "554a9a94e53b370f0cd0c5fbbd322c34d1f695cbcea6a6a32dcb8c9f595b3fea"
# Compile the versions of OpenSSH. # Compile the versions of OpenSSH.
compile_openssh '4.0p1' compile_openssh "4.0p1"
compile_openssh '5.6p1' compile_openssh "5.6p1"
compile_openssh '8.0p1' compile_openssh "8.0p1"
# Compile the versions of Dropbear. # Compile the versions of Dropbear.
compile_dropbear '2019.78' compile_dropbear "2019.78"
# Compile the versions of TinySSH. # Compile the versions of TinySSH.
compile_tinyssh '20190101' compile_tinyssh "20190101"
# Rename the default config files so we know they are our originals. # Rename the default config files so we know they are our originals.
@ -166,7 +175,7 @@ function create_docker_image {
# #
# Test 1: Basic test. # Test 1: Basic test.
create_openssh_config '4.0p1' 'test1' "HostKey /etc/ssh/ssh1_host_key\nHostKey /etc/ssh/ssh_host_rsa_key_1024\nHostKey /etc/ssh/ssh_host_dsa_key" create_openssh_config "4.0p1" "test1" "HostKey /etc/ssh/ssh1_host_key\nHostKey /etc/ssh/ssh_host_rsa_key_1024\nHostKey /etc/ssh/ssh_host_dsa_key"
# #
@ -174,19 +183,19 @@ function create_docker_image {
# #
# Test 1: Basic test. # Test 1: Basic test.
create_openssh_config '5.6p1' 'test1' "HostKey /etc/ssh/ssh_host_rsa_key_1024\nHostKey /etc/ssh/ssh_host_dsa_key" create_openssh_config "5.6p1" "test1" "HostKey /etc/ssh/ssh_host_rsa_key_1024\nHostKey /etc/ssh/ssh_host_dsa_key"
# Test 2: RSA 1024 host key with RSA 1024 certificate. # Test 2: RSA 1024 host key with RSA 1024 certificate.
create_openssh_config '5.6p1' 'test2' "HostKey /etc/ssh/ssh_host_rsa_key_1024\nHostCertificate /etc/ssh/ssh_host_rsa_key_1024-cert_1024.pub" create_openssh_config "5.6p1" "test2" "HostKey /etc/ssh/ssh_host_rsa_key_1024\nHostCertificate /etc/ssh/ssh_host_rsa_key_1024-cert_1024.pub"
# Test 3: RSA 1024 host key with RSA 3072 certificate. # Test 3: RSA 1024 host key with RSA 3072 certificate.
create_openssh_config '5.6p1' 'test3' "HostKey /etc/ssh/ssh_host_rsa_key_1024\nHostCertificate /etc/ssh/ssh_host_rsa_key_1024-cert_3072.pub" create_openssh_config "5.6p1" "test3" "HostKey /etc/ssh/ssh_host_rsa_key_1024\nHostCertificate /etc/ssh/ssh_host_rsa_key_1024-cert_3072.pub"
# Test 4: RSA 3072 host key with RSA 1024 certificate. # Test 4: RSA 3072 host key with RSA 1024 certificate.
create_openssh_config '5.6p1' 'test4' "HostKey /etc/ssh/ssh_host_rsa_key_3072\nHostCertificate /etc/ssh/ssh_host_rsa_key_3072-cert_1024.pub" create_openssh_config "5.6p1" "test4" "HostKey /etc/ssh/ssh_host_rsa_key_3072\nHostCertificate /etc/ssh/ssh_host_rsa_key_3072-cert_1024.pub"
# Test 5: RSA 3072 host key with RSA 3072 certificate. # Test 5: RSA 3072 host key with RSA 3072 certificate.
create_openssh_config '5.6p1' 'test5' "HostKey /etc/ssh/ssh_host_rsa_key_3072\nHostCertificate /etc/ssh/ssh_host_rsa_key_3072-cert_3072.pub" create_openssh_config "5.6p1" "test5" "HostKey /etc/ssh/ssh_host_rsa_key_3072\nHostCertificate /etc/ssh/ssh_host_rsa_key_3072-cert_3072.pub"
# #
@ -194,64 +203,64 @@ function create_docker_image {
# #
# Test 1: Basic test. # Test 1: Basic test.
create_openssh_config '8.0p1' 'test1' "HostKey /etc/ssh/ssh_host_rsa_key_3072\nHostKey /etc/ssh/ssh_host_ecdsa_key\nHostKey /etc/ssh/ssh_host_ed25519_key" create_openssh_config "8.0p" "test1" "HostKey /etc/ssh/ssh_host_rsa_key_3072\nHostKey /etc/ssh/ssh_host_ecdsa_key\nHostKey /etc/ssh/ssh_host_ed25519_key"
# Test 2: ED25519 certificate test. # Test 2: ED25519 certificate test.
create_openssh_config '8.0p1' 'test2' "HostKey /etc/ssh/ssh_host_ed25519_key\nHostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub" create_openssh_config "8.0p1" "test2" "HostKey /etc/ssh/ssh_host_ed25519_key\nHostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub"
# Test 3: Hardened installation test. # Test 3: Hardened installation test.
create_openssh_config '8.0p1' 'test3' "HostKey /etc/ssh/ssh_host_ed25519_key\nKexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr\nMACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com" create_openssh_config "8.0p1" "test3" "HostKey /etc/ssh/ssh_host_ed25519_key\nKexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr\nMACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com"
# Now build the docker image! # Now build the docker image!
docker build --tag $IMAGE_NAME:$IMAGE_VERSION . docker build --tag "$IMAGE_NAME:$IMAGE_VERSION" .
popd > /dev/null popd || exit > /dev/null
rm -rf $TMP_DIR rm -rf -- "$TMP_DIR"
} }
# Creates an OpenSSH configuration file for a specific test. # Creates an OpenSSH configuration file for a specific test.
function create_openssh_config { create_openssh_config() {
openssh_version=$1 openssh_version=$1
test_number=$2 test_number=$2
config_text=$3 config_text=$3
cp sshd_config-${openssh_version}_orig sshd_config-${openssh_version}_${test_number} cp "sshd_config-${openssh_version}_orig" "sshd_config-${openssh_version}_${test_number}"
echo -e "${config_text}" >> sshd_config-${openssh_version}_${test_number} echo -e "${config_text}" >> "sshd_config-${openssh_version}_${test_number}"
} }
# Downloads the Dropbear release key and adds it to the local keyring. # Downloads the Dropbear release key and adds it to the local keyring.
function get_dropbear_release_key { get_dropbear_release_key() {
get_release_key 'Dropbear' 'https://matt.ucc.asn.au/dropbear/releases/dropbear-key-2015.asc' 'F29C6773' 'F734 7EF2 EE2E 07A2 6762 8CA9 4493 1494 F29C 6773' get_release_key "Dropbear" "https://matt.ucc.asn.au/dropbear/releases/dropbear-key-2015.asc" "F29C6773" "F734 7EF2 EE2E 07A2 6762 8CA9 4493 1494 F29C 6773"
} }
# Downloads the OpenSSH release key and adds it to the local keyring. # Downloads the OpenSSH release key and adds it to the local keyring.
function get_openssh_release_key { get_openssh_release_key() {
get_release_key 'OpenSSH' 'https://ftp.openbsd.org/pub/OpenBSD/OpenSSH/RELEASE_KEY.asc' '6D920D30' '59C2 118E D206 D927 E667 EBE3 D3E5 F56B 6D92 0D30' get_release_key "OpenSSH" "https://ftp.openbsd.org/pub/OpenBSD/OpenSSH/RELEASE_KEY.asc" "6D920D30" "59C2 118E D206 D927 E667 EBE3 D3E5 F56B 6D92 0D30"
} }
# Downloads the TinySSH release key and adds it to the local keyring. # Downloads the TinySSH release key and adds it to the local keyring.
function get_tinyssh_release_key { get_tinyssh_release_key() {
get_release_key 'TinySSH' '' '96939FF9' 'AADF 2EDF 5529 F170 2772 C8A2 DEC4 D246 931E F49B' get_release_key "TinySSH" "" "96939FF9" "AADF 2EDF 5529 F170 2772 C8A2 DEC4 D246 931E F49B"
} }
function get_release_key { get_release_key() {
project=$1 project=$1
key_url=$2 key_url=$2
key_id=$3 key_id=$3
release_key_fingerprint_expected=$4 release_key_fingerprint_expected=$4
# The TinySSH release key isn't on any website, apparently. # The TinySSH release key isn't on any website, apparently.
if [[ $project == 'TinySSH' ]]; then if [[ $project == "TinySSH" ]]; then
gpg --keyserver keys.gnupg.net --recv-key $key_id gpg --keyserver keys.gnupg.net --recv-key "$key_id"
else else
echo -e "\nGetting ${project} release key...\n" echo -e "\nGetting ${project} release key...\n"
wget -O key.asc $2 wget -O key.asc "$2"
echo -e "\nImporting ${project} release key...\n" echo -e "\nImporting ${project} release key...\n"
gpg --import key.asc gpg --import key.asc
@ -259,40 +268,41 @@ function get_release_key {
rm key.asc rm key.asc
fi fi
local release_key_fingerprint_actual=`gpg --fingerprint ${key_id}` local release_key_fingerprint_actual
release_key_fingerprint_actual=$(gpg --fingerprint "$key_id")
if [[ $release_key_fingerprint_actual != *"$release_key_fingerprint_expected"* ]]; then if [[ $release_key_fingerprint_actual != *"$release_key_fingerprint_expected"* ]]; then
echo -e "\n${REDB}Error: ${project} release key fingerprint does not match expected value!\n\tExpected: $release_key_fingerprint_expected\n\tActual: $release_key_fingerprint_actual\n\nTerminating.${CLR}" echo -e "\n${REDB}Error: ${project} release key fingerprint does not match expected value!\n\tExpected: $release_key_fingerprint_expected\n\tActual: $release_key_fingerprint_actual\n\nTerminating.${CLR}"
exit -1 exit 1
fi fi
echo -e "\n\n${GREEN}${project} release key matches expected value.${CLR}\n" echo -e "\n\n${GREEN}${project} release key matches expected value.${CLR}\n"
} }
# Downloads the specified version of Dropbear. # Downloads the specified version of Dropbear.
function get_dropbear { get_dropbear() {
version=$1 version=$1
tarball_checksum_expected=$2 tarball_checksum_expected=$2
get_source 'Dropbear' $version $tarball_checksum_expected get_source "Dropbear" "$version" "$tarball_checksum_expected"
} }
# Downloads the specified version of OpenSSH. # Downloads the specified version of OpenSSH.
function get_openssh { get_openssh() {
version=$1 version=$1
tarball_checksum_expected=$2 tarball_checksum_expected=$2
get_source 'OpenSSH' $version $tarball_checksum_expected get_source "OpenSSH" "$version" "$tarball_checksum_expected"
} }
# Downloads the specified version of TinySSH. # Downloads the specified version of TinySSH.
function get_tinyssh { get_tinyssh() {
version=$1 version=$1
tarball_checksum_expected=$2 tarball_checksum_expected=$2
get_source 'TinySSH' $version $tarball_checksum_expected get_source "TinySSH" "$version" "$tarball_checksum_expected"
} }
function get_source { get_source() {
project=$1 project=$1
version=$2 version=$2
tarball_checksum_expected=$3 tarball_checksum_expected=$3
@ -302,20 +312,20 @@ function get_source {
tarball= tarball=
sig= sig=
signer= signer=
if [[ $project == 'OpenSSH' ]]; then if [[ $project == "OpenSSH" ]]; then
base_url_source='https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/' base_url_source="https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/"
base_url_sig=$base_url_source base_url_sig=$base_url_source
tarball="openssh-${version}.tar.gz" tarball="openssh-${version}.tar.gz"
sig="${tarball}.asc" sig="${tarball}.asc"
signer="Damien Miller " signer="Damien Miller "
elif [[ $project == 'Dropbear' ]]; then elif [[ $project == "Dropbear" ]]; then
base_url_source='https://matt.ucc.asn.au/dropbear/releases/' base_url_source="https://matt.ucc.asn.au/dropbear/releases/"
base_url_sig=$base_url_source base_url_sig=$base_url_source
tarball="dropbear-${version}.tar.bz2" tarball="dropbear-${version}.tar.bz2"
sig="${tarball}.asc" sig="${tarball}.asc"
signer="Dropbear SSH Release Signing <matt@ucc.asn.au>" signer="Dropbear SSH Release Signing <matt@ucc.asn.au>"
elif [[ $project == 'TinySSH' ]]; then elif [[ $project == "TinySSH" ]]; then
base_url_source='https://github.com/janmojzis/tinyssh/archive/' base_url_source="https://github.com/janmojzis/tinyssh/archive/"
base_url_sig="https://github.com/janmojzis/tinyssh/releases/download/${version}/" base_url_sig="https://github.com/janmojzis/tinyssh/releases/download/${version}/"
tarball="${version}.tar.gz" tarball="${version}.tar.gz"
sig="${tarball}.asc" sig="${tarball}.asc"
@ -330,81 +340,85 @@ function get_source {
# Older OpenSSH releases were .sigs. # Older OpenSSH releases were .sigs.
if [[ ($project == 'OpenSSH') && (! -f $sig) ]]; then if [[ ($project == "OpenSSH") && (! -f $sig) ]]; then
wget ${base_url_sig}openssh-${version}.tar.gz.sig wget "${base_url_sig}openssh-${version}.tar.gz.sig"
sig=openssh-${version}.tar.gz.sig sig=openssh-${version}.tar.gz.sig
fi fi
local gpg_verify=`gpg --verify ${sig} ${tarball} 2>&1` local gpg_verify
gpg_verify=$(gpg --verify "${sig}" "${tarball}" 2>&1)
retval=$?
if [[ $gpg_verify != *"Good signature from \"${signer}"* ]]; then if [[ $gpg_verify != *"Good signature from \"${signer}"* ]]; then
echo -e "\n\n${REDB}Error: ${project} signature invalid!\n$gpg_verify\n\nTerminating.${CLR}" echo -e "\n\n${REDB}Error: ${project} signature invalid!\n$gpg_verify\n\nTerminating.${CLR}"
exit -1 exit 1
fi fi
# Check GPG's return value. 0 denotes a valid signature, and 1 is returned # Check GPG's return value. 0 denotes a valid signature, and 1 is returned
# on invalid signatures. # on invalid signatures.
if [[ $? != 0 ]]; then if [[ ${retval} != 0 ]]; then
echo -e "\n\n${REDB}Error: ${project} signature invalid! Verification returned code: $?\n\nTerminating.${CLR}" echo -e "\n\n${REDB}Error: ${project} signature invalid! Verification returned code: $?\n\nTerminating.${CLR}"
exit -1 exit 1
fi fi
echo -e "${GREEN}Signature on ${project} sources verified.${CLR}\n" echo -e "${GREEN}Signature on ${project} sources verified.${CLR}\n"
local checksum_actual=`sha256sum ${tarball} | cut -f1 -d" "` local checksum_actual
if [[ $checksum_actual != $tarball_checksum_expected ]]; then checksum_actual=$(sha256sum "${tarball}" | cut -f1 -d" ")
if [[ $checksum_actual != "$tarball_checksum_expected" ]]; then
echo -e "${REDB}Error: ${project} checksum is invalid!\n Expected: ${tarball_checksum_expected}\n Actual: ${checksum_actual}\n\n Terminating.${CLR}" echo -e "${REDB}Error: ${project} checksum is invalid!\n Expected: ${tarball_checksum_expected}\n Actual: ${checksum_actual}\n\n Terminating.${CLR}"
exit -1 exit 1
fi fi
} }
# Pulls the defined image from Dockerhub. # Pulls the defined image from Dockerhub.
function pull_docker_image { pull_docker_image() {
docker pull $IMAGE_NAME:$IMAGE_VERSION docker pull "${IMAGE_NAME}:${IMAGE_VERSION}"
if [[ $? == 0 ]]; then retval=$?
if [[ ${retval} == 0 ]]; then
echo -e "${GREEN}Successfully downloaded image ${IMAGE_NAME}:${IMAGE_VERSION} from Dockerhub.${CLR}\n" echo -e "${GREEN}Successfully downloaded image ${IMAGE_NAME}:${IMAGE_VERSION} from Dockerhub.${CLR}\n"
else else
echo -e "${REDB}Failed to pull image ${IMAGE_NAME}:${IMAGE_VERSION} from Dockerhub! Error code: $?${CLR}\n" echo -e "${REDB}Failed to pull image ${IMAGE_NAME}:${IMAGE_VERSION} from Dockerhub! Error code: ${retval}${CLR}\n"
exit -1 exit 1
fi fi
} }
# Runs a Dropbear test. Upon failure, a diff between the expected and actual results # Runs a Dropbear test. Upon failure, a diff between the expected and actual results
# is shown, then the script immediately terminates. # is shown, then the script immediately terminates.
function run_dropbear_test { run_dropbear_test() {
dropbear_version=$1 dropbear_version=$1
test_number=$2 test_number=$2
options=$3 options=$3
expected_retval=$4 expected_retval=$4
run_test 'Dropbear' $dropbear_version $test_number "$options" $expected_retval run_test "Dropbear" "${dropbear_version}" "${test_number}" "${options}" "${expected_retval}"
} }
# Runs an OpenSSH test. Upon failure, a diff between the expected and actual results # Runs an OpenSSH test. Upon failure, a diff between the expected and actual results
# is shown, then the script immediately terminates. # is shown, then the script immediately terminates.
function run_openssh_test { run_openssh_test() {
openssh_version=$1 openssh_version=$1
test_number=$2 test_number=$2
expected_retval=$3 expected_retval=$3
run_test 'OpenSSH' $openssh_version $test_number '' $expected_retval run_test "OpenSSH" "${openssh_version}" "${test_number}" "" "${expected_retval}"
} }
# Runs a TinySSH test. Upon failure, a diff between the expected and actual results # Runs a TinySSH test. Upon failure, a diff between the expected and actual results
# is shown, then the script immediately terminates. # is shown, then the script immediately terminates.
function run_tinyssh_test { run_tinyssh_test() {
tinyssh_version=$1 tinyssh_version=$1
test_number=$2 test_number=$2
expected_retval=$3 expected_retval=$3
run_test 'TinySSH' $tinyssh_version $test_number '' $expected_retval run_test "TinySSH" "${tinyssh_version}" "${test_number}" "" "${expected_retval}"
} }
function run_test { run_test() {
server_type=$1 server_type=$1
version=$2 version=$2
test_number=$3 test_number=$3
@ -418,7 +432,7 @@ function run_test {
expected_result_stdout= expected_result_stdout=
expected_result_json= expected_result_json=
test_name= test_name=
if [[ $server_type == 'OpenSSH' ]]; then if [[ $server_type == "OpenSSH" ]]; then
server_exec="/openssh/sshd-${version} -D -f /etc/ssh/sshd_config-${version}_${test_number}" server_exec="/openssh/sshd-${version} -D -f /etc/ssh/sshd_config-${version}_${test_number}"
test_result_stdout="${TEST_RESULT_DIR}/openssh_${version}_${test_number}.txt" test_result_stdout="${TEST_RESULT_DIR}/openssh_${version}_${test_number}.txt"
test_result_json="${TEST_RESULT_DIR}/openssh_${version}_${test_number}.json" test_result_json="${TEST_RESULT_DIR}/openssh_${version}_${test_number}.json"
@ -426,14 +440,14 @@ function run_test {
expected_result_json="test/docker/expected_results/openssh_${version}_${test_number}.json" expected_result_json="test/docker/expected_results/openssh_${version}_${test_number}.json"
test_name="OpenSSH ${version} ${test_number}" test_name="OpenSSH ${version} ${test_number}"
options= options=
elif [[ $server_type == 'Dropbear' ]]; then elif [[ $server_type == "Dropbear" ]]; then
server_exec="/dropbear/dropbear-${version} -F ${options}" server_exec="/dropbear/dropbear-${version} -F ${options}"
test_result_stdout="${TEST_RESULT_DIR}/dropbear_${version}_${test_number}.txt" test_result_stdout="${TEST_RESULT_DIR}/dropbear_${version}_${test_number}.txt"
test_result_json="${TEST_RESULT_DIR}/dropbear_${version}_${test_number}.json" test_result_json="${TEST_RESULT_DIR}/dropbear_${version}_${test_number}.json"
expected_result_stdout="test/docker/expected_results/dropbear_${version}_${test_number}.txt" expected_result_stdout="test/docker/expected_results/dropbear_${version}_${test_number}.txt"
expected_result_json="test/docker/expected_results/dropbear_${version}_${test_number}.json" expected_result_json="test/docker/expected_results/dropbear_${version}_${test_number}.json"
test_name="Dropbear ${version} ${test_number}" test_name="Dropbear ${version} ${test_number}"
elif [[ $server_type == 'TinySSH' ]]; then elif [[ $server_type == "TinySSH" ]]; then
server_exec="/usr/bin/tcpserver -HRDl0 0.0.0.0 22 /tinysshd/tinyssh-20190101 -v /etc/tinyssh/" server_exec="/usr/bin/tcpserver -HRDl0 0.0.0.0 22 /tinysshd/tinyssh-20190101 -v /etc/tinyssh/"
test_result_stdout="${TEST_RESULT_DIR}/tinyssh_${version}_${test_number}.txt" test_result_stdout="${TEST_RESULT_DIR}/tinyssh_${version}_${test_number}.txt"
test_result_json="${TEST_RESULT_DIR}/tinyssh_${version}_${test_number}.json" test_result_json="${TEST_RESULT_DIR}/tinyssh_${version}_${test_number}.json"
@ -442,65 +456,97 @@ function run_test {
test_name="TinySSH ${version} ${test_number}" test_name="TinySSH ${version} ${test_number}"
fi fi
cid=`docker run -d -p 2222:22 ${IMAGE_NAME}:${IMAGE_VERSION} ${server_exec}` cid=$(docker run -d -p 2222:22 "${IMAGE_NAME}:${IMAGE_VERSION}" ${server_exec})
#echo "Running: docker run -d -p 2222:22 ${IMAGE_NAME}:${IMAGE_VERSION} ${server_exec}" retval=$?
if [[ $? != 0 ]]; then #echo "Running: docker run -d -p 2222:22 $IMAGE_NAME:$IMAGE_VERSION ${server_exec}"
echo -e "${REDB}Failed to run docker image! (exit code: $?)${CLR}" if [[ ${retval} != 0 ]]; then
echo -e "${REDB}Failed to run docker image! (exit code: ${retval})${CLR}"
exit 1 exit 1
fi fi
./ssh-audit.py localhost:2222 > $test_result_stdout ./ssh-audit.py localhost:2222 > "$test_result_stdout"
actual_retval=$? actual_retval=$?
if [[ $actual_retval != $expected_retval ]]; then if [[ $actual_retval != "$expected_retval" ]]; then
echo -e "${REDB}Unexpected return value. Expected: ${expected_retval}; Actual: ${actual_retval}${CLR}" echo -e "${REDB}Unexpected return value. Expected: ${expected_retval}; Actual: ${actual_retval}${CLR}"
docker container stop -t 0 $cid > /dev/null
if [[ $accept == 1 ]]; then
echo -e "\n${REDB}This failure cannot be automatically fixed; this script must be manually updated with the new expected return value.${CLR}"
fi
cat "${test_result_stdout}"
docker container stop -t 0 "${cid}" > /dev/null
exit 1 exit 1
fi fi
./ssh-audit.py -j localhost:2222 > $test_result_json ./ssh-audit.py -jj localhost:2222 > "$test_result_json"
actual_retval=$? actual_retval=$?
if [[ $actual_retval != $expected_retval ]]; then if [[ $actual_retval != "$expected_retval" ]]; then
echo -e "${REDB}Unexpected return value. Expected: ${expected_retval}; Actual: ${actual_retval}${CLR}" echo -e "${REDB}Unexpected return value. Expected: ${expected_retval}; Actual: ${actual_retval}${CLR}"
docker container stop -t 0 $cid > /dev/null
if [[ $accept == 1 ]]; then
echo -e "\n${REDB}This failure cannot be automatically fixed; this script must be manually updated with the new expected return value.${CLR}"
fi
cat "${test_result_json}"
docker container stop -t 0 "${cid}" > /dev/null
exit 1 exit 1
fi fi
docker container stop -t 0 $cid > /dev/null docker container stop -t 0 "${cid}" > /dev/null
if [[ $? != 0 ]]; then retval=$?
echo -e "${REDB}Failed to stop docker container ${cid}! (exit code: $?)${CLR}" if [[ ${retval} != 0 ]]; then
echo -e "${REDB}Failed to stop docker container ${cid}! (exit code: ${retval})${CLR}"
exit 1 exit 1
fi fi
# TinySSH outputs a random string in each banner, which breaks our test. So # TinySSH outputs a random string in each banner, which breaks our test. So
# we need to filter out the banner part of the output so we get stable, repeatable # we need to filter out the banner part of the output so we get stable, repeatable
# results. # results.
if [[ $server_type == 'TinySSH' ]]; then if [[ $server_type == "TinySSH" ]]; then
grep -v "(gen) banner: " ${test_result_stdout} > "${test_result_stdout}.tmp" grep -v "(gen) banner: " "${test_result_stdout}" > "${test_result_stdout}.tmp"
mv "${test_result_stdout}.tmp" ${test_result_stdout} mv "${test_result_stdout}.tmp" "${test_result_stdout}"
cat "${test_result_json}" | perl -pe 's/"comments": ".*?"/"comments": ""/' | perl -pe 's/"raw": ".+?"/"raw": ""/' > "${test_result_json}.tmp" cat "${test_result_json}" | perl -pe 's/"comments": ".*?"/"comments": ""/' | perl -pe 's/"raw": ".+?"/"raw": ""/' > "${test_result_json}.tmp"
mv "${test_result_json}.tmp" ${test_result_json} mv "${test_result_json}.tmp" "${test_result_json}"
fi fi
diff=`diff -u ${expected_result_stdout} ${test_result_stdout}` diff=$(diff -u "${expected_result_stdout}" "${test_result_stdout}")
if [[ $? != 0 ]]; then retval=$?
if [[ ${retval} != 0 ]]; then
# If the user wants to update the tests, then overwrite the expected results with the actual results.
if [[ $accept == 1 ]]; then
cp "${test_result_stdout}" "${expected_result_stdout}"
echo -e "${test_name} ${YELLOWB}UPDATED${CLR}\n"
else
echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n" echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n"
failed=1 failed=1
num_failures=$((num_failures+1)) num_failures=$((num_failures+1))
fi fi
diff=`diff -u ${expected_result_json} ${test_result_json}` fi
if [[ $? != 0 ]]; then
diff=$(diff -u "${expected_result_json}" "${test_result_json}")
retval=$?
if [[ ${retval} != 0 ]]; then
# If the user wants to update the tests, then overwrite the expected results with the actual results.
if [[ $accept == 1 ]]; then
cp "${test_result_json}" "${expected_result_json}"
echo -e "${test_name} ${YELLOWB}UPDATED${CLR}\n"
else
echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n" echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n"
failed=1 failed=1
num_failures=$((num_failures+1)) num_failures=$((num_failures+1))
fi fi
fi
if [[ $failed == 0 ]]; then if [[ $failed == 0 ]]; then
echo -e "${test_name} ${GREEN}passed${CLR}." echo -e "${test_name} ${GREEN}passed${CLR}."
fi fi
} }
function run_builtin_policy_test { run_builtin_policy_test() {
policy_name=$1 # The built-in policy name to use. policy_name=$1 # The built-in policy name to use.
version=$2 # Version of OpenSSH to test with. version=$2 # Version of OpenSSH to test with.
test_number=$3 # The test number to run. test_number=$3 # The test number to run.
@ -518,22 +564,22 @@ function run_builtin_policy_test {
} }
function run_custom_policy_test { run_custom_policy_test() {
config_number=$1 # The configuration number to use. config_number=$1 # The configuration number to use.
test_number=$2 # The policy test number to run. test_number=$2 # The policy test number to run.
expected_exit_code=$3 # The expected exit code of ssh-audit.py. expected_exit_code=$3 # The expected exit code of ssh-audit.py.
version= version=
config= config=
if [[ ${config_number} == 'config1' ]]; then if [[ ${config_number} == "config1" ]]; then
version='5.6p1' version="5.6p1"
config='sshd_config-5.6p1_test1' config="sshd_config-5.6p1_test1"
elif [[ ${config_number} == 'config2' ]]; then elif [[ ${config_number} == "config2" ]]; then
version='8.0p1' version="8.0p1"
config='sshd_config-8.0p1_test1' config="sshd_config-8.0p1_test1"
elif [[ ${config_number} == 'config3' ]]; then elif [[ ${config_number} == "config3" ]]; then
version='5.6p1' version="5.6p1"
config='sshd_config-5.6p1_test4' config="sshd_config-5.6p1_test4"
fi fi
server_exec="/openssh/sshd-${version} -D -f /etc/ssh/${config}" server_exec="/openssh/sshd-${version} -D -f /etc/ssh/${config}"
@ -548,7 +594,7 @@ function run_custom_policy_test {
} }
function run_policy_test { run_policy_test() {
test_name=$1 test_name=$1
server_exec=$2 server_exec=$2
policy_path=$3 policy_path=$3
@ -557,59 +603,90 @@ function run_policy_test {
expected_exit_code=$6 expected_exit_code=$6
#echo "Running: docker run -d -p 2222:22 ${IMAGE_NAME}:${IMAGE_VERSION} ${server_exec}" #echo "Running: docker run -d -p 2222:22 $IMAGE_NAME:$IMAGE_VERSION ${server_exec}"
cid=`docker run -d -p 2222:22 ${IMAGE_NAME}:${IMAGE_VERSION} ${server_exec}` cid=$(docker run -d -p 2222:22 "${IMAGE_NAME}:${IMAGE_VERSION}" ${server_exec})
if [[ $? != 0 ]]; then retval=$?
echo -e "${REDB}Failed to run docker image! (exit code: $?)${CLR}" if [[ ${retval} != 0 ]]; then
echo -e "${REDB}Failed to run docker image! (exit code: ${retval})${CLR}"
exit 1 exit 1
fi fi
#echo "Running: ./ssh-audit.py -P \"${policy_path}\" localhost:2222 > ${test_result_stdout}" #echo "Running: ./ssh-audit.py -P \"${policy_path}\" localhost:2222 > ${test_result_stdout}"
./ssh-audit.py -P "${policy_path}" localhost:2222 > ${test_result_stdout} ./ssh-audit.py -P "${policy_path}" localhost:2222 > "${test_result_stdout}"
actual_exit_code=$? actual_exit_code=$?
if [[ ${actual_exit_code} != ${expected_exit_code} ]]; then if [[ ${actual_exit_code} != "${expected_exit_code}" ]]; then
echo -e "${test_name} ${REDB}FAILED${CLR} (expected exit code: ${expected_exit_code}; actual exit code: ${actual_exit_code}\n" echo -e "${test_name} ${REDB}FAILED${CLR} (expected exit code: ${expected_exit_code}; actual exit code: ${actual_exit_code}\n"
cat ${test_result_stdout}
docker container stop -t 0 $cid > /dev/null if [[ $accept == 1 ]]; then
echo -e "\n${REDB}This failure cannot be automatically fixed; this script must be manually updated with the new expected return value.${CLR}"
fi
cat "${test_result_stdout}"
docker container stop -t 0 "${cid}" > /dev/null
exit 1 exit 1
fi fi
#echo "Running: ./ssh-audit.py -P \"${policy_path}\" -j localhost:2222 > ${test_result_json}" #echo "Running: ./ssh-audit.py -P \"${policy_path}\" -jj localhost:2222 > ${test_result_json} 2> /dev/null"
./ssh-audit.py -P "${policy_path}" -j localhost:2222 > ${test_result_json} ./ssh-audit.py -P "${policy_path}" -jj localhost:2222 > "${test_result_json}" 2> /dev/null
actual_exit_code=$? actual_exit_code=$?
if [[ ${actual_exit_code} != ${expected_exit_code} ]]; then if [[ ${actual_exit_code} != "${expected_exit_code}" ]]; then
echo -e "${test_name} ${REDB}FAILED${CLR} (expected exit code: ${expected_exit_code}; actual exit code: ${actual_exit_code}\n" echo -e "${test_name} ${REDB}FAILED${CLR} (expected exit code: ${expected_exit_code}; actual exit code: ${actual_exit_code}\n"
cat ${test_result_json}
docker container stop -t 0 $cid > /dev/null if [[ $accept == 1 ]]; then
echo -e "\n${REDB}This failure cannot be automatically fixed; this script must be manually updated with the new expected return value.${CLR}"
fi
cat "${test_result_json}"
docker container stop -t 0 "${cid}" > /dev/null
exit 1 exit 1
fi fi
docker container stop -t 0 $cid > /dev/null docker container stop -t 0 "${cid}" > /dev/null
if [[ $? != 0 ]]; then retval=$?
echo -e "${REDB}Failed to stop docker container ${cid}! (exit code: $?)${CLR}" if [[ ${retval} != 0 ]]; then
echo -e "${REDB}Failed to stop docker container ${cid}! (exit code: ${retval})${CLR}"
exit 1 exit 1
fi fi
diff=`diff -u ${expected_result_stdout} ${test_result_stdout}` diff=$(diff -u "${expected_result_stdout}" "${test_result_stdout}")
if [[ $? != 0 ]]; then retval=$?
if [[ ${retval} != 0 ]]; then
# If the user wants to update the tests, then overwrite the expected results with the actual results.
if [[ $accept == 1 ]]; then
cp "${test_result_stdout}" "${expected_result_stdout}"
echo -e "${test_name} ${YELLOWB}UPDATED${CLR}\n"
else
echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n" echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n"
exit 1 exit 1
fi fi
diff=`diff -u ${expected_result_json} ${test_result_json}` fi
if [[ $? != 0 ]]; then
diff=$(diff -u "${expected_result_json}" "${test_result_json}")
retval=$?
if [[ ${retval} != 0 ]]; then
# If the user wants to update the tests, then overwrite the expected results with the actual results.
if [[ $accept == 1 ]]; then
cp "${test_result_json}" "${expected_result_json}"
echo -e "${test_name} ${YELLOWB}UPDATED${CLR}\n"
else
echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n" echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n"
exit 1 exit 1
fi fi
fi
echo -e "${test_name} ${GREEN}passed${CLR}." echo -e "${test_name} ${GREEN}passed${CLR}."
} }
# First check if docker is functional. # First check if docker is functional.
docker version > /dev/null docker version > /dev/null
if [[ $? != 0 ]]; then retval=$?
echo -e "${REDB}Error: 'docker version' command failed (error code: $?). Is docker installed and functioning?${CLR}" if [[ ${retval} != 0 ]]; then
echo -e "${REDB}Error: 'docker version' command failed (error code: ${retval}). Is docker installed and functioning?${CLR}"
exit 1 exit 1
fi fi
@ -617,7 +694,8 @@ fi
# Check if the docker image is the most up-to-date version. # Check if the docker image is the most up-to-date version.
docker_image_exists=0 docker_image_exists=0
check_if_docker_image_exists check_if_docker_image_exists
if [[ $? == 0 ]]; then retval=$?
if [[ ${retval} == 0 ]]; then
docker_image_exists=1 docker_image_exists=1
fi fi
@ -625,11 +703,11 @@ fi
# Check if the user specified --create to build a new image. # Check if the user specified --create to build a new image.
if [[ ($# == 1) && ($1 == "--create") ]]; then if [[ ($# == 1) && ($1 == "--create") ]]; then
# Ensure that the image name doesn't already exist before building. # Ensure that the image name doesn't already exist before building.
if [[ $docker_image_exists == 1 ]]; then if [[ ${docker_image_exists} == 1 ]]; then
echo -e "${REDB}Error: --create specified, but $IMAGE_NAME:$IMAGE_VERSION already exists!${CLR}" echo -e "${REDB}Error: --create specified, but ${IMAGE_NAME}:${IMAGE_VERSION} already exists!${CLR}"
exit 1 exit 1
else else
echo -e "\nCreating docker image $IMAGE_NAME:$IMAGE_VERSION..." echo -e "\nCreating docker image ${IMAGE_NAME}:${IMAGE_VERSION}..."
create_docker_image create_docker_image
echo -e "\n${GREEN}Done creating docker image!${CLR}" echo -e "\n${GREEN}Done creating docker image!${CLR}"
exit 0 exit 0
@ -637,9 +715,16 @@ if [[ ($# == 1) && ($1 == "--create") ]]; then
fi fi
# If the user passes --accept, then the actual results will replace the expected results (meaning the user wants to update the tests themselves due to new functionality).
if [[ ($# == 1) && ($1 == "--accept") ]]; then
accept=1
echo -e "\n${YELLOWB}Expected test results will be replaced with actual results.${CLR}"
fi
# If we weren't explicitly told to create a new image, and it doesn't exist, then pull it from Dockerhub. # If we weren't explicitly told to create a new image, and it doesn't exist, then pull it from Dockerhub.
if [[ $docker_image_exists == 0 ]]; then if [[ ${docker_image_exists} == 0 ]]; then
echo -e "\nPulling docker image $IMAGE_NAME:$IMAGE_VERSION..." echo -e "\nPulling docker image ${IMAGE_NAME}:${IMAGE_VERSION}..."
pull_docker_image pull_docker_image
fi fi
@ -647,68 +732,68 @@ fi
echo -e "\n${GREEN}Starting tests...${CLR}" echo -e "\n${GREEN}Starting tests...${CLR}"
# Create a temporary directory to write test results to. # Create a temporary directory to write test results to.
TEST_RESULT_DIR=`mktemp -d /tmp/ssh-audit_test-results_XXXXXXXXXX` TEST_RESULT_DIR=$(mktemp -d /tmp/ssh-audit_test-results_XXXXXXXXXX)
# Now run all the tests. # Now run all the tests.
echo -e "\nRunning tests..." echo -e "\nRunning tests..."
run_openssh_test '4.0p1' 'test1' $PROGRAM_RETVAL_FAILURE run_openssh_test "4.0p1" "test1" "${PROGRAM_RETVAL_FAILURE}"
echo echo
run_openssh_test '5.6p1' 'test1' $PROGRAM_RETVAL_FAILURE run_openssh_test "5.6p1" "test1" "${PROGRAM_RETVAL_FAILURE}"
run_openssh_test '5.6p1' 'test2' $PROGRAM_RETVAL_FAILURE run_openssh_test "5.6p1" "test2" "${PROGRAM_RETVAL_FAILURE}"
run_openssh_test '5.6p1' 'test3' $PROGRAM_RETVAL_FAILURE run_openssh_test "5.6p1" "test3" "${PROGRAM_RETVAL_FAILURE}"
run_openssh_test '5.6p1' 'test4' $PROGRAM_RETVAL_FAILURE run_openssh_test "5.6p1" "test4" "${PROGRAM_RETVAL_FAILURE}"
run_openssh_test '5.6p1' 'test5' $PROGRAM_RETVAL_FAILURE run_openssh_test "5.6p1" "test5" "${PROGRAM_RETVAL_FAILURE}"
echo echo
run_openssh_test '8.0p1' 'test1' $PROGRAM_RETVAL_FAILURE run_openssh_test "8.0p1" "test1" "${PROGRAM_RETVAL_FAILURE}"
run_openssh_test '8.0p1' 'test2' $PROGRAM_RETVAL_FAILURE run_openssh_test "8.0p1" "test2" "${PROGRAM_RETVAL_FAILURE}"
run_openssh_test '8.0p1' 'test3' $PROGRAM_RETVAL_GOOD run_openssh_test "8.0p1" "test3" "${PROGRAM_RETVAL_GOOD}"
echo echo
run_dropbear_test '2019.78' 'test1' '-r /etc/dropbear/dropbear_rsa_host_key_1024 -r /etc/dropbear/dropbear_dss_host_key -r /etc/dropbear/dropbear_ecdsa_host_key' 3 run_dropbear_test "2019.78" "test1" "-r /etc/dropbear/dropbear_rsa_host_key_1024 -r /etc/dropbear/dropbear_dss_host_key -r /etc/dropbear/dropbear_ecdsa_host_key" 3
echo echo
run_tinyssh_test '20190101' 'test1' $PROGRAM_RETVAL_WARNING run_tinyssh_test "20190101" "test1" "${PROGRAM_RETVAL_WARNING}"
echo echo
echo echo
run_custom_policy_test 'config1' 'test1' $PROGRAM_RETVAL_GOOD run_custom_policy_test "config1" "test1" "${PROGRAM_RETVAL_GOOD}"
run_custom_policy_test 'config1' 'test2' $PROGRAM_RETVAL_FAILURE run_custom_policy_test "config1" "test2" "${PROGRAM_RETVAL_FAILURE}"
run_custom_policy_test 'config1' 'test3' $PROGRAM_RETVAL_FAILURE run_custom_policy_test "config1" "test3" "${PROGRAM_RETVAL_FAILURE}"
run_custom_policy_test 'config1' 'test4' $PROGRAM_RETVAL_FAILURE run_custom_policy_test "config1" "test4" "${PROGRAM_RETVAL_FAILURE}"
run_custom_policy_test 'config1' 'test5' $PROGRAM_RETVAL_FAILURE run_custom_policy_test "config1" "test5" "${PROGRAM_RETVAL_FAILURE}"
run_custom_policy_test 'config2' 'test6' $PROGRAM_RETVAL_GOOD run_custom_policy_test "config2" "test6" "${PROGRAM_RETVAL_GOOD}"
# Passing test with host key certificate and CA key certificates. # Passing test with host key certificate and CA key certificates.
run_custom_policy_test 'config3' 'test7' $PROGRAM_RETVAL_GOOD run_custom_policy_test "config3" "test7" "${PROGRAM_RETVAL_GOOD}"
# Failing test with host key certificate and non-compliant CA key length. # Failing test with host key certificate and non-compliant CA key length.
run_custom_policy_test 'config3' 'test8' $PROGRAM_RETVAL_FAILURE run_custom_policy_test "config3" "test8" "${PROGRAM_RETVAL_FAILURE}"
# Failing test with non-compliant host key certificate and CA key certificate. # Failing test with non-compliant host key certificate and CA key certificate.
run_custom_policy_test 'config3' 'test9' $PROGRAM_RETVAL_FAILURE run_custom_policy_test "config3" "test9" "${PROGRAM_RETVAL_FAILURE}"
# Failing test with non-compliant host key certificate and non-compliant CA key certificate. # Failing test with non-compliant host key certificate and non-compliant CA key certificate.
run_custom_policy_test 'config3' 'test10' $PROGRAM_RETVAL_FAILURE run_custom_policy_test "config3" "test10" "${PROGRAM_RETVAL_FAILURE}"
# Passing test with host key size check. # Passing test with host key size check.
run_custom_policy_test 'config2' 'test11' $PROGRAM_RETVAL_GOOD run_custom_policy_test "config2" "test11" "${PROGRAM_RETVAL_GOOD}"
# Failing test with non-compliant host key size check. # Failing test with non-compliant host key size check.
run_custom_policy_test 'config2' 'test12' $PROGRAM_RETVAL_FAILURE run_custom_policy_test "config2" "test12" "${PROGRAM_RETVAL_FAILURE}"
# Passing test with DH modulus test. # Passing test with DH modulus test.
run_custom_policy_test 'config2' 'test13' $PROGRAM_RETVAL_GOOD run_custom_policy_test "config2" "test13" "${PROGRAM_RETVAL_GOOD}"
# Failing test with DH modulus test. # Failing test with DH modulus test.
run_custom_policy_test 'config2' 'test14' $PROGRAM_RETVAL_FAILURE run_custom_policy_test "config2" "test14" "${PROGRAM_RETVAL_FAILURE}"
# Passing test for built-in OpenSSH 8.0p1 server policy. # Failing test for built-in OpenSSH 8.0p1 server policy (RSA host key size is 3072 instead of 4096).
run_builtin_policy_test "Hardened OpenSSH Server v8.0 (version 1)" "8.0p1" "test1" "-o HostKeyAlgorithms=rsa-sha2-512,rsa-sha2-256,ssh-ed25519 -o KexAlgorithms=curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr -o MACs=hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com" $PROGRAM_RETVAL_GOOD run_builtin_policy_test "Hardened OpenSSH Server v8.0 (version 3)" "8.0p1" "test1" "-o HostKeyAlgorithms=rsa-sha2-512,rsa-sha2-256,ssh-ed25519 -o KexAlgorithms=curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr -o MACs=hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com" "${PROGRAM_RETVAL_FAILURE}"
# Failing test for built-in OpenSSH 8.0p1 server policy (MACs not hardened). # Failing test for built-in OpenSSH 8.0p1 server policy (MACs not hardened).
run_builtin_policy_test "Hardened OpenSSH Server v8.0 (version 1)" "8.0p1" "test2" "-o HostKeyAlgorithms=rsa-sha2-512,rsa-sha2-256,ssh-ed25519 -o KexAlgorithms=curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr" $PROGRAM_RETVAL_FAILURE run_builtin_policy_test "Hardened OpenSSH Server v8.0 (version 3)" "8.0p1" "test2" "-o HostKeyAlgorithms=rsa-sha2-512,rsa-sha2-256,ssh-ed25519 -o KexAlgorithms=curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr" "${PROGRAM_RETVAL_FAILURE}"
if [[ $num_failures == 0 ]]; then if [[ $num_failures == 0 ]]; then
echo -e "\n${GREENB}ALL TESTS PASS!${CLR}\n" echo -e "\n${GREENB}ALL TESTS PASS!${CLR}\n"
rm -rf $TEST_RESULT_DIR rm -rf -- "${TEST_RESULT_DIR}"
else else
echo -e "\n${REDB}${num_failures} TESTS FAILED!${CLR}\n" echo -e "\n${REDB}${num_failures} TESTS FAILED!${CLR}\n"
fi fi

View File

@ -6,7 +6,8 @@ author_email = jtesta@positronsecurity.com
description = An SSH server & client configuration security auditing tool description = An SSH server & client configuration security auditing tool
long_description = file: README.md long_description = file: README.md
long_description_content_type = text/markdown long_description_content_type = text/markdown
license_file = LICENSE license = MIT
license_files = LICENSE
url = https://github.com/jtesta/ssh-audit url = https://github.com/jtesta/ssh-audit
project_urls = project_urls =
Source Code = https://github.com/jtesta/ssh-audit Source Code = https://github.com/jtesta/ssh-audit
@ -18,10 +19,11 @@ classifiers =
License :: OSI Approved :: MIT License License :: OSI Approved :: MIT License
Operating System :: OS Independent Operating System :: OS Independent
Programming Language :: Python :: 3 Programming Language :: Python :: 3
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Programming Language :: Python :: Implementation :: CPython Programming Language :: Python :: Implementation :: CPython
Programming Language :: Python :: Implementation :: PyPy Programming Language :: Python :: Implementation :: PyPy
Topic :: Security Topic :: Security
@ -31,7 +33,7 @@ classifiers =
packages = find: packages = find:
package_dir = package_dir =
= src = src
python_requires = >=3.6,<4 python_requires = >=3.7,<4
[options.packages.find] [options.packages.find]
where = src where = src

View File

@ -1,21 +1,20 @@
name: ssh-audit name: ssh-audit
version: '2.4.0-1' # 'version' field will be automatically added by build_snap.sh.
license: 'MIT' license: 'MIT'
summary: ssh-audit summary: ssh-audit
description: | description: |
SSH server and client security configuration auditor. Official repository: <https://github.com/jtesta/ssh-audit> SSH server and client security configuration auditor. Official repository: <https://github.com/jtesta/ssh-audit>
base: core20 base: core22
grade: stable grade: stable
confinement: strict confinement: strict
apps: apps:
ssh-audit: ssh-audit:
command: bin/ssh-audit command: bin/ssh-audit
plugs: [network,network-bind] plugs: [network,network-bind,home]
parts: parts:
ssh-audit: ssh-audit:
plugin: python plugin: python
# python-version: python3
source: . source: .

View File

@ -54,7 +54,7 @@ class Algorithms:
def ssh1(self) -> Optional['Algorithms.Item']: def ssh1(self) -> Optional['Algorithms.Item']:
if self.ssh1kex is None: if self.ssh1kex is None:
return None return None
item = Algorithms.Item(1, SSH1_KexDB.ALGORITHMS) item = Algorithms.Item(1, SSH1_KexDB.get_db())
item.add('key', ['ssh-rsa1']) item.add('key', ['ssh-rsa1'])
item.add('enc', self.ssh1kex.supported_ciphers) item.add('enc', self.ssh1kex.supported_ciphers)
item.add('aut', self.ssh1kex.supported_authentications) item.add('aut', self.ssh1kex.supported_authentications)
@ -64,7 +64,7 @@ class Algorithms:
def ssh2(self) -> Optional['Algorithms.Item']: def ssh2(self) -> Optional['Algorithms.Item']:
if self.ssh2kex is None: if self.ssh2kex is None:
return None return None
item = Algorithms.Item(2, SSH2_KexDB.ALGORITHMS) item = Algorithms.Item(2, SSH2_KexDB.get_db())
item.add('kex', self.ssh2kex.kex_algorithms) item.add('kex', self.ssh2kex.kex_algorithms)
item.add('key', self.ssh2kex.key_algorithms) item.add('key', self.ssh2kex.key_algorithms)
item.add('enc', self.ssh2kex.server.encryption) item.add('enc', self.ssh2kex.server.encryption)

View File

@ -59,6 +59,7 @@ class AuditConf:
self.lookup = '' self.lookup = ''
self.manual = False self.manual = False
self.debug = False self.debug = False
self.gex_test = ''
def __setattr__(self, name: str, value: Union[str, int, float, bool, Sequence[int]]) -> None: def __setattr__(self, name: str, value: Union[str, int, float, bool, Sequence[int]]) -> None:
valid = False valid = False
@ -86,7 +87,7 @@ class AuditConf:
if value == -1.0: if value == -1.0:
raise ValueError('invalid timeout: {}'.format(value)) raise ValueError('invalid timeout: {}'.format(value))
valid = True valid = True
elif name in ['ip_version_preference', 'lookup', 'policy_file', 'policy', 'target_file', 'target_list']: elif name in ['ip_version_preference', 'lookup', 'policy_file', 'policy', 'target_file', 'target_list', 'gex_test']:
valid = True valid = True
elif name == "threads": elif name == "threads":
valid, num_threads = True, Utils.parse_int(value) valid, num_threads = True, Utils.parse_int(value)

View File

@ -1,7 +1,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (C) 2017-2021 Joe Testa (jtesta@positronsecurity.com) Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -21,18 +21,19 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
""" """
import traceback
# pylint: disable=unused-import # pylint: disable=unused-import
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401 from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
from typing import Callable, Optional, Union, Any # noqa: F401 from typing import Callable, Optional, Union, Any # noqa: F401
import traceback from ssh_audit.banner import Banner
from ssh_audit.kexdh import KexDHException, KexGroupExchange, KexGroupExchange_SHA1, KexGroupExchange_SHA256
from ssh_audit.kexdh import KexGroupExchange_SHA1, KexGroupExchange_SHA256
from ssh_audit.ssh2_kexdb import SSH2_KexDB from ssh_audit.ssh2_kexdb import SSH2_KexDB
from ssh_audit.ssh2_kex import SSH2_Kex from ssh_audit.ssh2_kex import SSH2_Kex
from ssh_audit.ssh_socket import SSH_Socket from ssh_audit.ssh_socket import SSH_Socket
from ssh_audit.outputbuffer import OutputBuffer from ssh_audit.outputbuffer import OutputBuffer
from ssh_audit import exitcodes
# Performs DH group exchanges to find what moduli are supported, and checks # Performs DH group exchanges to find what moduli are supported, and checks
@ -63,16 +64,66 @@ class GEXTest:
try: try:
# Parse the server's KEX. # Parse the server's KEX.
_, payload = s.read_packet(2) _, payload = s.read_packet(2)
SSH2_Kex.parse(payload) SSH2_Kex.parse(out, payload)
except Exception: except KexDHException:
out.v("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc()), write_now=True) out.v("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc()), write_now=True)
return False return False
return True return True
@staticmethod
def granular_modulus_size_test(out: 'OutputBuffer', s: 'SSH_Socket', kex: 'SSH2_Kex', bits_min: int, bits_pref: int, bits_max: int, modulus_dict: Dict[str, List[int]]) -> int:
'''
Tests for granular modulus sizes.
Builds a dictionary, where a key represents a DH algorithm name and the
values are the modulus sizes (in bits) that have been returned by the
target server.
Returns an exitcodes.* flag.
'''
retval = exitcodes.GOOD
out.d("Starting modulus_size_test...")
out.d("Bits Min: " + str(bits_min))
out.d("Bits Pref: " + str(bits_pref))
out.d("Bits Max: " + str(bits_max))
GEX_ALGS = {
'diffie-hellman-group-exchange-sha1': KexGroupExchange_SHA1,
'diffie-hellman-group-exchange-sha256': KexGroupExchange_SHA256,
}
# Check if the server supports any of the group-exchange
# algorithms. If so, test each one.
for gex_alg, kex_group_class in GEX_ALGS.items():
if gex_alg not in kex.kex_algorithms:
out.d('Server does not support the algorithm "' + gex_alg + '".', write_now=True)
else:
kex_group = kex_group_class(out)
out.d('Preparing to perform DH group exchange using ' + gex_alg + ' with min, pref and max modulus sizes of ' + str(bits_min) + ' bits, ' + str(bits_pref) + ' bits and ' + str(bits_max) + ' bits...', write_now=True)
# It has been observed that reconnecting to some SSH servers
# multiple times in quick succession can eventually result
# in a "connection reset by peer" error. It may be possible
# to recover from such an error by sleeping for some time
# before continuing to issue reconnects.
modulus_size_returned, reconnect_failed = GEXTest._send_init(out, s, kex_group, kex, gex_alg, bits_min, bits_pref, bits_max)
if reconnect_failed:
out.fail('Reconnect failed.')
return exitcodes.FAILURE
if modulus_size_returned > 0:
if gex_alg in modulus_dict:
if modulus_size_returned not in modulus_dict[gex_alg]:
modulus_dict[gex_alg].append(modulus_size_returned)
else:
modulus_dict[gex_alg] = [modulus_size_returned]
return retval
# Runs the DH moduli test against the specified target. # Runs the DH moduli test against the specified target.
@staticmethod @staticmethod
def run(out: 'OutputBuffer', s: 'SSH_Socket', kex: 'SSH2_Kex') -> None: def run(out: 'OutputBuffer', s: 'SSH_Socket', banner: Optional['Banner'], kex: 'SSH2_Kex') -> None:
GEX_ALGS = { GEX_ALGS = {
'diffie-hellman-group-exchange-sha1': KexGroupExchange_SHA1, 'diffie-hellman-group-exchange-sha1': KexGroupExchange_SHA1,
'diffie-hellman-group-exchange-sha256': KexGroupExchange_SHA256, 'diffie-hellman-group-exchange-sha256': KexGroupExchange_SHA256,
@ -86,31 +137,15 @@ class GEXTest:
# Check if the server supports any of the group-exchange # Check if the server supports any of the group-exchange
# algorithms. If so, test each one. # algorithms. If so, test each one.
for gex_alg, kex_group_class in GEX_ALGS.items(): for gex_alg, kex_group_class in GEX_ALGS.items(): # pylint: disable=too-many-nested-blocks
if gex_alg in kex.kex_algorithms: if gex_alg in kex.kex_algorithms:
out.d('Preparing to perform DH group exchange using ' + gex_alg + '...', write_now=True) out.d('Preparing to perform DH group exchange using ' + gex_alg + ' with min, pref and max modulus sizes of 512 bits, 1024 bits and 1536 bits...', write_now=True)
if GEXTest.reconnect(out, s, kex, gex_alg) is False: kex_group = kex_group_class(out)
smallest_modulus, reconnect_failed = GEXTest._send_init(out, s, kex_group, kex, gex_alg, 512, 1024, 1536)
if reconnect_failed:
break break
kex_group = kex_group_class()
smallest_modulus = -1
# First try a range of weak sizes.
try:
kex_group.send_init_gex(s, 512, 1024, 1536)
kex_group.recv_reply(s, False)
# Its been observed that servers will return a group
# larger than the requested max. So just because we
# got here, doesn't mean the server is vulnerable...
smallest_modulus = kex_group.get_dh_modulus_size()
except Exception:
pass
finally:
s.close()
# Try an array of specific modulus sizes... one at a time. # Try an array of specific modulus sizes... one at a time.
reconnect_failed = False reconnect_failed = False
for bits in [512, 768, 1024, 1536, 2048, 3072, 4096]: for bits in [512, 768, 1024, 1536, 2048, 3072, 4096]:
@ -120,33 +155,25 @@ class GEXTest:
if bits >= smallest_modulus > 0: if bits >= smallest_modulus > 0:
break break
out.d('Preparing to perform DH group exchange using ' + gex_alg + ' with modulus size ' + str(bits) + '...', write_now=True) smallest_modulus, reconnect_failed = GEXTest._send_init(out, s, kex_group, kex, gex_alg, bits, bits, bits)
if GEXTest.reconnect(out, s, kex, gex_alg) is False: # If the smallest modulus is 2048 and the server is OpenSSH, then we may have triggered the fallback mechanism, which tends to happen in testing scenarios such as this but not in most real-world conditions (see X). To better test this condition, we will do an additional check to see if the server supports sizes between 2048 and 4096, and consider this the definitive result.
reconnect_failed = True openssh_test_updated = False
break if (smallest_modulus == 2048) and (banner is not None) and (banner.software is not None) and (banner.software.find('OpenSSH') != -1):
out.d('First pass found a minimum GEX modulus of 2048 against OpenSSH server. Performing a second pass to get a more accurate result...')
try: smallest_modulus, _ = GEXTest._send_init(out, s, kex_group, kex, gex_alg, 2048, 3072, 4096)
kex_group.send_init_gex(s, bits, bits, bits) out.d('Modulus size returned by server during second pass: %d bits' % smallest_modulus, write_now=True)
kex_group.recv_reply(s, False) openssh_test_updated = bool((smallest_modulus > 0) and (smallest_modulus != 2048))
smallest_modulus = kex_group.get_dh_modulus_size()
except Exception:
# import traceback
# print(traceback.format_exc())
pass
finally:
# The server is in a state that is not re-testable,
# so there's nothing else to do with this open
# connection.
s.close()
if smallest_modulus > 0: if smallest_modulus > 0:
kex.set_dh_modulus_size(gex_alg, smallest_modulus) kex.set_dh_modulus_size(gex_alg, smallest_modulus)
lst = SSH2_KexDB.get_db()['kex'][gex_alg]
# We flag moduli smaller than 2048 as a failure. # We flag moduli smaller than 2048 as a failure.
if smallest_modulus < 2048: if smallest_modulus < 2048:
text = 'using small %d-bit modulus' % smallest_modulus text = 'using small %d-bit modulus' % smallest_modulus
lst = SSH2_KexDB.ALGORITHMS['kex'][gex_alg]
# For 'diffie-hellman-group-exchange-sha256', add # For 'diffie-hellman-group-exchange-sha256', add
# a failure reason. # a failure reason.
if len(lst) == 1: if len(lst) == 1:
@ -158,5 +185,51 @@ class GEXTest:
del lst[1] del lst[1]
lst.insert(1, [text]) lst.insert(1, [text])
# Moduli smaller than 3072 get flagged as a warning.
elif smallest_modulus < 3072:
# Ensure that a warning list exists for us to append to, below.
while len(lst) < 3:
lst.append([])
# Ensure this is only added once.
text = '2048-bit modulus only provides 112-bits of symmetric strength'
if text not in lst[2]:
lst[2].append(text)
# If we retested against OpenSSH (because its fallback mechanism was triggered), add a special note for the user.
if openssh_test_updated:
text = "OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use %u. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477)." % smallest_modulus
# Ensure that an info list exists for us to append to, below.
while len(lst) < 4:
lst.append([])
# Ensure this is only added once.
if text not in lst[3]:
lst[3].append(text)
if reconnect_failed: if reconnect_failed:
break break
@staticmethod
def _send_init(out: 'OutputBuffer', s: 'SSH_Socket', kex_group: 'KexGroupExchange', kex: 'SSH2_Kex', gex_alg: str, min_bits: int, pref_bits: int, max_bits: int) -> Tuple[int, bool]:
'''Internal function for sending the GEX initialization to the server with the minimum, preferred, and maximum modulus bits. Returns a Tuple of the modulus size received from the server (or -1 on error) and boolean signifying that the connection to the server failed.'''
smallest_modulus = -1
reconnect_failed = False
try:
if GEXTest.reconnect(out, s, kex, gex_alg) is False:
reconnect_failed = True
out.d('GEXTest._send_init(%s, %u, %u, %u): reconnection failed.' % (gex_alg, min_bits, pref_bits, max_bits), write_now=True)
else:
kex_group.send_init_gex(s, min_bits, pref_bits, max_bits)
kex_group.recv_reply(s, False)
smallest_modulus = kex_group.get_dh_modulus_size()
out.d('GEXTest._send_init(%s, %u, %u, %u): received modulus size: %d' % (gex_alg, min_bits, pref_bits, max_bits, smallest_modulus), write_now=True)
except KexDHException as e:
out.d('GEXTest._send_init(%s, %u, %u, %u): exception when performing DH group exchange init: %s' % (gex_alg, min_bits, pref_bits, max_bits, str(e)), write_now=True)
finally:
s.close()
return smallest_modulus, reconnect_failed

View File

@ -1,7 +1,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (C) 2017-2021 Joe Testa (jtesta@positronsecurity.com) Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -21,7 +21,20 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
""" """
VERSION = 'v2.5.0' # The version to display.
SSH_HEADER = 'SSH-{0}-OpenSSH_8.2' # SSH software to impersonate VERSION = 'v3.0.0'
GITHUB_ISSUES_URL = 'https://github.com/jtesta/ssh-audit/issues' # The URL to the Github issues tracker.
# SSH software to impersonate
SSH_HEADER = 'SSH-{0}-OpenSSH_8.2'
# The URL to the Github issues tracker.
GITHUB_ISSUES_URL = 'https://github.com/jtesta/ssh-audit/issues'
# The man page. Only filled in on Windows systems.
WINDOWS_MAN_PAGE = '' WINDOWS_MAN_PAGE = ''
# True when installed from a Snap package, otherwise False.
SNAP_PACKAGE = False
# Error message when installed as a Snap package and a file access fails.
SNAP_PERMISSIONS_ERROR = 'Error while accessing file. It appears that ssh-audit was installed as a Snap package. In that case, there are two options: 1.) only try to read & write files in the $HOME/snap/ssh-audit/common/ directory, or 2.) grant permissions to read & write files in $HOME using the following command: "sudo snap connect ssh-audit:home :home"'

View File

@ -1,7 +1,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (C) 2017-2021 Joe Testa (jtesta@positronsecurity.com) Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -28,7 +28,7 @@ from typing import Callable, Optional, Union, Any # noqa: F401
import traceback import traceback
from ssh_audit.kexdh import KexDH, KexGroup1, KexGroup14_SHA1, KexGroup14_SHA256, KexCurve25519_SHA256, KexGroup16_SHA512, KexGroup18_SHA512, KexGroupExchange_SHA1, KexGroupExchange_SHA256, KexNISTP256, KexNISTP384, KexNISTP521 from ssh_audit.kexdh import KexDH, KexDHException, KexGroup1, KexGroup14_SHA1, KexGroup14_SHA256, KexCurve25519_SHA256, KexGroup16_SHA512, KexGroup18_SHA512, KexGroupExchange_SHA1, KexGroupExchange_SHA256, KexNISTP256, KexNISTP384, KexNISTP521
from ssh_audit.ssh2_kex import SSH2_Kex from ssh_audit.ssh2_kex import SSH2_Kex
from ssh_audit.ssh2_kexdb import SSH2_KexDB from ssh_audit.ssh2_kexdb import SSH2_KexDB
from ssh_audit.ssh_socket import SSH_Socket from ssh_audit.ssh_socket import SSH_Socket
@ -54,6 +54,10 @@ class HostKeyTest:
'ssh-ed25519-cert-v01@openssh.com': {'cert': True, 'variable_key_len': False}, 'ssh-ed25519-cert-v01@openssh.com': {'cert': True, 'variable_key_len': False},
} }
TWO2K_MODULUS_WARNING = '2048-bit modulus only provides 112-bits of symmetric strength'
SMALL_ECC_MODULUS_WARNING = '224-bit ECC modulus only provides 112-bits of symmetric strength'
@staticmethod @staticmethod
def run(out: 'OutputBuffer', s: 'SSH_Socket', server_kex: 'SSH2_Kex') -> None: def run(out: 'OutputBuffer', s: 'SSH_Socket', server_kex: 'SSH2_Kex') -> None:
KEX_TO_DHGROUP = { KEX_TO_DHGROUP = {
@ -79,7 +83,7 @@ class HostKeyTest:
for server_kex_alg in server_kex.kex_algorithms: for server_kex_alg in server_kex.kex_algorithms:
if server_kex_alg in KEX_TO_DHGROUP: if server_kex_alg in KEX_TO_DHGROUP:
kex_str = server_kex_alg kex_str = server_kex_alg
kex_group = KEX_TO_DHGROUP[kex_str]() kex_group = KEX_TO_DHGROUP[kex_str](out)
break break
if kex_str is not None and kex_group is not None: if kex_str is not None and kex_group is not None:
@ -98,6 +102,9 @@ class HostKeyTest:
# For each host key type... # For each host key type...
for host_key_type in host_key_types: for host_key_type in host_key_types:
key_fail_comments = []
key_warn_comments = []
# Skip those already handled (i.e.: those in the RSA family, as testing one tests them all). # Skip those already handled (i.e.: those in the RSA family, as testing one tests them all).
if 'parsed' in host_key_types[host_key_type] and host_key_types[host_key_type]['parsed']: if 'parsed' in host_key_types[host_key_type] and host_key_types[host_key_type]['parsed']:
continue continue
@ -107,7 +114,6 @@ class HostKeyTest:
out.d('Preparing to obtain ' + host_key_type + ' host key...', write_now=True) out.d('Preparing to obtain ' + host_key_type + ' host key...', write_now=True)
cert = host_key_types[host_key_type]['cert'] cert = host_key_types[host_key_type]['cert']
variable_key_len = host_key_types[host_key_type]['variable_key_len']
# If the connection is closed, re-open it and get the kex again. # If the connection is closed, re-open it and get the kex again.
if not s.is_connected(): if not s.is_connected():
@ -128,7 +134,7 @@ class HostKeyTest:
try: try:
# Parse the server's KEX. # Parse the server's KEX.
_, payload = s.read_packet() _, payload = s.read_packet()
SSH2_Kex.parse(payload) SSH2_Kex.parse(out, payload)
except Exception: except Exception:
out.v("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc()), write_now=True) out.v("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc()), write_now=True)
return return
@ -136,15 +142,29 @@ class HostKeyTest:
# Do the initial DH exchange. The server responds back # Do the initial DH exchange. The server responds back
# with the host key and its length. Bingo. We also get back the host key fingerprint. # with the host key and its length. Bingo. We also get back the host key fingerprint.
kex_group.send_init(s) kex_group.send_init(s)
raw_hostkey_bytes = b''
try: try:
host_key = kex_group.recv_reply(s, variable_key_len) kex_reply = kex_group.recv_reply(s)
if host_key is not None: raw_hostkey_bytes = kex_reply if kex_reply is not None else b''
server_kex.set_host_key(host_key_type, host_key) except KexDHException:
except Exception: out.v("Failed to parse server's host key. Stack trace:\n%s" % str(traceback.format_exc()), write_now=True)
pass
# Since parsing this host key failed, there's nothing more to do but close the socket and move on to the next host key type.
s.close()
continue
hostkey_modulus_size = kex_group.get_hostkey_size() hostkey_modulus_size = kex_group.get_hostkey_size()
ca_key_type = kex_group.get_ca_type()
ca_modulus_size = kex_group.get_ca_size() ca_modulus_size = kex_group.get_ca_size()
out.d("Hostkey type: [%s]; hostkey size: %u; CA type: [%s]; CA modulus size: %u" % (host_key_type, hostkey_modulus_size, ca_key_type, ca_modulus_size), write_now=True)
# Record all the host key info.
server_kex.set_host_key(host_key_type, raw_hostkey_bytes, hostkey_modulus_size, ca_key_type, ca_modulus_size)
# Set the hostkey size for all RSA key types since 'ssh-rsa', 'rsa-sha2-256', etc. are all using the same host key. Note, however, that this may change in the future.
if cert is False and host_key_type in HostKeyTest.RSA_FAMILY:
for rsa_type in HostKeyTest.RSA_FAMILY:
server_kex.set_host_key(rsa_type, raw_hostkey_bytes, hostkey_modulus_size, ca_key_type, ca_modulus_size)
# Close the socket, as the connection has # Close the socket, as the connection has
# been put in a state that later tests can't use. # been put in a state that later tests can't use.
@ -152,37 +172,62 @@ class HostKeyTest:
# If the host key modulus or CA modulus was successfully parsed, check to see that its a safe size. # If the host key modulus or CA modulus was successfully parsed, check to see that its a safe size.
if hostkey_modulus_size > 0 or ca_modulus_size > 0: if hostkey_modulus_size > 0 or ca_modulus_size > 0:
# Set the hostkey size for all RSA key types since 'ssh-rsa', # The minimum good modulus size for RSA host keys is 3072. However, since ECC cryptosystems are fundamentally different, the minimum good is 256.
# 'rsa-sha2-256', etc. are all using the same host key. hostkey_min_good = cakey_min_good = 3072
# Note, however, that this may change in the future. hostkey_min_warn = cakey_min_warn = 2048
if cert is False and host_key_type in HostKeyTest.RSA_FAMILY: hostkey_warn_str = cakey_warn_str = HostKeyTest.TWO2K_MODULUS_WARNING
for rsa_type in HostKeyTest.RSA_FAMILY: if host_key_type.startswith('ssh-ed25519') or host_key_type.startswith('ecdsa-sha2-nistp'):
server_kex.set_rsa_key_size(rsa_type, hostkey_modulus_size) hostkey_min_good = 256
elif cert is True: hostkey_min_warn = 224
server_kex.set_rsa_key_size(host_key_type, hostkey_modulus_size, ca_modulus_size) hostkey_warn_str = HostKeyTest.SMALL_ECC_MODULUS_WARNING
if ca_key_type.startswith('ssh-ed25519') or host_key_type.startswith('ecdsa-sha2-nistp'):
cakey_min_good = 256
cakey_min_warn = 224
cakey_warn_str = HostKeyTest.SMALL_ECC_MODULUS_WARNING
# Keys smaller than 2048 result in a failure. Update the database accordingly. # 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 < 2048): if (cert is False) and (hostkey_modulus_size < hostkey_min_good):
for rsa_type in HostKeyTest.RSA_FAMILY:
alg_list = SSH2_KexDB.ALGORITHMS['key'][rsa_type]
# If no failure list exists, add an empty failure list. # If the key is under 2048, add to the failure list.
if len(alg_list) < 2: if hostkey_modulus_size < hostkey_min_warn:
alg_list.append([]) key_fail_comments.append('using small %d-bit modulus' % hostkey_modulus_size)
alg_list[1].append('using small %d-bit modulus' % hostkey_modulus_size) elif hostkey_warn_str not in key_warn_comments: # Issue a warning about 2048-bit moduli.
elif (cert is True) and ((hostkey_modulus_size < 2048) or (ca_modulus_size > 0 and ca_modulus_size < 2048)): # pylint: disable=chained-comparison key_warn_comments.append(hostkey_warn_str)
alg_list = SSH2_KexDB.ALGORITHMS['key'][host_key_type]
min_modulus = min(hostkey_modulus_size, ca_modulus_size)
min_modulus = min_modulus if min_modulus > 0 else max(hostkey_modulus_size, ca_modulus_size)
# If no failure list exists, add an empty failure list. elif (cert is True) and ((hostkey_modulus_size < hostkey_min_good) or (0 < ca_modulus_size < cakey_min_good)):
if len(alg_list) < 2: # If the host key is smaller than 2048-bit/224-bit, flag this as a failure.
alg_list.append([]) if hostkey_modulus_size < hostkey_min_warn:
alg_list[1].append('using small %d-bit modulus' % min_modulus) key_fail_comments.append('using small %d-bit hostkey modulus' % hostkey_modulus_size)
# Otherwise, this is just a warning.
elif (hostkey_modulus_size < hostkey_min_good) and (hostkey_warn_str not in key_warn_comments):
key_warn_comments.append(hostkey_warn_str)
# If the CA key is smaller than 2048-bit/224-bit, flag this as a failure.
if 0 < ca_modulus_size < cakey_min_warn:
key_fail_comments.append('using small %d-bit CA key modulus' % ca_modulus_size)
# Otherwise, this is just a warning.
elif (0 < ca_modulus_size < cakey_min_good) and (cakey_warn_str not in key_warn_comments):
key_warn_comments.append(cakey_warn_str)
# If this host key type is in the RSA family, then mark them all as parsed (since results in one are valid for them all). # If this host key type is in the RSA family, then mark them all as parsed (since results in one are valid for them all).
if host_key_type in HostKeyTest.RSA_FAMILY: if host_key_type in HostKeyTest.RSA_FAMILY:
for rsa_type in HostKeyTest.RSA_FAMILY: for rsa_type in HostKeyTest.RSA_FAMILY:
host_key_types[rsa_type]['parsed'] = True host_key_types[rsa_type]['parsed'] = True
# If the current key is a member of the RSA family, then populate all RSA family members with the same
# failure and/or warning comments.
db = SSH2_KexDB.get_db()
while len(db['key'][rsa_type]) < 3:
db['key'][rsa_type].append([])
db['key'][rsa_type][1].extend(key_fail_comments)
db['key'][rsa_type][2].extend(key_warn_comments)
else: else:
host_key_types[host_key_type]['parsed'] = True host_key_types[host_key_type]['parsed'] = True
db = SSH2_KexDB.get_db()
while len(db['key'][host_key_type]) < 3:
db['key'][host_key_type].append([])
db['key'][host_key_type][1].extend(key_fail_comments)
db['key'][host_key_type][2].extend(key_warn_comments)

View File

@ -1,7 +1,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (C) 2017-2021 Joe Testa (jtesta@positronsecurity.com) Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu) Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
@ -26,17 +26,24 @@ import binascii
import os import os
import random import random
import struct import struct
import traceback
# pylint: disable=unused-import # pylint: disable=unused-import
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401 from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
from typing import Callable, Optional, Union, Any # noqa: F401 from typing import Callable, Optional, Union, Any # noqa: F401
from ssh_audit.outputbuffer import OutputBuffer
from ssh_audit.protocol import Protocol from ssh_audit.protocol import Protocol
from ssh_audit.ssh_socket import SSH_Socket from ssh_audit.ssh_socket import SSH_Socket
class KexDHException(Exception):
pass
class KexDH: # pragma: nocover class KexDH: # pragma: nocover
def __init__(self, kex_name: str, hash_alg: str, g: int, p: int) -> None: def __init__(self, out: 'OutputBuffer', kex_name: str, hash_alg: str, g: int, p: int) -> None:
self.out = out
self.__kex_name = kex_name # pylint: disable=unused-private-member self.__kex_name = kex_name # pylint: disable=unused-private-member
self.__hash_alg = hash_alg # pylint: disable=unused-private-member self.__hash_alg = hash_alg # pylint: disable=unused-private-member
self.__g = 0 self.__g = 0
@ -47,10 +54,11 @@ class KexDH: # pragma: nocover
self.set_params(g, p) self.set_params(g, p)
self.__ed25519_pubkey: Optional[bytes] = None # pylint: disable=unused-private-member self.__ed25519_pubkey: Optional[bytes] = None # pylint: disable=unused-private-member
self.__hostkey_type: Optional[bytes] = None self.__hostkey_type = ''
self.__hostkey_e = 0 # pylint: disable=unused-private-member self.__hostkey_e = 0 # pylint: disable=unused-private-member
self.__hostkey_n = 0 # pylint: disable=unused-private-member self.__hostkey_n = 0 # pylint: disable=unused-private-member
self.__hostkey_n_len = 0 # Length of the host key modulus. self.__hostkey_n_len = 0 # Length of the host key modulus.
self.__ca_key_type = '' # Type of CA key ('ssh-rsa', etc).
self.__ca_n_len = 0 # Length of the CA key modulus (if hostkey is a cert). self.__ca_n_len = 0 # Length of the CA key modulus (if hostkey is a cert).
def set_params(self, g: int, p: int) -> None: def set_params(self, g: int, p: int) -> None:
@ -72,6 +80,14 @@ class KexDH: # pragma: nocover
# contains the host key, among other things. Function returns the host # contains the host key, among other things. Function returns the host
# key blob (from which the fingerprint can be calculated). # key blob (from which the fingerprint can be calculated).
def recv_reply(self, s: 'SSH_Socket', parse_host_key_size: bool = True) -> Optional[bytes]: def recv_reply(self, s: 'SSH_Socket', parse_host_key_size: bool = True) -> Optional[bytes]:
# Reset the CA info, in case it was set from a prior invokation.
self.__hostkey_type = ''
self.__hostkey_e = 0 # pylint: disable=unused-private-member
self.__hostkey_n = 0 # pylint: disable=unused-private-member
self.__hostkey_n_len = 0
self.__ca_key_type = ''
self.__ca_n_len = 0
packet_type, payload = s.read_packet(2) packet_type, payload = s.read_packet(2)
# Skip any & all MSG_DEBUG messages. # Skip any & all MSG_DEBUG messages.
@ -79,29 +95,17 @@ class KexDH: # pragma: nocover
packet_type, payload = s.read_packet(2) packet_type, payload = s.read_packet(2)
if packet_type != -1 and packet_type not in [Protocol.MSG_KEXDH_REPLY, Protocol.MSG_KEXDH_GEX_REPLY]: # pylint: disable=no-else-raise if packet_type != -1 and packet_type not in [Protocol.MSG_KEXDH_REPLY, Protocol.MSG_KEXDH_GEX_REPLY]: # pylint: disable=no-else-raise
# TODO: change Exception to something more specific. raise KexDHException('Expected MSG_KEXDH_REPLY (%d) or MSG_KEXDH_GEX_REPLY (%d), but got %d instead.' % (Protocol.MSG_KEXDH_REPLY, Protocol.MSG_KEXDH_GEX_REPLY, packet_type))
raise Exception('Expected MSG_KEXDH_REPLY (%d) or MSG_KEXDH_GEX_REPLY (%d), but got %d instead.' % (Protocol.MSG_KEXDH_REPLY, Protocol.MSG_KEXDH_GEX_REPLY, packet_type))
elif packet_type == -1: elif packet_type == -1:
# A connection error occurred. We can't parse anything, so just # A connection error occurred. We can't parse anything, so just
# return. The host key modulus (and perhaps certificate modulus) # return. The host key modulus (and perhaps certificate modulus)
# will remain at length 0. # will remain at length 0.
self.out.d("KexDH.recv_reply(): received packge_type == -1.")
return None return None
hostkey_len = 0 # pylint: disable=unused-variable
hostkey_type_len = hostkey_e_len = 0 # pylint: disable=unused-variable
key_id_len = principles_len = 0 # pylint: disable=unused-variable
critical_options_len = extensions_len = 0 # pylint: disable=unused-variable
nonce_len = ca_key_len = ca_key_type_len = 0 # pylint: disable=unused-variable
ca_key_len = ca_key_type_len = ca_key_e_len = 0 # pylint: disable=unused-variable
key_id = principles = None # pylint: disable=unused-variable
critical_options = extensions = None # pylint: disable=unused-variable
nonce = ca_key = ca_key_type = None # pylint: disable=unused-variable
ca_key_e = ca_key_n = None # pylint: disable=unused-variable
# Get the host key blob, F, and signature. # Get the host key blob, F, and signature.
ptr = 0 ptr = 0
hostkey, hostkey_len, ptr = KexDH.__get_bytes(payload, ptr) hostkey, _, ptr = KexDH.__get_bytes(payload, ptr)
# If we are not supposed to parse the host key size (i.e.: it is a type that is of fixed size such as ed25519), then stop here. # If we are not supposed to parse the host key size (i.e.: it is a type that is of fixed size such as ed25519), then stop here.
if not parse_host_key_size: if not parse_host_key_size:
@ -113,23 +117,44 @@ class KexDH: # pragma: nocover
# Now pick apart the host key blob. # Now pick apart the host key blob.
# Get the host key type (i.e.: 'ssh-rsa', 'ssh-ed25519', etc). # Get the host key type (i.e.: 'ssh-rsa', 'ssh-ed25519', etc).
ptr = 0 ptr = 0
self.__hostkey_type, hostkey_type_len, ptr = KexDH.__get_bytes(hostkey, ptr) hostkey_type, _, ptr = KexDH.__get_bytes(hostkey, ptr)
self.__hostkey_type = hostkey_type.decode('ascii')
self.out.d("Parsing host key type: %s" % self.__hostkey_type)
# If this is an RSA certificate, skip over the nonce. # If this is an RSA certificate, skip over the nonce.
if self.__hostkey_type.startswith(b'ssh-rsa-cert-v0'): if self.__hostkey_type.startswith('ssh-rsa-cert-v0'):
nonce, nonce_len, ptr = KexDH.__get_bytes(hostkey, ptr) self.out.d("RSA certificate found, so skipping nonce.")
_, _, ptr = KexDH.__get_bytes(hostkey, ptr) # Read & skip over the nonce.
# The public key exponent. # The public key exponent.
hostkey_e, hostkey_e_len, ptr = KexDH.__get_bytes(hostkey, ptr) hostkey_e, _, ptr = KexDH.__get_bytes(hostkey, ptr)
self.__hostkey_e = int(binascii.hexlify(hostkey_e), 16) # pylint: disable=unused-private-member self.__hostkey_e = int(binascii.hexlify(hostkey_e), 16) # pylint: disable=unused-private-member
# ED25519 moduli are fixed at 32 bytes.
if self.__hostkey_type == 'ssh-ed25519':
self.out.d("%s has a fixed host key modulus of 32." % self.__hostkey_type)
self.__hostkey_n_len = 32
else:
# Here is the modulus size & actual modulus of the host key public key. # Here is the modulus size & actual modulus of the host key public key.
hostkey_n, self.__hostkey_n_len, ptr = KexDH.__get_bytes(hostkey, ptr) hostkey_n, self.__hostkey_n_len, ptr = KexDH.__get_bytes(hostkey, ptr)
self.__hostkey_n = int(binascii.hexlify(hostkey_n), 16) # pylint: disable=unused-private-member self.__hostkey_n = int(binascii.hexlify(hostkey_n), 16) # pylint: disable=unused-private-member
# If this is an RSA certificate, continue parsing to extract the CA # If this is a certificate, continue parsing to extract the CA type and key length. Even though a hostkey type might be 'ssh-ed25519-cert-v01@openssh.com', its CA may still be RSA.
# key. if self.__hostkey_type.startswith('ssh-rsa-cert-v0') or self.__hostkey_type.startswith('ssh-ed25519-cert-v0'):
if self.__hostkey_type.startswith(b'ssh-rsa-cert-v0'): # Get the CA key type and key length.
self.__ca_key_type, self.__ca_n_len = self.__parse_ca_key(hostkey, self.__hostkey_type, ptr)
self.out.d("KexDH.__parse_ca_key(): CA key type: [%s]; CA key length: %u" % (self.__ca_key_type, self.__ca_n_len))
return hostkey
def __parse_ca_key(self, hostkey: bytes, hostkey_type: str, ptr: int) -> Tuple[str, int]:
ca_key_type = ''
ca_key_n_len = 0
# If this is a certificate, continue parsing to extract the CA type and key length. Even though a hostkey type might be 'ssh-ed25519-cert-v01@openssh.com', its CA may still be RSA.
# if hostkey_type.startswith('ssh-rsa-cert-v0') or hostkey_type.startswith('ssh-ed25519-cert-v0'):
self.out.d("Parsing CA for hostkey type [%s]..." % hostkey_type)
# Skip over the serial number. # Skip over the serial number.
ptr += 8 ptr += 8
@ -142,10 +167,10 @@ class KexDH: # pragma: nocover
# Skip the key ID (this is the serial number of the # Skip the key ID (this is the serial number of the
# certificate). # certificate).
key_id, key_id_len, ptr = KexDH.__get_bytes(hostkey, ptr) key_id, key_id_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
# The principles, which are... I don't know what. # The principles, which are... I don't know what.
principles, principles_len, ptr = KexDH.__get_bytes(hostkey, ptr) principles, principles_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
# Skip over the timestamp that this certificate is valid after. # Skip over the timestamp that this certificate is valid after.
ptr += 8 ptr += 8
@ -156,16 +181,16 @@ class KexDH: # pragma: nocover
# TODO: validate the principles, and time range. # TODO: validate the principles, and time range.
# The critical options. # The critical options.
critical_options, critical_options_len, ptr = KexDH.__get_bytes(hostkey, ptr) critical_options, critical_options_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
# Certificate extensions. # Certificate extensions.
extensions, extensions_len, ptr = KexDH.__get_bytes(hostkey, ptr) extensions, extensions_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
# Another nonce. # Another nonce.
nonce, nonce_len, ptr = KexDH.__get_bytes(hostkey, ptr) nonce, nonce_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
# Finally, we get to the CA key. # Finally, we get to the CA key.
ca_key, ca_key_len, ptr = KexDH.__get_bytes(hostkey, ptr) ca_key, ca_key_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
# Last in the host key blob is the CA signature. It isn't # Last in the host key blob is the CA signature. It isn't
# interesting to us, so we won't bother parsing any further. # interesting to us, so we won't bother parsing any further.
@ -173,15 +198,24 @@ class KexDH: # pragma: nocover
ptr = 0 ptr = 0
# 'ssh-rsa', 'rsa-sha2-256', etc. # 'ssh-rsa', 'rsa-sha2-256', etc.
ca_key_type, ca_key_type_len, ptr = KexDH.__get_bytes(ca_key, ptr) ca_key_type_bytes, ca_key_type_len, ptr = KexDH.__get_bytes(ca_key, ptr) # pylint: disable=unused-variable
ca_key_type = ca_key_type_bytes.decode('ascii')
self.out.d("Found CA type: [%s]" % ca_key_type)
# ED25519 CA's don't explicitly include the modulus size in the public key, since its fixed at 32 in all cases.
if ca_key_type == 'ssh-ed25519':
ca_key_n_len = 32
else:
# CA's public key exponent. # CA's public key exponent.
ca_key_e, ca_key_e_len, ptr = KexDH.__get_bytes(ca_key, ptr) ca_key_e, ca_key_e_len, ptr = KexDH.__get_bytes(ca_key, ptr) # pylint: disable=unused-variable
# CA's modulus. Bingo. # CA's modulus. Bingo.
ca_key_n, self.__ca_n_len, ptr = KexDH.__get_bytes(ca_key, ptr) ca_key_n, ca_key_n_len, ptr = KexDH.__get_bytes(ca_key, ptr) # pylint: disable=unused-variable
return hostkey else:
self.out.d("Certificate type %u found; this is not usually valid in the context of a host key! Skipping it..." % cert_type)
return ca_key_type, ca_key_n_len
@staticmethod @staticmethod
def __get_bytes(buf: bytes, ptr: int) -> Tuple[bytes, int, int]: def __get_bytes(buf: bytes, ptr: int) -> Tuple[bytes, int, int]:
@ -202,10 +236,18 @@ class KexDH: # pragma: nocover
size = size - 8 size = size - 8
return size return size
# Returns the hostkey type.
def get_hostkey_type(self) -> str:
return self.__hostkey_type
# Returns the size of the hostkey, in bits. # Returns the size of the hostkey, in bits.
def get_hostkey_size(self) -> int: def get_hostkey_size(self) -> int:
return KexDH.__adjust_key_size(self.__hostkey_n_len) return KexDH.__adjust_key_size(self.__hostkey_n_len)
# Returns the CA type ('ssh-rsa', 'ssh-ed25519', etc).
def get_ca_type(self) -> str:
return self.__ca_key_type
# Returns the size of the CA key, in bits. # Returns the size of the CA key, in bits.
def get_ca_size(self) -> int: def get_ca_size(self) -> int:
return KexDH.__adjust_key_size(self.__ca_n_len) return KexDH.__adjust_key_size(self.__ca_n_len)
@ -217,46 +259,46 @@ class KexDH: # pragma: nocover
class KexGroup1(KexDH): # pragma: nocover class KexGroup1(KexDH): # pragma: nocover
def __init__(self) -> None: def __init__(self, out: 'OutputBuffer') -> None:
# rfc2409: second oakley group # rfc2409: second oakley group
p = int('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff', 16) p = int('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff', 16)
super(KexGroup1, self).__init__('KexGroup1', 'sha1', 2, p) super(KexGroup1, self).__init__(out, 'KexGroup1', 'sha1', 2, p)
class KexGroup14(KexDH): # pragma: nocover class KexGroup14(KexDH): # pragma: nocover
def __init__(self, hash_alg: str) -> None: def __init__(self, out: 'OutputBuffer', hash_alg: str) -> None:
# rfc3526: 2048-bit modp group # rfc3526: 2048-bit modp group
p = int('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff', 16) p = int('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff', 16)
super(KexGroup14, self).__init__('KexGroup14', hash_alg, 2, p) super(KexGroup14, self).__init__(out, 'KexGroup14', hash_alg, 2, p)
class KexGroup14_SHA1(KexGroup14): class KexGroup14_SHA1(KexGroup14):
def __init__(self) -> None: def __init__(self, out: 'OutputBuffer') -> None:
super(KexGroup14_SHA1, self).__init__('sha1') super(KexGroup14_SHA1, self).__init__(out, 'sha1')
class KexGroup14_SHA256(KexGroup14): class KexGroup14_SHA256(KexGroup14):
def __init__(self) -> None: def __init__(self, out: 'OutputBuffer') -> None:
super(KexGroup14_SHA256, self).__init__('sha256') super(KexGroup14_SHA256, self).__init__(out, 'sha256')
class KexGroup16_SHA512(KexDH): class KexGroup16_SHA512(KexDH):
def __init__(self) -> None: def __init__(self, out: 'OutputBuffer') -> None:
# rfc3526: 4096-bit modp group # rfc3526: 4096-bit modp group
p = int('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c934063199ffffffffffffffff', 16) p = int('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c934063199ffffffffffffffff', 16)
super(KexGroup16_SHA512, self).__init__('KexGroup16_SHA512', 'sha512', 2, p) super(KexGroup16_SHA512, self).__init__(out, 'KexGroup16_SHA512', 'sha512', 2, p)
class KexGroup18_SHA512(KexDH): class KexGroup18_SHA512(KexDH):
def __init__(self) -> None: def __init__(self, out: 'OutputBuffer') -> None:
# rfc3526: 8192-bit modp group # rfc3526: 8192-bit modp group
p = int('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dbe115974a3926f12fee5e438777cb6a932df8cd8bec4d073b931ba3bc832b68d9dd300741fa7bf8afc47ed2576f6936ba424663aab639c5ae4f5683423b4742bf1c978238f16cbe39d652de3fdb8befc848ad922222e04a4037c0713eb57a81a23f0c73473fc646cea306b4bcbc8862f8385ddfa9d4b7fa2c087e879683303ed5bdd3a062b3cf5b3a278a66d2a13f83f44f82ddf310ee074ab6a364597e899a0255dc164f31cc50846851df9ab48195ded7ea1b1d510bd7ee74d73faf36bc31ecfa268359046f4eb879f924009438b481c6cd7889a002ed5ee382bc9190da6fc026e479558e4475677e9aa9e3050e2765694dfc81f56e880b96e7160c980dd98edd3dfffffffffffffffff', 16) p = int('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dbe115974a3926f12fee5e438777cb6a932df8cd8bec4d073b931ba3bc832b68d9dd300741fa7bf8afc47ed2576f6936ba424663aab639c5ae4f5683423b4742bf1c978238f16cbe39d652de3fdb8befc848ad922222e04a4037c0713eb57a81a23f0c73473fc646cea306b4bcbc8862f8385ddfa9d4b7fa2c087e879683303ed5bdd3a062b3cf5b3a278a66d2a13f83f44f82ddf310ee074ab6a364597e899a0255dc164f31cc50846851df9ab48195ded7ea1b1d510bd7ee74d73faf36bc31ecfa268359046f4eb879f924009438b481c6cd7889a002ed5ee382bc9190da6fc026e479558e4475677e9aa9e3050e2765694dfc81f56e880b96e7160c980dd98edd3dfffffffffffffffff', 16)
super(KexGroup18_SHA512, self).__init__('KexGroup18_SHA512', 'sha512', 2, p) super(KexGroup18_SHA512, self).__init__(out, 'KexGroup18_SHA512', 'sha512', 2, p)
class KexCurve25519_SHA256(KexDH): class KexCurve25519_SHA256(KexDH):
def __init__(self) -> None: def __init__(self, out: 'OutputBuffer') -> None:
super(KexCurve25519_SHA256, self).__init__('KexCurve25519_SHA256', 'sha256', 0, 0) super(KexCurve25519_SHA256, self).__init__(out, 'KexCurve25519_SHA256', 'sha256', 0, 0)
# To start an ED25519 kex, we simply send a random 256-bit number as the # To start an ED25519 kex, we simply send a random 256-bit number as the
# public key. # public key.
@ -268,8 +310,8 @@ class KexCurve25519_SHA256(KexDH):
class KexNISTP256(KexDH): class KexNISTP256(KexDH):
def __init__(self) -> None: def __init__(self, out: 'OutputBuffer') -> None:
super(KexNISTP256, self).__init__('KexNISTP256', 'sha256', 0, 0) super(KexNISTP256, self).__init__(out, 'KexNISTP256', 'sha256', 0, 0)
# Because the server checks that the value sent here is valid (i.e.: it lies # Because the server checks that the value sent here is valid (i.e.: it lies
# on the curve, among other things), we would have to write a lot of code # on the curve, among other things), we would have to write a lot of code
@ -283,8 +325,8 @@ class KexNISTP256(KexDH):
class KexNISTP384(KexDH): class KexNISTP384(KexDH):
def __init__(self) -> None: def __init__(self, out: 'OutputBuffer') -> None:
super(KexNISTP384, self).__init__('KexNISTP384', 'sha256', 0, 0) super(KexNISTP384, self).__init__(out, 'KexNISTP384', 'sha256', 0, 0)
# See comment for KexNISTP256.send_init(). # See comment for KexNISTP256.send_init().
def send_init(self, s: 'SSH_Socket', init_msg: int = Protocol.MSG_KEXDH_INIT) -> None: def send_init(self, s: 'SSH_Socket', init_msg: int = Protocol.MSG_KEXDH_INIT) -> None:
@ -294,8 +336,8 @@ class KexNISTP384(KexDH):
class KexNISTP521(KexDH): class KexNISTP521(KexDH):
def __init__(self) -> None: def __init__(self, out: 'OutputBuffer') -> None:
super(KexNISTP521, self).__init__('KexNISTP521', 'sha256', 0, 0) super(KexNISTP521, self).__init__(out, 'KexNISTP521', 'sha256', 0, 0)
# See comment for KexNISTP256.send_init(). # See comment for KexNISTP256.send_init().
def send_init(self, s: 'SSH_Socket', init_msg: int = Protocol.MSG_KEXDH_INIT) -> None: def send_init(self, s: 'SSH_Socket', init_msg: int = Protocol.MSG_KEXDH_INIT) -> None:
@ -305,8 +347,8 @@ class KexNISTP521(KexDH):
class KexGroupExchange(KexDH): class KexGroupExchange(KexDH):
def __init__(self, classname: str, hash_alg: str) -> None: def __init__(self, out: 'OutputBuffer', classname: str, hash_alg: str) -> None:
super(KexGroupExchange, self).__init__(classname, hash_alg, 0, 0) super(KexGroupExchange, self).__init__(out, classname, hash_alg, 0, 0)
def send_init(self, s: 'SSH_Socket', init_msg: int = Protocol.MSG_KEXDH_GEX_REQUEST) -> None: def send_init(self, s: 'SSH_Socket', init_msg: int = Protocol.MSG_KEXDH_GEX_REQUEST) -> None:
self.send_init_gex(s) self.send_init_gex(s)
@ -328,13 +370,13 @@ class KexGroupExchange(KexDH):
packet_type, payload = s.read_packet(2) packet_type, payload = s.read_packet(2)
if packet_type not in [Protocol.MSG_KEXDH_GEX_GROUP, Protocol.MSG_DEBUG]: if packet_type not in [Protocol.MSG_KEXDH_GEX_GROUP, Protocol.MSG_DEBUG]:
# TODO: replace with a better exception type. raise KexDHException('Expected MSG_KEXDH_GEX_REPLY (%d), but got %d instead.' % (Protocol.MSG_KEXDH_GEX_REPLY, packet_type))
raise Exception('Expected MSG_KEXDH_GEX_REPLY (%d), but got %d instead.' % (Protocol.MSG_KEXDH_GEX_REPLY, packet_type))
# Skip any & all MSG_DEBUG messages. # Skip any & all MSG_DEBUG messages.
while packet_type == Protocol.MSG_DEBUG: while packet_type == Protocol.MSG_DEBUG:
packet_type, payload = s.read_packet(2) packet_type, payload = s.read_packet(2)
try:
# Parse the modulus (p) and generator (g) values from the server. # Parse the modulus (p) and generator (g) values from the server.
ptr = 0 ptr = 0
p_len = struct.unpack('>I', payload[ptr:ptr + 4])[0] p_len = struct.unpack('>I', payload[ptr:ptr + 4])[0]
@ -348,6 +390,8 @@ class KexGroupExchange(KexDH):
g = int(binascii.hexlify(payload[ptr:ptr + g_len]), 16) g = int(binascii.hexlify(payload[ptr:ptr + g_len]), 16)
ptr += g_len ptr += g_len
except struct.error:
raise KexDHException("Error while parsing modulus and generator during GEX init: %s" % str(traceback.format_exc())) from None
# Now that we got the generator and modulus, perform the DH exchange # Now that we got the generator and modulus, perform the DH exchange
# like usual. # like usual.
@ -356,10 +400,10 @@ class KexGroupExchange(KexDH):
class KexGroupExchange_SHA1(KexGroupExchange): class KexGroupExchange_SHA1(KexGroupExchange):
def __init__(self) -> None: def __init__(self, out: 'OutputBuffer') -> None:
super(KexGroupExchange_SHA1, self).__init__('KexGroupExchange_SHA1', 'sha1') super(KexGroupExchange_SHA1, self).__init__(out, 'KexGroupExchange_SHA1', 'sha1')
class KexGroupExchange_SHA256(KexGroupExchange): class KexGroupExchange_SHA256(KexGroupExchange):
def __init__(self) -> None: def __init__(self, out: 'OutputBuffer') -> None:
super(KexGroupExchange_SHA256, self).__init__('KexGroupExchange_SHA256', 'sha256') super(KexGroupExchange_SHA256, self).__init__(out, 'KexGroupExchange_SHA256', 'sha256')

View File

@ -1,7 +1,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (C) 2020-2021 Joe Testa (jtesta@positronsecurity.com) Copyright (C) 2020-2023 Joe Testa (jtesta@positronsecurity.com)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -21,6 +21,8 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
""" """
import copy
import json
import sys import sys
from typing import Dict, List, Tuple from typing import Dict, List, Tuple
@ -28,62 +30,82 @@ from typing import Optional, Any, Union, cast
from datetime import date from datetime import date
from ssh_audit import exitcodes from ssh_audit import exitcodes
from ssh_audit.ssh2_kex import SSH2_Kex # pylint: disable=unused-import from ssh_audit.banner import Banner
from ssh_audit.banner import Banner # pylint: disable=unused-import from ssh_audit.globals import SNAP_PACKAGE, SNAP_PERMISSIONS_ERROR
from ssh_audit.ssh2_kex import SSH2_Kex
# Validates policy files and performs policy testing # Validates policy files and performs policy testing
class Policy: class Policy:
# Each field maps directly to a private member variable of the Policy class. # Each field maps directly to a private member variable of the Policy class.
BUILTIN_POLICIES: Dict[str, Dict[str, Union[Optional[str], Optional[List[str]], bool, Dict[str, int]]]] = { BUILTIN_POLICIES: Dict[str, Dict[str, Union[Optional[str], Optional[List[str]], bool, Dict[str, Any]]]] = {
# Ubuntu Server policies # Ubuntu Server policies
'Hardened Ubuntu Server 16.04 LTS (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256@libssh.org', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True}, 'Hardened Ubuntu Server 16.04 LTS (version 3)': {'version': '3', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256@libssh.org', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened Ubuntu Server 18.04 LTS (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True}, 'Hardened Ubuntu Server 18.04 LTS (version 3)': {'version': '3', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened Ubuntu Server 20.04 LTS (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-v01@openssh.com': 4096, 'rsa-sha2-512-cert-v01@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True}, 'Hardened Ubuntu Server 20.04 LTS (version 3)': {'version': '3', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened Ubuntu Server 22.04 LTS (version 3)': {'version': '3', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
# Generic OpenSSH Server policies # Generic OpenSSH Server policies
'Hardened OpenSSH Server v7.7 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True}, 'Hardened OpenSSH Server v7.7 (version 3)': {'version': '3', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v7.8 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True}, 'Hardened OpenSSH Server v7.8 (version 3)': {'version': '3', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v7.9 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True}, 'Hardened OpenSSH Server v7.9 (version 3)': {'version': '3', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v8.0 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True}, 'Hardened OpenSSH Server v8.0 (version 3)': {'version': '3', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v8.1 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True}, 'Hardened OpenSSH Server v8.1 (version 3)': {'version': '3', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v8.2 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-v01@openssh.com': 4096, 'rsa-sha2-512-cert-v01@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True}, 'Hardened OpenSSH Server v8.2 (version 3)': {'version': '3', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v8.3 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-v01@openssh.com': 4096, 'rsa-sha2-512-cert-v01@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True}, 'Hardened OpenSSH Server v8.3 (version 3)': {'version': '3', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v8.4 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-v01@openssh.com': 4096, 'rsa-sha2-512-cert-v01@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True}, 'Hardened OpenSSH Server v8.4 (version 3)': {'version': '3', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v8.5 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-v01@openssh.com': 4096, 'rsa-sha2-512-cert-v01@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True}, 'Hardened OpenSSH Server v8.5 (version 3)': {'version': '3', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v8.6 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-v01@openssh.com': 4096, 'rsa-sha2-512-cert-v01@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True}, 'Hardened OpenSSH Server v8.6 (version 3)': {'version': '3', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v8.7 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-v01@openssh.com': 4096, 'rsa-sha2-512-cert-v01@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True}, 'Hardened OpenSSH Server v8.7 (version 3)': {'version': '3', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v8.8 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v8.9 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v9.0 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v9.1 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v9.2 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v9.3 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
'Hardened OpenSSH Server v9.4 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 4096}, 'server_policy': True},
# Ubuntu Client policies # Ubuntu Client policies
'Hardened Ubuntu Client 16.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256', 'rsa-sha2-512'], 'optional_host_keys': None, 'kex': ['curve25519-sha256@libssh.org', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False}, 'Hardened Ubuntu Client 16.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256', 'rsa-sha2-512'], 'optional_host_keys': None, 'kex': ['curve25519-sha256@libssh.org', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
'Hardened Ubuntu Client 18.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256', 'rsa-sha2-512'], 'optional_host_keys': None, 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False}, 'Hardened Ubuntu Client 18.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256', 'rsa-sha2-512'], 'optional_host_keys': None, 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
'Hardened Ubuntu Client 20.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512', 'rsa-sha2-512-cert-v01@openssh.com'], 'optional_host_keys': None, 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False}, 'Hardened Ubuntu Client 20.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512', 'rsa-sha2-512-cert-v01@openssh.com'], 'optional_host_keys': None, 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
'Hardened Ubuntu Client 22.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['sk-ssh-ed25519-cert-v01@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519@openssh.com', 'ssh-ed25519', 'rsa-sha2-512-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512', 'rsa-sha2-256'], 'optional_host_keys': None, 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
} }
WARNING_DEPRECATED_DIRECTIVES = "\nWARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.\n"
def __init__(self, policy_file: Optional[str] = None, policy_data: Optional[str] = None, manual_load: bool = False) -> None: def __init__(self, policy_file: Optional[str] = None, policy_data: Optional[str] = None, manual_load: bool = False, json_output: bool = False) -> None:
self._name: Optional[str] = None self._name: Optional[str] = None
self._version: Optional[str] = None self._version: Optional[str] = None
self._banner: Optional[str] = None self._banner: Optional[str] = None
@ -93,13 +115,18 @@ class Policy:
self._kex: Optional[List[str]] = None self._kex: Optional[List[str]] = None
self._ciphers: Optional[List[str]] = None self._ciphers: Optional[List[str]] = None
self._macs: Optional[List[str]] = None self._macs: Optional[List[str]] = None
self._hostkey_sizes: Optional[Dict[str, int]] = None self._hostkey_sizes: Optional[Dict[str, Dict[str, Union[int, str, bytes]]]] = None
self._cakey_sizes: Optional[Dict[str, int]] = None
self._dh_modulus_sizes: Optional[Dict[str, int]] = None self._dh_modulus_sizes: Optional[Dict[str, int]] = None
self._server_policy = True self._server_policy = True
self._name_and_version: str = '' self._name_and_version: str = ''
# If invoked while JSON output is expected, send warnings to stderr instead of stdout (which would corrupt the JSON output).
if json_output:
self._warning_target = sys.stderr
else:
self._warning_target = sys.stdout
# Ensure that only one mode was specified. # Ensure that only one mode was specified.
num_modes = 0 num_modes = 0
if policy_file is not None: if policy_file is not None:
@ -122,6 +149,13 @@ class Policy:
except FileNotFoundError: except FileNotFoundError:
print("Error: policy file not found: %s" % policy_file) print("Error: policy file not found: %s" % policy_file)
sys.exit(exitcodes.UNKNOWN_ERROR) sys.exit(exitcodes.UNKNOWN_ERROR)
except PermissionError as e:
# If installed as a Snap package, print a more useful message with potential work-arounds.
if SNAP_PACKAGE:
print(SNAP_PERMISSIONS_ERROR)
else:
print("Error: insufficient permissions: %s" % str(e))
sys.exit(exitcodes.UNKNOWN_ERROR)
lines = [] lines = []
if policy_data is not None: if policy_data is not None:
@ -142,7 +176,7 @@ class Policy:
key = key.strip() key = key.strip()
val = val.strip() val = val.strip()
if key not in ['name', 'version', 'banner', 'compressions', 'host keys', 'optional host keys', 'key exchanges', 'ciphers', 'macs', 'client policy'] and not key.startswith('hostkey_size_') and not key.startswith('cakey_size_') and not key.startswith('dh_modulus_size_'): if key not in ['name', 'version', 'banner', 'compressions', 'host keys', 'optional host keys', 'key exchanges', 'ciphers', 'macs', 'client policy', 'host_key_sizes', 'dh_modulus_sizes'] and not key.startswith('hostkey_size_') and not key.startswith('cakey_size_') and not key.startswith('dh_modulus_size_'):
raise ValueError("invalid field found in policy: %s" % line) raise ValueError("invalid field found in policy: %s" % line)
if key in ['name', 'banner']: if key in ['name', 'banner']:
@ -161,8 +195,10 @@ class Policy:
self._name = val self._name = val
elif key == 'banner': elif key == 'banner':
self._banner = val self._banner = val
elif key == 'version': elif key == 'version':
self._version = val self._version = val
elif key in ['compressions', 'host keys', 'optional host keys', 'key exchanges', 'ciphers', 'macs']: elif key in ['compressions', 'host keys', 'optional host keys', 'key exchanges', 'ciphers', 'macs']:
try: try:
algs = val.split(',') algs = val.split(',')
@ -185,21 +221,52 @@ class Policy:
self._ciphers = algs self._ciphers = algs
elif key == 'macs': elif key == 'macs':
self._macs = algs self._macs = algs
elif key.startswith('hostkey_size_'):
elif key.startswith('hostkey_size_'): # Old host key size format.
print(Policy.WARNING_DEPRECATED_DIRECTIVES, file=self._warning_target) # Warn the user that the policy file is using deprecated directives.
hostkey_type = key[13:] hostkey_type = key[13:]
hostkey_size = int(val)
if self._hostkey_sizes is None: if self._hostkey_sizes is None:
self._hostkey_sizes = {} self._hostkey_sizes = {}
self._hostkey_sizes[hostkey_type] = int(val)
elif key.startswith('cakey_size_'): self._hostkey_sizes[hostkey_type] = {'hostkey_size': hostkey_size, 'ca_key_type': '', 'ca_key_size': 0}
cakey_type = key[11:]
if self._cakey_sizes is None: elif key.startswith('cakey_size_'): # Old host key size format.
self._cakey_sizes = {} print(Policy.WARNING_DEPRECATED_DIRECTIVES, file=self._warning_target) # Warn the user that the policy file is using deprecated directives.
self._cakey_sizes[cakey_type] = int(val)
elif key.startswith('dh_modulus_size_'): hostkey_type = key[11:]
dh_modulus_type = key[16:] ca_key_size = int(val)
ca_key_type = 'ssh-ed25519'
if hostkey_type in ['ssh-rsa-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com']:
ca_key_type = 'ssh-rsa'
if self._hostkey_sizes is None:
self._hostkey_sizes = {}
self._hostkey_sizes[hostkey_type] = {'hostkey_size': hostkey_size, 'ca_key_type': ca_key_type, 'ca_key_size': ca_key_size}
elif key == 'host_key_sizes': # New host key size format.
self._hostkey_sizes = json.loads(val)
# Fill in the trimmed fields that were omitted from the policy.
self._normalize_hostkey_sizes()
elif key.startswith('dh_modulus_size_'): # Old DH modulus format.
print(Policy.WARNING_DEPRECATED_DIRECTIVES, file=self._warning_target) # Warn the user that the policy file is using deprecated directives.
dh_type = key[16:]
dh_size = int(val)
if self._dh_modulus_sizes is None: if self._dh_modulus_sizes is None:
self._dh_modulus_sizes = {} self._dh_modulus_sizes = {}
self._dh_modulus_sizes[dh_modulus_type] = int(val)
self._dh_modulus_sizes[dh_type] = dh_size
elif key == 'dh_modulus_sizes': # New DH modulus format.
self._dh_modulus_sizes = json.loads(val)
elif key.startswith('client policy') and val.lower() == 'true': elif key.startswith('client policy') and val.lower() == 'true':
self._server_policy = False self._server_policy = False
@ -221,6 +288,19 @@ class Policy:
errors.append({'mismatched_field': mismatched_field, 'expected_required': expected_required, 'expected_optional': expected_optional, 'actual': actual}) errors.append({'mismatched_field': mismatched_field, 'expected_required': expected_required, 'expected_optional': expected_optional, 'actual': actual})
def _normalize_hostkey_sizes(self) -> None:
'''Normalizes the self._hostkey_sizes structure to ensure all required fields are present.'''
if self._hostkey_sizes is not None:
for host_key_type in self._hostkey_sizes:
if 'ca_key_type' not in self._hostkey_sizes[host_key_type]:
self._hostkey_sizes[host_key_type]['ca_key_type'] = ''
if 'ca_key_size' not in self._hostkey_sizes[host_key_type]:
self._hostkey_sizes[host_key_type]['ca_key_size'] = 0
if 'raw_hostkey_bytes' not in self._hostkey_sizes[host_key_type]:
self._hostkey_sizes[host_key_type]['raw_hostkey_bytes'] = b''
@staticmethod @staticmethod
def create(source: Optional[str], banner: Optional['Banner'], kex: Optional['SSH2_Kex'], client_audit: bool) -> str: def create(source: Optional[str], banner: Optional['Banner'], kex: Optional['SSH2_Kex'], client_audit: bool) -> str:
'''Creates a policy based on a server configuration. Returns a string.''' '''Creates a policy based on a server configuration. Returns a string.'''
@ -231,10 +311,9 @@ class Policy:
kex_algs = None kex_algs = None
ciphers = None ciphers = None
macs = None macs = None
rsa_hostkey_sizes_str = ''
rsa_cakey_sizes_str = ''
dh_modulus_sizes_str = '' dh_modulus_sizes_str = ''
client_policy_str = '' client_policy_str = ''
host_keys_json = ''
if client_audit: if client_audit:
client_policy_str = "\n# Set to true to signify this is a policy for clients, not servers.\nclient policy = true\n" client_policy_str = "\n# Set to true to signify this is a policy for clients, not servers.\nclient policy = true\n"
@ -250,26 +329,23 @@ class Policy:
ciphers = ', '.join(kex.server.encryption) ciphers = ', '.join(kex.server.encryption)
if kex.server.mac is not None: if kex.server.mac is not None:
macs = ', '.join(kex.server.mac) macs = ', '.join(kex.server.mac)
if kex.rsa_key_sizes():
rsa_key_sizes_dict = kex.rsa_key_sizes()
for host_key_type in sorted(rsa_key_sizes_dict):
hostkey_size, cakey_size = rsa_key_sizes_dict[host_key_type]
rsa_hostkey_sizes_str = "%shostkey_size_%s = %d\n" % (rsa_hostkey_sizes_str, host_key_type, hostkey_size) if kex.host_keys():
if cakey_size != -1:
rsa_cakey_sizes_str = "%scakey_size_%s = %d\n" % (rsa_cakey_sizes_str, host_key_type, cakey_size) # Make a deep copy of the host keys dict, then delete all the raw hostkey bytes from the copy.
host_keys_trimmed = copy.deepcopy(kex.host_keys())
for hostkey_alg in host_keys_trimmed:
del host_keys_trimmed[hostkey_alg]['raw_hostkey_bytes']
# Delete the CA signature if any of its fields are empty.
if host_keys_trimmed[hostkey_alg]['ca_key_type'] == '' or host_keys_trimmed[hostkey_alg]['ca_key_size'] == 0:
del host_keys_trimmed[hostkey_alg]['ca_key_type']
del host_keys_trimmed[hostkey_alg]['ca_key_size']
host_keys_json = "\n# Dictionary containing all host key and size information. Optionally contains the certificate authority's signature algorithm ('ca_key_type') and signature length ('ca_key_size'), if any.\nhost_key_sizes = %s\n" % json.dumps(host_keys_trimmed)
if len(rsa_hostkey_sizes_str) > 0:
rsa_hostkey_sizes_str = "\n# RSA host key sizes.\n%s" % rsa_hostkey_sizes_str
if len(rsa_cakey_sizes_str) > 0:
rsa_cakey_sizes_str = "\n# RSA CA key sizes.\n%s" % rsa_cakey_sizes_str
if kex.dh_modulus_sizes(): if kex.dh_modulus_sizes():
dh_modulus_sizes_dict = kex.dh_modulus_sizes() dh_modulus_sizes_str = "\n# Group exchange DH modulus sizes.\ndh_modulus_sizes = %s\n" % json.dumps(kex.dh_modulus_sizes())
for gex_type in sorted(dh_modulus_sizes_dict):
modulus_size, _ = dh_modulus_sizes_dict[gex_type]
dh_modulus_sizes_str = "%sdh_modulus_size_%s = %d\n" % (dh_modulus_sizes_str, gex_type, modulus_size)
if len(dh_modulus_sizes_str) > 0:
dh_modulus_sizes_str = "\n# Group exchange DH modulus sizes.\n%s" % dh_modulus_sizes_str
policy_data = '''# policy_data = '''#
@ -287,7 +363,7 @@ version = 1
# The compression options that must match exactly (order matters). Commented out to ignore by default. # The compression options that must match exactly (order matters). Commented out to ignore by default.
# compressions = %s # compressions = %s
%s%s%s %s%s
# The host key types that must match exactly (order matters). # The host key types that must match exactly (order matters).
host keys = %s host keys = %s
@ -302,7 +378,7 @@ ciphers = %s
# The MACs that must match exactly (order matters). # The MACs that must match exactly (order matters).
macs = %s macs = %s
''' % (source, today, client_policy_str, source, today, banner, compressions, rsa_hostkey_sizes_str, rsa_cakey_sizes_str, dh_modulus_sizes_str, host_keys, kex_algs, ciphers, macs) ''' % (source, today, client_policy_str, source, today, banner, compressions, host_keys_json, dh_modulus_sizes_str, host_keys, kex_algs, ciphers, macs)
return policy_data return policy_data
@ -339,23 +415,29 @@ macs = %s
hostkey_types = list(self._hostkey_sizes.keys()) hostkey_types = list(self._hostkey_sizes.keys())
hostkey_types.sort() # Sorted to make testing output repeatable. hostkey_types.sort() # Sorted to make testing output repeatable.
for hostkey_type in hostkey_types: for hostkey_type in hostkey_types:
expected_hostkey_size = self._hostkey_sizes[hostkey_type] expected_hostkey_size = self._hostkey_sizes[hostkey_type]['hostkey_size']
if hostkey_type in kex.rsa_key_sizes(): server_host_keys = kex.host_keys()
actual_hostkey_size, actual_cakey_size = kex.rsa_key_sizes()[hostkey_type] if hostkey_type in server_host_keys:
actual_hostkey_size = server_host_keys[hostkey_type]['hostkey_size']
if actual_hostkey_size != expected_hostkey_size: if actual_hostkey_size != expected_hostkey_size:
ret = False ret = False
self._append_error(errors, 'RSA host key (%s) sizes' % hostkey_type, [str(expected_hostkey_size)], None, [str(actual_hostkey_size)]) self._append_error(errors, 'Host key (%s) sizes' % hostkey_type, [str(expected_hostkey_size)], None, [str(actual_hostkey_size)])
if self._cakey_sizes is not None: # If we have expected CA signatures set, check them against what the server returned.
hostkey_types = list(self._cakey_sizes.keys()) if self._hostkey_sizes is not None and len(cast(str, self._hostkey_sizes[hostkey_type]['ca_key_type'])) > 0 and cast(int, self._hostkey_sizes[hostkey_type]['ca_key_size']) > 0:
hostkey_types.sort() # Sorted to make testing output repeatable. expected_ca_key_type = cast(str, self._hostkey_sizes[hostkey_type]['ca_key_type'])
for hostkey_type in hostkey_types: expected_ca_key_size = cast(int, self._hostkey_sizes[hostkey_type]['ca_key_size'])
expected_cakey_size = self._cakey_sizes[hostkey_type] actual_ca_key_type = cast(str, server_host_keys[hostkey_type]['ca_key_type'])
if hostkey_type in kex.rsa_key_sizes(): actual_ca_key_size = cast(int, server_host_keys[hostkey_type]['ca_key_size'])
actual_hostkey_size, actual_cakey_size = kex.rsa_key_sizes()[hostkey_type]
if actual_cakey_size != expected_cakey_size: # Ensure that the CA signature type is what's expected (i.e.: the server doesn't have an RSA sig when we're expecting an ED25519 sig).
if actual_ca_key_type != expected_ca_key_type:
ret = False ret = False
self._append_error(errors, 'RSA CA key (%s) sizes' % hostkey_type, [str(expected_cakey_size)], None, [str(actual_cakey_size)]) self._append_error(errors, 'CA signature type', [expected_ca_key_type], None, [actual_ca_key_type])
# Ensure that the actual and expected signature sizes match.
elif actual_ca_key_size != expected_ca_key_size:
ret = False
self._append_error(errors, 'CA signature size (%s)' % actual_ca_key_type, [str(expected_ca_key_size)], None, [str(actual_ca_key_size)])
if kex.kex_algorithms != self._kex: if kex.kex_algorithms != self._kex:
ret = False ret = False
@ -375,7 +457,7 @@ macs = %s
for dh_modulus_type in dh_modulus_types: for dh_modulus_type in dh_modulus_types:
expected_dh_modulus_size = self._dh_modulus_sizes[dh_modulus_type] expected_dh_modulus_size = self._dh_modulus_sizes[dh_modulus_type]
if dh_modulus_type in kex.dh_modulus_sizes(): if dh_modulus_type in kex.dh_modulus_sizes():
actual_dh_modulus_size, _ = kex.dh_modulus_sizes()[dh_modulus_type] actual_dh_modulus_size = kex.dh_modulus_sizes()[dh_modulus_type]
if expected_dh_modulus_size != actual_dh_modulus_size: if expected_dh_modulus_size != actual_dh_modulus_size:
ret = False ret = False
self._append_error(errors, 'Group exchange (%s) modulus sizes' % dh_modulus_type, [str(expected_dh_modulus_size)], None, [str(actual_dh_modulus_size)]) self._append_error(errors, 'Group exchange (%s) modulus sizes' % dh_modulus_type, [str(expected_dh_modulus_size)], None, [str(actual_dh_modulus_size)])
@ -437,12 +519,12 @@ macs = %s
@staticmethod @staticmethod
def load_builtin_policy(policy_name: str) -> Optional['Policy']: def load_builtin_policy(policy_name: str, json_output: bool = False) -> Optional['Policy']:
'''Returns a Policy with the specified built-in policy name loaded, or None if no policy of that name exists.''' '''Returns a Policy with the specified built-in policy name loaded, or None if no policy of that name exists.'''
p = None p = None
if policy_name in Policy.BUILTIN_POLICIES: if policy_name in Policy.BUILTIN_POLICIES:
policy_struct = Policy.BUILTIN_POLICIES[policy_name] policy_struct = Policy.BUILTIN_POLICIES[policy_name]
p = Policy(manual_load=True) p = Policy(manual_load=True, json_output=json_output)
policy_name_without_version = policy_name[0:policy_name.rfind(' (')] policy_name_without_version = policy_name[0:policy_name.rfind(' (')]
p._name = policy_name_without_version # pylint: disable=protected-access p._name = policy_name_without_version # pylint: disable=protected-access
p._version = cast(str, policy_struct['version']) # pylint: disable=protected-access p._version = cast(str, policy_struct['version']) # pylint: disable=protected-access
@ -453,13 +535,14 @@ macs = %s
p._kex = cast(Optional[List[str]], policy_struct['kex']) # pylint: disable=protected-access p._kex = cast(Optional[List[str]], policy_struct['kex']) # pylint: disable=protected-access
p._ciphers = cast(Optional[List[str]], policy_struct['ciphers']) # pylint: disable=protected-access p._ciphers = cast(Optional[List[str]], policy_struct['ciphers']) # pylint: disable=protected-access
p._macs = cast(Optional[List[str]], policy_struct['macs']) # pylint: disable=protected-access p._macs = cast(Optional[List[str]], policy_struct['macs']) # pylint: disable=protected-access
p._hostkey_sizes = cast(Optional[Dict[str, int]], policy_struct['hostkey_sizes']) # pylint: disable=protected-access p._hostkey_sizes = cast(Optional[Dict[str, Dict[str, Union[int, str, bytes]]]], policy_struct['hostkey_sizes']) # pylint: disable=protected-access
p._cakey_sizes = cast(Optional[Dict[str, int]], policy_struct['cakey_sizes']) # pylint: disable=protected-access
p._dh_modulus_sizes = cast(Optional[Dict[str, int]], policy_struct['dh_modulus_sizes']) # pylint: disable=protected-access p._dh_modulus_sizes = cast(Optional[Dict[str, int]], policy_struct['dh_modulus_sizes']) # pylint: disable=protected-access
p._server_policy = cast(bool, policy_struct['server_policy']) # pylint: disable=protected-access p._server_policy = cast(bool, policy_struct['server_policy']) # pylint: disable=protected-access
p._name_and_version = "%s (version %s)" % (p._name, p._version) # pylint: disable=protected-access p._name_and_version = "%s (version %s)" % (p._name, p._version) # pylint: disable=protected-access
# Ensure this struct has all the necessary fields.
p._normalize_hostkey_sizes() # pylint: disable=protected-access
return p return p
@ -488,7 +571,6 @@ macs = %s
ciphers_str = undefined ciphers_str = undefined
macs_str = undefined macs_str = undefined
hostkey_sizes_str = undefined hostkey_sizes_str = undefined
cakey_sizes_str = undefined
dh_modulus_sizes_str = undefined dh_modulus_sizes_str = undefined
@ -513,9 +595,7 @@ macs = %s
macs_str = ', '.join(self._macs) macs_str = ', '.join(self._macs)
if self._hostkey_sizes is not None: if self._hostkey_sizes is not None:
hostkey_sizes_str = str(self._hostkey_sizes) hostkey_sizes_str = str(self._hostkey_sizes)
if self._cakey_sizes is not None:
cakey_sizes_str = str(self._cakey_sizes)
if self._dh_modulus_sizes is not None: if self._dh_modulus_sizes is not None:
dh_modulus_sizes_str = str(self._dh_modulus_sizes) dh_modulus_sizes_str = str(self._dh_modulus_sizes)
return "Name: %s\nVersion: %s\nBanner: %s\nCompressions: %s\nHost Keys: %s\nOptional Host Keys: %s\nKey Exchanges: %s\nCiphers: %s\nMACs: %s\nHost Key Sizes: %s\nCA Key Sizes: %s\nDH Modulus Sizes: %s\nServer Policy: %r" % (name, version, banner, compressions_str, host_keys_str, optional_host_keys_str, kex_str, ciphers_str, macs_str, hostkey_sizes_str, cakey_sizes_str, dh_modulus_sizes_str, self._server_policy) return "Name: %s\nVersion: %s\nBanner: %s\nCompressions: %s\nHost Keys: %s\nOptional Host Keys: %s\nKey Exchanges: %s\nCiphers: %s\nMACs: %s\nHost Key Sizes: %s\nDH Modulus Sizes: %s\nServer Policy: %r" % (name, version, banner, compressions_str, host_keys_str, optional_host_keys_str, kex_str, ciphers_str, macs_str, hostkey_sizes_str, dh_modulus_sizes_str, self._server_policy)

View File

@ -22,6 +22,9 @@
THE SOFTWARE. THE SOFTWARE.
""" """
# pylint: disable=unused-import # pylint: disable=unused-import
import copy
import threading
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401 from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
from typing import Callable, Optional, Union, Any # noqa: F401 from typing import Callable, Optional, Union, Any # noqa: F401
@ -34,7 +37,9 @@ class SSH1_KexDB: # pylint: disable=too-few-public-methods
FAIL_NA_UNSAFE = 'not implemented in OpenSSH (server), unsafe algorithm' FAIL_NA_UNSAFE = 'not implemented in OpenSSH (server), unsafe algorithm'
TEXT_CIPHER_IDEA = 'cipher used by commercial SSH' TEXT_CIPHER_IDEA = 'cipher used by commercial SSH'
ALGORITHMS: Dict[str, Dict[str, List[List[Optional[str]]]]] = { DB_PER_THREAD: Dict[int, Dict[str, Dict[str, List[List[Optional[str]]]]]] = {}
MASTER_DB: Dict[str, Dict[str, List[List[Optional[str]]]]] = {
'key': { 'key': {
'ssh-rsa1': [['1.2.2']], 'ssh-rsa1': [['1.2.2']],
}, },
@ -56,3 +61,24 @@ class SSH1_KexDB: # pylint: disable=too-few-public-methods
'kerberos': [['1.2.2', '3.6'], [FAIL_OPENSSH37_REMOVE]], 'kerberos': [['1.2.2', '3.6'], [FAIL_OPENSSH37_REMOVE]],
} }
} }
@staticmethod
def get_db() -> Dict[str, Dict[str, List[List[Optional[str]]]]]:
'''Returns a copy of the MASTER_DB that is private to the calling thread. This prevents multiple threads from polluting the results of other threads.'''
calling_thread_id = threading.get_ident()
if calling_thread_id not in SSH1_KexDB.DB_PER_THREAD:
SSH1_KexDB.DB_PER_THREAD[calling_thread_id] = copy.deepcopy(SSH1_KexDB.MASTER_DB)
return SSH1_KexDB.DB_PER_THREAD[calling_thread_id]
@staticmethod
def thread_exit() -> None:
'''Deletes the calling thread's copy of the MASTER_DB. This is needed because, in rare circumstances, a terminated thread's ID can be re-used by new threads.'''
calling_thread_id = threading.get_ident()
if calling_thread_id in SSH1_KexDB.DB_PER_THREAD:
del SSH1_KexDB.DB_PER_THREAD[calling_thread_id]

View File

@ -22,17 +22,18 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
""" """
# pylint: disable=unused-import from typing import Dict, List
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401 from typing import Union
from typing import Callable, Optional, Union, Any # noqa: F401
from ssh_audit.ssh2_kexparty import SSH2_KexParty from ssh_audit.outputbuffer import OutputBuffer
from ssh_audit.readbuf import ReadBuf from ssh_audit.readbuf import ReadBuf
from ssh_audit.ssh2_kexparty import SSH2_KexParty
from ssh_audit.writebuf import WriteBuf from ssh_audit.writebuf import WriteBuf
class SSH2_Kex: class SSH2_Kex:
def __init__(self, cookie: bytes, kex_algs: List[str], key_algs: List[str], cli: 'SSH2_KexParty', srv: 'SSH2_KexParty', follows: bool, unused: int = 0) -> None: def __init__(self, outputbuffer: 'OutputBuffer', cookie: bytes, kex_algs: List[str], key_algs: List[str], cli: 'SSH2_KexParty', srv: 'SSH2_KexParty', follows: bool, unused: int = 0) -> None: # pylint: disable=too-many-arguments
self.__outputbuffer = outputbuffer
self.__cookie = cookie self.__cookie = cookie
self.__kex_algs = kex_algs self.__kex_algs = kex_algs
self.__key_algs = key_algs self.__key_algs = key_algs
@ -41,9 +42,8 @@ class SSH2_Kex:
self.__follows = follows self.__follows = follows
self.__unused = unused self.__unused = unused
self.__rsa_key_sizes: Dict[str, Tuple[int, int]] = {} self.__dh_modulus_sizes: Dict[str, int] = {}
self.__dh_modulus_sizes: Dict[str, Tuple[int, int]] = {} self.__host_keys: Dict[str, Dict[str, Union[bytes, str, int]]] = {}
self.__host_keys: Dict[str, bytes] = {}
@property @property
def cookie(self) -> bytes: def cookie(self) -> bytes:
@ -75,22 +75,20 @@ class SSH2_Kex:
def unused(self) -> int: def unused(self) -> int:
return self.__unused return self.__unused
def set_rsa_key_size(self, rsa_type: str, hostkey_size: int, ca_size: int = -1) -> None:
self.__rsa_key_sizes[rsa_type] = (hostkey_size, ca_size)
def rsa_key_sizes(self) -> Dict[str, Tuple[int, int]]:
return self.__rsa_key_sizes
def set_dh_modulus_size(self, gex_alg: str, modulus_size: int) -> None: def set_dh_modulus_size(self, gex_alg: str, modulus_size: int) -> None:
self.__dh_modulus_sizes[gex_alg] = (modulus_size, -1) self.__dh_modulus_sizes[gex_alg] = modulus_size
def dh_modulus_sizes(self) -> Dict[str, Tuple[int, int]]: def dh_modulus_sizes(self) -> Dict[str, int]:
return self.__dh_modulus_sizes return self.__dh_modulus_sizes
def set_host_key(self, key_type: str, hostkey: bytes) -> None: def set_host_key(self, key_type: str, raw_hostkey_bytes: bytes, hostkey_size: int, ca_key_type: str, ca_key_size: int) -> None:
self.__host_keys[key_type] = hostkey
def host_keys(self) -> Dict[str, bytes]: if key_type not in self.__host_keys:
self.__host_keys[key_type] = {'raw_hostkey_bytes': raw_hostkey_bytes, 'hostkey_size': hostkey_size, 'ca_key_type': ca_key_type, 'ca_key_size': ca_key_size}
else: # A host key may only have one CA signature...
self.__outputbuffer.d("WARNING: called SSH2_Kex.set_host_key() multiple times with the same host key type (%s)! Existing info: %r, %r, %r; Duplicate (ignored) info: %r, %r, %r" % (key_type, self.__host_keys[key_type]['hostkey_size'], self.__host_keys[key_type]['ca_key_type'], self.__host_keys[key_type]['ca_key_size'], hostkey_size, ca_key_type, ca_key_size))
def host_keys(self) -> Dict[str, Dict[str, Union[bytes, str, int]]]:
return self.__host_keys return self.__host_keys
def write(self, wbuf: 'WriteBuf') -> None: def write(self, wbuf: 'WriteBuf') -> None:
@ -115,7 +113,7 @@ class SSH2_Kex:
return wbuf.write_flush() return wbuf.write_flush()
@classmethod @classmethod
def parse(cls, payload: bytes) -> 'SSH2_Kex': def parse(cls, outputbuffer: 'OutputBuffer', payload: bytes) -> 'SSH2_Kex':
buf = ReadBuf(payload) buf = ReadBuf(payload)
cookie = buf.read(16) cookie = buf.read(16)
kex_algs = buf.read_list() kex_algs = buf.read_list()
@ -132,5 +130,5 @@ class SSH2_Kex:
unused = buf.read_int() unused = buf.read_int()
cli = SSH2_KexParty(cli_enc, cli_mac, cli_compression, cli_languages) cli = SSH2_KexParty(cli_enc, cli_mac, cli_compression, cli_languages)
srv = SSH2_KexParty(srv_enc, srv_mac, srv_compression, srv_languages) srv = SSH2_KexParty(srv_enc, srv_mac, srv_compression, srv_languages)
kex = cls(cookie, kex_algs, key_algs, cli, srv, follows, unused) kex = cls(outputbuffer, cookie, kex_algs, key_algs, cli, srv, follows, unused)
return kex return kex

View File

@ -1,7 +1,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (C) 2017-2021 Joe Testa (jtesta@positronsecurity.com) Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu) Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
@ -23,68 +23,70 @@
THE SOFTWARE. THE SOFTWARE.
""" """
# pylint: disable=unused-import # pylint: disable=unused-import
import copy
import threading
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401 from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
from typing import Callable, Optional, Union, Any # noqa: F401 from typing import Callable, Optional, Union, Any # noqa: F401
class SSH2_KexDB: # pylint: disable=too-few-public-methods class SSH2_KexDB: # pylint: disable=too-few-public-methods
WARN_OPENSSH74_UNSAFE = 'disabled (in client) since OpenSSH 7.4, unsafe algorithm'
WARN_OPENSSH72_LEGACY = 'disabled (in client) since OpenSSH 7.2, legacy algorithm'
FAIL_OPENSSH70_LEGACY = 'removed since OpenSSH 7.0, legacy algorithm'
FAIL_OPENSSH70_WEAK = 'removed (in server) and disabled (in client) since OpenSSH 7.0, weak algorithm'
FAIL_OPENSSH70_LOGJAM = 'disabled (in client) since OpenSSH 7.0, logjam attack'
INFO_OPENSSH69_CHACHA = 'default cipher since OpenSSH 6.9.'
FAIL_OPENSSH67_UNSAFE = 'removed (in server) since OpenSSH 6.7, unsafe algorithm'
FAIL_OPENSSH61_REMOVE = 'removed since OpenSSH 6.1, removed from specification'
FAIL_OPENSSH31_REMOVE = 'removed since OpenSSH 3.1'
INFO_OPENSSH82_FUTURE_DEPRECATION = 'a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2'
FAIL_DBEAR67_DISABLED = 'disabled since Dropbear SSH 2015.67'
FAIL_DBEAR53_DISABLED = 'disabled since Dropbear SSH 0.53'
FAIL_DEPRECATED_CIPHER = 'deprecated cipher'
FAIL_WEAK_CIPHER = 'using weak cipher'
FAIL_WEAK_ALGORITHM = 'using weak/obsolete algorithm'
FAIL_PLAINTEXT = 'no encryption/integrity'
FAIL_DEPRECATED_MAC = 'deprecated MAC'
FAIL_1024BIT_MODULUS = 'using small 1024-bit modulus' FAIL_1024BIT_MODULUS = 'using small 1024-bit modulus'
FAIL_3DES = 'using broken & deprecated 3DES cipher'
FAIL_BLOWFISH = 'using weak & deprecated Blowfish cipher'
FAIL_CAST = 'using weak & deprecated CAST cipher'
FAIL_DES = 'using broken DES cipher'
FAIL_IDEA = 'using deprecated IDEA cipher'
FAIL_LOGJAM_ATTACK = 'vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)'
FAIL_MD5 = 'using broken MD5 hash algorithm'
FAIL_NSA_BACKDOORED_CURVE = 'using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency'
FAIL_PLAINTEXT = 'no encryption/integrity'
FAIL_RC4 = 'using broken RC4 cipher'
FAIL_RIJNDAEL = 'using deprecated & non-standardized Rijndael cipher'
FAIL_RIPEMD = 'using deprecated RIPEMD hash algorithm'
FAIL_SEED = 'using deprecated SEED cipher'
FAIL_SERPENT = 'using deprecated Serpent cipher'
FAIL_SHA1 = 'using broken SHA-1 hash algorithm'
FAIL_SMALL_ECC_MODULUS = 'using small ECC modulus'
FAIL_UNKNOWN = 'using unknown algorithm'
FAIL_UNPROVEN = 'using unproven algorithm' FAIL_UNPROVEN = 'using unproven algorithm'
FAIL_HASH_WEAK = 'using weak hashing algorithm' FAIL_UNTRUSTED = 'using untrusted algorithm developed in secret by a government entity'
WARN_CURVES_WEAK = 'using weak elliptic curves'
WARN_RNDSIG_KEY = 'using weak random number generator could reveal the key' WARN_2048BIT_MODULUS = '2048-bit modulus only provides 112-bits of symmetric strength'
WARN_HASH_WEAK = 'using weak hashing algorithm'
WARN_CIPHER_MODE = 'using weak cipher mode'
WARN_BLOCK_SIZE = 'using small 64-bit block size' WARN_BLOCK_SIZE = 'using small 64-bit block size'
WARN_CIPHER_WEAK = 'using weak cipher' WARN_CIPHER_MODE = 'using weak cipher mode'
WARN_ENCRYPT_AND_MAC = 'using encrypt-and-MAC mode' WARN_ENCRYPT_AND_MAC = 'using encrypt-and-MAC mode'
WARN_EXPERIMENTAL = 'using experimental algorithm'
WARN_RNDSIG_KEY = 'using weak random number generator could reveal the key'
WARN_TAG_SIZE = 'using small 64-bit tag size' WARN_TAG_SIZE = 'using small 64-bit tag size'
WARN_TAG_SIZE_96 = 'using small 96-bit tag size' WARN_TAG_SIZE_96 = 'using small 96-bit tag size'
WARN_EXPERIMENTAL = 'using experimental algorithm'
WARN_OBSOLETE = 'using obsolete algorithm'
WARN_UNTRUSTED = 'using untrusted algorithm'
ALGORITHMS: Dict[str, Dict[str, List[List[Optional[str]]]]] = { INFO_DEFAULT_OPENSSH_CIPHER = 'default cipher since OpenSSH 6.9'
# Format: 'algorithm_name': [['version_first_appeared_in'], [reason_for_failure1, reason_for_failure2, ...], [warning1, warning2, ...]] INFO_DEFAULT_OPENSSH_KEX = 'default key exchange since OpenSSH 6.4'
INFO_DEPRECATED_IN_OPENSSH88 = 'deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8'
INFO_DISABLED_IN_DBEAR67 = 'disabled in Dropbear SSH 2015.67'
INFO_DISABLED_IN_OPENSSH70 = 'disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0'
INFO_NEVER_IMPLEMENTED_IN_OPENSSH = 'despite the @openssh.com tag, this was never implemented in OpenSSH'
INFO_REMOVED_IN_OPENSSH61 = 'removed since OpenSSH 6.1, removed from specification'
INFO_REMOVED_IN_OPENSSH69 = 'removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9'
INFO_REMOVED_IN_OPENSSH70 = 'removed in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0'
INFO_WITHDRAWN_PQ_ALG = 'the sntrup4591761 algorithm was withdrawn, as it may not provide strong post-quantum security'
# Maintains a dictionary per calling thread that yields its own copy of MASTER_DB. This prevents results from one thread polluting the results of another thread.
DB_PER_THREAD: Dict[int, Dict[str, Dict[str, List[List[Optional[str]]]]]] = {}
MASTER_DB: Dict[str, Dict[str, List[List[Optional[str]]]]] = {
# Format: 'algorithm_name': [['version_first_appeared_in'], [reason_for_failure1, reason_for_failure2, ...], [warning1, warning2, ...], [info1, info2, ...]]
'kex': { 'kex': {
'diffie-hellman-group1-sha1': [['2.3.0,d0.28,l10.2', '6.6', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH67_UNSAFE, FAIL_OPENSSH70_LOGJAM], [WARN_HASH_WEAK]], 'Curve25519SHA256': [[]],
'gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g==': [[], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH67_UNSAFE, FAIL_OPENSSH70_LOGJAM], [WARN_HASH_WEAK]], 'curve25519-sha256': [['7.4,d2018.76'], [], [], [INFO_DEFAULT_OPENSSH_KEX]],
'gss-gex-sha1-eipGX3TCiQSrx573bT1o1Q==': [[], [], [WARN_HASH_WEAK]], 'curve25519-sha256@libssh.org': [['6.4,d2013.62,l10.6.0'], [], [], [INFO_DEFAULT_OPENSSH_KEX]],
'gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==': [[], [], [WARN_HASH_WEAK]], 'curve448-sha512': [[]],
'gss-gex-sha1-': [[], [], [WARN_HASH_WEAK]], 'curve448-sha512@libssh.org': [[]],
'gss-group1-sha1-eipGX3TCiQSrx573bT1o1Q==': [[], [FAIL_1024BIT_MODULUS], [WARN_HASH_WEAK]], 'diffie-hellman-group14-sha1': [['3.9,d0.53,l10.6.0'], [FAIL_SHA1], [WARN_2048BIT_MODULUS]],
'gss-group1-sha1-': [[], [FAIL_1024BIT_MODULUS], [WARN_HASH_WEAK]], 'diffie-hellman-group14-sha224@ssh.com': [[]],
'gss-group14-sha1-': [[], [], [WARN_HASH_WEAK]], 'diffie-hellman-group14-sha256': [['7.3,d2016.73'], [], [WARN_2048BIT_MODULUS]],
'gss-group14-sha1-eipGX3TCiQSrx573bT1o1Q==': [[], [], [WARN_HASH_WEAK]], 'diffie-hellman-group14-sha256@ssh.com': [[], [], [WARN_2048BIT_MODULUS]],
'gss-group14-sha1-toWM5Slw5Ew8Mqkay+al2g==': [[], [], [WARN_HASH_WEAK]],
'gss-group14-sha256-': [[]],
'gss-group14-sha256-toWM5Slw5Ew8Mqkay+al2g==': [[]],
'gss-group15-sha512-': [[]],
'gss-group15-sha512-toWM5Slw5Ew8Mqkay+al2g==': [[]],
'gss-group16-sha512-': [[]],
'gss-nistp256-sha256-': [[], [WARN_CURVES_WEAK]],
'gss-curve25519-sha256-': [[]],
'diffie-hellman-group1-sha256': [[], [FAIL_1024BIT_MODULUS]],
'diffie-hellman-group14-sha1': [['3.9,d0.53,l10.6.0'], [], [WARN_HASH_WEAK]],
'diffie-hellman-group14-sha256': [['7.3,d2016.73']],
'diffie-hellman-group14-sha256@ssh.com': [[]],
'diffie-hellman-group15-sha256': [[]], 'diffie-hellman-group15-sha256': [[]],
'diffie-hellman-group15-sha256@ssh.com': [[]], 'diffie-hellman-group15-sha256@ssh.com': [[]],
'diffie-hellman-group15-sha384@ssh.com': [[]], 'diffie-hellman-group15-sha384@ssh.com': [[]],
@ -94,187 +96,369 @@ class SSH2_KexDB: # pylint: disable=too-few-public-methods
'diffie-hellman-group16-sha512': [['7.3,d2016.73']], 'diffie-hellman-group16-sha512': [['7.3,d2016.73']],
'diffie-hellman-group16-sha512@ssh.com': [[]], 'diffie-hellman-group16-sha512@ssh.com': [[]],
'diffie-hellman-group17-sha512': [[]], 'diffie-hellman-group17-sha512': [[]],
'diffie-hellman_group17-sha512': [[]],
'diffie-hellman-group18-sha512': [['7.3']], 'diffie-hellman-group18-sha512': [['7.3']],
'diffie-hellman-group18-sha512@ssh.com': [[]], 'diffie-hellman-group18-sha512@ssh.com': [[]],
'diffie-hellman-group-exchange-sha1': [['2.3.0', '6.6', None], [FAIL_OPENSSH67_UNSAFE], [WARN_HASH_WEAK]], 'diffie-hellman-group1-sha1': [['2.3.0,d0.28,l10.2', '6.6', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1], [], [INFO_REMOVED_IN_OPENSSH69]],
'diffie-hellman-group1-sha256': [[], [FAIL_1024BIT_MODULUS]],
'diffie-hellman-group-exchange-sha1': [['2.3.0', '6.6', None], [FAIL_SHA1]],
'diffie-hellman-group-exchange-sha224@ssh.com': [[]],
'diffie-hellman-group-exchange-sha256': [['4.4']], 'diffie-hellman-group-exchange-sha256': [['4.4']],
'diffie-hellman-group-exchange-sha256@ssh.com': [[]], 'diffie-hellman-group-exchange-sha256@ssh.com': [[]],
'diffie-hellman-group-exchange-sha384@ssh.com': [[]],
'diffie-hellman-group-exchange-sha512@ssh.com': [[]], 'diffie-hellman-group-exchange-sha512@ssh.com': [[]],
'ecdh-sha2-curve25519': [[], []], 'ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-sha2-nistb233': [[], [WARN_CURVES_WEAK]], 'ecdh-nistp384-kyber-768r3-sha384-d00@openquantumsafe.org': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-sha2-nistb409': [[], [WARN_CURVES_WEAK]], 'ecdh-nistp521-kyber-1024r3-sha512-d00@openquantumsafe.org': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-sha2-nistk163': [[], [WARN_CURVES_WEAK]], 'ecdh-sha2-1.2.840.10045.3.1.1': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # NIST P-192 / secp192r1
'ecdh-sha2-nistk233': [[], [WARN_CURVES_WEAK]], 'ecdh-sha2-1.2.840.10045.3.1.7': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-256 / secp256r1
'ecdh-sha2-nistk283': [[], [WARN_CURVES_WEAK]],
'ecdh-sha2-nistk409': [[], [WARN_CURVES_WEAK]],
'ecdh-sha2-nistp192': [[], [WARN_CURVES_WEAK]],
'ecdh-sha2-nistp224': [[], [WARN_CURVES_WEAK]],
'ecdh-sha2-nistp256': [['5.7,d2013.62,l10.6.0'], [WARN_CURVES_WEAK]],
'ecdh-sha2-nistp384': [['5.7,d2013.62'], [WARN_CURVES_WEAK]],
'ecdh-sha2-nistp521': [['5.7,d2013.62'], [WARN_CURVES_WEAK]],
'ecdh-sha2-nistt571': [[], [WARN_CURVES_WEAK]],
'ecdh-sha2-1.3.132.0.10': [[]], # ECDH over secp256k1 (i.e.: the Bitcoin curve) 'ecdh-sha2-1.3.132.0.10': [[]], # ECDH over secp256k1 (i.e.: the Bitcoin curve)
'curve25519-sha256@libssh.org': [['6.5,d2013.62,l10.6.0']], 'ecdh-sha2-1.3.132.0.16': [[], [FAIL_UNPROVEN]], # sect283k1
'curve25519-sha256': [['7.4,d2018.76']], 'ecdh-sha2-1.3.132.0.1': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]], # sect163k1
'curve448-sha512': [[]], 'ecdh-sha2-1.3.132.0.26': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]], # sect233k1
'kexguess2@matt.ucc.asn.au': [['d2013.57']], 'ecdh-sha2-1.3.132.0.27': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # sect233r1
'rsa1024-sha1': [[], [FAIL_1024BIT_MODULUS], [WARN_HASH_WEAK]], 'ecdh-sha2-1.3.132.0.33': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # NIST P-224 / secp224r1
'rsa2048-sha256': [[]], 'ecdh-sha2-1.3.132.0.34': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-384 / secp384r1
'sntrup4591761x25519-sha512@tinyssh.org': [['8.0', '8.4'], [], [WARN_EXPERIMENTAL]], 'ecdh-sha2-1.3.132.0.35': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-521 / secp521r1
'sntrup761x25519-sha512@openssh.com': [['8.5'], [], [WARN_EXPERIMENTAL]], 'ecdh-sha2-1.3.132.0.36': [[], [FAIL_UNPROVEN]], # sect409k1
'kexAlgoCurve25519SHA256': [[]], 'ecdh-sha2-1.3.132.0.37': [[], [FAIL_NSA_BACKDOORED_CURVE]], # sect409r1
'Curve25519SHA256': [[]], 'ecdh-sha2-1.3.132.0.38': [[], [FAIL_UNPROVEN]], # sect571k1
# Note: the base64 strings, according to draft 6 of RFC5656, is Base64(MD5(DER(OID))). The final RFC5656 dropped the base64 strings in favor of plain OID concatenation, but apparently some SSH servers implement them anyway. See: https://datatracker.ietf.org/doc/html/draft-green-secsh-ecc-06#section-9.2
'ecdh-sha2-4MHB+NBt3AlaSRQ7MnB4cg==': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]], # sect163k1
'ecdh-sha2-5pPrSUQtIaTjUSt5VZNBjg==': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # NIST P-192 / secp192r1
'ecdh-sha2-9UzNcgwTlEnSCECZa7V1mw==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-256 / secp256r1
'ecdh-sha2-brainpoolp256r1@genua.de': [[], [FAIL_UNPROVEN]],
'ecdh-sha2-brainpoolp384r1@genua.de': [[], [FAIL_UNPROVEN]],
'ecdh-sha2-brainpoolp521r1@genua.de': [[], [FAIL_UNPROVEN]],
'ecdh-sha2-curve25519': [[], []],
'ecdh-sha2-D3FefCjYoJ/kfXgAyLddYA==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # sect409r1
'ecdh-sha2-h/SsxnLCtRBh7I9ATyeB3A==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-521 / secp521r1
'ecdh-sha2-m/FtSAmrV4j/Wy6RVUaK7A==': [[], [FAIL_UNPROVEN]], # sect409k1
'ecdh-sha2-mNVwCXAoS1HGmHpLvBC94w==': [[], [FAIL_UNPROVEN]], # sect571k1
'ecdh-sha2-nistb233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]],
'ecdh-sha2-nistb409': [[], [FAIL_UNPROVEN]],
'ecdh-sha2-nistk163': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]],
'ecdh-sha2-nistk233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]],
'ecdh-sha2-nistk283': [[], [FAIL_UNPROVEN]],
'ecdh-sha2-nistk409': [[], [FAIL_UNPROVEN]],
'ecdh-sha2-nistp192': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-sha2-nistp224': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-sha2-nistp256': [['5.7,d2013.62,l10.6.0'], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-sha2-nistp384': [['5.7,d2013.62'], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-sha2-nistp521': [['5.7,d2013.62'], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-sha2-nistt571': [[], [FAIL_UNPROVEN]],
'ecdh-sha2-qCbG5Cn/jjsZ7nBeR7EnOA==': [[FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # sect233r1
'ecdh-sha2-qcFQaMAMGhTziMT0z+Tuzw==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-384 / secp384r1
'ecdh-sha2-VqBg4QRPjxx1EXZdV0GdWQ==': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_SMALL_ECC_MODULUS]], # NIST P-224 / secp224r1
'ecdh-sha2-wiRIU8TKjMZ418sMqlqtvQ==': [[], [FAIL_UNPROVEN]], # sect283k1
'ecdh-sha2-zD/b3hu/71952ArpUG4OjQ==': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]], # sect233k1
'ecmqv-sha2': [[], [FAIL_UNPROVEN]],
'ext-info-c': [[]], # Extension negotiation (RFC 8308) 'ext-info-c': [[]], # Extension negotiation (RFC 8308)
'ext-info-s': [[]], # Extension negotiation (RFC 8308) 'ext-info-s': [[]], # Extension negotiation (RFC 8308)
# The GSS kex algorithms get special wildcard handling, since they include variable base64 data after their standard prefixes.
'gss-13.3.132.0.10-sha256-*': [[], [FAIL_UNKNOWN]],
'gss-curve25519-sha256-*': [[]],
'gss-curve448-sha512-*': [[]],
'gss-gex-sha1-*': [[], [FAIL_SHA1]],
'gss-gex-sha256-*': [[]],
'gss-group14-sha1-*': [[], [FAIL_SHA1], [WARN_2048BIT_MODULUS]],
'gss-group14-sha256-*': [[], [], [WARN_2048BIT_MODULUS]],
'gss-group15-sha512-*': [[]],
'gss-group16-sha512-*': [[]],
'gss-group17-sha512-*': [[]],
'gss-group18-sha512-*': [[]],
'gss-group1-sha1-*': [[], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1]],
'gss-nistp256-sha256-*': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'gss-nistp384-sha256-*': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'gss-nistp521-sha512-*': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'kexAlgoCurve25519SHA256': [[]],
'kexAlgoDH14SHA1': [[], [FAIL_SHA1], [WARN_2048BIT_MODULUS]],
'kexAlgoDH1SHA1': [[], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1]],
'kexAlgoECDH256': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'kexAlgoECDH384': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'kexAlgoECDH521': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'kexguess2@matt.ucc.asn.au': [['d2013.57']],
'm383-sha384@libassh.org': [[], [FAIL_UNPROVEN]],
'm511-sha512@libassh.org': [[], [FAIL_UNPROVEN]],
'rsa1024-sha1': [[], [FAIL_1024BIT_MODULUS, FAIL_SHA1]],
'rsa2048-sha256': [[], [], [WARN_2048BIT_MODULUS]],
'sm2kep-sha2-nistp256': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_UNTRUSTED]],
'sntrup4591761x25519-sha512@tinyssh.org': [['8.0', '8.4'], [], [WARN_EXPERIMENTAL], [INFO_WITHDRAWN_PQ_ALG]],
'sntrup761x25519-sha512@openssh.com': [['8.5'], [], []],
'x25519-kyber-512r3-sha256-d00@amazon.com': [[]],
'x25519-kyber512-sha512@aws.amazon.com': [[]],
}, },
'key': { 'key': {
'ssh-rsa1': [[], [FAIL_WEAK_ALGORITHM]], 'dsa2048-sha224@libassh.org': [[], [FAIL_UNPROVEN], [WARN_2048BIT_MODULUS]],
'rsa-sha2-256': [['7.2']], 'dsa2048-sha256@libassh.org': [[], [FAIL_UNPROVEN], [WARN_2048BIT_MODULUS]],
'rsa-sha2-512': [['7.2']], 'dsa3072-sha256@libassh.org': [[], [FAIL_UNPROVEN]],
'ssh-ed25519': [['6.5,l10.7.0']], 'ecdsa-sha2-1.3.132.0.10-cert-v01@openssh.com': [[], [FAIL_UNKNOWN]],
'ssh-ed25519-cert-v01@openssh.com': [['6.5']],
'ssh-rsa': [['2.5.0,d0.28,l10.2'], [FAIL_HASH_WEAK], [], [INFO_OPENSSH82_FUTURE_DEPRECATION]],
'ssh-dss': [['2.1.0,d0.28,l10.2', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH70_WEAK], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp256': [['5.7,d2013.62,l10.6.4'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp384': [['5.7,d2013.62,l10.6.4'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp521': [['5.7,d2013.62,l10.6.4'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-1.3.132.0.10': [[], [], [WARN_RNDSIG_KEY]], # ECDSA over secp256k1 (i.e.: the Bitcoin curve) 'ecdsa-sha2-1.3.132.0.10': [[], [], [WARN_RNDSIG_KEY]], # ECDSA over secp256k1 (i.e.: the Bitcoin curve)
'x509v3-sign-dss': [[], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH70_WEAK], [WARN_RNDSIG_KEY]], 'ecdsa-sha2-curve25519': [[], [], [WARN_RNDSIG_KEY]], # ECDSA with Curve25519? Bizarre...
'x509v3-sign-rsa': [[], [FAIL_HASH_WEAK], [], [INFO_OPENSSH82_FUTURE_DEPRECATION]], 'ecdsa-sha2-nistb233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_RNDSIG_KEY]],
'x509v3-sign-rsa-sha256@ssh.com': [[]], 'ecdsa-sha2-nistb409': [[], [FAIL_UNPROVEN], [WARN_RNDSIG_KEY]],
'x509v3-ssh-dss': [[], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH70_WEAK], [WARN_RNDSIG_KEY]], 'ecdsa-sha2-nistk163': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_RNDSIG_KEY]],
'x509v3-ssh-rsa': [[], [FAIL_HASH_WEAK], [], [INFO_OPENSSH82_FUTURE_DEPRECATION]], 'ecdsa-sha2-nistk233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_RNDSIG_KEY]],
'ssh-rsa-cert-v00@openssh.com': [['5.4', '6.9'], [FAIL_OPENSSH70_LEGACY, FAIL_HASH_WEAK], [], [INFO_OPENSSH82_FUTURE_DEPRECATION]], 'ecdsa-sha2-nistk283': [[], [FAIL_UNPROVEN], [WARN_RNDSIG_KEY]],
'ssh-dss-cert-v00@openssh.com': [['5.4', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH70_LEGACY], [WARN_RNDSIG_KEY]], 'ecdsa-sha2-nistk409': [[], [FAIL_UNPROVEN], [WARN_RNDSIG_KEY]],
'ssh-rsa-cert-v01@openssh.com': [['5.6'], [FAIL_HASH_WEAK], [], [INFO_OPENSSH82_FUTURE_DEPRECATION]], 'ecdsa-sha2-nistp224': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_SMALL_ECC_MODULUS], [WARN_RNDSIG_KEY]],
'ssh-dss-cert-v01@openssh.com': [['5.6', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH70_WEAK], [WARN_RNDSIG_KEY]], 'ecdsa-sha2-nistp192': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_SMALL_ECC_MODULUS], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp256-cert-v01@openssh.com': [['5.7'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]], 'ecdsa-sha2-nistp256': [['5.7,d2013.62,l10.6.4'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp384-cert-v01@openssh.com': [['5.7'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]], 'ecdsa-sha2-nistp256-cert-v01@openssh.com': [['5.7'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp521-cert-v01@openssh.com': [['5.7'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]], 'ecdsa-sha2-nistp384': [['5.7,d2013.62,l10.6.4'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp384-cert-v01@openssh.com': [['5.7'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp521': [['5.7,d2013.62,l10.6.4'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp521-cert-v01@openssh.com': [['5.7'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistt571': [[], [FAIL_UNPROVEN], [WARN_RNDSIG_KEY]],
'eddsa-e382-shake256@libassh.org': [[], [FAIL_UNPROVEN]],
'eddsa-e521-shake256@libassh.org': [[], [FAIL_UNPROVEN]],
'null': [[], [FAIL_PLAINTEXT]],
'pgp-sign-dss': [[], [FAIL_1024BIT_MODULUS]],
'pgp-sign-rsa': [[], [FAIL_1024BIT_MODULUS]],
'rsa-sha2-256': [['7.2']],
'rsa-sha2-256-cert-v01@openssh.com': [['7.8']], 'rsa-sha2-256-cert-v01@openssh.com': [['7.8']],
'rsa-sha2-512': [['7.2']],
'rsa-sha2-512-cert-v01@openssh.com': [['7.8']], 'rsa-sha2-512-cert-v01@openssh.com': [['7.8']],
'ssh-rsa-sha256@ssh.com': [[]], 'sk-ecdsa-sha2-nistp256-cert-v01@openssh.com': [['8.2'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'ssh-dss-sha256@ssh.com': [[], [FAIL_1024BIT_MODULUS]], 'sk-ecdsa-sha2-nistp256@openssh.com': [['8.2'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'sk-ecdsa-sha2-nistp256-cert-v01@openssh.com': [['8.2'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]],
'sk-ecdsa-sha2-nistp256@openssh.com': [['8.2'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]],
'sk-ssh-ed25519-cert-v01@openssh.com': [['8.2']], 'sk-ssh-ed25519-cert-v01@openssh.com': [['8.2']],
'sk-ssh-ed25519@openssh.com': [['8.2']], 'sk-ssh-ed25519@openssh.com': [['8.2']],
'ssh-gost2001': [[], [], [WARN_UNTRUSTED]],
'ssh-gost2012-256': [[], [], [WARN_UNTRUSTED]],
'ssh-gost2012-512': [[], [], [WARN_UNTRUSTED]],
'spi-sign-rsa': [[]], 'spi-sign-rsa': [[]],
'spki-sign-dss': [[], [FAIL_1024BIT_MODULUS]],
'spki-sign-rsa': [[], [FAIL_1024BIT_MODULUS]],
'ssh-dsa': [[], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY]],
'ssh-dss': [['2.1.0,d0.28,l10.2', '6.9'], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY], [INFO_DISABLED_IN_OPENSSH70]],
'ssh-dss-cert-v00@openssh.com': [['5.4', '6.9'], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY], [INFO_DISABLED_IN_OPENSSH70]],
'ssh-dss-cert-v01@openssh.com': [['5.6', '6.9'], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY]],
'ssh-dss-sha224@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'ssh-dss-sha256@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'ssh-dss-sha384@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'ssh-dss-sha512@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'ssh-ed25519': [['6.5,l10.7.0']],
'ssh-ed25519-cert-v01@openssh.com': [['6.5']],
'ssh-ed448': [[]], 'ssh-ed448': [[]],
'x509v3-ecdsa-sha2-nistp256': [[], [WARN_CURVES_WEAK]], 'ssh-ed448-cert-v01@openssh.com': [[], [], [], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]],
'x509v3-ecdsa-sha2-nistp384': [[], [WARN_CURVES_WEAK]], 'ssh-gost2001': [[], [FAIL_UNTRUSTED]],
'x509v3-ecdsa-sha2-nistp521': [[], [WARN_CURVES_WEAK]], 'ssh-gost2012-256': [[], [FAIL_UNTRUSTED]],
'ssh-gost2012-512': [[], [FAIL_UNTRUSTED]],
'ssh-rsa1': [[], [FAIL_SHA1]],
'ssh-rsa': [['2.5.0,d0.28,l10.2'], [FAIL_SHA1], [], [INFO_DEPRECATED_IN_OPENSSH88]],
'ssh-rsa-cert-v00@openssh.com': [['5.4', '6.9'], [FAIL_SHA1], [], [INFO_REMOVED_IN_OPENSSH70]],
'ssh-rsa-cert-v01@openssh.com': [['5.6'], [FAIL_SHA1], [], [INFO_DEPRECATED_IN_OPENSSH88]],
'ssh-rsa-sha224@ssh.com': [[]],
'ssh-rsa-sha2-256': [[]],
'ssh-rsa-sha2-512': [[]],
'ssh-rsa-sha256@ssh.com': [[]],
'ssh-rsa-sha384@ssh.com': [[]],
'ssh-rsa-sha512@ssh.com': [[]],
'ssh-xmss-cert-v01@openssh.com': [['7.7'], [WARN_EXPERIMENTAL]],
'ssh-xmss@openssh.com': [['7.7'], [WARN_EXPERIMENTAL]],
'webauthn-sk-ecdsa-sha2-nistp256@openssh.com': [['8.3'], [FAIL_NSA_BACKDOORED_CURVE]],
'x509v3-ecdsa-sha2-1.3.132.0.10': [[], [FAIL_UNKNOWN]],
'x509v3-ecdsa-sha2-nistp256': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'x509v3-ecdsa-sha2-nistp384': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'x509v3-ecdsa-sha2-nistp521': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'x509v3-rsa2048-sha256': [[]], 'x509v3-rsa2048-sha256': [[]],
'x509v3-sign-dss': [[], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY]],
'x509v3-sign-dss-sha1': [[], [FAIL_1024BIT_MODULUS, FAIL_SHA1]],
'x509v3-sign-dss-sha224@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'x509v3-sign-dss-sha256@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'x509v3-sign-dss-sha384@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'x509v3-sign-dss-sha512@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'x509v3-sign-rsa': [[], [FAIL_SHA1]],
'x509v3-sign-rsa-sha1': [[], [FAIL_SHA1]],
'x509v3-sign-rsa-sha224@ssh.com': [[]],
'x509v3-sign-rsa-sha256': [[]],
'x509v3-sign-rsa-sha256@ssh.com': [[]],
'x509v3-sign-rsa-sha384@ssh.com': [[]],
'x509v3-sign-rsa-sha512@ssh.com': [[]],
'x509v3-ssh-dss': [[], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY]],
'x509v3-ssh-rsa': [[], [FAIL_SHA1], [], [INFO_DEPRECATED_IN_OPENSSH88]],
}, },
'enc': { 'enc': {
'none': [['1.2.2,d2013.56,l10.2'], [FAIL_PLAINTEXT]], '3des-cbc': [['1.2.2,d0.28,l10.2', '6.6', None], [FAIL_3DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'des': [[], [FAIL_WEAK_CIPHER], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]], '3des-cfb': [[], [FAIL_3DES], [WARN_CIPHER_MODE]],
'des-cbc': [[], [FAIL_WEAK_CIPHER], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]], '3des-ctr': [['d0.52'], [FAIL_3DES]],
'des-cbc@ssh.com': [[], [FAIL_WEAK_CIPHER], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]], '3des-ecb': [[], [FAIL_3DES], [WARN_CIPHER_MODE]],
'des-cbc-ssh1': [[], [FAIL_WEAK_CIPHER], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]], '3des': [[], [FAIL_3DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'3des': [[], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH74_UNSAFE, WARN_CIPHER_WEAK, WARN_CIPHER_MODE, WARN_BLOCK_SIZE]], '3des-ofb': [[], [FAIL_3DES], [WARN_CIPHER_MODE]],
'3des-cbc': [['1.2.2,d0.28,l10.2', '6.6', None], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH74_UNSAFE, WARN_CIPHER_WEAK, WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'3des-ctr': [['d0.52'], [FAIL_WEAK_CIPHER]],
'blowfish': [[], [FAIL_WEAK_ALGORITHM], [WARN_BLOCK_SIZE]],
'blowfish-cbc': [['1.2.2,d0.28,l10.2', '6.6,d0.52', '7.1,d0.52'], [FAIL_OPENSSH67_UNSAFE, FAIL_DBEAR53_DISABLED], [WARN_OPENSSH72_LEGACY, WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'blowfish-ctr': [[], [FAIL_OPENSSH67_UNSAFE, FAIL_DBEAR53_DISABLED], [WARN_OPENSSH72_LEGACY, WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'twofish-cbc': [['d0.28', 'd2014.66'], [FAIL_DBEAR67_DISABLED], [WARN_CIPHER_MODE]],
'twofish128-cbc': [['d0.47', 'd2014.66'], [FAIL_DBEAR67_DISABLED], [WARN_CIPHER_MODE]],
'twofish192-cbc': [[], [], [WARN_CIPHER_MODE]],
'twofish256-cbc': [['d0.47', 'd2014.66'], [FAIL_DBEAR67_DISABLED], [WARN_CIPHER_MODE]],
'twofish-ctr': [[]],
'twofish128-ctr': [['d2015.68']],
'twofish192-ctr': [[]],
'twofish256-ctr': [['d2015.68']],
'serpent128-cbc': [[], [FAIL_DEPRECATED_CIPHER], [WARN_CIPHER_MODE]],
'serpent192-cbc': [[], [FAIL_DEPRECATED_CIPHER], [WARN_CIPHER_MODE]],
'serpent256-cbc': [[], [FAIL_DEPRECATED_CIPHER], [WARN_CIPHER_MODE]],
'serpent128-ctr': [[], [FAIL_DEPRECATED_CIPHER]],
'serpent192-ctr': [[], [FAIL_DEPRECATED_CIPHER]],
'serpent256-ctr': [[], [FAIL_DEPRECATED_CIPHER]],
'idea-cbc': [[], [FAIL_DEPRECATED_CIPHER], [WARN_CIPHER_MODE]],
'idea-ctr': [[], [FAIL_DEPRECATED_CIPHER]],
'cast128-ctr': [[], [FAIL_DEPRECATED_CIPHER]],
'cast128-cbc': [['2.1.0', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'arcfour': [['2.1.0', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_CIPHER_WEAK]],
'arcfour128': [['4.2', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_CIPHER_WEAK]],
'arcfour256': [['4.2', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_CIPHER_WEAK]],
'aes128-cbc': [['2.3.0,d0.28,l10.2', '6.6', None], [FAIL_OPENSSH67_UNSAFE], [WARN_CIPHER_MODE]],
'aes192-cbc': [['2.3.0,l10.2', '6.6', None], [FAIL_OPENSSH67_UNSAFE], [WARN_CIPHER_MODE]],
'aes256-cbc': [['2.3.0,d0.47,l10.2', '6.6', None], [FAIL_OPENSSH67_UNSAFE], [WARN_CIPHER_MODE]],
'rijndael128-cbc': [['2.3.0', '3.0.2'], [FAIL_OPENSSH31_REMOVE], [WARN_CIPHER_MODE]],
'rijndael192-cbc': [['2.3.0', '3.0.2'], [FAIL_OPENSSH31_REMOVE], [WARN_CIPHER_MODE]],
'rijndael256-cbc': [['2.3.0', '3.0.2'], [FAIL_OPENSSH31_REMOVE], [WARN_CIPHER_MODE]],
'rijndael-cbc@lysator.liu.se': [['2.3.0', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_CIPHER_MODE]],
'aes128-ctr': [['3.7,d0.52,l10.4.1']],
'aes192-ctr': [['3.7,l10.4.1']],
'aes256-ctr': [['3.7,d0.52,l10.4.1']],
'aes128-gcm': [[]],
'aes256-gcm': [[]],
'AEAD_AES_128_GCM': [[]], 'AEAD_AES_128_GCM': [[]],
'AEAD_AES_256_GCM': [[]], 'AEAD_AES_256_GCM': [[]],
'aes128-cbc': [['2.3.0,d0.28,l10.2', '6.6', None], [], [WARN_CIPHER_MODE]],
'aes128-ctr': [['3.7,d0.52,l10.4.1']],
'aes128-gcm': [[]],
'aes128-gcm@openssh.com': [['6.2']], 'aes128-gcm@openssh.com': [['6.2']],
'aes192-cbc': [['2.3.0,l10.2', '6.6', None], [], [WARN_CIPHER_MODE]],
'aes192-ctr': [['3.7,l10.4.1']],
'aes192-gcm@openssh.com': [[], [], [], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]],
'aes256-cbc': [['2.3.0,d0.47,l10.2', '6.6', None], [], [WARN_CIPHER_MODE]],
'aes256-ctr': [['3.7,d0.52,l10.4.1']],
'aes256-gcm': [[]],
'aes256-gcm@openssh.com': [['6.2']], 'aes256-gcm@openssh.com': [['6.2']],
'chacha20-poly1305': [[], [], [], [INFO_OPENSSH69_CHACHA]], 'arcfour128': [['4.2', '6.6', '7.1'], [FAIL_RC4]],
'chacha20-poly1305@openssh.com': [['6.5'], [], [], [INFO_OPENSSH69_CHACHA]], 'arcfour': [['2.1.0', '6.6', '7.1'], [FAIL_RC4]],
'arcfour256': [['4.2', '6.6', '7.1'], [FAIL_RC4]],
'blowfish-cbc': [['1.2.2,d0.28,l10.2', '6.6,d0.52', '7.1,d0.52'], [FAIL_BLOWFISH], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'blowfish-cfb': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE]],
'blowfish-ctr': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'blowfish-ecb': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE]],
'blowfish': [[], [FAIL_BLOWFISH], [WARN_BLOCK_SIZE]],
'blowfish-ofb': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE]],
'camellia128-cbc@openssh.org': [[], [], [WARN_CIPHER_MODE]],
'camellia128-cbc': [[], [], [WARN_CIPHER_MODE]], 'camellia128-cbc': [[], [], [WARN_CIPHER_MODE]],
'camellia128-ctr': [[]], 'camellia128-ctr': [[]],
'camellia128-ctr@openssh.org': [[]],
'camellia192-cbc@openssh.org': [[], [], [WARN_CIPHER_MODE]],
'camellia192-cbc': [[], [], [WARN_CIPHER_MODE]], 'camellia192-cbc': [[], [], [WARN_CIPHER_MODE]],
'camellia192-ctr': [[]], 'camellia192-ctr': [[]],
'camellia192-ctr@openssh.org': [[]],
'camellia256-cbc@openssh.org': [[], [], [WARN_CIPHER_MODE]],
'camellia256-cbc': [[], [], [WARN_CIPHER_MODE]], 'camellia256-cbc': [[], [], [WARN_CIPHER_MODE]],
'camellia256-ctr': [[]], 'camellia256-ctr': [[]],
'camellia256-ctr@openssh.org': [[]],
'cast128-12-cbc@ssh.com': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'cast128-cbc': [['2.1.0', '6.6', '7.1'], [FAIL_CAST], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'cast128-12-cbc': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'cast128-12-cfb': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'cast128-12-ecb': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'cast128-12-ofb': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'cast128-cfb': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'cast128-ctr': [[], [FAIL_CAST]],
'cast128-ecb': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'cast128-ofb': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'chacha20-poly1305': [[], [], [], [INFO_DEFAULT_OPENSSH_CIPHER]],
'chacha20-poly1305@openssh.com': [['6.5'], [], [], [INFO_DEFAULT_OPENSSH_CIPHER]],
'crypticore128@ssh.com': [[], [FAIL_UNPROVEN]], 'crypticore128@ssh.com': [[], [FAIL_UNPROVEN]],
'seed-cbc@ssh.com': [[], [], [WARN_OBSOLETE, WARN_CIPHER_MODE]], 'des-cbc': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'des-cfb': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'des-ecb': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'des-ofb': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'des-cbc-ssh1': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'des-cbc@ssh.com': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'des': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'idea-cbc': [[], [FAIL_IDEA], [WARN_CIPHER_MODE]],
'idea-cfb': [[], [FAIL_IDEA], [WARN_CIPHER_MODE]],
'idea-ctr': [[], [FAIL_IDEA]],
'idea-ecb': [[], [FAIL_IDEA], [WARN_CIPHER_MODE]],
'idea-ofb': [[], [FAIL_IDEA], [WARN_CIPHER_MODE]],
'none': [['1.2.2,d2013.56,l10.2'], [FAIL_PLAINTEXT]],
'rijndael128-cbc': [['2.3.0', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70]],
'rijndael192-cbc': [['2.3.0', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70]],
'rijndael256-cbc': [['2.3.0', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70]],
'rijndael-cbc@lysator.liu.se': [['2.3.0', '6.6', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70]],
'rijndael-cbc@ssh.com': [[], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE]],
'seed-cbc@ssh.com': [[], [FAIL_SEED], [WARN_CIPHER_MODE]],
'seed-ctr@ssh.com': [[], [FAIL_SEED]],
'serpent128-cbc': [[], [FAIL_SERPENT], [WARN_CIPHER_MODE]],
'serpent128-ctr': [[], [FAIL_SERPENT]],
'serpent128-gcm@libassh.org': [[], [FAIL_SERPENT]],
'serpent192-cbc': [[], [FAIL_SERPENT], [WARN_CIPHER_MODE]],
'serpent192-ctr': [[], [FAIL_SERPENT]],
'serpent256-cbc': [[], [FAIL_SERPENT], [WARN_CIPHER_MODE]],
'serpent256-ctr': [[], [FAIL_SERPENT]],
'serpent256-gcm@libassh.org': [[], [FAIL_SERPENT]],
'twofish128-cbc': [['d0.47', 'd2014.66'], [], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_DBEAR67]],
'twofish128-ctr': [['d2015.68']],
'twofish128-gcm@libassh.org': [[]],
'twofish192-cbc': [[], [], [WARN_CIPHER_MODE]],
'twofish192-ctr': [[]],
'twofish256-cbc': [['d0.47', 'd2014.66'], [], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_DBEAR67]],
'twofish256-ctr': [['d2015.68']],
'twofish256-gcm@libassh.org': [[]],
'twofish-cbc': [['d0.28', 'd2014.66'], [], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_DBEAR67]],
'twofish-cfb': [[], [], [WARN_CIPHER_MODE]],
'twofish-ctr': [[]],
'twofish-ecb': [[], [], [WARN_CIPHER_MODE]],
'twofish-ofb': [[], [], [WARN_CIPHER_MODE]],
}, },
'mac': { 'mac': {
'none': [['d2013.56'], [FAIL_PLAINTEXT]], 'AEAD_AES_128_GCM': [[]],
'hmac-sha1': [['2.1.0,d0.28,l10.2'], [], [WARN_ENCRYPT_AND_MAC, WARN_HASH_WEAK]], 'AEAD_AES_256_GCM': [[]],
'hmac-sha1-96': [['2.5.0,d0.47', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC, WARN_HASH_WEAK]], 'aes128-gcm': [[]],
'hmac-sha2-56': [[], [], [WARN_TAG_SIZE, WARN_ENCRYPT_AND_MAC]], 'aes256-gcm': [[]],
'cbcmac-3des': [[], [FAIL_UNPROVEN, FAIL_3DES]],
'cbcmac-aes': [[], [FAIL_UNPROVEN]],
'cbcmac-blowfish': [[], [FAIL_UNPROVEN, FAIL_BLOWFISH]],
'cbcmac-des': [[], [FAIL_UNPROVEN, FAIL_DES]],
'cbcmac-rijndael': [[], [FAIL_UNPROVEN, FAIL_RIJNDAEL]],
'cbcmac-twofish': [[], [FAIL_UNPROVEN]],
'chacha20-poly1305@openssh.com': [[], [], [], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]], # Despite the @openssh.com tag, this was never shipped as a MAC in OpenSSH (only as a cipher); it is only implemented as a MAC in Syncplify.
'crypticore-mac@ssh.com': [[], [FAIL_UNPROVEN]],
'hmac-md5': [['2.1.0,d0.28', '6.6', '7.1'], [FAIL_MD5], [WARN_ENCRYPT_AND_MAC]],
'hmac-md5-96': [['2.5.0', '6.6', '7.1'], [FAIL_MD5], [WARN_ENCRYPT_AND_MAC]],
'hmac-md5-96-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_MD5]],
'hmac-md5-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_MD5]],
'hmac-ripemd160': [['2.5.0', '6.6', '7.1'], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC]],
'hmac-ripemd160-96': [[], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]],
'hmac-ripemd160-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_RIPEMD]],
'hmac-ripemd160@openssh.com': [['2.1.0', '6.6', '7.1'], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC]],
'hmac-ripemd': [[], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha1': [['2.1.0,d0.28,l10.2'], [FAIL_SHA1], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha1-96': [['2.5.0,d0.47', '6.6', '7.1'], [FAIL_SHA1], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha1-96-etm@openssh.com': [['6.2', '6.6', None], [FAIL_SHA1]],
'hmac-sha1-96@openssh.com': [[], [FAIL_SHA1], [WARN_TAG_SIZE, WARN_ENCRYPT_AND_MAC], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]],
'hmac-sha1-etm@openssh.com': [['6.2'], [FAIL_SHA1]],
'hmac-sha2-224': [[], [], [WARN_TAG_SIZE, WARN_ENCRYPT_AND_MAC]], 'hmac-sha2-224': [[], [], [WARN_TAG_SIZE, WARN_ENCRYPT_AND_MAC]],
'hmac-sha224@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha2-256': [['5.9,d2013.56,l10.7.0'], [], [WARN_ENCRYPT_AND_MAC]], 'hmac-sha2-256': [['5.9,d2013.56,l10.7.0'], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha2-256-96': [['5.9', '6.0'], [FAIL_OPENSSH61_REMOVE], [WARN_ENCRYPT_AND_MAC]], 'hmac-sha2-256-96': [['5.9', '6.0'], [], [WARN_ENCRYPT_AND_MAC], [INFO_REMOVED_IN_OPENSSH61]],
'hmac-sha2-256-96-etm@openssh.com': [[], [], [WARN_TAG_SIZE_96], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]], # Only ever implemented in AsyncSSH (?).
'hmac-sha2-256-etm@openssh.com': [['6.2']],
'hmac-sha2-384': [[], [], [WARN_ENCRYPT_AND_MAC]], 'hmac-sha2-384': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha2-512': [['5.9,d2013.56,l10.7.0'], [], [WARN_ENCRYPT_AND_MAC]], 'hmac-sha2-512': [['5.9,d2013.56,l10.7.0'], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha2-512-96': [['5.9', '6.0'], [FAIL_OPENSSH61_REMOVE], [WARN_ENCRYPT_AND_MAC]], 'hmac-sha2-512-96': [['5.9', '6.0'], [], [WARN_ENCRYPT_AND_MAC], [INFO_REMOVED_IN_OPENSSH61]],
'hmac-sha2-512-96-etm@openssh.com': [[], [], [WARN_TAG_SIZE_96], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]], # Only ever implemented in AsyncSSH (?).
'hmac-sha2-512-etm@openssh.com': [['6.2']],
'hmac-sha256-2@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha256-96@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]],
'hmac-sha256-96': [[], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]],
'hmac-sha256@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha256': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha2-56': [[], [], [WARN_TAG_SIZE, WARN_ENCRYPT_AND_MAC]],
'hmac-sha3-224': [[], [], [WARN_ENCRYPT_AND_MAC]], 'hmac-sha3-224': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha3-256': [[], [], [WARN_ENCRYPT_AND_MAC]], 'hmac-sha3-256': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha3-384': [[], [], [WARN_ENCRYPT_AND_MAC]], 'hmac-sha3-384': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha3-512': [[], [], [WARN_ENCRYPT_AND_MAC]], 'hmac-sha3-512': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha256': [[], [], [WARN_ENCRYPT_AND_MAC]], 'hmac-sha384@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha256-96@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]],
'hmac-sha256@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha512': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha512@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]], 'hmac-sha512@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-md5': [['2.1.0,d0.28', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC, WARN_HASH_WEAK]], 'hmac-sha512': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-md5-96': [['2.5.0', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC, WARN_HASH_WEAK]], 'hmac-whirlpool': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-ripemd': [[], [FAIL_DEPRECATED_MAC], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC]], 'md5': [[], [FAIL_PLAINTEXT]],
'hmac-ripemd160': [['2.5.0', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC]], 'md5-8': [[], [FAIL_PLAINTEXT]],
'hmac-ripemd160-96': [[], [FAIL_DEPRECATED_MAC], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]], 'none': [['d2013.56'], [FAIL_PLAINTEXT]],
'hmac-ripemd160@openssh.com': [['2.1.0', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC]], 'ripemd160': [[], [FAIL_PLAINTEXT]],
'umac-64@openssh.com': [['4.7'], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]], 'ripemd160-8': [[], [FAIL_PLAINTEXT]],
'umac-128@openssh.com': [['6.2'], [], [WARN_ENCRYPT_AND_MAC]], 'sha1': [[], [FAIL_PLAINTEXT]],
'hmac-sha1-etm@openssh.com': [['6.2'], [], [WARN_HASH_WEAK]], 'sha1-8': [[], [FAIL_PLAINTEXT]],
'hmac-sha1-96-etm@openssh.com': [['6.2', '6.6', None], [FAIL_OPENSSH67_UNSAFE], [WARN_HASH_WEAK]], 'umac-128': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha2-256-96-etm@openssh.com': [[], [], [WARN_TAG_SIZE_96]], # Despite the @openssh.com tag, it doesn't appear that this was ever shipped with OpenSSH; it is only implemented in AsyncSSH (?).
'hmac-sha2-512-96-etm@openssh.com': [[], [], [WARN_TAG_SIZE_96]], # Despite the @openssh.com tag, it doesn't appear that this was ever shipped with OpenSSH; it is only implemented in AsyncSSH (?).
'hmac-sha2-256-etm@openssh.com': [['6.2']],
'hmac-sha2-512-etm@openssh.com': [['6.2']],
'hmac-md5-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_HASH_WEAK]],
'hmac-md5-96-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_HASH_WEAK]],
'hmac-ripemd160-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY]],
'umac-32@openssh.com': [[], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]], # Despite having the @openssh.com suffix, this may never have shipped with OpenSSH (!).
'umac-64-etm@openssh.com': [['6.2'], [], [WARN_TAG_SIZE]],
'umac-96@openssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]], # Despite having the @openssh.com suffix, this may never have shipped with OpenSSH (!).
'umac-128-etm@openssh.com': [['6.2']], 'umac-128-etm@openssh.com': [['6.2']],
'aes128-gcm': [[]], 'umac-128@openssh.com': [['6.2'], [], [WARN_ENCRYPT_AND_MAC]],
'aes256-gcm': [[]], 'umac-32@openssh.com': [[], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]],
'chacha20-poly1305@openssh.com': [[]], # Despite the @openssh.com tag, this was never shipped as a MAC in OpenSSH (only as a cipher); it is only implemented as a MAC in Syncplify. 'umac-64-etm@openssh.com': [['6.2'], [], [WARN_TAG_SIZE]],
'crypticore-mac@ssh.com': [[], [FAIL_UNPROVEN]], 'umac-64@openssh.com': [['4.7'], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]],
'AEAD_AES_128_GCM': [[]], 'umac-96@openssh.com': [[], [], [WARN_ENCRYPT_AND_MAC], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]],
'AEAD_AES_256_GCM': [[]],
} }
} }
@staticmethod
def get_db() -> Dict[str, Dict[str, List[List[Optional[str]]]]]:
'''Returns a copy of the MASTER_DB that is private to the calling thread. This prevents multiple threads from polluting the results of other threads.'''
calling_thread_id = threading.get_ident()
if calling_thread_id not in SSH2_KexDB.DB_PER_THREAD:
SSH2_KexDB.DB_PER_THREAD[calling_thread_id] = copy.deepcopy(SSH2_KexDB.MASTER_DB)
return SSH2_KexDB.DB_PER_THREAD[calling_thread_id]
@staticmethod
def thread_exit() -> None:
'''Deletes the calling thread's copy of the MASTER_DB. This is needed because, in rare circumstances, a terminated thread's ID can be re-used by new threads.'''
calling_thread_id = threading.get_ident()
if calling_thread_id in SSH2_KexDB.DB_PER_THREAD:
del SSH2_KexDB.DB_PER_THREAD[calling_thread_id]

View File

@ -2,7 +2,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (C) 2017-2021 Joe Testa (jtesta@positronsecurity.com) Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu) Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
@ -34,8 +34,10 @@ import traceback
# pylint: disable=unused-import # pylint: disable=unused-import
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401 from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
from typing import Callable, Optional, Union, Any # noqa: F401 from typing import cast, Callable, Optional, Union, Any # noqa: F401
from ssh_audit.globals import SNAP_PACKAGE
from ssh_audit.globals import SNAP_PERMISSIONS_ERROR
from ssh_audit.globals import VERSION from ssh_audit.globals import VERSION
from ssh_audit.globals import WINDOWS_MAN_PAGE from ssh_audit.globals import WINDOWS_MAN_PAGE
from ssh_audit.algorithm import Algorithm from ssh_audit.algorithm import Algorithm
@ -59,22 +61,32 @@ from ssh_audit.ssh_socket import SSH_Socket
from ssh_audit.utils import Utils from ssh_audit.utils import Utils
from ssh_audit.versionvulnerabilitydb import VersionVulnerabilityDB from ssh_audit.versionvulnerabilitydb import VersionVulnerabilityDB
# no_idna_workaround = False
# Only import colorama under Windows. Other OSes can natively handle terminal colors. # Only import colorama under Windows. Other OSes can natively handle terminal colors.
if sys.platform == 'win32': if sys.platform == 'win32':
try: try:
from colorama import init as colorama_init from colorama import just_fix_windows_console
colorama_init() just_fix_windows_console()
except ImportError: except ImportError:
pass pass
# This is a workaround for a Python bug that causes a crash on Windows when multiple threads are used (see https://github.com/python/cpython/issues/73474). Importing the idna module and using it in a no-op seems to fix the issue. Otherwise, if idna isn't available at run-time, force single threaded scans.
# try:
# import idna # noqa: F401
#
# ''.encode('idna')
# except ImportError:
# no_idna_workaround = True
def usage(err: Optional[str] = None) -> None:
def usage(uout: OutputBuffer, err: Optional[str] = None) -> None:
retval = exitcodes.GOOD retval = exitcodes.GOOD
uout = OutputBuffer()
p = os.path.basename(sys.argv[0]) p = os.path.basename(sys.argv[0])
uout.head('# {} {}, https://github.com/jtesta/ssh-audit\n'.format(p, VERSION)) uout.head('# {} {}, https://github.com/jtesta/ssh-audit\n'.format(p, VERSION))
if err is not None and len(err) > 0: if err is not None and len(err) > 0:
uout.fail('\n' + err) uout.fail(err + '\n')
retval = exitcodes.UNKNOWN_ERROR retval = exitcodes.UNKNOWN_ERROR
uout.info('usage: {0} [options] <host>\n'.format(p)) uout.info('usage: {0} [options] <host>\n'.format(p))
uout.info(' -h, --help print this help') uout.info(' -h, --help print this help')
@ -85,6 +97,9 @@ def usage(err: Optional[str] = None) -> None:
uout.info(' -b, --batch batch output') uout.info(' -b, --batch batch output')
uout.info(' -c, --client-audit starts a server on port 2222 to audit client\n software config (use -p to change port;\n use -t to change timeout)') uout.info(' -c, --client-audit starts a server on port 2222 to audit client\n software config (use -p to change port;\n use -t to change timeout)')
uout.info(' -d, --debug debug output') uout.info(' -d, --debug debug output')
uout.info(' -g, --gex-test=<x[,y,...]> dh gex modulus size test')
uout.info(' <min1:pref1:max1[,min2:pref2:max2,...]>')
uout.info(' <x-y[:step]>')
uout.info(' -j, --json JSON output (use -jj to enable indents)') uout.info(' -j, --json JSON output (use -jj to enable indents)')
uout.info(' -l, --level=<level> minimum output level (info|warn|fail)') uout.info(' -l, --level=<level> minimum output level (info|warn|fail)')
uout.info(' -L, --list-policies list all the official, built-in policies') uout.info(' -L, --list-policies list all the official, built-in policies')
@ -103,10 +118,10 @@ def usage(err: Optional[str] = None) -> None:
sys.exit(retval) sys.exit(retval)
def output_algorithms(out: OutputBuffer, title: str, alg_db: Dict[str, Dict[str, List[List[Optional[str]]]]], alg_type: str, algorithms: List[str], unknown_algs: List[str], is_json_output: bool, program_retval: int, maxlen: int = 0, alg_sizes: Optional[Dict[str, Tuple[int, int]]] = None) -> int: # pylint: disable=too-many-arguments def output_algorithms(out: OutputBuffer, title: str, alg_db: Dict[str, Dict[str, List[List[Optional[str]]]]], alg_type: str, algorithms: List[str], unknown_algs: List[str], is_json_output: bool, program_retval: int, maxlen: int = 0, host_keys: Optional[Dict[str, Dict[str, Union[bytes, str, int]]]] = None, dh_modulus_sizes: Optional[Dict[str, int]] = None) -> int: # pylint: disable=too-many-arguments
with out: with out:
for algorithm in algorithms: for algorithm in algorithms:
program_retval = output_algorithm(out, alg_db, alg_type, algorithm, unknown_algs, program_retval, maxlen, alg_sizes) program_retval = output_algorithm(out, alg_db, alg_type, algorithm, unknown_algs, program_retval, maxlen, host_keys=host_keys, dh_modulus_sizes=dh_modulus_sizes)
if not out.is_section_empty() and not is_json_output: if not out.is_section_empty() and not is_json_output:
out.head('# ' + title) out.head('# ' + title)
out.flush_section() out.flush_section()
@ -115,7 +130,7 @@ def output_algorithms(out: OutputBuffer, title: str, alg_db: Dict[str, Dict[str,
return program_retval return program_retval
def output_algorithm(out: OutputBuffer, alg_db: Dict[str, Dict[str, List[List[Optional[str]]]]], alg_type: str, alg_name: str, unknown_algs: List[str], program_retval: int, alg_max_len: int = 0, alg_sizes: Optional[Dict[str, Tuple[int, int]]] = None) -> int: def output_algorithm(out: OutputBuffer, alg_db: Dict[str, Dict[str, List[List[Optional[str]]]]], alg_type: str, alg_name: str, unknown_algs: List[str], program_retval: int, alg_max_len: int = 0, host_keys: Optional[Dict[str, Dict[str, Union[bytes, str, int]]]] = None, dh_modulus_sizes: Optional[Dict[str, int]] = None) -> int: # pylint: disable=too-many-arguments
prefix = '(' + alg_type + ') ' prefix = '(' + alg_type + ') '
if alg_max_len == 0: if alg_max_len == 0:
alg_max_len = len(alg_name) alg_max_len = len(alg_name)
@ -124,14 +139,30 @@ def output_algorithm(out: OutputBuffer, alg_db: Dict[str, Dict[str, List[List[Op
# If this is an RSA host key or DH GEX, append the size to its name and fix # If this is an RSA host key or DH GEX, append the size to its name and fix
# the padding. # the padding.
alg_name_with_size = None alg_name_with_size = None
if (alg_sizes is not None) and (alg_name in alg_sizes): if (dh_modulus_sizes is not None) and (alg_name in dh_modulus_sizes):
hostkey_size, ca_size = alg_sizes[alg_name] alg_name_with_size = '%s (%u-bit)' % (alg_name, dh_modulus_sizes[alg_name])
if ca_size > 0:
alg_name_with_size = '%s (%d-bit cert/%d-bit CA)' % (alg_name, hostkey_size, ca_size)
padding = padding[0:-15]
else:
alg_name_with_size = '%s (%d-bit)' % (alg_name, hostkey_size)
padding = padding[0:-11] padding = padding[0:-11]
elif (host_keys is not None) and (alg_name in host_keys):
hostkey_size = cast(int, host_keys[alg_name]['hostkey_size'])
ca_key_type = cast(str, host_keys[alg_name]['ca_key_type'])
ca_key_size = cast(int, host_keys[alg_name]['ca_key_size'])
# If this is an RSA variant, just print "RSA".
if ca_key_type in HostKeyTest.RSA_FAMILY:
ca_key_type = "RSA"
if len(ca_key_type) > 0 and ca_key_size > 0:
alg_name_with_size = '%s (%u-bit cert/%u-bit %s CA)' % (alg_name, hostkey_size, ca_key_size, ca_key_type)
padding = padding[0:-15]
elif alg_name in HostKeyTest.RSA_FAMILY:
alg_name_with_size = '%s (%u-bit)' % (alg_name, hostkey_size)
padding = padding[0:-11]
# If this is a kex algorithm and starts with 'gss-', then normalize its name (i.e.: 'gss-gex-sha1-vz8J1E9PzLr8b1K+0remTg==' => 'gss-gex-sha1-*'). The base64 field can vary, so we'll convert it to the wildcard that our database uses and we'll just resume doing a straight match like all other algorithm names.
alg_name_original = alg_name
if alg_type == 'kex' and alg_name.startswith('gss-'):
last_dash = alg_name.rindex('-')
alg_name = "%s-*" % alg_name[0:last_dash]
texts = [] texts = []
if len(alg_name.strip()) == 0: if len(alg_name.strip()) == 0:
@ -158,8 +189,13 @@ def output_algorithm(out: OutputBuffer, alg_db: Dict[str, Dict[str, List[List[Op
texts.append(('warn', 'unknown algorithm')) texts.append(('warn', 'unknown algorithm'))
unknown_algs.append(alg_name) unknown_algs.append(alg_name)
# For kex GSS algorithms, now that we already did the database lookup (above), restore the original algorithm name so its reported properly in the output.
if alg_name != alg_name_original:
alg_name = alg_name_original
alg_name = alg_name_with_size if alg_name_with_size is not None else alg_name alg_name = alg_name_with_size if alg_name_with_size is not None else alg_name
first = True first = True
use_good_for_all = False
for level, text in texts: for level, text in texts:
if level == 'fail': if level == 'fail':
program_retval = exitcodes.FAILURE program_retval = exitcodes.FAILURE
@ -168,16 +204,20 @@ def output_algorithm(out: OutputBuffer, alg_db: Dict[str, Dict[str, List[List[Op
f = getattr(out, level) f = getattr(out, level)
comment = (padding + ' -- [' + level + '] ' + text) if text != '' else '' comment = (padding + ' -- [' + level + '] ' + text) if text != '' else ''
if first:
if first and level == 'info': # If the first algorithm's comment is an 'info', this implies that it is rated good. Hence, the out.good() function should be used to write all subsequent notes for this algorithm as well.
if (first and level == 'info') or use_good_for_all:
f = out.good f = out.good
use_good_for_all = True
if first:
f(prefix + alg_name + comment) f(prefix + alg_name + comment)
first = False first = False
else: # pylint: disable=else-if-used else: # pylint: disable=else-if-used
if out.verbose: if out.verbose:
f(prefix + alg_name + comment) f(prefix + alg_name + comment)
elif text != '': elif text != '':
comment = (padding + ' `- [' + level + '] ' + text) comment = padding + ' `- [' + level + '] ' + text
f(' ' * len(prefix + alg_name) + comment) f(' ' * len(prefix + alg_name) + comment)
return program_retval return program_retval
@ -213,10 +253,12 @@ def output_compatibility(out: OutputBuffer, algs: Algorithms, client_audit: bool
out.good('(gen) compatibility: ' + ', '.join(comp_text)) out.good('(gen) compatibility: ' + ', '.join(comp_text))
def output_security_sub(out: OutputBuffer, sub: str, software: Optional[Software], client_audit: bool, padlen: int) -> None: def output_security_sub(out: OutputBuffer, sub: str, software: Optional[Software], client_audit: bool, padlen: int) -> List[Dict[str, Union[str, float]]]:
ret: List[Dict[str, Union[str, float]]] = []
secdb = VersionVulnerabilityDB.CVE if sub == 'cve' else VersionVulnerabilityDB.TXT secdb = VersionVulnerabilityDB.CVE if sub == 'cve' else VersionVulnerabilityDB.TXT
if software is None or software.product not in secdb: if software is None or software.product not in secdb:
return return ret
for line in secdb[software.product]: for line in secdb[software.product]:
vfrom: str = '' vfrom: str = ''
vtill: str = '' vtill: str = ''
@ -244,17 +286,22 @@ def output_security_sub(out: OutputBuffer, sub: str, software: Optional[Software
if cvss >= 8.0: if cvss >= 8.0:
out_func = out.fail out_func = out.fail
out_func('(cve) {}{} -- (CVSSv2: {}) {}'.format(name, p, cvss, descr)) out_func('(cve) {}{} -- (CVSSv2: {}) {}'.format(name, p, cvss, descr))
ret.append({'name': name, 'cvssv2': cvss, 'description': descr})
else: else:
descr = line[4] descr = line[4]
out.fail('(sec) {}{} -- {}'.format(name, p, descr)) out.fail('(sec) {}{} -- {}'.format(name, p, descr))
return ret
def output_security(out: OutputBuffer, banner: Optional[Banner], client_audit: bool, padlen: int, is_json_output: bool) -> List[Dict[str, Union[str, float]]]:
cves = []
def output_security(out: OutputBuffer, banner: Optional[Banner], client_audit: bool, padlen: int, is_json_output: bool) -> None:
with out: with out:
if banner is not None: if banner is not None:
software = Software.parse(banner) software = Software.parse(banner)
output_security_sub(out, 'cve', software, client_audit, padlen) cves = output_security_sub(out, 'cve', software, client_audit, padlen)
output_security_sub(out, 'txt', software, client_audit, padlen) _ = output_security_sub(out, 'txt', software, client_audit, padlen)
if banner.protocol[0] == 1: if banner.protocol[0] == 1:
p = '' if out.batch else ' ' * (padlen - 14) p = '' if out.batch else ' ' * (padlen - 14)
out.fail('(sec) SSH v1 enabled{} -- SSH v1 can be exploited to recover plaintext passwords'.format(p)) out.fail('(sec) SSH v1 enabled{} -- SSH v1 can be exploited to recover plaintext passwords'.format(p))
@ -263,39 +310,41 @@ def output_security(out: OutputBuffer, banner: Optional[Banner], client_audit: b
out.flush_section() out.flush_section()
out.sep() out.sep()
return cves
def output_fingerprints(out: OutputBuffer, algs: Algorithms, is_json_output: bool) -> None: def output_fingerprints(out: OutputBuffer, algs: Algorithms, is_json_output: bool) -> None:
with out: with out:
fps = [] fps = {}
if algs.ssh1kex is not None: if algs.ssh1kex is not None:
name = 'ssh-rsa1' name = 'ssh-rsa1'
fp = Fingerprint(algs.ssh1kex.host_key_fingerprint_data) fp = Fingerprint(algs.ssh1kex.host_key_fingerprint_data)
# bits = algs.ssh1kex.host_key_bits # bits = algs.ssh1kex.host_key_bits
fps.append((name, fp)) fps[name] = fp
if algs.ssh2kex is not None: if algs.ssh2kex is not None:
host_keys = algs.ssh2kex.host_keys() host_keys = algs.ssh2kex.host_keys()
for host_key_type in algs.ssh2kex.host_keys(): for host_key_type in algs.ssh2kex.host_keys():
if host_keys[host_key_type] is None: if host_keys[host_key_type] is None:
continue continue
fp = Fingerprint(host_keys[host_key_type]) fp = Fingerprint(cast(bytes, host_keys[host_key_type]['raw_hostkey_bytes']))
# Workaround for Python's order-indifference in dicts. We might get a random RSA type (ssh-rsa, rsa-sha2-256, or rsa-sha2-512), so running the tool against the same server three times may give three different host key types here. So if we have any RSA type, we will simply hard-code it to 'ssh-rsa'. # Workaround for Python's order-indifference in dicts. We might get a random RSA type (ssh-rsa, rsa-sha2-256, or rsa-sha2-512), so running the tool against the same server three times may give three different host key types here. So if we have any RSA type, we will simply hard-code it to 'ssh-rsa'.
if host_key_type in HostKeyTest.RSA_FAMILY: if host_key_type in HostKeyTest.RSA_FAMILY:
host_key_type = 'ssh-rsa' host_key_type = 'ssh-rsa'
# Skip over certificate host types (or we would return invalid fingerprints). # Skip over certificate host types (or we would return invalid fingerprints), and only add one fingerprint in the RSA family.
if '-cert-' not in host_key_type: if '-cert-' not in host_key_type:
fps.append((host_key_type, fp)) fps[host_key_type] = fp
# Similarly, the host keys can be processed in random order due to Python's order-indifference in dicts. So we sort this list before printing; this makes automated testing possible. # Similarly, the host keys can be processed in random order due to Python's order-indifference in dicts. So we sort this list before printing; this makes automated testing possible.
fps = sorted(fps) fp_types = sorted(fps.keys())
for fpp in fps: for fp_type in fp_types:
name, fp = fpp fp = fps[fp_type]
out.good('(fin) {}: {}'.format(name, fp.sha256)) out.good('(fin) {}: {}'.format(fp_type, fp.sha256))
# Output the MD5 hash too if verbose mode is enabled. # Output the MD5 hash too if verbose mode is enabled.
if out.verbose: if out.verbose:
out.info('(fin) {}: {} -- [info] do not rely on MD5 fingerprints for server identification; it is insecure for this use case'.format(name, fp.md5)) 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))
if not out.is_section_empty() and not is_json_output: if not out.is_section_empty() and not is_json_output:
out.head('# fingerprints') out.head('# fingerprints')
@ -304,7 +353,7 @@ def output_fingerprints(out: OutputBuffer, algs: Algorithms, is_json_output: boo
# Returns True if no warnings or failures encountered in configuration. # Returns True if no warnings or failures encountered in configuration.
def output_recommendations(out: OutputBuffer, algs: Algorithms, software: Optional[Software], is_json_output: bool, padlen: int = 0) -> bool: def output_recommendations(out: OutputBuffer, algs: Algorithms, algorithm_recommendation_suppress_list: List[str], software: Optional[Software], is_json_output: bool, padlen: int = 0) -> bool:
ret = True ret = True
# PuTTY's algorithms cannot be modified, so there's no point in issuing recommendations. # PuTTY's algorithms cannot be modified, so there's no point in issuing recommendations.
@ -335,35 +384,41 @@ def output_recommendations(out: OutputBuffer, algs: Algorithms, software: Option
ret = False ret = False
return ret return ret
for_server = True level_to_output = {
"informational": out.good,
"warning": out.warn,
"critical": out.fail
}
with out: with out:
software, alg_rec = algs.get_recommendations(software, for_server) recommendations = get_algorithm_recommendations(algs, algorithm_recommendation_suppress_list, software, for_server=True)
for sshv in range(2, 0, -1):
if sshv not in alg_rec: for level in recommendations: # pylint: disable=consider-using-dict-items
continue for action in recommendations[level]:
for alg_type in ['kex', 'key', 'enc', 'mac']: for alg_type in recommendations[level][action]:
if alg_type not in alg_rec[sshv]: for alg_name_and_notes in recommendations[level][action][alg_type]:
continue name = alg_name_and_notes['name']
for action in ['del', 'add', 'chg']: notes = alg_name_and_notes['notes']
if action not in alg_rec[sshv][alg_type]:
continue
for name in alg_rec[sshv][alg_type][action]:
p = '' if out.batch else ' ' * (padlen - len(name)) p = '' if out.batch else ' ' * (padlen - len(name))
chg_additional_info = ''
fn = level_to_output[level]
if action == 'del': if action == 'del':
an, sg, fn = 'remove', '-', out.warn an, sg = 'remove', '-'
ret = False ret = False
if alg_rec[sshv][alg_type][action][name] >= 10:
fn = out.fail
elif action == 'add': elif action == 'add':
an, sg, fn = 'append', '+', out.good an, sg = 'append', '+'
elif action == 'chg': elif action == 'chg':
an, sg, fn = 'change', '!', out.fail an, sg = 'change', '!'
ret = False ret = False
chg_additional_info = ' (increase modulus size to 2048 bits or larger)'
b = '(SSH{})'.format(sshv) if sshv == 1 else '' if notes != '':
fm = '(rec) {0}{1}{2}-- {3} algorithm to {4}{5} {6}' notes = " (%s)" % notes
fn(fm.format(sg, name, p, alg_type, an, chg_additional_info, b))
fm = '(rec) {0}{1}{2}-- {3} algorithm to {4}{5} '
fn(fm.format(sg, name, p, alg_type, an, notes))
if not out.is_section_empty() and not is_json_output: if not out.is_section_empty() and not is_json_output:
if software is not None: if software is not None:
title = '(for {})'.format(software.display(False)) title = '(for {})'.format(software.display(False))
@ -392,6 +447,28 @@ def output_info(out: OutputBuffer, software: Optional['Software'], client_audit:
out.sep() out.sep()
def post_process_findings(banner: Optional[Banner], algs: Algorithms) -> List[str]:
'''Perform post-processing on scan results before reporting them to the user. Returns a list of algorithms that should not be recommended'''
algorithm_recommendation_suppress_list = []
# If the server is OpenSSH, and the diffie-hellman-group-exchange-sha256 key exchange was found with modulus size 2048, add a note regarding the bug that causes the server to support 2048-bit moduli no matter the configuration.
if (algs.ssh2kex is not None and 'diffie-hellman-group-exchange-sha256' in algs.ssh2kex.kex_algorithms and 'diffie-hellman-group-exchange-sha256' in algs.ssh2kex.dh_modulus_sizes() and algs.ssh2kex.dh_modulus_sizes()['diffie-hellman-group-exchange-sha256'] == 2048) and (banner is not None and banner.software is not None and banner.software.find('OpenSSH') != -1):
# Ensure a list for notes exists.
db = SSH2_KexDB.get_db()
while len(db['kex']['diffie-hellman-group-exchange-sha256']) < 4:
db['kex']['diffie-hellman-group-exchange-sha256'].append([])
db['kex']['diffie-hellman-group-exchange-sha256'][3].append("A bug in OpenSSH causes it to fall back to a 2048-bit modulus regardless of server configuration (https://bugzilla.mindrot.org/show_bug.cgi?id=2793)")
# Ensure that this algorithm doesn't appear in the recommendations section since the user cannot control this OpenSSH bug.
algorithm_recommendation_suppress_list.append('diffie-hellman-group-exchange-sha256')
return algorithm_recommendation_suppress_list
# Returns a exitcodes.* flag to denote if any failures or warnings were encountered. # Returns a exitcodes.* flag to denote if any failures or warnings were encountered.
def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header: List[str], client_host: Optional[str] = None, kex: Optional[SSH2_Kex] = None, pkm: Optional[SSH1_PublicKeyMessage] = None, print_target: bool = False) -> int: def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header: List[str], client_host: Optional[str] = None, kex: Optional[SSH2_Kex] = None, pkm: Optional[SSH1_PublicKeyMessage] = None, print_target: bool = False) -> int:
@ -399,6 +476,10 @@ def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header
client_audit = client_host is not None # If set, this is a client audit. client_audit = client_host is not None # If set, this is a client audit.
sshv = 1 if pkm is not None else 2 sshv = 1 if pkm is not None else 2
algs = Algorithms(pkm, kex) algs = Algorithms(pkm, kex)
# Perform post-processing on the findings to make final adjustments before outputting the results.
algorithm_recommendation_suppress_list = post_process_findings(banner, algs)
with out: with out:
if print_target: if print_target:
host = aconf.host host = aconf.host
@ -447,11 +528,13 @@ def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header
out.flush_section() out.flush_section()
out.sep() out.sep()
maxlen = algs.maxlen + 1 maxlen = algs.maxlen + 1
output_security(out, banner, client_audit, maxlen, aconf.json) cves = output_security(out, banner, client_audit, maxlen, aconf.json)
# Filled in by output_algorithms() with unidentified algs. # Filled in by output_algorithms() with unidentified algs.
unknown_algorithms: List[str] = [] unknown_algorithms: List[str] = []
# SSHv1
if pkm is not None: if pkm is not None:
adb = SSH1_KexDB.ALGORITHMS adb = SSH1_KexDB.get_db()
ciphers = pkm.supported_ciphers ciphers = pkm.supported_ciphers
auths = pkm.supported_authentications auths = pkm.supported_authentications
title, atype = 'SSH1 host-key algorithms', 'key' title, atype = 'SSH1 host-key algorithms', 'key'
@ -460,24 +543,27 @@ def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header
program_retval = output_algorithms(out, title, adb, atype, ciphers, unknown_algorithms, aconf.json, program_retval, maxlen) program_retval = output_algorithms(out, title, adb, atype, ciphers, unknown_algorithms, aconf.json, program_retval, maxlen)
title, atype = 'SSH1 authentication types', 'aut' title, atype = 'SSH1 authentication types', 'aut'
program_retval = output_algorithms(out, title, adb, atype, auths, unknown_algorithms, aconf.json, program_retval, maxlen) program_retval = output_algorithms(out, title, adb, atype, auths, unknown_algorithms, aconf.json, program_retval, maxlen)
# SSHv2
if kex is not None: if kex is not None:
adb = SSH2_KexDB.ALGORITHMS adb = SSH2_KexDB.get_db()
title, atype = 'key exchange algorithms', 'kex' title, atype = 'key exchange algorithms', 'kex'
program_retval = output_algorithms(out, title, adb, atype, kex.kex_algorithms, unknown_algorithms, aconf.json, program_retval, maxlen, kex.dh_modulus_sizes()) program_retval = output_algorithms(out, title, adb, atype, kex.kex_algorithms, unknown_algorithms, aconf.json, program_retval, maxlen, dh_modulus_sizes=kex.dh_modulus_sizes())
title, atype = 'host-key algorithms', 'key' title, atype = 'host-key algorithms', 'key'
program_retval = output_algorithms(out, title, adb, atype, kex.key_algorithms, unknown_algorithms, aconf.json, program_retval, maxlen, kex.rsa_key_sizes()) program_retval = output_algorithms(out, title, adb, atype, kex.key_algorithms, unknown_algorithms, aconf.json, program_retval, maxlen, host_keys=kex.host_keys())
title, atype = 'encryption algorithms (ciphers)', 'enc' title, atype = 'encryption algorithms (ciphers)', 'enc'
program_retval = output_algorithms(out, title, adb, atype, kex.server.encryption, unknown_algorithms, aconf.json, program_retval, maxlen) program_retval = output_algorithms(out, title, adb, atype, kex.server.encryption, unknown_algorithms, aconf.json, program_retval, maxlen)
title, atype = 'message authentication code algorithms', 'mac' title, atype = 'message authentication code algorithms', 'mac'
program_retval = output_algorithms(out, title, adb, atype, kex.server.mac, unknown_algorithms, aconf.json, program_retval, maxlen) program_retval = output_algorithms(out, title, adb, atype, kex.server.mac, unknown_algorithms, aconf.json, program_retval, maxlen)
output_fingerprints(out, algs, aconf.json) output_fingerprints(out, algs, aconf.json)
perfect_config = output_recommendations(out, algs, software, aconf.json, maxlen) perfect_config = output_recommendations(out, algs, algorithm_recommendation_suppress_list, software, aconf.json, maxlen)
output_info(out, software, client_audit, not perfect_config, aconf.json) output_info(out, software, client_audit, not perfect_config, aconf.json)
if aconf.json: if aconf.json:
out.reset() out.reset()
# Build & write the JSON struct. # Build & write the JSON struct.
out.info(json.dumps(build_struct(aconf.host, banner, kex=kex, client_host=client_host), indent=4 if aconf.json_print_indent else None, sort_keys=True)) out.info(json.dumps(build_struct(aconf.host + ":" + str(aconf.port), banner, cves, kex=kex, client_host=client_host, software=software, algorithms=algs, algorithm_recommendation_suppress_list=algorithm_recommendation_suppress_list), indent=4 if aconf.json_print_indent else None, sort_keys=True))
elif len(unknown_algorithms) > 0: # If we encountered any unknown algorithms, ask the user to report them. elif len(unknown_algorithms) > 0: # If we encountered any unknown algorithms, ask the user to report them.
out.warn("\n\n!!! WARNING: unknown algorithm(s) found!: %s. Please email the full output above to the maintainer (jtesta@positronsecurity.com), or create a Github issue at <https://github.com/jtesta/ssh-audit/issues>.\n" % ','.join(unknown_algorithms)) out.warn("\n\n!!! WARNING: unknown algorithm(s) found!: %s. Please email the full output above to the maintainer (jtesta@positronsecurity.com), or create a Github issue at <https://github.com/jtesta/ssh-audit/issues>.\n" % ','.join(unknown_algorithms))
@ -527,6 +613,55 @@ def evaluate_policy(out: OutputBuffer, aconf: AuditConf, banner: Optional['Banne
return passed return passed
def get_algorithm_recommendations(algs: Optional[Algorithms], algorithm_recommendation_suppress_list: Optional[List[str]], software: Optional[Software], for_server: bool = True) -> Dict[str, Any]:
'''Returns the algorithm recommendations.'''
ret: Dict[str, Any] = {}
if algs is None or software is None:
return ret
software, alg_rec = algs.get_recommendations(software, for_server)
for sshv in range(2, 0, -1):
if sshv not in alg_rec:
continue
for alg_type in ['kex', 'key', 'enc', 'mac']:
if alg_type not in alg_rec[sshv]:
continue
for action in ['del', 'add', 'chg']:
if action not in alg_rec[sshv][alg_type]:
continue
for name in alg_rec[sshv][alg_type][action]:
# If this algorithm should be suppressed, skip it.
if algorithm_recommendation_suppress_list is not None and name in algorithm_recommendation_suppress_list:
continue
level = 'informational'
points = alg_rec[sshv][alg_type][action][name]
if points >= 10:
level = 'critical'
elif points >= 1:
level = 'warning'
if level not in ret:
ret[level] = {}
if action not in ret[level]:
ret[level][action] = {}
if alg_type not in ret[level][action]:
ret[level][action][alg_type] = []
notes = ''
if action == 'chg':
notes = 'increase modulus size to 3072 bits or larger'
ret[level][action][alg_type].append({'name': name, 'notes': notes})
return ret
def list_policies(out: OutputBuffer) -> None: def list_policies(out: OutputBuffer) -> None:
'''Prints a list of server & client policies.''' '''Prints a list of server & client policies.'''
@ -560,36 +695,50 @@ def make_policy(aconf: AuditConf, banner: Optional['Banner'], kex: Optional['SSH
if aconf.policy_file is None: if aconf.policy_file is None:
raise RuntimeError('Internal error: cannot write policy file since filename is None!') raise RuntimeError('Internal error: cannot write policy file since filename is None!')
# Open with mode 'x' (creates the file, or fails if it already exist). succeeded = False
succeeded = True err = ''
try: try:
# Open with mode 'x' (creates the file, or fails if it already exist).
with open(aconf.policy_file, 'x', encoding='utf-8') as f: with open(aconf.policy_file, 'x', encoding='utf-8') as f:
f.write(policy_data) f.write(policy_data)
succeeded = True
except FileExistsError: except FileExistsError:
succeeded = False err = "Error: file already exists: %s" % aconf.policy_file
except PermissionError as e:
# If installed as a Snap package, print a more useful message with potential work-arounds.
if SNAP_PACKAGE:
print(SNAP_PERMISSIONS_ERROR)
sys.exit(exitcodes.UNKNOWN_ERROR)
else:
err = "Error: insufficient permissions: %s" % str(e)
if succeeded: if succeeded:
print("Wrote policy to %s. Customize as necessary, then run a policy scan with -P option." % aconf.policy_file) print("Wrote policy to %s. Customize as necessary, then run a policy scan with -P option." % aconf.policy_file)
else: else:
print("Error: file already exists: %s" % aconf.policy_file) print(err)
def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[..., None]) -> 'AuditConf': # pylint: disable=too-many-statements def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[..., None]) -> 'AuditConf': # pylint: disable=too-many-statements
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
aconf = AuditConf() aconf = AuditConf()
enable_colors = not any(i in args for i in ['--no-colors', '-n'])
aconf.colors = enable_colors
out.use_colors = enable_colors
try: try:
sopts = 'h1246M:p:P:jbcnvl:t:T:Lmd' sopts = 'h1246M:p:P:jbcnvl:t:T:Lmdg:'
lopts = ['help', 'ssh1', 'ssh2', 'ipv4', 'ipv6', 'make-policy=', 'port=', 'policy=', 'json', 'batch', 'client-audit', 'no-colors', 'verbose', 'level=', 'timeout=', 'targets=', 'list-policies', 'lookup=', 'threads=', 'manual', 'debug'] lopts = ['help', 'ssh1', 'ssh2', 'ipv4', 'ipv6', 'make-policy=', 'port=', 'policy=', 'json', 'batch', 'client-audit', 'no-colors', 'verbose', 'level=', 'timeout=', 'targets=', 'list-policies', 'lookup=', 'threads=', 'manual', 'debug', 'gex-test=']
opts, args = getopt.gnu_getopt(args, sopts, lopts) opts, args = getopt.gnu_getopt(args, sopts, lopts)
except getopt.GetoptError as err: except getopt.GetoptError as err:
usage_cb(str(err)) usage_cb(out, str(err))
aconf.ssh1, aconf.ssh2 = False, False aconf.ssh1, aconf.ssh2 = False, False
host: str = '' host: str = ''
oport: Optional[str] = None oport: Optional[str] = None
port: int = 0 port: int = 0
for o, a in opts: for o, a in opts:
if o in ('-h', '--help'): if o in ('-h', '--help'):
usage_cb() usage_cb(out)
elif o in ('-1', '--ssh1'): elif o in ('-1', '--ssh1'):
aconf.ssh1 = True aconf.ssh1 = True
elif o in ('-2', '--ssh2'): elif o in ('-2', '--ssh2'):
@ -605,9 +754,6 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
aconf.verbose = True aconf.verbose = True
elif o in ('-c', '--client-audit'): elif o in ('-c', '--client-audit'):
aconf.client_audit = True aconf.client_audit = True
elif o in ('-n', '--no-colors'):
aconf.colors = False
out.use_colors = False
elif o in ('-j', '--json'): elif o in ('-j', '--json'):
if aconf.json: # If specified twice, enable indent printing. if aconf.json: # If specified twice, enable indent printing.
aconf.json_print_indent = True aconf.json_print_indent = True
@ -618,7 +764,7 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
out.verbose = True out.verbose = True
elif o in ('-l', '--level'): elif o in ('-l', '--level'):
if a not in ('info', 'warn', 'fail'): if a not in ('info', 'warn', 'fail'):
usage_cb('level {} is not valid'.format(a)) usage_cb(out, 'level {} is not valid'.format(a))
aconf.level = a aconf.level = a
elif o in ('-t', '--timeout'): elif o in ('-t', '--timeout'):
aconf.timeout = float(a) aconf.timeout = float(a)
@ -630,8 +776,15 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
aconf.policy_file = a aconf.policy_file = a
elif o in ('-T', '--targets'): elif o in ('-T', '--targets'):
aconf.target_file = a aconf.target_file = a
# If we're on Windows, and we can't use the idna workaround, force only one thread to be used (otherwise a crash would occur).
# if no_idna_workaround:
# print("\nWARNING: the idna module was not found on this system, thus only single-threaded scanning will be done (this is a workaround for this Windows-specific crash: https://github.com/python/cpython/issues/73474). Multi-threaded scanning can be enabled by installing the idna module (pip install idna).\n")
# aconf.threads = 1
elif o == '--threads': elif o == '--threads':
aconf.threads = int(a) aconf.threads = int(a)
# if no_idna_workaround:
# aconf.threads = 1
elif o in ('-L', '--list-policies'): elif o in ('-L', '--list-policies'):
aconf.list_policies = True aconf.list_policies = True
elif o == '--lookup': elif o == '--lookup':
@ -641,9 +794,32 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
elif o in ('-d', '--debug'): elif o in ('-d', '--debug'):
aconf.debug = True aconf.debug = True
out.debug = True out.debug = True
elif o in ('-g', '--gex-test'):
permitted_syntax = get_permitted_syntax_for_gex_test()
if not any(re.search(regex_str, a) for regex_str in permitted_syntax.values()):
usage_cb(out, '{} {} is not valid'.format(o, a))
if re.search(permitted_syntax['RANGE'], a):
extracted_digits = re.findall(r'\d+', a)
bits_left_bound = int(extracted_digits[0])
bits_right_bound = int(extracted_digits[1])
bits_step = 1
if (len(extracted_digits)) == 3:
bits_step = int(extracted_digits[2])
if bits_step <= 0:
usage_cb(out, '{} {} is not valid'.format(o, bits_step))
if all(x < 0 for x in (bits_left_bound, bits_right_bound)):
usage_cb(out, '{} {} {} is not valid'.format(o, bits_left_bound, bits_right_bound))
aconf.gex_test = a
if len(args) == 0 and aconf.client_audit is False and aconf.target_file is None and aconf.list_policies is False and aconf.lookup == '' and aconf.manual is False: if len(args) == 0 and aconf.client_audit is False and aconf.target_file is None and aconf.list_policies is False and aconf.lookup == '' and aconf.manual is False:
usage_cb() usage_cb(out)
if aconf.manual: if aconf.manual:
return aconf return aconf
@ -661,7 +837,7 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
else: else:
host, port = Utils.parse_host_and_port(args[0]) host, port = Utils.parse_host_and_port(args[0])
if not host and aconf.target_file is None: if not host and aconf.target_file is None:
usage_cb('host is empty') usage_cb(out, 'host is empty')
if port == 0 and oport is None: if port == 0 and oport is None:
if aconf.client_audit: # The default port to listen on during a client audit is 2222. if aconf.client_audit: # The default port to listen on during a client audit is 2222.
@ -672,7 +848,7 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
if oport is not None: if oport is not None:
port = Utils.parse_int(oport) port = Utils.parse_int(oport)
if port <= 0 or port > 65535: if port <= 0 or port > 65535:
usage_cb('port {} is not valid'.format(oport)) usage_cb(out, 'port {} is not valid'.format(oport))
aconf.host = host aconf.host = host
aconf.port = port aconf.port = port
@ -681,8 +857,16 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
# If a file containing a list of targets was given, read it. # If a file containing a list of targets was given, read it.
if aconf.target_file is not None: if aconf.target_file is not None:
try:
with open(aconf.target_file, 'r', encoding='utf-8') as f: with open(aconf.target_file, 'r', encoding='utf-8') as f:
aconf.target_list = f.readlines() aconf.target_list = f.readlines()
except PermissionError as e:
# If installed as a Snap package, print a more useful message with potential work-arounds.
if SNAP_PACKAGE:
print(SNAP_PERMISSIONS_ERROR)
else:
print("Error: insufficient permissions: %s" % str(e))
sys.exit(exitcodes.UNKNOWN_ERROR)
# Strip out whitespace from each line in target file, and skip empty lines. # Strip out whitespace from each line in target file, and skip empty lines.
aconf.target_list = [target.strip() for target in aconf.target_list if target not in ("", "\n")] aconf.target_list = [target.strip() for target in aconf.target_list if target not in ("", "\n")]
@ -691,10 +875,10 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
if (aconf.policy_file is not None) and (aconf.make_policy is False): if (aconf.policy_file is not None) and (aconf.make_policy is False):
# First, see if this is a built-in policy name. If not, assume a file path was provided, and try to load it from disk. # First, see if this is a built-in policy name. If not, assume a file path was provided, and try to load it from disk.
aconf.policy = Policy.load_builtin_policy(aconf.policy_file) aconf.policy = Policy.load_builtin_policy(aconf.policy_file, json_output=aconf.json)
if aconf.policy is None: if aconf.policy is None:
try: try:
aconf.policy = Policy(policy_file=aconf.policy_file) aconf.policy = Policy(policy_file=aconf.policy_file, json_output=aconf.json)
except Exception as e: except Exception as e:
out.fail("Error while loading policy file: %s: %s" % (str(e), traceback.format_exc())) out.fail("Error while loading policy file: %s: %s" % (str(e), traceback.format_exc()))
out.write() out.write()
@ -715,7 +899,35 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
return aconf return aconf
def build_struct(target_host: str, banner: Optional['Banner'], kex: Optional['SSH2_Kex'] = None, pkm: Optional['SSH1_PublicKeyMessage'] = None, client_host: Optional[str] = None) -> Any: def build_struct(target_host: str, banner: Optional['Banner'], cves: List[Dict[str, Union[str, float]]], kex: Optional['SSH2_Kex'] = None, pkm: Optional['SSH1_PublicKeyMessage'] = None, client_host: Optional[str] = None, software: Optional[Software] = None, algorithms: Optional[Algorithms] = None, algorithm_recommendation_suppress_list: Optional[List[str]] = None) -> Any: # pylint: disable=too-many-arguments
def fetch_notes(algorithm: str, alg_type: str) -> Dict[str, List[Optional[str]]]:
'''Returns a dictionary containing the messages in the "fail", "warn", and "info" levels for this algorithm.'''
alg_db = SSH2_KexDB.get_db()
alg_info = {}
if algorithm in alg_db[alg_type]:
alg_desc = alg_db[alg_type][algorithm]
alg_desc_len = len(alg_desc)
# If a list for the failure notes exists, add it to the return value. Similarly, add the related lists for the warnings and informational notes.
if (alg_desc_len >= 2) and (len(alg_desc[1]) > 0):
alg_info["fail"] = alg_desc[1]
if (alg_desc_len >= 3) and (len(alg_desc[2]) > 0):
alg_info["warn"] = alg_desc[2]
if (alg_desc_len >= 4) and (len(alg_desc[3]) > 0):
alg_info["info"] = alg_desc[3]
# Add information about when this algorithm was implemented in OpenSSH/Dropbear.
since_text = Algorithm.get_since_text(alg_desc[0])
if (since_text is not None) and (len(since_text) > 0):
# Add the "info" key with an empty list if the if-block above didn't create it already.
if "info" not in alg_info:
alg_info["info"] = []
alg_info["info"].append(since_text)
else:
alg_info["fail"] = [SSH2_KexDB.FAIL_UNKNOWN]
return alg_info
banner_str = '' banner_str = ''
banner_protocol = None banner_protocol = None
@ -723,7 +935,7 @@ def build_struct(target_host: str, banner: Optional['Banner'], kex: Optional['SS
banner_comments = None banner_comments = None
if banner is not None: if banner is not None:
banner_str = str(banner) banner_str = str(banner)
banner_protocol = banner.protocol banner_protocol = '.'.join(str(x) for x in banner.protocol)
banner_software = banner.software banner_software = banner.software
banner_comments = banner.comments banner_comments = banner.comments
@ -746,33 +958,61 @@ def build_struct(target_host: str, banner: Optional['Banner'], kex: Optional['SS
res['compression'] = kex.server.compression res['compression'] = kex.server.compression
res['kex'] = [] res['kex'] = []
alg_sizes = kex.dh_modulus_sizes() dh_alg_sizes = kex.dh_modulus_sizes()
for algorithm in kex.kex_algorithms: for algorithm in kex.kex_algorithms:
alg_notes = fetch_notes(algorithm, 'kex')
entry: Any = { entry: Any = {
'algorithm': algorithm, 'algorithm': algorithm,
'notes': alg_notes,
} }
if algorithm in alg_sizes: if algorithm in dh_alg_sizes:
hostkey_size, ca_size = alg_sizes[algorithm] hostkey_size = dh_alg_sizes[algorithm]
entry['keysize'] = hostkey_size entry['keysize'] = hostkey_size
if ca_size > 0:
entry['casize'] = ca_size
res['kex'].append(entry) res['kex'].append(entry)
res['key'] = [] res['key'] = []
alg_sizes = kex.rsa_key_sizes() host_keys = kex.host_keys()
for algorithm in kex.key_algorithms: for algorithm in kex.key_algorithms:
alg_notes = fetch_notes(algorithm, 'key')
entry = { entry = {
'algorithm': algorithm, 'algorithm': algorithm,
'notes': alg_notes,
} }
if algorithm in alg_sizes: if algorithm in host_keys:
hostkey_size, ca_size = alg_sizes[algorithm] hostkey_info = host_keys[algorithm]
hostkey_size = cast(int, hostkey_info['hostkey_size'])
ca_type = ''
ca_size = 0
if 'ca_key_type' in hostkey_info:
ca_type = cast(str, hostkey_info['ca_key_type'])
if 'ca_key_size' in hostkey_info:
ca_size = cast(int, hostkey_info['ca_key_size'])
if algorithm in HostKeyTest.RSA_FAMILY or algorithm.startswith('ssh-rsa-cert-v0'):
entry['keysize'] = hostkey_size entry['keysize'] = hostkey_size
if ca_size > 0: if ca_size > 0:
entry['ca_algorithm'] = ca_type
entry['casize'] = ca_size entry['casize'] = ca_size
res['key'].append(entry) res['key'].append(entry)
res['enc'] = kex.server.encryption res['enc'] = []
res['mac'] = kex.server.mac for algorithm in kex.server.encryption:
alg_notes = fetch_notes(algorithm, 'enc')
entry = {
'algorithm': algorithm,
'notes': alg_notes,
}
res['enc'].append(entry)
res['mac'] = []
for algorithm in kex.server.mac:
alg_notes = fetch_notes(algorithm, 'mac')
entry = {
'algorithm': algorithm,
'notes': alg_notes,
}
res['mac'].append(entry)
res['fingerprints'] = [] res['fingerprints'] = []
host_keys = kex.host_keys() host_keys = kex.host_keys()
@ -787,7 +1027,7 @@ def build_struct(target_host: str, banner: Optional['Banner'], kex: Optional['SS
if host_keys[host_key_type] is None: if host_keys[host_key_type] is None:
continue continue
fp = Fingerprint(host_keys[host_key_type]) fp = Fingerprint(cast(bytes, host_keys[host_key_type]['raw_hostkey_bytes']))
# Skip over certificate host types (or we would return invalid fingerprints). # Skip over certificate host types (or we would return invalid fingerprints).
if '-cert-' in host_key_type: if '-cert-' in host_key_type:
@ -821,6 +1061,12 @@ def build_struct(target_host: str, banner: Optional['Banner'], kex: Optional['SS
'fp': pkm_fp, 'fp': pkm_fp,
}] }]
# Add in the CVE information.
res['cves'] = cves
# Add in the recommendations.
res['recommendations'] = get_algorithm_recommendations(algorithms, algorithm_recommendation_suppress_list, software, for_server=True)
return res return res
@ -896,14 +1142,17 @@ def audit(out: OutputBuffer, aconf: AuditConf, sshv: Optional[int] = None, print
program_retval = output(out, aconf, banner, header, pkm=SSH1_PublicKeyMessage.parse(payload)) program_retval = output(out, aconf, banner, header, pkm=SSH1_PublicKeyMessage.parse(payload))
elif sshv == 2: elif sshv == 2:
try: try:
kex = SSH2_Kex.parse(payload) kex = SSH2_Kex.parse(out, payload)
except Exception: except Exception:
out.fail("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc())) out.fail("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc()))
return exitcodes.CONNECTION_ERROR return exitcodes.CONNECTION_ERROR
if aconf.client_audit is False: if aconf.client_audit is False:
HostKeyTest.run(out, s, kex) HostKeyTest.run(out, s, kex)
GEXTest.run(out, s, kex) if aconf.gex_test != '':
return run_gex_granular_modulus_size_test(out, s, kex, aconf)
else:
GEXTest.run(out, s, banner, kex)
# This is a standard audit scan. # This is a standard audit scan.
if (aconf.policy is None) and (aconf.make_policy is False): if (aconf.policy is None) and (aconf.make_policy is False):
@ -934,7 +1183,7 @@ def algorithm_lookup(out: OutputBuffer, alg_names: str) -> int:
} }
algorithm_names = alg_names.split(",") algorithm_names = alg_names.split(",")
adb = SSH2_KexDB.ALGORITHMS adb = SSH2_KexDB.get_db()
# Use nested dictionary comprehension to iterate an outer dictionary where # Use nested dictionary comprehension to iterate an outer dictionary where
# each key is an alg type that consists of a value (which is itself a # each key is an alg type that consists of a value (which is itself a
@ -1042,6 +1291,79 @@ def windows_manual(out: OutputBuffer) -> int:
return retval return retval
def get_permitted_syntax_for_gex_test() -> Dict[str, str]:
syntax = {
'RANGE': r'^\d+-\d+(:\d+)?$',
'LIST_WITHOUT_MIN_PREF_MAX': r'^\d+(,\d+)*$',
'LIST_WITH_MIN_PREF_MAX': r'^\d+:\d+:\d+(,\d+:\d+:\d+)*$'
}
return syntax
def run_gex_granular_modulus_size_test(out: OutputBuffer, s: 'SSH_Socket', kex: 'SSH2_Kex', aconf: AuditConf) -> int:
'''Extracts the user specified modulus sizes and submits them for testing against the target server. Returns an exitcodes.* flag.'''
permitted_syntax = get_permitted_syntax_for_gex_test()
mod_dict: Dict[str, List[int]] = {}
# Range syntax.
if re.search(permitted_syntax['RANGE'], aconf.gex_test):
extracted_digits = re.findall(r'\d+', aconf.gex_test)
bits_left_bound = int(extracted_digits[0])
bits_right_bound = int(extracted_digits[1])
bits_step = 1
if (len(extracted_digits)) == 3:
bits_step = int(extracted_digits[2])
# If the left value is greater than the right value, then the sequence
# operates from right to left.
if bits_left_bound <= bits_right_bound:
bits_in_range_to_test = range(bits_left_bound, bits_right_bound + 1, bits_step)
else:
bits_in_range_to_test = range(bits_left_bound, bits_right_bound - 1, -abs(bits_step))
out.v("A separate test will be performed against each of the following modulus sizes: " + ", ".join([str(x) for x in bits_in_range_to_test]) + ".", write_now=True)
for i_bits in bits_in_range_to_test:
program_retval = GEXTest.granular_modulus_size_test(out, s, kex, i_bits, i_bits, i_bits, mod_dict)
if program_retval != exitcodes.GOOD:
return program_retval
# Two variations of list syntax.
if re.search(permitted_syntax['LIST_WITHOUT_MIN_PREF_MAX'], aconf.gex_test):
bits_in_list_to_test = aconf.gex_test.split(',')
out.v("A separate test will be performed against each of the following modulus sizes: " + ", ".join([str(x) for x in bits_in_list_to_test]) + ".", write_now=True)
for s_bits in bits_in_list_to_test:
program_retval = GEXTest.granular_modulus_size_test(out, s, kex, int(s_bits), int(s_bits), int(s_bits), mod_dict)
if program_retval != exitcodes.GOOD:
return program_retval
if re.search(permitted_syntax['LIST_WITH_MIN_PREF_MAX'], aconf.gex_test):
sets_of_min_pref_max = aconf.gex_test.split(',')
out.v("A separate test will be performed against each of the following sets of 'min:pref:max' modulus sizes: " + ', '.join(sets_of_min_pref_max), write_now=True)
for set_of_min_pref_max in sets_of_min_pref_max:
bits_in_list_to_test = set_of_min_pref_max.split(':')
program_retval = GEXTest.granular_modulus_size_test(out, s, kex, int(bits_in_list_to_test[0]), int(bits_in_list_to_test[1]), int(bits_in_list_to_test[2]), mod_dict)
if program_retval != exitcodes.GOOD:
return program_retval
if mod_dict:
if aconf.json:
json_struct = {'dh-gex-modulus-size': mod_dict}
out.info(json.dumps(json_struct, indent=4 if aconf.json_print_indent else None, sort_keys=True))
else:
out.head('# diffie-hellman group exchange modulus size')
max_key_len = len(max(mod_dict, key=len))
for key, value in mod_dict.items():
padding = (max_key_len - len(key)) + 1
out.info(key + " " * padding + '--> ' + ', '.join([str(i) for i in value]))
return program_retval
def main() -> int: def main() -> int:
out = OutputBuffer() out = OutputBuffer()
aconf = process_commandline(out, sys.argv[1:], usage) aconf = process_commandline(out, sys.argv[1:], usage)
@ -1083,7 +1405,7 @@ def main() -> int:
host, port = Utils.parse_host_and_port(target, default_port=22) host, port = Utils.parse_host_and_port(target, default_port=22)
target_servers.append((host, port)) target_servers.append((host, port))
# A ranked list of return codes. Those with higher indices will take precendence over lower ones. For example, if three servers are scanned, yielding WARNING, GOOD, and UNKNOWN_ERROR, the overall result will be UNKNOWN_ERROR, since its index is the highest. Errors have highest priority, followed by failures, then warnings. # A ranked list of return codes. Those with higher indices will take precedence over lower ones. For example, if three servers are scanned, yielding WARNING, GOOD, and UNKNOWN_ERROR, the overall result will be UNKNOWN_ERROR, since its index is the highest. Errors have highest priority, followed by failures, then warnings.
ranked_return_codes = [exitcodes.GOOD, exitcodes.WARNING, exitcodes.FAILURE, exitcodes.CONNECTION_ERROR, exitcodes.UNKNOWN_ERROR] ranked_return_codes = [exitcodes.GOOD, exitcodes.WARNING, exitcodes.FAILURE, exitcodes.CONNECTION_ERROR, exitcodes.UNKNOWN_ERROR]
# Queue all worker threads. # Queue all worker threads.
@ -1113,6 +1435,10 @@ def main() -> int:
if aconf.json: if aconf.json:
print(']') print(']')
# Send notification that this thread is exiting. This deletes the thread's local copy of the algorithm databases.
SSH1_KexDB.thread_exit()
SSH2_KexDB.thread_exit()
else: # Just a scan against a single target. else: # Just a scan against a single target.
ret = audit(out, aconf) ret = audit(out, aconf)
out.write() out.write()

View File

@ -75,24 +75,26 @@ class SSH_Socket(ReadBuf, WriteBuf):
self.client_port = None self.client_port = None
def _resolve(self) -> Iterable[Tuple[int, Tuple[Any, ...]]]: def _resolve(self) -> Iterable[Tuple[int, Tuple[Any, ...]]]:
"""Resolves a hostname into a list of IPs
Raises
------
socket.gaierror [Errno -2]
If the hostname cannot be resolved.
"""
# If __ip_version_preference has only one entry, then it means that ONLY that IP version should be used. # If __ip_version_preference has only one entry, then it means that ONLY that IP version should be used.
if len(self.__ip_version_preference) == 1: if len(self.__ip_version_preference) == 1:
family = socket.AF_INET if self.__ip_version_preference[0] == 4 else socket.AF_INET6 family = socket.AF_INET if self.__ip_version_preference[0] == 4 else socket.AF_INET6
else: else:
family = socket.AF_UNSPEC family = socket.AF_UNSPEC
try:
stype = socket.SOCK_STREAM stype = socket.SOCK_STREAM
r = socket.getaddrinfo(self.__host, self.__port, family, stype) r = socket.getaddrinfo(self.__host, self.__port, family, stype)
# If the user has a preference for using IPv4 over IPv6 (or vice-versa), then sort the list returned by getaddrinfo() so that the preferred address type comes first. # If the user has a preference for using IPv4 over IPv6 (or vice-versa), then sort the list returned by getaddrinfo() so that the preferred address type comes first.
if len(self.__ip_version_preference) == 2: if len(self.__ip_version_preference) == 2:
r = sorted(r, key=lambda x: x[0], reverse=(self.__ip_version_preference[0] == 6)) r = sorted(r, key=lambda x: x[0], reverse=(self.__ip_version_preference[0] == 6)) # pylint: disable=superfluous-parens
for af, socktype, _proto, _canonname, addr in r: for af, socktype, _proto, _canonname, addr in r:
if socktype == socket.SOCK_STREAM: if socktype == socket.SOCK_STREAM:
yield af, addr yield af, addr
except socket.error as e:
self.__outputbuffer.fail('[exception] {}'.format(e)).write()
sys.exit(exitcodes.CONNECTION_ERROR)
# Listens on a server socket and accepts one connection (used for # Listens on a server socket and accepts one connection (used for
# auditing client connections). # auditing client connections).
@ -105,8 +107,8 @@ class SSH_Socket(ReadBuf, WriteBuf):
s.bind(('0.0.0.0', self.__port)) s.bind(('0.0.0.0', self.__port))
s.listen() s.listen()
self.__sock_map[s.fileno()] = s self.__sock_map[s.fileno()] = s
except Exception: except Exception as e:
print("Warning: failed to listen on any IPv4 interfaces.") print("Warning: failed to listen on any IPv4 interfaces: %s" % str(e))
try: try:
# Socket to listen on all IPv6 addresses. # Socket to listen on all IPv6 addresses.
@ -116,8 +118,8 @@ class SSH_Socket(ReadBuf, WriteBuf):
s.bind(('::', self.__port)) s.bind(('::', self.__port))
s.listen() s.listen()
self.__sock_map[s.fileno()] = s self.__sock_map[s.fileno()] = s
except Exception: except Exception as e:
print("Warning: failed to listen on any IPv6 interfaces.") print("Warning: failed to listen on any IPv6 interfaces: %s" % str(e))
# If we failed to listen on any interfaces, terminate. # If we failed to listen on any interfaces, terminate.
if len(self.__sock_map.keys()) == 0: if len(self.__sock_map.keys()) == 0:
@ -152,9 +154,9 @@ class SSH_Socket(ReadBuf, WriteBuf):
def connect(self) -> Optional[str]: def connect(self) -> Optional[str]:
'''Returns None on success, or an error string.''' '''Returns None on success, or an error string.'''
err = None err = None
for af, addr in self._resolve():
s = None s = None
try: try:
for af, addr in self._resolve():
s = socket.socket(af, socket.SOCK_STREAM) s = socket.socket(af, socket.SOCK_STREAM)
s.settimeout(self.__timeout) s.settimeout(self.__timeout)
self.__outputbuffer.d(("Connecting to %s:%d..." % ('[%s]' % addr[0] if Utils.is_ipv6_address(addr[0]) else addr[0], addr[1])), write_now=True) self.__outputbuffer.d(("Connecting to %s:%d..." % ('[%s]' % addr[0] if Utils.is_ipv6_address(addr[0]) else addr[0], addr[1])), write_now=True)
@ -236,7 +238,7 @@ class SSH_Socket(ReadBuf, WriteBuf):
self.__outputbuffer.d('KEX initialisation...', write_now=True) self.__outputbuffer.d('KEX initialisation...', write_now=True)
kexparty = SSH2_KexParty(ciphers, macs, compressions, languages) kexparty = SSH2_KexParty(ciphers, macs, compressions, languages)
kex = SSH2_Kex(os.urandom(16), key_exchanges, hostkeys, kexparty, kexparty, False, 0) kex = SSH2_Kex(self.__outputbuffer, os.urandom(16), key_exchanges, hostkeys, kexparty, kexparty, False, 0)
self.write_byte(Protocol.MSG_KEXINIT) self.write_byte(Protocol.MSG_KEXINIT)
kex.write(self) kex.write(self)
@ -325,7 +327,7 @@ class SSH_Socket(ReadBuf, WriteBuf):
self.__header = [] self.__header = []
self.__banner = None self.__banner = None
def _close_socket(self, s: Optional[socket.socket]) -> None: # pylint: disable=no-self-use def _close_socket(self, s: Optional[socket.socket]) -> None:
try: try:
if s is not None: if s is not None:
s.shutdown(socket.SHUT_RDWR) s.shutdown(socket.SHUT_RDWR)

View File

@ -35,6 +35,7 @@ class VersionVulnerabilityDB: # pylint: disable=too-few-public-methods
# then affected = 1 + 4 = 5. # then affected = 1 + 4 = 5.
CVE: Dict[str, List[List[Any]]] = { CVE: Dict[str, List[List[Any]]] = {
'Dropbear SSH': [ 'Dropbear SSH': [
['0.0', '2020.81', 2, 'CVE-2021-36369', 7.5, 'trivial authentication attack to bypass FIDO tokens and SSH-ASKPASS'],
['0.0', '2018.76', 1, 'CVE-2018-15599', 5.0, 'remote users may enumerate users on the system'], ['0.0', '2018.76', 1, 'CVE-2018-15599', 5.0, 'remote users may enumerate users on the system'],
['0.0', '2017.74', 5, 'CVE-2017-9079', 4.7, 'local users can read certain files as root'], ['0.0', '2017.74', 5, 'CVE-2017-9079', 4.7, 'local users can read certain files as root'],
['0.0', '2017.74', 5, 'CVE-2017-9078', 9.3, 'local users may elevate privileges to root under certain conditions'], ['0.0', '2017.74', 5, 'CVE-2017-9078', 9.3, 'local users may elevate privileges to root under certain conditions'],
@ -66,7 +67,21 @@ class VersionVulnerabilityDB: # pylint: disable=too-few-public-methods
['0.4.7', '0.5.2', 1, 'CVE-2012-4560', 7.5, 'cause DoS or execute arbitrary code (buffer overflow)'], ['0.4.7', '0.5.2', 1, 'CVE-2012-4560', 7.5, 'cause DoS or execute arbitrary code (buffer overflow)'],
['0.4.7', '0.5.2', 1, 'CVE-2012-4559', 6.8, 'cause DoS or execute arbitrary code (double free)']], ['0.4.7', '0.5.2', 1, 'CVE-2012-4559', 6.8, 'cause DoS or execute arbitrary code (double free)']],
'OpenSSH': [ 'OpenSSH': [
['1.0', '7.7', 1, 'CVE-2018-15473', 5.3, 'enumerate usernames due to timing discrepencies'], ['6.2', '8.7', 5, 'CVE-2021-41617', 7.0, 'privilege escalation via supplemental groups'],
['1.0', '8.8', 2, 'CVE-2021-36368', 3.7, 'trivial authentication attack to bypass FIDO tokens and SSH-ASKPASS'],
['8.2', '8.4', 2, 'CVE-2021-28041', 7.1, 'double free via ssh-agent'],
['1.0', '8.3', 5, 'CVE-2020-15778', 7.8, 'command injection via anomalous argument transfers'],
['5.7', '8.3', 2, 'CVE-2020-14145', 5.9, 'information leak via algorithm negotiation'],
['8.2', '8.2', 2, 'CVE-2020-12062', 7.5, 'arbitrary files overwrite via scp'],
['7.7', '8.0', 7, 'CVE-2019-16905', 7.8, 'memory corruption and local code execution via pre-authentication integer overflow'],
['1.0', '7.9', 2, 'CVE-2019-6111', 5.9, 'arbitrary files overwrite via scp'],
['1.0', '7.9', 2, 'CVE-2019-6110', 6.8, 'output manipulation'],
['1.0', '7.9', 2, 'CVE-2019-6109', 6.8, 'output manipulation'],
['1.0', '7.9', 2, 'CVE-2018-20685', 5.3, 'directory permissions modification via scp'],
['5.9', '7.8', 1, 'CVE-2018-15919', 5.3, 'username enumeration via GS2'],
['1.0', '7.7', 1, 'CVE-2018-15473', 5.3, 'enumerate usernames due to timing discrepancies'],
['1.2', '6.292', 1, 'CVE-2017-15906', 5.3, 'readonly bypass via sftp'],
['1.0', '8.7', 1, 'CVE-2016-20012', 5.3, 'enumerate usernames via challenge response'],
['7.2', '7.2p2', 1, 'CVE-2016-6515', 7.8, 'cause DoS via long password string (crypt CPU consumption)'], ['7.2', '7.2p2', 1, 'CVE-2016-6515', 7.8, 'cause DoS via long password string (crypt CPU consumption)'],
['1.2.2', '7.2', 1, 'CVE-2016-3115', 5.5, 'bypass command restrictions via crafted X11 forwarding data'], ['1.2.2', '7.2', 1, 'CVE-2016-3115', 5.5, 'bypass command restrictions via crafted X11 forwarding data'],
['5.4', '7.1', 1, 'CVE-2016-1907', 5.0, 'cause DoS via crafted network traffic (out of bounds read)'], ['5.4', '7.1', 1, 'CVE-2016-1907', 5.0, 'cause DoS via crafted network traffic (out of bounds read)'],
@ -125,6 +140,10 @@ class VersionVulnerabilityDB: # pylint: disable=too-few-public-methods
['1.2.3', '2.1.1', 1, 'CVE-2001-0361', 4.0, 'recover plaintext from ciphertext'], ['1.2.3', '2.1.1', 1, 'CVE-2001-0361', 4.0, 'recover plaintext from ciphertext'],
['1.2', '2.1', 1, 'CVE-2000-0525', 10.0, 'execute arbitrary code (improper privileges)']], ['1.2', '2.1', 1, 'CVE-2000-0525', 10.0, 'execute arbitrary code (improper privileges)']],
'PuTTY': [ 'PuTTY': [
# info for CVE-2021-36367 - only PuTTY up to 0.71 is affected - see https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/reject-trivial-auth.html
['0.0', '0.71', 2, 'CVE-2021-36367', 8.1, 'trivial authentication attack to bypass FIDO tokens and SSH-ASKPASS'],
['0.0', '0.74', 2, 'CVE-2021-33500', 5.0, 'denial of service of the complete windows desktop'],
['0.68', '0.73', 2, 'CVE-2020-14002', 4.3, 'Observable Discrepancy which allows man-in-the-middle attackers to target initial connection attempts'],
['0.54', '0.73', 2, 'CVE-2020-XXXX', 5.0, 'out of bounds memory read'], ['0.54', '0.73', 2, 'CVE-2020-XXXX', 5.0, 'out of bounds memory read'],
['0.0', '0.72', 2, 'CVE-2019-17069', 5.0, 'potential DOS by remote SSHv1 server'], ['0.0', '0.72', 2, 'CVE-2019-17069', 5.0, 'potential DOS by remote SSHv1 server'],
['0.71', '0.72', 2, 'CVE-2019-17068', 5.0, 'xterm bracketed paste mode command injection'], ['0.71', '0.72', 2, 'CVE-2019-17068', 5.0, 'xterm bracketed paste mode command injection'],

View File

@ -1,4 +1,4 @@
.TH SSH-AUDIT 1 "March 2, 2021" .TH SSH-AUDIT 1 "March 13, 2022"
.SH NAME .SH NAME
\fBssh-audit\fP \- SSH server & client configuration auditor \fBssh-audit\fP \- SSH server & client configuration auditor
.SH SYNOPSIS .SH SYNOPSIS
@ -6,7 +6,7 @@
.RI [ options ] " <target_host>" .RI [ options ] " <target_host>"
.SH DESCRIPTION .SH DESCRIPTION
.PP .PP
\fBssh-audit\fP analyzes the configuration of SSH servers & clients, then warns the user of weak, obsolete, and/or un-tested cryptographic primitives. It is very useful for hardening SSH tunnels, which by default tend to be optimized for compatibility, not security. \fBssh-audit\fP analyzes the configuration of SSH servers & clients, then warns the user of weak, obsolete, and/or untested cryptographic primitives. It is very useful for hardening SSH tunnels, which by default tend to be optimized for compatibility, not security.
.PP .PP
See <https://www.ssh\-audit.com/> for official hardening guides for common platforms. See <https://www.ssh\-audit.com/> for official hardening guides for common platforms.
@ -51,6 +51,36 @@ Starts a server on port 2222 to audit client software configuration. Use -p/--p
.br .br
Enable debug output. Enable debug output.
.TP
.B -g, \-\-gex-test=<x[,y,...] | min1:pref1:max1[,min2:pref2:max2,...] | x-y[:step]>
.br
Runs a Diffie-Hellman Group Exchange modulus size test against a server.
Diffie-Hellman requires the client and server to agree on a generator value and a modulus value. In the "Group Exchange" implementation of Diffie-Hellman, the client specifies the size of the modulus in bits by providing the server with minimum, preferred and maximum values. The server then finds a group that best matches the client's request, returning the corresponding generator and modulus. For a full explanation of this process see RFC 4419 and its successors.
This test acts as a client by providing an SSH server with the size of a modulus and then obtains the size of the modulus returned by the server.
Three types of syntax are supported:
1. <x[,y,...]>
A comma delimited list of modulus sizes.
A test is performed against each value in the list where it acts as the minimum, preferred and maximum modulus size.
2. <min:pref:max[,min:pref:max,...]>
A set of three colon delimited values denoting minimum, preferred and maximum modulus size.
A test is performed against each set.
Multiple sets can specified as a comma separated list.
3. <x-y[:step]>
A range of modulus sizes with an optional step value. Step defaults to 1 if omitted.
If the left value is greater than the right value, then the sequence operates from right to left.
A test is performed against each value in the range where it acts as the minimum, preferred and maximum modulus size.
Duplicates are excluded from the return value.
.TP .TP
.B -j, \-\-json .B -j, \-\-json
.br .br
@ -219,6 +249,30 @@ ssh-audit -M new_policy.txt targetserver
.fi .fi
.RE .RE
.LP
To run a Diffie-Hellman Group Exchange modulus size test using the values 2000 bits, 3000 bits, 4000 bits and 5000 bits:
.RS
.nf
ssh-audit targetserver --gex-test=2000,3000,4000,5000
.fi
.RE
.LP
To run a Diffie-Hellman Group Exchange modulus size test where 2048 bits is the minimum, 3072 bits is the preferred and 5000 bits is the maximum:
.RS
.nf
ssh-audit targetserver --gex-test=2048:3072:5000
.fi
.RE
.LP
To run a Diffie-Hellman Group Exchange modulus size test from 0 bits to 5120 bits in increments of 1024 bits:
.RS
.nf
ssh-audit targetserver --gex-test=0-5120:1024
.fi
.RE
.SH RETURN VALUES .SH RETURN VALUES
When a successful connection is made and all algorithms are rated as "good", \fBssh-audit\fP returns 0. Other possible return values are: When a successful connection is made and all algorithms are rated as "good", \fBssh-audit\fP returns 0. Other possible return values are:

View File

@ -1 +1,368 @@
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-dropbear_2019.78", "software": "dropbear_2019.78"}, "compression": ["zlib@openssh.com", "none"], "enc": ["aes128-ctr", "aes256-ctr", "aes128-cbc", "aes256-cbc", "3des-ctr", "3des-cbc"], "fingerprints": [{"hash": "CDfAU12pjQS7/91kg7gYacza0U/6PDbE04Ic3IpYxkM", "hash_alg": "SHA256", "hostkey": "ssh-rsa"}, {"hash": "63:7f:54:f7:0a:28:7f:75:0b:f4:07:0b:fc:66:51:a2", "hash_alg": "MD5", "hostkey": "ssh-rsa"}], "kex": [{"algorithm": "curve25519-sha256"}, {"algorithm": "curve25519-sha256@libssh.org"}, {"algorithm": "ecdh-sha2-nistp521"}, {"algorithm": "ecdh-sha2-nistp384"}, {"algorithm": "ecdh-sha2-nistp256"}, {"algorithm": "diffie-hellman-group14-sha256"}, {"algorithm": "diffie-hellman-group14-sha1"}, {"algorithm": "kexguess2@matt.ucc.asn.au"}], "key": [{"algorithm": "ecdsa-sha2-nistp256"}, {"algorithm": "ssh-rsa", "keysize": 1024}, {"algorithm": "ssh-dss"}], "mac": ["hmac-sha1-96", "hmac-sha1", "hmac-sha2-256"], "target": "localhost"} {
"banner": {
"comments": null,
"protocol": "2.0",
"raw": "SSH-2.0-dropbear_2019.78",
"software": "dropbear_2019.78"
},
"compression": [
"zlib@openssh.com",
"none"
],
"cves": [],
"enc": [
{
"algorithm": "aes128-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "aes256-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "aes128-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "aes256-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0, Dropbear SSH 0.47"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "3des-ctr",
"notes": {
"fail": [
"using broken & deprecated 3DES cipher"
],
"info": [
"available since Dropbear SSH 0.52"
]
}
},
{
"algorithm": "3des-cbc",
"notes": {
"fail": [
"using broken & deprecated 3DES cipher"
],
"info": [
"available since OpenSSH 1.2.2, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
}
],
"fingerprints": [
{
"hash": "CDfAU12pjQS7/91kg7gYacza0U/6PDbE04Ic3IpYxkM",
"hash_alg": "SHA256",
"hostkey": "ssh-rsa"
},
{
"hash": "63:7f:54:f7:0a:28:7f:75:0b:f4:07:0b:fc:66:51:a2",
"hash_alg": "MD5",
"hostkey": "ssh-rsa"
}
],
"kex": [
{
"algorithm": "curve25519-sha256",
"notes": {
"info": [
"default key exchange since OpenSSH 6.4",
"available since OpenSSH 7.4, Dropbear SSH 2018.76"
]
}
},
{
"algorithm": "curve25519-sha256@libssh.org",
"notes": {
"info": [
"default key exchange since OpenSSH 6.4",
"available since OpenSSH 6.4, Dropbear SSH 2013.62"
]
}
},
{
"algorithm": "ecdh-sha2-nistp521",
"notes": {
"fail": [
"using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency"
],
"info": [
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
]
}
},
{
"algorithm": "ecdh-sha2-nistp384",
"notes": {
"fail": [
"using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency"
],
"info": [
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
]
}
},
{
"algorithm": "ecdh-sha2-nistp256",
"notes": {
"fail": [
"using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency"
],
"info": [
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
]
}
},
{
"algorithm": "diffie-hellman-group14-sha256",
"notes": {
"info": [
"available since OpenSSH 7.3, Dropbear SSH 2016.73"
],
"warn": [
"2048-bit modulus only provides 112-bits of symmetric strength"
]
}
},
{
"algorithm": "diffie-hellman-group14-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 3.9, Dropbear SSH 0.53"
],
"warn": [
"2048-bit modulus only provides 112-bits of symmetric strength"
]
}
},
{
"algorithm": "kexguess2@matt.ucc.asn.au",
"notes": {
"info": [
"available since Dropbear SSH 2013.57"
]
}
}
],
"key": [
{
"algorithm": "ecdsa-sha2-nistp256",
"notes": {
"fail": [
"using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency"
],
"info": [
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
],
"warn": [
"using weak random number generator could reveal the key"
]
}
},
{
"algorithm": "ssh-rsa",
"keysize": 1024,
"notes": {
"fail": [
"using broken SHA-1 hash algorithm",
"using small 1024-bit modulus"
],
"info": [
"deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8",
"available since OpenSSH 2.5.0, Dropbear SSH 0.28"
]
}
},
{
"algorithm": "ssh-dss",
"notes": {
"fail": [
"using small 1024-bit modulus"
],
"info": [
"disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0",
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using weak random number generator could reveal the key"
]
}
}
],
"mac": [
{
"algorithm": "hmac-sha1-96",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0, Dropbear SSH 0.47"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha2-256",
"notes": {
"info": [
"available since OpenSSH 5.9, Dropbear SSH 2013.56"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
}
],
"recommendations": {
"critical": {
"del": {
"enc": [
{
"name": "3des-cbc",
"notes": ""
},
{
"name": "3des-ctr",
"notes": ""
}
],
"kex": [
{
"name": "diffie-hellman-group14-sha1",
"notes": ""
},
{
"name": "ecdh-sha2-nistp256",
"notes": ""
},
{
"name": "ecdh-sha2-nistp384",
"notes": ""
},
{
"name": "ecdh-sha2-nistp521",
"notes": ""
}
],
"key": [
{
"name": "ecdsa-sha2-nistp256",
"notes": ""
},
{
"name": "ssh-dss",
"notes": ""
},
{
"name": "ssh-rsa",
"notes": ""
}
],
"mac": [
{
"name": "hmac-sha1",
"notes": ""
},
{
"name": "hmac-sha1-96",
"notes": ""
}
]
}
},
"informational": {
"add": {
"enc": [
{
"name": "twofish128-ctr",
"notes": ""
},
{
"name": "twofish256-ctr",
"notes": ""
}
],
"kex": [
{
"name": "diffie-hellman-group16-sha512",
"notes": ""
}
]
}
},
"warning": {
"del": {
"enc": [
{
"name": "aes128-cbc",
"notes": ""
},
{
"name": "aes256-cbc",
"notes": ""
}
],
"kex": [
{
"name": "diffie-hellman-group14-sha256",
"notes": ""
}
],
"mac": [
{
"name": "hmac-sha2-256",
"notes": ""
}
]
}
}
},
"target": "localhost:2222"
}

View File

@ -6,57 +6,55 @@
# key exchange algorithms # key exchange algorithms
(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76 (kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.5, Dropbear SSH 2013.62  `- [info] default key exchange since OpenSSH 6.4
(kex) ecdh-sha2-nistp521 -- [fail] using weak elliptic curves (kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
 `- [info] default key exchange since OpenSSH 6.4
(kex) ecdh-sha2-nistp521 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62 `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) ecdh-sha2-nistp384 -- [fail] using weak elliptic curves (kex) ecdh-sha2-nistp384 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62 `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) ecdh-sha2-nistp256 -- [fail] using weak elliptic curves (kex) ecdh-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62 `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) diffie-hellman-group14-sha256 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73 (kex) diffie-hellman-group14-sha256 -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength
(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing algorithm `- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53 `- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
(kex) kexguess2@matt.ucc.asn.au -- [info] available since Dropbear SSH 2013.57 (kex) kexguess2@matt.ucc.asn.au -- [info] available since Dropbear SSH 2013.57
# host-key algorithms # host-key algorithms
(key) ecdsa-sha2-nistp256 -- [fail] using weak elliptic curves (key) ecdsa-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
 `- [warn] using weak random number generator could reveal the key  `- [warn] using weak random number generator could reveal the key
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62 `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(key) ssh-rsa (1024-bit) -- [fail] using weak hashing algorithm (key) ssh-rsa (1024-bit) -- [fail] using broken SHA-1 hash algorithm
 `- [fail] using small 1024-bit modulus  `- [fail] using small 1024-bit modulus
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2 `- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
(key) ssh-dss -- [fail] using small 1024-bit modulus (key) ssh-dss -- [fail] using small 1024-bit modulus
 `- [fail] removed (in server) and disabled (in client) since OpenSSH 7.0, weak algorithm
 `- [warn] using weak random number generator could reveal the key  `- [warn] using weak random number generator could reveal the key
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
# encryption algorithms (ciphers) # encryption algorithms (ciphers)
(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes128-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
(enc) aes256-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes256-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47
(enc) 3des-ctr -- [fail] using weak cipher (enc) 3des-ctr -- [fail] using broken & deprecated 3DES cipher
`- [info] available since Dropbear SSH 0.52 `- [info] available since Dropbear SSH 0.52
(enc) 3des-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) 3des-cbc -- [fail] using broken & deprecated 3DES cipher
 `- [warn] disabled (in client) since OpenSSH 7.4, unsafe algorithm
 `- [warn] using weak cipher
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28 `- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
# message authentication code algorithms # message authentication code algorithms
(mac) hmac-sha1-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-sha1-96 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47
(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode (mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] using weak hashing algorithm  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
(mac) hmac-sha2-256 -- [warn] using encrypt-and-MAC mode (mac) hmac-sha2-256 -- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56 `- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56
@ -67,20 +65,21 @@
# algorithm recommendations (for Dropbear SSH 2019.78) # algorithm recommendations (for Dropbear SSH 2019.78)
(rec) -3des-cbc -- enc algorithm to remove  (rec) -3des-cbc -- enc algorithm to remove 
(rec) -3des-ctr -- enc algorithm to remove  (rec) -3des-ctr -- enc algorithm to remove 
(rec) -aes128-cbc -- enc algorithm to remove  (rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove 
(rec) -aes256-cbc -- enc algorithm to remove 
(rec) -ecdh-sha2-nistp256 -- kex algorithm to remove  (rec) -ecdh-sha2-nistp256 -- kex algorithm to remove 
(rec) -ecdh-sha2-nistp384 -- kex algorithm to remove  (rec) -ecdh-sha2-nistp384 -- kex algorithm to remove 
(rec) -ecdh-sha2-nistp521 -- kex algorithm to remove  (rec) -ecdh-sha2-nistp521 -- kex algorithm to remove 
(rec) -ecdsa-sha2-nistp256 -- key algorithm to remove  (rec) -ecdsa-sha2-nistp256 -- key algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove 
(rec) -hmac-sha1-96 -- mac algorithm to remove  (rec) -hmac-sha1-96 -- mac algorithm to remove 
(rec) -ssh-dss -- key algorithm to remove  (rec) -ssh-dss -- key algorithm to remove 
(rec) -ssh-rsa -- key algorithm to remove  (rec) -ssh-rsa -- key algorithm to remove 
(rec) +diffie-hellman-group16-sha512 -- kex algorithm to append  (rec) +diffie-hellman-group16-sha512 -- kex algorithm to append 
(rec) +twofish128-ctr -- enc algorithm to append  (rec) +twofish128-ctr -- enc algorithm to append 
(rec) +twofish256-ctr -- enc algorithm to append  (rec) +twofish256-ctr -- enc algorithm to append 
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove  (rec) -aes128-cbc -- enc algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove  (rec) -aes256-cbc -- enc algorithm to remove 
(rec) -diffie-hellman-group14-sha256 -- kex algorithm to remove 
(rec) -hmac-sha2-256 -- mac algorithm to remove  (rec) -hmac-sha2-256 -- mac algorithm to remove 
# additional info # additional info

View File

@ -1 +1,522 @@
{"banner": {"comments": null, "protocol": [1, 99], "raw": "SSH-1.99-OpenSSH_4.0", "software": "OpenSSH_4.0"}, "compression": ["none", "zlib"], "enc": ["aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "arcfour", "aes192-cbc", "aes256-cbc", "rijndael-cbc@lysator.liu.se", "aes128-ctr", "aes192-ctr", "aes256-ctr"], "fingerprints": [{"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4", "hash_alg": "SHA256", "hostkey": "ssh-rsa"}, {"hash": "3c:c3:38:f8:55:39:c0:4a:5a:17:89:60:2c:a1:fc:6a", "hash_alg": "MD5", "hostkey": "ssh-rsa"}], "kex": [{"algorithm": "diffie-hellman-group-exchange-sha1", "keysize": 1024}, {"algorithm": "diffie-hellman-group14-sha1"}, {"algorithm": "diffie-hellman-group1-sha1"}], "key": [{"algorithm": "ssh-rsa", "keysize": 1024}, {"algorithm": "ssh-dss"}], "mac": ["hmac-md5", "hmac-sha1", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"} {
"banner": {
"comments": null,
"protocol": "1.99",
"raw": "SSH-1.99-OpenSSH_4.0",
"software": "OpenSSH_4.0"
},
"compression": [
"none",
"zlib"
],
"cves": [
{
"cvssv2": 7.8,
"description": "command injection via anomalous argument transfers",
"name": "CVE-2020-15778"
},
{
"cvssv2": 5.3,
"description": "enumerate usernames due to timing discrepancies",
"name": "CVE-2018-15473"
},
{
"cvssv2": 5.3,
"description": "readonly bypass via sftp",
"name": "CVE-2017-15906"
},
{
"cvssv2": 5.3,
"description": "enumerate usernames via challenge response",
"name": "CVE-2016-20012"
},
{
"cvssv2": 5.5,
"description": "bypass command restrictions via crafted X11 forwarding data",
"name": "CVE-2016-3115"
},
{
"cvssv2": 7.5,
"description": "cause DoS via triggering error condition (memory corruption)",
"name": "CVE-2014-1692"
},
{
"cvssv2": 3.5,
"description": "leak data via debug messages",
"name": "CVE-2012-0814"
},
{
"cvssv2": 3.5,
"description": "cause DoS via large value in certain length field (memory consumption)",
"name": "CVE-2011-5000"
},
{
"cvssv2": 5.0,
"description": "cause DoS via large number of connections (slot exhaustion)",
"name": "CVE-2010-5107"
},
{
"cvssv2": 4.0,
"description": "cause DoS via crafted glob expression (CPU and memory consumption)",
"name": "CVE-2010-4755"
},
{
"cvssv2": 7.5,
"description": "bypass authentication check via crafted values",
"name": "CVE-2010-4478"
},
{
"cvssv2": 2.6,
"description": "recover plaintext data from ciphertext",
"name": "CVE-2008-5161"
},
{
"cvssv2": 5.0,
"description": "cause DoS via multiple login attempts (slot exhaustion)",
"name": "CVE-2008-4109"
},
{
"cvssv2": 6.5,
"description": "bypass command restrictions via modifying session file",
"name": "CVE-2008-1657"
},
{
"cvssv2": 6.9,
"description": "hijack forwarded X11 connections",
"name": "CVE-2008-1483"
},
{
"cvssv2": 7.5,
"description": "privilege escalation via causing an X client to be trusted",
"name": "CVE-2007-4752"
},
{
"cvssv2": 5.0,
"description": "discover valid usernames through different responses",
"name": "CVE-2007-2243"
},
{
"cvssv2": 5.0,
"description": "discover valid usernames through different responses",
"name": "CVE-2006-5052"
},
{
"cvssv2": 9.3,
"description": "cause DoS or execute arbitrary code (double free)",
"name": "CVE-2006-5051"
},
{
"cvssv2": 7.8,
"description": "cause DoS via crafted packet (CPU consumption)",
"name": "CVE-2006-4924"
},
{
"cvssv2": 4.6,
"description": "execute arbitrary code",
"name": "CVE-2006-0225"
},
{
"cvssv2": 5.0,
"description": "leak data about authentication credentials",
"name": "CVE-2005-2798"
}
],
"enc": [
{
"algorithm": "aes128-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "3des-cbc",
"notes": {
"fail": [
"using broken & deprecated 3DES cipher"
],
"info": [
"available since OpenSSH 1.2.2, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "blowfish-cbc",
"notes": {
"fail": [
"using weak & deprecated Blowfish cipher"
],
"info": [
"available since OpenSSH 1.2.2, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "cast128-cbc",
"notes": {
"fail": [
"using weak & deprecated CAST cipher"
],
"info": [
"available since OpenSSH 2.1.0"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "arcfour",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 2.1.0"
]
}
},
{
"algorithm": "aes192-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "aes256-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0, Dropbear SSH 0.47"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "rijndael-cbc@lysator.liu.se",
"notes": {
"fail": [
"using deprecated & non-standardized Rijndael cipher"
],
"info": [
"disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0",
"available since OpenSSH 2.3.0"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "aes128-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "aes192-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7"
]
}
},
{
"algorithm": "aes256-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
}
],
"fingerprints": [
{
"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4",
"hash_alg": "SHA256",
"hostkey": "ssh-rsa"
},
{
"hash": "3c:c3:38:f8:55:39:c0:4a:5a:17:89:60:2c:a1:fc:6a",
"hash_alg": "MD5",
"hostkey": "ssh-rsa"
}
],
"kex": [
{
"algorithm": "diffie-hellman-group-exchange-sha1",
"keysize": 1024,
"notes": {
"fail": [
"using small 1024-bit modulus"
],
"info": [
"available since OpenSSH 2.3.0"
]
}
},
{
"algorithm": "diffie-hellman-group14-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 3.9, Dropbear SSH 0.53"
],
"warn": [
"2048-bit modulus only provides 112-bits of symmetric strength"
]
}
},
{
"algorithm": "diffie-hellman-group1-sha1",
"notes": {
"fail": [
"using small 1024-bit modulus",
"vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)",
"using broken SHA-1 hash algorithm"
],
"info": [
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
]
}
}
],
"key": [
{
"algorithm": "ssh-rsa",
"keysize": 1024,
"notes": {
"fail": [
"using broken SHA-1 hash algorithm",
"using small 1024-bit modulus"
],
"info": [
"deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8",
"available since OpenSSH 2.5.0, Dropbear SSH 0.28"
]
}
},
{
"algorithm": "ssh-dss",
"notes": {
"fail": [
"using small 1024-bit modulus"
],
"info": [
"disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0",
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using weak random number generator could reveal the key"
]
}
}
],
"mac": [
{
"algorithm": "hmac-md5",
"notes": {
"fail": [
"using broken MD5 hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-ripemd160",
"notes": {
"fail": [
"using deprecated RIPEMD hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-ripemd160@openssh.com",
"notes": {
"fail": [
"using deprecated RIPEMD hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha1-96",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0, Dropbear SSH 0.47"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-md5-96",
"notes": {
"fail": [
"using broken MD5 hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
}
],
"recommendations": {
"critical": {
"del": {
"enc": [
{
"name": "3des-cbc",
"notes": ""
},
{
"name": "arcfour",
"notes": ""
},
{
"name": "blowfish-cbc",
"notes": ""
},
{
"name": "cast128-cbc",
"notes": ""
},
{
"name": "rijndael-cbc@lysator.liu.se",
"notes": ""
}
],
"kex": [
{
"name": "diffie-hellman-group14-sha1",
"notes": ""
},
{
"name": "diffie-hellman-group1-sha1",
"notes": ""
},
{
"name": "diffie-hellman-group-exchange-sha1",
"notes": ""
}
],
"key": [
{
"name": "ssh-dss",
"notes": ""
},
{
"name": "ssh-rsa",
"notes": ""
}
],
"mac": [
{
"name": "hmac-md5",
"notes": ""
},
{
"name": "hmac-md5-96",
"notes": ""
},
{
"name": "hmac-ripemd160",
"notes": ""
},
{
"name": "hmac-ripemd160@openssh.com",
"notes": ""
},
{
"name": "hmac-sha1",
"notes": ""
},
{
"name": "hmac-sha1-96",
"notes": ""
}
]
}
},
"warning": {
"del": {
"enc": [
{
"name": "aes128-cbc",
"notes": ""
},
{
"name": "aes192-cbc",
"notes": ""
},
{
"name": "aes256-cbc",
"notes": ""
}
]
}
}
},
"target": "localhost:2222"
}

View File

@ -6,7 +6,10 @@
(gen) compression: enabled (zlib) (gen) compression: enabled (zlib)
# security # security
(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepencies (cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers
(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepancies
(cve) CVE-2017-15906 -- (CVSSv2: 5.3) readonly bypass via sftp
(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response
(cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data (cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data
(cve) CVE-2014-1692 -- (CVSSv2: 7.5) cause DoS via triggering error condition (memory corruption) (cve) CVE-2014-1692 -- (CVSSv2: 7.5) cause DoS via triggering error condition (memory corruption)
(cve) CVE-2012-0814 -- (CVSSv2: 3.5) leak data via debug messages (cve) CVE-2012-0814 -- (CVSSv2: 3.5) leak data via debug messages
@ -29,91 +32,73 @@
# key exchange algorithms # key exchange algorithms
(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing algorithm (kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53 `- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus
 `- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm  `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)
 `- [fail] disabled (in client) since OpenSSH 7.0, logjam attack  `- [fail] using broken SHA-1 hash algorithm
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
# host-key algorithms # host-key algorithms
(key) ssh-rsa (1024-bit) -- [fail] using weak hashing algorithm (key) ssh-rsa (1024-bit) -- [fail] using broken SHA-1 hash algorithm
 `- [fail] using small 1024-bit modulus  `- [fail] using small 1024-bit modulus
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2 `- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
(key) ssh-dss -- [fail] using small 1024-bit modulus (key) ssh-dss -- [fail] using small 1024-bit modulus
 `- [fail] removed (in server) and disabled (in client) since OpenSSH 7.0, weak algorithm
 `- [warn] using weak random number generator could reveal the key  `- [warn] using weak random number generator could reveal the key
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
# encryption algorithms (ciphers) # encryption algorithms (ciphers)
(enc) aes128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes128-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
(enc) 3des-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) 3des-cbc -- [fail] using broken & deprecated 3DES cipher
 `- [warn] disabled (in client) since OpenSSH 7.4, unsafe algorithm
 `- [warn] using weak cipher
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28 `- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
(enc) blowfish-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) blowfish-cbc -- [fail] using weak & deprecated Blowfish cipher
 `- [fail] disabled since Dropbear SSH 0.53
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28 `- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
(enc) cast128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) cast128-cbc -- [fail] using weak & deprecated CAST cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(enc) arcfour -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(enc) aes192-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes192-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
(enc) aes256-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes256-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47
(enc) rijndael-cbc@lysator.liu.se -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) rijndael-cbc@lysator.liu.se -- [fail] using deprecated & non-standardized Rijndael cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes192-ctr -- [info] available since OpenSSH 3.7 (enc) aes192-ctr -- [info] available since OpenSSH 3.7
(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
# message authentication code algorithms # message authentication code algorithms
(mac) hmac-md5 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-md5 -- [fail] using broken MD5 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode (mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] using weak hashing algorithm  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
(mac) hmac-ripemd160 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-ripemd160 -- [fail] using deprecated RIPEMD hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.5.0 `- [info] available since OpenSSH 2.5.0
(mac) hmac-ripemd160@openssh.com -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-ripemd160@openssh.com -- [fail] using deprecated RIPEMD hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(mac) hmac-sha1-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-sha1-96 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47
(mac) hmac-md5-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-md5-96 -- [fail] using broken MD5 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.5.0 `- [info] available since OpenSSH 2.5.0
# fingerprints # fingerprints
@ -121,24 +106,24 @@
# algorithm recommendations (for OpenSSH 4.0) # algorithm recommendations (for OpenSSH 4.0)
(rec) -3des-cbc -- enc algorithm to remove  (rec) -3des-cbc -- enc algorithm to remove 
(rec) -aes128-cbc -- enc algorithm to remove 
(rec) -aes192-cbc -- enc algorithm to remove 
(rec) -aes256-cbc -- enc algorithm to remove 
(rec) -arcfour -- enc algorithm to remove  (rec) -arcfour -- enc algorithm to remove 
(rec) -blowfish-cbc -- enc algorithm to remove  (rec) -blowfish-cbc -- enc algorithm to remove 
(rec) -cast128-cbc -- enc algorithm to remove  (rec) -cast128-cbc -- enc algorithm to remove 
(rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove  (rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove 
(rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove  (rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove 
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove 
(rec) -hmac-md5 -- mac algorithm to remove  (rec) -hmac-md5 -- mac algorithm to remove 
(rec) -hmac-md5-96 -- mac algorithm to remove  (rec) -hmac-md5-96 -- mac algorithm to remove 
(rec) -hmac-ripemd160 -- mac algorithm to remove  (rec) -hmac-ripemd160 -- mac algorithm to remove 
(rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove  (rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove 
(rec) -hmac-sha1-96 -- mac algorithm to remove  (rec) -hmac-sha1-96 -- mac algorithm to remove 
(rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove  (rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove 
(rec) -ssh-dss -- key algorithm to remove  (rec) -ssh-dss -- key algorithm to remove 
(rec) -ssh-rsa -- key algorithm to remove  (rec) -ssh-rsa -- key algorithm to remove 
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove  (rec) -aes128-cbc -- enc algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove  (rec) -aes192-cbc -- enc algorithm to remove 
(rec) -aes256-cbc -- enc algorithm to remove 
# additional info # additional info
(nfo) For hardening guides on common OSes, please see: <https://www.ssh-audit.com/hardening_guides.html> (nfo) For hardening guides on common OSes, please see: <https://www.ssh-audit.com/hardening_guides.html>

View File

@ -1 +1,6 @@
{"errors": [], "host": "localhost", "passed": true, "policy": "Docker policy: test1 (version 1)"} {
"errors": [],
"host": "localhost",
"passed": true,
"policy": "Docker policy: test1 (version 1)"
}

View File

@ -1 +1,31 @@
{"errors": [{"actual": ["3072"], "expected_optional": [""], "expected_required": ["4096"], "mismatched_field": "RSA host key (ssh-rsa-cert-v01@openssh.com) sizes"}, {"actual": ["1024"], "expected_optional": [""], "expected_required": ["4096"], "mismatched_field": "RSA CA key (ssh-rsa-cert-v01@openssh.com) sizes"}], "host": "localhost", "passed": false, "policy": "Docker poliicy: test10 (version 1)"} {
"errors": [
{
"actual": [
"3072"
],
"expected_optional": [
""
],
"expected_required": [
"4096"
],
"mismatched_field": "Host key (ssh-rsa-cert-v01@openssh.com) sizes"
},
{
"actual": [
"1024"
],
"expected_optional": [
""
],
"expected_required": [
"4096"
],
"mismatched_field": "CA signature size (ssh-rsa)"
}
],
"host": "localhost",
"passed": false,
"policy": "Docker poliicy: test10 (version 1)"
}

View File

@ -1,13 +1,28 @@
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
Host: localhost:2222 Host: localhost:2222
Policy: Docker poliicy: test10 (version 1) Policy: Docker poliicy: test10 (version 1)
Result: ❌ Failed! Result: ❌ Failed!
 
Errors: Errors:
* RSA CA key (ssh-rsa-cert-v01@openssh.com) sizes did not match. * CA signature size (ssh-rsa) did not match.
- Expected: 4096 - Expected: 4096
- Actual: 1024 - Actual: 1024
* RSA host key (ssh-rsa-cert-v01@openssh.com) sizes did not match. * Host key (ssh-rsa-cert-v01@openssh.com) sizes did not match.
- Expected: 4096 - Expected: 4096
- Actual: 3072 - Actual: 3072
 

View File

@ -1 +1,23 @@
{"errors": [{"actual": ["diffie-hellman-group-exchange-sha256", "diffie-hellman-group-exchange-sha1", "diffie-hellman-group14-sha1", "diffie-hellman-group1-sha1"], "expected_optional": [""], "expected_required": ["kex_alg1", "kex_alg2"], "mismatched_field": "Key exchanges"}], "host": "localhost", "passed": false, "policy": "Docker policy: test2 (version 1)"} {
"errors": [
{
"actual": [
"diffie-hellman-group-exchange-sha256",
"diffie-hellman-group-exchange-sha1",
"diffie-hellman-group14-sha1",
"diffie-hellman-group1-sha1"
],
"expected_optional": [
""
],
"expected_required": [
"kex_alg1",
"kex_alg2"
],
"mismatched_field": "Key exchanges"
}
],
"host": "localhost",
"passed": false,
"policy": "Docker policy: test2 (version 1)"
}

View File

@ -1 +1,22 @@
{"errors": [{"actual": ["ssh-rsa", "ssh-dss"], "expected_optional": [""], "expected_required": ["ssh-rsa", "ssh-dss", "key_alg1"], "mismatched_field": "Host keys"}], "host": "localhost", "passed": false, "policy": "Docker policy: test3 (version 1)"} {
"errors": [
{
"actual": [
"ssh-rsa",
"ssh-dss"
],
"expected_optional": [
""
],
"expected_required": [
"ssh-rsa",
"ssh-dss",
"key_alg1"
],
"mismatched_field": "Host keys"
}
],
"host": "localhost",
"passed": false,
"policy": "Docker policy: test3 (version 1)"
}

View File

@ -1 +1,32 @@
{"errors": [{"actual": ["aes128-ctr", "aes192-ctr", "aes256-ctr", "arcfour256", "arcfour128", "aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "aes192-cbc", "aes256-cbc", "arcfour", "rijndael-cbc@lysator.liu.se"], "expected_optional": [""], "expected_required": ["cipher_alg1", "cipher_alg2"], "mismatched_field": "Ciphers"}], "host": "localhost", "passed": false, "policy": "Docker policy: test4 (version 1)"} {
"errors": [
{
"actual": [
"aes128-ctr",
"aes192-ctr",
"aes256-ctr",
"arcfour256",
"arcfour128",
"aes128-cbc",
"3des-cbc",
"blowfish-cbc",
"cast128-cbc",
"aes192-cbc",
"aes256-cbc",
"arcfour",
"rijndael-cbc@lysator.liu.se"
],
"expected_optional": [
""
],
"expected_required": [
"cipher_alg1",
"cipher_alg2"
],
"mismatched_field": "Ciphers"
}
],
"host": "localhost",
"passed": false,
"policy": "Docker policy: test4 (version 1)"
}

View File

@ -1 +1,31 @@
{"errors": [{"actual": ["hmac-md5", "hmac-sha1", "umac-64@openssh.com", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "expected_optional": [""], "expected_required": ["hmac-md5", "hmac-sha1", "umac-64@openssh.com", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac_alg1", "hmac-md5-96"], "mismatched_field": "MACs"}], "host": "localhost", "passed": false, "policy": "Docker policy: test5 (version 1)"} {
"errors": [
{
"actual": [
"hmac-md5",
"hmac-sha1",
"umac-64@openssh.com",
"hmac-ripemd160",
"hmac-ripemd160@openssh.com",
"hmac-sha1-96",
"hmac-md5-96"
],
"expected_optional": [
""
],
"expected_required": [
"hmac-md5",
"hmac-sha1",
"umac-64@openssh.com",
"hmac-ripemd160",
"hmac-ripemd160@openssh.com",
"hmac_alg1",
"hmac-md5-96"
],
"mismatched_field": "MACs"
}
],
"host": "localhost",
"passed": false,
"policy": "Docker policy: test5 (version 1)"
}

View File

@ -1 +1,6 @@
{"errors": [], "host": "localhost", "passed": true, "policy": "Docker poliicy: test7 (version 1)"} {
"errors": [],
"host": "localhost",
"passed": true,
"policy": "Docker poliicy: test7 (version 1)"
}

View File

@ -1,3 +1,18 @@
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
Host: localhost:2222 Host: localhost:2222
Policy: Docker poliicy: test7 (version 1) Policy: Docker poliicy: test7 (version 1)
Result: ✔ Passed Result: ✔ Passed

View File

@ -1 +1,19 @@
{"errors": [{"actual": ["1024"], "expected_optional": [""], "expected_required": ["2048"], "mismatched_field": "RSA CA key (ssh-rsa-cert-v01@openssh.com) sizes"}], "host": "localhost", "passed": false, "policy": "Docker poliicy: test8 (version 1)"} {
"errors": [
{
"actual": [
"1024"
],
"expected_optional": [
""
],
"expected_required": [
"2048"
],
"mismatched_field": "CA signature size (ssh-rsa)"
}
],
"host": "localhost",
"passed": false,
"policy": "Docker poliicy: test8 (version 1)"
}

View File

@ -1,9 +1,24 @@
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
Host: localhost:2222 Host: localhost:2222
Policy: Docker poliicy: test8 (version 1) Policy: Docker poliicy: test8 (version 1)
Result: ❌ Failed! Result: ❌ Failed!
 
Errors: Errors:
* RSA CA key (ssh-rsa-cert-v01@openssh.com) sizes did not match. * CA signature size (ssh-rsa) did not match.
- Expected: 2048 - Expected: 2048
- Actual: 1024 - Actual: 1024
 

View File

@ -1 +1,19 @@
{"errors": [{"actual": ["3072"], "expected_optional": [""], "expected_required": ["4096"], "mismatched_field": "RSA host key (ssh-rsa-cert-v01@openssh.com) sizes"}], "host": "localhost", "passed": false, "policy": "Docker poliicy: test9 (version 1)"} {
"errors": [
{
"actual": [
"3072"
],
"expected_optional": [
""
],
"expected_required": [
"4096"
],
"mismatched_field": "Host key (ssh-rsa-cert-v01@openssh.com) sizes"
}
],
"host": "localhost",
"passed": false,
"policy": "Docker poliicy: test9 (version 1)"
}

View File

@ -1,9 +1,24 @@
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
Host: localhost:2222 Host: localhost:2222
Policy: Docker poliicy: test9 (version 1) Policy: Docker poliicy: test9 (version 1)
Result: ❌ Failed! Result: ❌ Failed!
 
Errors: Errors:
* RSA host key (ssh-rsa-cert-v01@openssh.com) sizes did not match. * Host key (ssh-rsa-cert-v01@openssh.com) sizes did not match.
- Expected: 4096 - Expected: 4096
- Actual: 3072 - Actual: 3072
 

View File

@ -1 +1,555 @@
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_5.6", "software": "OpenSSH_5.6"}, "compression": ["none", "zlib@openssh.com"], "enc": ["aes128-ctr", "aes192-ctr", "aes256-ctr", "arcfour256", "arcfour128", "aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "aes192-cbc", "aes256-cbc", "arcfour", "rijndael-cbc@lysator.liu.se"], "fingerprints": [{"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4", "hash_alg": "SHA256", "hostkey": "ssh-rsa"}, {"hash": "3c:c3:38:f8:55:39:c0:4a:5a:17:89:60:2c:a1:fc:6a", "hash_alg": "MD5", "hostkey": "ssh-rsa"}], "kex": [{"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 1024}, {"algorithm": "diffie-hellman-group-exchange-sha1", "keysize": 1024}, {"algorithm": "diffie-hellman-group14-sha1"}, {"algorithm": "diffie-hellman-group1-sha1"}], "key": [{"algorithm": "ssh-rsa", "keysize": 1024}, {"algorithm": "ssh-dss"}], "mac": ["hmac-md5", "hmac-sha1", "umac-64@openssh.com", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"} {
"banner": {
"comments": null,
"protocol": "2.0",
"raw": "SSH-2.0-OpenSSH_5.6",
"software": "OpenSSH_5.6"
},
"compression": [
"none",
"zlib@openssh.com"
],
"cves": [
{
"cvssv2": 7.8,
"description": "command injection via anomalous argument transfers",
"name": "CVE-2020-15778"
},
{
"cvssv2": 5.3,
"description": "enumerate usernames due to timing discrepancies",
"name": "CVE-2018-15473"
},
{
"cvssv2": 5.3,
"description": "readonly bypass via sftp",
"name": "CVE-2017-15906"
},
{
"cvssv2": 5.3,
"description": "enumerate usernames via challenge response",
"name": "CVE-2016-20012"
},
{
"cvssv2": 5.5,
"description": "bypass command restrictions via crafted X11 forwarding data",
"name": "CVE-2016-3115"
},
{
"cvssv2": 5.0,
"description": "cause DoS via crafted network traffic (out of bounds read)",
"name": "CVE-2016-1907"
},
{
"cvssv2": 6.9,
"description": "privilege escalation via leveraging sshd uid",
"name": "CVE-2015-6564"
},
{
"cvssv2": 1.9,
"description": "conduct impersonation attack",
"name": "CVE-2015-6563"
},
{
"cvssv2": 5.8,
"description": "bypass environment restrictions via specific string before wildcard",
"name": "CVE-2014-2532"
},
{
"cvssv2": 7.5,
"description": "cause DoS via triggering error condition (memory corruption)",
"name": "CVE-2014-1692"
},
{
"cvssv2": 3.5,
"description": "leak data via debug messages",
"name": "CVE-2012-0814"
},
{
"cvssv2": 3.5,
"description": "cause DoS via large value in certain length field (memory consumption)",
"name": "CVE-2011-5000"
},
{
"cvssv2": 5.0,
"description": "cause DoS via large number of connections (slot exhaustion)",
"name": "CVE-2010-5107"
},
{
"cvssv2": 4.0,
"description": "cause DoS via crafted glob expression (CPU and memory consumption)",
"name": "CVE-2010-4755"
},
{
"cvssv2": 7.5,
"description": "bypass authentication check via crafted values",
"name": "CVE-2010-4478"
}
],
"enc": [
{
"algorithm": "aes128-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "aes192-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7"
]
}
},
{
"algorithm": "aes256-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "arcfour256",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 4.2"
]
}
},
{
"algorithm": "arcfour128",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 4.2"
]
}
},
{
"algorithm": "aes128-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "3des-cbc",
"notes": {
"fail": [
"using broken & deprecated 3DES cipher"
],
"info": [
"available since OpenSSH 1.2.2, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "blowfish-cbc",
"notes": {
"fail": [
"using weak & deprecated Blowfish cipher"
],
"info": [
"available since OpenSSH 1.2.2, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "cast128-cbc",
"notes": {
"fail": [
"using weak & deprecated CAST cipher"
],
"info": [
"available since OpenSSH 2.1.0"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "aes192-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "aes256-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0, Dropbear SSH 0.47"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "arcfour",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 2.1.0"
]
}
},
{
"algorithm": "rijndael-cbc@lysator.liu.se",
"notes": {
"fail": [
"using deprecated & non-standardized Rijndael cipher"
],
"info": [
"disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0",
"available since OpenSSH 2.3.0"
],
"warn": [
"using weak cipher mode"
]
}
}
],
"fingerprints": [
{
"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4",
"hash_alg": "SHA256",
"hostkey": "ssh-rsa"
},
{
"hash": "3c:c3:38:f8:55:39:c0:4a:5a:17:89:60:2c:a1:fc:6a",
"hash_alg": "MD5",
"hostkey": "ssh-rsa"
}
],
"kex": [
{
"algorithm": "diffie-hellman-group-exchange-sha256",
"keysize": 1024,
"notes": {
"fail": [
"using small 1024-bit modulus"
],
"info": [
"available since OpenSSH 4.4"
]
}
},
{
"algorithm": "diffie-hellman-group-exchange-sha1",
"keysize": 1024,
"notes": {
"fail": [
"using small 1024-bit modulus"
],
"info": [
"available since OpenSSH 2.3.0"
]
}
},
{
"algorithm": "diffie-hellman-group14-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 3.9, Dropbear SSH 0.53"
],
"warn": [
"2048-bit modulus only provides 112-bits of symmetric strength"
]
}
},
{
"algorithm": "diffie-hellman-group1-sha1",
"notes": {
"fail": [
"using small 1024-bit modulus",
"vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)",
"using broken SHA-1 hash algorithm"
],
"info": [
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
]
}
}
],
"key": [
{
"algorithm": "ssh-rsa",
"keysize": 1024,
"notes": {
"fail": [
"using broken SHA-1 hash algorithm",
"using small 1024-bit modulus"
],
"info": [
"deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8",
"available since OpenSSH 2.5.0, Dropbear SSH 0.28"
]
}
},
{
"algorithm": "ssh-dss",
"notes": {
"fail": [
"using small 1024-bit modulus"
],
"info": [
"disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0",
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using weak random number generator could reveal the key"
]
}
}
],
"mac": [
{
"algorithm": "hmac-md5",
"notes": {
"fail": [
"using broken MD5 hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "umac-64@openssh.com",
"notes": {
"info": [
"available since OpenSSH 4.7"
],
"warn": [
"using encrypt-and-MAC mode",
"using small 64-bit tag size"
]
}
},
{
"algorithm": "hmac-ripemd160",
"notes": {
"fail": [
"using deprecated RIPEMD hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-ripemd160@openssh.com",
"notes": {
"fail": [
"using deprecated RIPEMD hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha1-96",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0, Dropbear SSH 0.47"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-md5-96",
"notes": {
"fail": [
"using broken MD5 hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
}
],
"recommendations": {
"critical": {
"chg": {
"kex": [
{
"name": "diffie-hellman-group-exchange-sha256",
"notes": "increase modulus size to 3072 bits or larger"
}
]
},
"del": {
"enc": [
{
"name": "3des-cbc",
"notes": ""
},
{
"name": "arcfour128",
"notes": ""
},
{
"name": "arcfour",
"notes": ""
},
{
"name": "arcfour256",
"notes": ""
},
{
"name": "blowfish-cbc",
"notes": ""
},
{
"name": "cast128-cbc",
"notes": ""
},
{
"name": "rijndael-cbc@lysator.liu.se",
"notes": ""
}
],
"kex": [
{
"name": "diffie-hellman-group14-sha1",
"notes": ""
},
{
"name": "diffie-hellman-group1-sha1",
"notes": ""
},
{
"name": "diffie-hellman-group-exchange-sha1",
"notes": ""
}
],
"key": [
{
"name": "ssh-dss",
"notes": ""
},
{
"name": "ssh-rsa",
"notes": ""
}
],
"mac": [
{
"name": "hmac-md5",
"notes": ""
},
{
"name": "hmac-md5-96",
"notes": ""
},
{
"name": "hmac-ripemd160",
"notes": ""
},
{
"name": "hmac-ripemd160@openssh.com",
"notes": ""
},
{
"name": "hmac-sha1",
"notes": ""
},
{
"name": "hmac-sha1-96",
"notes": ""
}
]
}
},
"warning": {
"del": {
"enc": [
{
"name": "aes128-cbc",
"notes": ""
},
{
"name": "aes192-cbc",
"notes": ""
},
{
"name": "aes256-cbc",
"notes": ""
}
],
"mac": [
{
"name": "umac-64@openssh.com",
"notes": ""
}
]
}
}
},
"target": "localhost:2222"
}

View File

@ -5,7 +5,10 @@
(gen) compression: enabled (zlib@openssh.com) (gen) compression: enabled (zlib@openssh.com)
# security # security
(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepencies (cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers
(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepancies
(cve) CVE-2017-15906 -- (CVSSv2: 5.3) readonly bypass via sftp
(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response
(cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data (cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data
(cve) CVE-2016-1907 -- (CVSSv2: 5.0) cause DoS via crafted network traffic (out of bounds read) (cve) CVE-2016-1907 -- (CVSSv2: 5.0) cause DoS via crafted network traffic (out of bounds read)
(cve) CVE-2015-6564 -- (CVSSv2: 6.9) privilege escalation via leveraging sshd uid (cve) CVE-2015-6564 -- (CVSSv2: 6.9) privilege escalation via leveraging sshd uid
@ -22,113 +25,88 @@
(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus
`- [info] available since OpenSSH 4.4 `- [info] available since OpenSSH 4.4
(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing algorithm (kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53 `- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus
 `- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm  `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)
 `- [fail] disabled (in client) since OpenSSH 7.0, logjam attack  `- [fail] using broken SHA-1 hash algorithm
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
# host-key algorithms # host-key algorithms
(key) ssh-rsa (1024-bit) -- [fail] using weak hashing algorithm (key) ssh-rsa (1024-bit) -- [fail] using broken SHA-1 hash algorithm
 `- [fail] using small 1024-bit modulus  `- [fail] using small 1024-bit modulus
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2 `- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
(key) ssh-dss -- [fail] using small 1024-bit modulus (key) ssh-dss -- [fail] using small 1024-bit modulus
 `- [fail] removed (in server) and disabled (in client) since OpenSSH 7.0, weak algorithm
 `- [warn] using weak random number generator could reveal the key  `- [warn] using weak random number generator could reveal the key
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
# encryption algorithms (ciphers) # encryption algorithms (ciphers)
(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes192-ctr -- [info] available since OpenSSH 3.7 (enc) aes192-ctr -- [info] available since OpenSSH 3.7
(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) arcfour256 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour256 -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 4.2 `- [info] available since OpenSSH 4.2
(enc) arcfour128 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour128 -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 4.2 `- [info] available since OpenSSH 4.2
(enc) aes128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes128-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
(enc) 3des-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) 3des-cbc -- [fail] using broken & deprecated 3DES cipher
 `- [warn] disabled (in client) since OpenSSH 7.4, unsafe algorithm
 `- [warn] using weak cipher
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28 `- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
(enc) blowfish-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) blowfish-cbc -- [fail] using weak & deprecated Blowfish cipher
 `- [fail] disabled since Dropbear SSH 0.53
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28 `- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
(enc) cast128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) cast128-cbc -- [fail] using weak & deprecated CAST cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(enc) aes192-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes192-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
(enc) aes256-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes256-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47
(enc) arcfour -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(enc) rijndael-cbc@lysator.liu.se -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) rijndael-cbc@lysator.liu.se -- [fail] using deprecated & non-standardized Rijndael cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
# message authentication code algorithms # message authentication code algorithms
(mac) hmac-md5 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-md5 -- [fail] using broken MD5 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode (mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] using weak hashing algorithm  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
(mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode (mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode
 `- [warn] using small 64-bit tag size  `- [warn] using small 64-bit tag size
`- [info] available since OpenSSH 4.7 `- [info] available since OpenSSH 4.7
(mac) hmac-ripemd160 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-ripemd160 -- [fail] using deprecated RIPEMD hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.5.0 `- [info] available since OpenSSH 2.5.0
(mac) hmac-ripemd160@openssh.com -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-ripemd160@openssh.com -- [fail] using deprecated RIPEMD hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(mac) hmac-sha1-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-sha1-96 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47
(mac) hmac-md5-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-md5-96 -- [fail] using broken MD5 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.5.0 `- [info] available since OpenSSH 2.5.0
# fingerprints # fingerprints
(fin) ssh-rsa: SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4 (fin) ssh-rsa: SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4
# algorithm recommendations (for OpenSSH 5.6) # algorithm recommendations (for OpenSSH 5.6)
(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 2048 bits or larger)  (rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 3072 bits or larger) 
(rec) -3des-cbc -- enc algorithm to remove  (rec) -3des-cbc -- enc algorithm to remove 
(rec) -aes128-cbc -- enc algorithm to remove 
(rec) -aes192-cbc -- enc algorithm to remove 
(rec) -aes256-cbc -- enc algorithm to remove 
(rec) -arcfour -- enc algorithm to remove  (rec) -arcfour -- enc algorithm to remove 
(rec) -arcfour128 -- enc algorithm to remove  (rec) -arcfour128 -- enc algorithm to remove 
(rec) -arcfour256 -- enc algorithm to remove  (rec) -arcfour256 -- enc algorithm to remove 
@ -136,16 +114,19 @@
(rec) -cast128-cbc -- enc algorithm to remove  (rec) -cast128-cbc -- enc algorithm to remove 
(rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove  (rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove 
(rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove  (rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove 
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove 
(rec) -hmac-md5 -- mac algorithm to remove  (rec) -hmac-md5 -- mac algorithm to remove 
(rec) -hmac-md5-96 -- mac algorithm to remove  (rec) -hmac-md5-96 -- mac algorithm to remove 
(rec) -hmac-ripemd160 -- mac algorithm to remove  (rec) -hmac-ripemd160 -- mac algorithm to remove 
(rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove  (rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove 
(rec) -hmac-sha1-96 -- mac algorithm to remove  (rec) -hmac-sha1-96 -- mac algorithm to remove 
(rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove  (rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove 
(rec) -ssh-dss -- key algorithm to remove  (rec) -ssh-dss -- key algorithm to remove 
(rec) -ssh-rsa -- key algorithm to remove  (rec) -ssh-rsa -- key algorithm to remove 
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove  (rec) -aes128-cbc -- enc algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove  (rec) -aes192-cbc -- enc algorithm to remove 
(rec) -aes256-cbc -- enc algorithm to remove 
(rec) -umac-64@openssh.com -- mac algorithm to remove  (rec) -umac-64@openssh.com -- mac algorithm to remove 
# additional info # additional info

View File

@ -1 +1,557 @@
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_5.6", "software": "OpenSSH_5.6"}, "compression": ["none", "zlib@openssh.com"], "enc": ["aes128-ctr", "aes192-ctr", "aes256-ctr", "arcfour256", "arcfour128", "aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "aes192-cbc", "aes256-cbc", "arcfour", "rijndael-cbc@lysator.liu.se"], "fingerprints": [{"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4", "hash_alg": "SHA256", "hostkey": "ssh-rsa"}, {"hash": "3c:c3:38:f8:55:39:c0:4a:5a:17:89:60:2c:a1:fc:6a", "hash_alg": "MD5", "hostkey": "ssh-rsa"}], "kex": [{"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 1024}, {"algorithm": "diffie-hellman-group-exchange-sha1", "keysize": 1024}, {"algorithm": "diffie-hellman-group14-sha1"}, {"algorithm": "diffie-hellman-group1-sha1"}], "key": [{"algorithm": "ssh-rsa", "keysize": 1024}, {"algorithm": "ssh-rsa-cert-v01@openssh.com", "casize": 1024, "keysize": 1024}], "mac": ["hmac-md5", "hmac-sha1", "umac-64@openssh.com", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"} {
"banner": {
"comments": null,
"protocol": "2.0",
"raw": "SSH-2.0-OpenSSH_5.6",
"software": "OpenSSH_5.6"
},
"compression": [
"none",
"zlib@openssh.com"
],
"cves": [
{
"cvssv2": 7.8,
"description": "command injection via anomalous argument transfers",
"name": "CVE-2020-15778"
},
{
"cvssv2": 5.3,
"description": "enumerate usernames due to timing discrepancies",
"name": "CVE-2018-15473"
},
{
"cvssv2": 5.3,
"description": "readonly bypass via sftp",
"name": "CVE-2017-15906"
},
{
"cvssv2": 5.3,
"description": "enumerate usernames via challenge response",
"name": "CVE-2016-20012"
},
{
"cvssv2": 5.5,
"description": "bypass command restrictions via crafted X11 forwarding data",
"name": "CVE-2016-3115"
},
{
"cvssv2": 5.0,
"description": "cause DoS via crafted network traffic (out of bounds read)",
"name": "CVE-2016-1907"
},
{
"cvssv2": 6.9,
"description": "privilege escalation via leveraging sshd uid",
"name": "CVE-2015-6564"
},
{
"cvssv2": 1.9,
"description": "conduct impersonation attack",
"name": "CVE-2015-6563"
},
{
"cvssv2": 5.8,
"description": "bypass environment restrictions via specific string before wildcard",
"name": "CVE-2014-2532"
},
{
"cvssv2": 7.5,
"description": "cause DoS via triggering error condition (memory corruption)",
"name": "CVE-2014-1692"
},
{
"cvssv2": 3.5,
"description": "leak data via debug messages",
"name": "CVE-2012-0814"
},
{
"cvssv2": 3.5,
"description": "cause DoS via large value in certain length field (memory consumption)",
"name": "CVE-2011-5000"
},
{
"cvssv2": 5.0,
"description": "cause DoS via large number of connections (slot exhaustion)",
"name": "CVE-2010-5107"
},
{
"cvssv2": 4.0,
"description": "cause DoS via crafted glob expression (CPU and memory consumption)",
"name": "CVE-2010-4755"
},
{
"cvssv2": 7.5,
"description": "bypass authentication check via crafted values",
"name": "CVE-2010-4478"
}
],
"enc": [
{
"algorithm": "aes128-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "aes192-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7"
]
}
},
{
"algorithm": "aes256-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "arcfour256",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 4.2"
]
}
},
{
"algorithm": "arcfour128",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 4.2"
]
}
},
{
"algorithm": "aes128-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "3des-cbc",
"notes": {
"fail": [
"using broken & deprecated 3DES cipher"
],
"info": [
"available since OpenSSH 1.2.2, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "blowfish-cbc",
"notes": {
"fail": [
"using weak & deprecated Blowfish cipher"
],
"info": [
"available since OpenSSH 1.2.2, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "cast128-cbc",
"notes": {
"fail": [
"using weak & deprecated CAST cipher"
],
"info": [
"available since OpenSSH 2.1.0"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "aes192-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "aes256-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0, Dropbear SSH 0.47"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "arcfour",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 2.1.0"
]
}
},
{
"algorithm": "rijndael-cbc@lysator.liu.se",
"notes": {
"fail": [
"using deprecated & non-standardized Rijndael cipher"
],
"info": [
"disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0",
"available since OpenSSH 2.3.0"
],
"warn": [
"using weak cipher mode"
]
}
}
],
"fingerprints": [
{
"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4",
"hash_alg": "SHA256",
"hostkey": "ssh-rsa"
},
{
"hash": "3c:c3:38:f8:55:39:c0:4a:5a:17:89:60:2c:a1:fc:6a",
"hash_alg": "MD5",
"hostkey": "ssh-rsa"
}
],
"kex": [
{
"algorithm": "diffie-hellman-group-exchange-sha256",
"keysize": 1024,
"notes": {
"fail": [
"using small 1024-bit modulus"
],
"info": [
"available since OpenSSH 4.4"
]
}
},
{
"algorithm": "diffie-hellman-group-exchange-sha1",
"keysize": 1024,
"notes": {
"fail": [
"using small 1024-bit modulus"
],
"info": [
"available since OpenSSH 2.3.0"
]
}
},
{
"algorithm": "diffie-hellman-group14-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 3.9, Dropbear SSH 0.53"
],
"warn": [
"2048-bit modulus only provides 112-bits of symmetric strength"
]
}
},
{
"algorithm": "diffie-hellman-group1-sha1",
"notes": {
"fail": [
"using small 1024-bit modulus",
"vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)",
"using broken SHA-1 hash algorithm"
],
"info": [
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
]
}
}
],
"key": [
{
"algorithm": "ssh-rsa",
"keysize": 1024,
"notes": {
"fail": [
"using broken SHA-1 hash algorithm",
"using small 1024-bit modulus"
],
"info": [
"deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8",
"available since OpenSSH 2.5.0, Dropbear SSH 0.28"
]
}
},
{
"algorithm": "ssh-rsa-cert-v01@openssh.com",
"ca_algorithm": "ssh-rsa",
"casize": 1024,
"keysize": 1024,
"notes": {
"fail": [
"using broken SHA-1 hash algorithm",
"using small 1024-bit hostkey modulus",
"using small 1024-bit CA key modulus"
],
"info": [
"deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8",
"available since OpenSSH 5.6"
]
}
}
],
"mac": [
{
"algorithm": "hmac-md5",
"notes": {
"fail": [
"using broken MD5 hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "umac-64@openssh.com",
"notes": {
"info": [
"available since OpenSSH 4.7"
],
"warn": [
"using encrypt-and-MAC mode",
"using small 64-bit tag size"
]
}
},
{
"algorithm": "hmac-ripemd160",
"notes": {
"fail": [
"using deprecated RIPEMD hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-ripemd160@openssh.com",
"notes": {
"fail": [
"using deprecated RIPEMD hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha1-96",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0, Dropbear SSH 0.47"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-md5-96",
"notes": {
"fail": [
"using broken MD5 hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
}
],
"recommendations": {
"critical": {
"chg": {
"kex": [
{
"name": "diffie-hellman-group-exchange-sha256",
"notes": "increase modulus size to 3072 bits or larger"
}
]
},
"del": {
"enc": [
{
"name": "3des-cbc",
"notes": ""
},
{
"name": "arcfour128",
"notes": ""
},
{
"name": "arcfour",
"notes": ""
},
{
"name": "arcfour256",
"notes": ""
},
{
"name": "blowfish-cbc",
"notes": ""
},
{
"name": "cast128-cbc",
"notes": ""
},
{
"name": "rijndael-cbc@lysator.liu.se",
"notes": ""
}
],
"kex": [
{
"name": "diffie-hellman-group14-sha1",
"notes": ""
},
{
"name": "diffie-hellman-group1-sha1",
"notes": ""
},
{
"name": "diffie-hellman-group-exchange-sha1",
"notes": ""
}
],
"key": [
{
"name": "ssh-rsa",
"notes": ""
},
{
"name": "ssh-rsa-cert-v01@openssh.com",
"notes": ""
}
],
"mac": [
{
"name": "hmac-md5",
"notes": ""
},
{
"name": "hmac-md5-96",
"notes": ""
},
{
"name": "hmac-ripemd160",
"notes": ""
},
{
"name": "hmac-ripemd160@openssh.com",
"notes": ""
},
{
"name": "hmac-sha1",
"notes": ""
},
{
"name": "hmac-sha1-96",
"notes": ""
}
]
}
},
"warning": {
"del": {
"enc": [
{
"name": "aes128-cbc",
"notes": ""
},
{
"name": "aes192-cbc",
"notes": ""
},
{
"name": "aes256-cbc",
"notes": ""
}
],
"mac": [
{
"name": "umac-64@openssh.com",
"notes": ""
}
]
}
}
},
"target": "localhost:2222"
}

View File

@ -5,7 +5,10 @@
(gen) compression: enabled (zlib@openssh.com) (gen) compression: enabled (zlib@openssh.com)
# security # security
(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepencies (cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers
(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepancies
(cve) CVE-2017-15906 -- (CVSSv2: 5.3) readonly bypass via sftp
(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response
(cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data (cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data
(cve) CVE-2016-1907 -- (CVSSv2: 5.0) cause DoS via crafted network traffic (out of bounds read) (cve) CVE-2016-1907 -- (CVSSv2: 5.0) cause DoS via crafted network traffic (out of bounds read)
(cve) CVE-2015-6564 -- (CVSSv2: 6.9) privilege escalation via leveraging sshd uid (cve) CVE-2015-6564 -- (CVSSv2: 6.9) privilege escalation via leveraging sshd uid
@ -22,113 +25,89 @@
(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus
`- [info] available since OpenSSH 4.4 `- [info] available since OpenSSH 4.4
(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing algorithm (kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53 `- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus
 `- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm  `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)
 `- [fail] disabled (in client) since OpenSSH 7.0, logjam attack  `- [fail] using broken SHA-1 hash algorithm
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
# host-key algorithms # host-key algorithms
(key) ssh-rsa (1024-bit) -- [fail] using weak hashing algorithm (key) ssh-rsa (1024-bit) -- [fail] using broken SHA-1 hash algorithm
 `- [fail] using small 1024-bit modulus  `- [fail] using small 1024-bit modulus
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2 `- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
(key) ssh-rsa-cert-v01@openssh.com (1024-bit cert/1024-bit CA) -- [fail] using weak hashing algorithm (key) ssh-rsa-cert-v01@openssh.com (1024-bit cert/1024-bit RSA CA) -- [fail] using broken SHA-1 hash algorithm
 `- [fail] using small 1024-bit modulus  `- [fail] using small 1024-bit hostkey modulus
 `- [fail] using small 1024-bit CA key modulus
`- [info] available since OpenSSH 5.6 `- [info] available since OpenSSH 5.6
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2 `- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
# encryption algorithms (ciphers) # encryption algorithms (ciphers)
(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes192-ctr -- [info] available since OpenSSH 3.7 (enc) aes192-ctr -- [info] available since OpenSSH 3.7
(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) arcfour256 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour256 -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 4.2 `- [info] available since OpenSSH 4.2
(enc) arcfour128 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour128 -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 4.2 `- [info] available since OpenSSH 4.2
(enc) aes128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes128-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
(enc) 3des-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) 3des-cbc -- [fail] using broken & deprecated 3DES cipher
 `- [warn] disabled (in client) since OpenSSH 7.4, unsafe algorithm
 `- [warn] using weak cipher
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28 `- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
(enc) blowfish-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) blowfish-cbc -- [fail] using weak & deprecated Blowfish cipher
 `- [fail] disabled since Dropbear SSH 0.53
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28 `- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
(enc) cast128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) cast128-cbc -- [fail] using weak & deprecated CAST cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(enc) aes192-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes192-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
(enc) aes256-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes256-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47
(enc) arcfour -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(enc) rijndael-cbc@lysator.liu.se -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) rijndael-cbc@lysator.liu.se -- [fail] using deprecated & non-standardized Rijndael cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
# message authentication code algorithms # message authentication code algorithms
(mac) hmac-md5 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-md5 -- [fail] using broken MD5 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode (mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] using weak hashing algorithm  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
(mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode (mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode
 `- [warn] using small 64-bit tag size  `- [warn] using small 64-bit tag size
`- [info] available since OpenSSH 4.7 `- [info] available since OpenSSH 4.7
(mac) hmac-ripemd160 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-ripemd160 -- [fail] using deprecated RIPEMD hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.5.0 `- [info] available since OpenSSH 2.5.0
(mac) hmac-ripemd160@openssh.com -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-ripemd160@openssh.com -- [fail] using deprecated RIPEMD hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(mac) hmac-sha1-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-sha1-96 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47
(mac) hmac-md5-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-md5-96 -- [fail] using broken MD5 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.5.0 `- [info] available since OpenSSH 2.5.0
# fingerprints # fingerprints
(fin) ssh-rsa: SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4 (fin) ssh-rsa: SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4
# algorithm recommendations (for OpenSSH 5.6) # algorithm recommendations (for OpenSSH 5.6)
(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 2048 bits or larger)  (rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 3072 bits or larger) 
(rec) -3des-cbc -- enc algorithm to remove  (rec) -3des-cbc -- enc algorithm to remove 
(rec) -aes128-cbc -- enc algorithm to remove 
(rec) -aes192-cbc -- enc algorithm to remove 
(rec) -aes256-cbc -- enc algorithm to remove 
(rec) -arcfour -- enc algorithm to remove  (rec) -arcfour -- enc algorithm to remove 
(rec) -arcfour128 -- enc algorithm to remove  (rec) -arcfour128 -- enc algorithm to remove 
(rec) -arcfour256 -- enc algorithm to remove  (rec) -arcfour256 -- enc algorithm to remove 
@ -136,16 +115,19 @@
(rec) -cast128-cbc -- enc algorithm to remove  (rec) -cast128-cbc -- enc algorithm to remove 
(rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove  (rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove 
(rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove  (rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove 
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove 
(rec) -hmac-md5 -- mac algorithm to remove  (rec) -hmac-md5 -- mac algorithm to remove 
(rec) -hmac-md5-96 -- mac algorithm to remove  (rec) -hmac-md5-96 -- mac algorithm to remove 
(rec) -hmac-ripemd160 -- mac algorithm to remove  (rec) -hmac-ripemd160 -- mac algorithm to remove 
(rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove  (rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove 
(rec) -hmac-sha1-96 -- mac algorithm to remove  (rec) -hmac-sha1-96 -- mac algorithm to remove 
(rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove  (rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove 
(rec) -ssh-rsa -- key algorithm to remove  (rec) -ssh-rsa -- key algorithm to remove 
(rec) -ssh-rsa-cert-v01@openssh.com -- key algorithm to remove  (rec) -ssh-rsa-cert-v01@openssh.com -- key algorithm to remove 
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove  (rec) -aes128-cbc -- enc algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove  (rec) -aes192-cbc -- enc algorithm to remove 
(rec) -aes256-cbc -- enc algorithm to remove 
(rec) -umac-64@openssh.com -- mac algorithm to remove  (rec) -umac-64@openssh.com -- mac algorithm to remove 
# additional info # additional info

View File

@ -1 +1,556 @@
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_5.6", "software": "OpenSSH_5.6"}, "compression": ["none", "zlib@openssh.com"], "enc": ["aes128-ctr", "aes192-ctr", "aes256-ctr", "arcfour256", "arcfour128", "aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "aes192-cbc", "aes256-cbc", "arcfour", "rijndael-cbc@lysator.liu.se"], "fingerprints": [{"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4", "hash_alg": "SHA256", "hostkey": "ssh-rsa"}, {"hash": "3c:c3:38:f8:55:39:c0:4a:5a:17:89:60:2c:a1:fc:6a", "hash_alg": "MD5", "hostkey": "ssh-rsa"}], "kex": [{"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 1024}, {"algorithm": "diffie-hellman-group-exchange-sha1", "keysize": 1024}, {"algorithm": "diffie-hellman-group14-sha1"}, {"algorithm": "diffie-hellman-group1-sha1"}], "key": [{"algorithm": "ssh-rsa", "keysize": 1024}, {"algorithm": "ssh-rsa-cert-v01@openssh.com", "casize": 3072, "keysize": 1024}], "mac": ["hmac-md5", "hmac-sha1", "umac-64@openssh.com", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"} {
"banner": {
"comments": null,
"protocol": "2.0",
"raw": "SSH-2.0-OpenSSH_5.6",
"software": "OpenSSH_5.6"
},
"compression": [
"none",
"zlib@openssh.com"
],
"cves": [
{
"cvssv2": 7.8,
"description": "command injection via anomalous argument transfers",
"name": "CVE-2020-15778"
},
{
"cvssv2": 5.3,
"description": "enumerate usernames due to timing discrepancies",
"name": "CVE-2018-15473"
},
{
"cvssv2": 5.3,
"description": "readonly bypass via sftp",
"name": "CVE-2017-15906"
},
{
"cvssv2": 5.3,
"description": "enumerate usernames via challenge response",
"name": "CVE-2016-20012"
},
{
"cvssv2": 5.5,
"description": "bypass command restrictions via crafted X11 forwarding data",
"name": "CVE-2016-3115"
},
{
"cvssv2": 5.0,
"description": "cause DoS via crafted network traffic (out of bounds read)",
"name": "CVE-2016-1907"
},
{
"cvssv2": 6.9,
"description": "privilege escalation via leveraging sshd uid",
"name": "CVE-2015-6564"
},
{
"cvssv2": 1.9,
"description": "conduct impersonation attack",
"name": "CVE-2015-6563"
},
{
"cvssv2": 5.8,
"description": "bypass environment restrictions via specific string before wildcard",
"name": "CVE-2014-2532"
},
{
"cvssv2": 7.5,
"description": "cause DoS via triggering error condition (memory corruption)",
"name": "CVE-2014-1692"
},
{
"cvssv2": 3.5,
"description": "leak data via debug messages",
"name": "CVE-2012-0814"
},
{
"cvssv2": 3.5,
"description": "cause DoS via large value in certain length field (memory consumption)",
"name": "CVE-2011-5000"
},
{
"cvssv2": 5.0,
"description": "cause DoS via large number of connections (slot exhaustion)",
"name": "CVE-2010-5107"
},
{
"cvssv2": 4.0,
"description": "cause DoS via crafted glob expression (CPU and memory consumption)",
"name": "CVE-2010-4755"
},
{
"cvssv2": 7.5,
"description": "bypass authentication check via crafted values",
"name": "CVE-2010-4478"
}
],
"enc": [
{
"algorithm": "aes128-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "aes192-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7"
]
}
},
{
"algorithm": "aes256-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "arcfour256",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 4.2"
]
}
},
{
"algorithm": "arcfour128",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 4.2"
]
}
},
{
"algorithm": "aes128-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "3des-cbc",
"notes": {
"fail": [
"using broken & deprecated 3DES cipher"
],
"info": [
"available since OpenSSH 1.2.2, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "blowfish-cbc",
"notes": {
"fail": [
"using weak & deprecated Blowfish cipher"
],
"info": [
"available since OpenSSH 1.2.2, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "cast128-cbc",
"notes": {
"fail": [
"using weak & deprecated CAST cipher"
],
"info": [
"available since OpenSSH 2.1.0"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "aes192-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "aes256-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0, Dropbear SSH 0.47"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "arcfour",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 2.1.0"
]
}
},
{
"algorithm": "rijndael-cbc@lysator.liu.se",
"notes": {
"fail": [
"using deprecated & non-standardized Rijndael cipher"
],
"info": [
"disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0",
"available since OpenSSH 2.3.0"
],
"warn": [
"using weak cipher mode"
]
}
}
],
"fingerprints": [
{
"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4",
"hash_alg": "SHA256",
"hostkey": "ssh-rsa"
},
{
"hash": "3c:c3:38:f8:55:39:c0:4a:5a:17:89:60:2c:a1:fc:6a",
"hash_alg": "MD5",
"hostkey": "ssh-rsa"
}
],
"kex": [
{
"algorithm": "diffie-hellman-group-exchange-sha256",
"keysize": 1024,
"notes": {
"fail": [
"using small 1024-bit modulus"
],
"info": [
"available since OpenSSH 4.4"
]
}
},
{
"algorithm": "diffie-hellman-group-exchange-sha1",
"keysize": 1024,
"notes": {
"fail": [
"using small 1024-bit modulus"
],
"info": [
"available since OpenSSH 2.3.0"
]
}
},
{
"algorithm": "diffie-hellman-group14-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 3.9, Dropbear SSH 0.53"
],
"warn": [
"2048-bit modulus only provides 112-bits of symmetric strength"
]
}
},
{
"algorithm": "diffie-hellman-group1-sha1",
"notes": {
"fail": [
"using small 1024-bit modulus",
"vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)",
"using broken SHA-1 hash algorithm"
],
"info": [
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
]
}
}
],
"key": [
{
"algorithm": "ssh-rsa",
"keysize": 1024,
"notes": {
"fail": [
"using broken SHA-1 hash algorithm",
"using small 1024-bit modulus"
],
"info": [
"deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8",
"available since OpenSSH 2.5.0, Dropbear SSH 0.28"
]
}
},
{
"algorithm": "ssh-rsa-cert-v01@openssh.com",
"ca_algorithm": "ssh-rsa",
"casize": 3072,
"keysize": 1024,
"notes": {
"fail": [
"using broken SHA-1 hash algorithm",
"using small 1024-bit hostkey modulus"
],
"info": [
"deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8",
"available since OpenSSH 5.6"
]
}
}
],
"mac": [
{
"algorithm": "hmac-md5",
"notes": {
"fail": [
"using broken MD5 hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "umac-64@openssh.com",
"notes": {
"info": [
"available since OpenSSH 4.7"
],
"warn": [
"using encrypt-and-MAC mode",
"using small 64-bit tag size"
]
}
},
{
"algorithm": "hmac-ripemd160",
"notes": {
"fail": [
"using deprecated RIPEMD hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-ripemd160@openssh.com",
"notes": {
"fail": [
"using deprecated RIPEMD hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha1-96",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0, Dropbear SSH 0.47"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-md5-96",
"notes": {
"fail": [
"using broken MD5 hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
}
],
"recommendations": {
"critical": {
"chg": {
"kex": [
{
"name": "diffie-hellman-group-exchange-sha256",
"notes": "increase modulus size to 3072 bits or larger"
}
]
},
"del": {
"enc": [
{
"name": "3des-cbc",
"notes": ""
},
{
"name": "arcfour128",
"notes": ""
},
{
"name": "arcfour",
"notes": ""
},
{
"name": "arcfour256",
"notes": ""
},
{
"name": "blowfish-cbc",
"notes": ""
},
{
"name": "cast128-cbc",
"notes": ""
},
{
"name": "rijndael-cbc@lysator.liu.se",
"notes": ""
}
],
"kex": [
{
"name": "diffie-hellman-group14-sha1",
"notes": ""
},
{
"name": "diffie-hellman-group1-sha1",
"notes": ""
},
{
"name": "diffie-hellman-group-exchange-sha1",
"notes": ""
}
],
"key": [
{
"name": "ssh-rsa",
"notes": ""
},
{
"name": "ssh-rsa-cert-v01@openssh.com",
"notes": ""
}
],
"mac": [
{
"name": "hmac-md5",
"notes": ""
},
{
"name": "hmac-md5-96",
"notes": ""
},
{
"name": "hmac-ripemd160",
"notes": ""
},
{
"name": "hmac-ripemd160@openssh.com",
"notes": ""
},
{
"name": "hmac-sha1",
"notes": ""
},
{
"name": "hmac-sha1-96",
"notes": ""
}
]
}
},
"warning": {
"del": {
"enc": [
{
"name": "aes128-cbc",
"notes": ""
},
{
"name": "aes192-cbc",
"notes": ""
},
{
"name": "aes256-cbc",
"notes": ""
}
],
"mac": [
{
"name": "umac-64@openssh.com",
"notes": ""
}
]
}
}
},
"target": "localhost:2222"
}

View File

@ -5,7 +5,10 @@
(gen) compression: enabled (zlib@openssh.com) (gen) compression: enabled (zlib@openssh.com)
# security # security
(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepencies (cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers
(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepancies
(cve) CVE-2017-15906 -- (CVSSv2: 5.3) readonly bypass via sftp
(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response
(cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data (cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data
(cve) CVE-2016-1907 -- (CVSSv2: 5.0) cause DoS via crafted network traffic (out of bounds read) (cve) CVE-2016-1907 -- (CVSSv2: 5.0) cause DoS via crafted network traffic (out of bounds read)
(cve) CVE-2015-6564 -- (CVSSv2: 6.9) privilege escalation via leveraging sshd uid (cve) CVE-2015-6564 -- (CVSSv2: 6.9) privilege escalation via leveraging sshd uid
@ -22,113 +25,88 @@
(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus
`- [info] available since OpenSSH 4.4 `- [info] available since OpenSSH 4.4
(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing algorithm (kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53 `- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus
 `- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm  `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)
 `- [fail] disabled (in client) since OpenSSH 7.0, logjam attack  `- [fail] using broken SHA-1 hash algorithm
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
# host-key algorithms # host-key algorithms
(key) ssh-rsa (1024-bit) -- [fail] using weak hashing algorithm (key) ssh-rsa (1024-bit) -- [fail] using broken SHA-1 hash algorithm
 `- [fail] using small 1024-bit modulus  `- [fail] using small 1024-bit modulus
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2 `- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
(key) ssh-rsa-cert-v01@openssh.com (1024-bit cert/3072-bit CA) -- [fail] using weak hashing algorithm (key) ssh-rsa-cert-v01@openssh.com (1024-bit cert/3072-bit RSA CA) -- [fail] using broken SHA-1 hash algorithm
 `- [fail] using small 1024-bit modulus  `- [fail] using small 1024-bit hostkey modulus
`- [info] available since OpenSSH 5.6 `- [info] available since OpenSSH 5.6
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2 `- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
# encryption algorithms (ciphers) # encryption algorithms (ciphers)
(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes192-ctr -- [info] available since OpenSSH 3.7 (enc) aes192-ctr -- [info] available since OpenSSH 3.7
(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) arcfour256 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour256 -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 4.2 `- [info] available since OpenSSH 4.2
(enc) arcfour128 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour128 -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 4.2 `- [info] available since OpenSSH 4.2
(enc) aes128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes128-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
(enc) 3des-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) 3des-cbc -- [fail] using broken & deprecated 3DES cipher
 `- [warn] disabled (in client) since OpenSSH 7.4, unsafe algorithm
 `- [warn] using weak cipher
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28 `- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
(enc) blowfish-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) blowfish-cbc -- [fail] using weak & deprecated Blowfish cipher
 `- [fail] disabled since Dropbear SSH 0.53
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28 `- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
(enc) cast128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) cast128-cbc -- [fail] using weak & deprecated CAST cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(enc) aes192-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes192-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
(enc) aes256-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes256-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47
(enc) arcfour -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(enc) rijndael-cbc@lysator.liu.se -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) rijndael-cbc@lysator.liu.se -- [fail] using deprecated & non-standardized Rijndael cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
# message authentication code algorithms # message authentication code algorithms
(mac) hmac-md5 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-md5 -- [fail] using broken MD5 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode (mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] using weak hashing algorithm  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
(mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode (mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode
 `- [warn] using small 64-bit tag size  `- [warn] using small 64-bit tag size
`- [info] available since OpenSSH 4.7 `- [info] available since OpenSSH 4.7
(mac) hmac-ripemd160 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-ripemd160 -- [fail] using deprecated RIPEMD hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.5.0 `- [info] available since OpenSSH 2.5.0
(mac) hmac-ripemd160@openssh.com -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-ripemd160@openssh.com -- [fail] using deprecated RIPEMD hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(mac) hmac-sha1-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-sha1-96 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47
(mac) hmac-md5-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-md5-96 -- [fail] using broken MD5 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.5.0 `- [info] available since OpenSSH 2.5.0
# fingerprints # fingerprints
(fin) ssh-rsa: SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4 (fin) ssh-rsa: SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4
# algorithm recommendations (for OpenSSH 5.6) # algorithm recommendations (for OpenSSH 5.6)
(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 2048 bits or larger)  (rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 3072 bits or larger) 
(rec) -3des-cbc -- enc algorithm to remove  (rec) -3des-cbc -- enc algorithm to remove 
(rec) -aes128-cbc -- enc algorithm to remove 
(rec) -aes192-cbc -- enc algorithm to remove 
(rec) -aes256-cbc -- enc algorithm to remove 
(rec) -arcfour -- enc algorithm to remove  (rec) -arcfour -- enc algorithm to remove 
(rec) -arcfour128 -- enc algorithm to remove  (rec) -arcfour128 -- enc algorithm to remove 
(rec) -arcfour256 -- enc algorithm to remove  (rec) -arcfour256 -- enc algorithm to remove 
@ -136,16 +114,19 @@
(rec) -cast128-cbc -- enc algorithm to remove  (rec) -cast128-cbc -- enc algorithm to remove 
(rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove  (rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove 
(rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove  (rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove 
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove 
(rec) -hmac-md5 -- mac algorithm to remove  (rec) -hmac-md5 -- mac algorithm to remove 
(rec) -hmac-md5-96 -- mac algorithm to remove  (rec) -hmac-md5-96 -- mac algorithm to remove 
(rec) -hmac-ripemd160 -- mac algorithm to remove  (rec) -hmac-ripemd160 -- mac algorithm to remove 
(rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove  (rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove 
(rec) -hmac-sha1-96 -- mac algorithm to remove  (rec) -hmac-sha1-96 -- mac algorithm to remove 
(rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove  (rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove 
(rec) -ssh-rsa -- key algorithm to remove  (rec) -ssh-rsa -- key algorithm to remove 
(rec) -ssh-rsa-cert-v01@openssh.com -- key algorithm to remove  (rec) -ssh-rsa-cert-v01@openssh.com -- key algorithm to remove 
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove  (rec) -aes128-cbc -- enc algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove  (rec) -aes192-cbc -- enc algorithm to remove 
(rec) -aes256-cbc -- enc algorithm to remove 
(rec) -umac-64@openssh.com -- mac algorithm to remove  (rec) -umac-64@openssh.com -- mac algorithm to remove 
# additional info # additional info

View File

@ -1 +1,555 @@
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_5.6", "software": "OpenSSH_5.6"}, "compression": ["none", "zlib@openssh.com"], "enc": ["aes128-ctr", "aes192-ctr", "aes256-ctr", "arcfour256", "arcfour128", "aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "aes192-cbc", "aes256-cbc", "arcfour", "rijndael-cbc@lysator.liu.se"], "fingerprints": [{"hash": "nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244", "hash_alg": "SHA256", "hostkey": "ssh-rsa"}, {"hash": "18:e2:51:fe:21:6c:78:d0:b8:cf:32:d4:bd:56:42:e1", "hash_alg": "MD5", "hostkey": "ssh-rsa"}], "kex": [{"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 1024}, {"algorithm": "diffie-hellman-group-exchange-sha1", "keysize": 1024}, {"algorithm": "diffie-hellman-group14-sha1"}, {"algorithm": "diffie-hellman-group1-sha1"}], "key": [{"algorithm": "ssh-rsa", "keysize": 3072}, {"algorithm": "ssh-rsa-cert-v01@openssh.com", "casize": 1024, "keysize": 3072}], "mac": ["hmac-md5", "hmac-sha1", "umac-64@openssh.com", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"} {
"banner": {
"comments": null,
"protocol": "2.0",
"raw": "SSH-2.0-OpenSSH_5.6",
"software": "OpenSSH_5.6"
},
"compression": [
"none",
"zlib@openssh.com"
],
"cves": [
{
"cvssv2": 7.8,
"description": "command injection via anomalous argument transfers",
"name": "CVE-2020-15778"
},
{
"cvssv2": 5.3,
"description": "enumerate usernames due to timing discrepancies",
"name": "CVE-2018-15473"
},
{
"cvssv2": 5.3,
"description": "readonly bypass via sftp",
"name": "CVE-2017-15906"
},
{
"cvssv2": 5.3,
"description": "enumerate usernames via challenge response",
"name": "CVE-2016-20012"
},
{
"cvssv2": 5.5,
"description": "bypass command restrictions via crafted X11 forwarding data",
"name": "CVE-2016-3115"
},
{
"cvssv2": 5.0,
"description": "cause DoS via crafted network traffic (out of bounds read)",
"name": "CVE-2016-1907"
},
{
"cvssv2": 6.9,
"description": "privilege escalation via leveraging sshd uid",
"name": "CVE-2015-6564"
},
{
"cvssv2": 1.9,
"description": "conduct impersonation attack",
"name": "CVE-2015-6563"
},
{
"cvssv2": 5.8,
"description": "bypass environment restrictions via specific string before wildcard",
"name": "CVE-2014-2532"
},
{
"cvssv2": 7.5,
"description": "cause DoS via triggering error condition (memory corruption)",
"name": "CVE-2014-1692"
},
{
"cvssv2": 3.5,
"description": "leak data via debug messages",
"name": "CVE-2012-0814"
},
{
"cvssv2": 3.5,
"description": "cause DoS via large value in certain length field (memory consumption)",
"name": "CVE-2011-5000"
},
{
"cvssv2": 5.0,
"description": "cause DoS via large number of connections (slot exhaustion)",
"name": "CVE-2010-5107"
},
{
"cvssv2": 4.0,
"description": "cause DoS via crafted glob expression (CPU and memory consumption)",
"name": "CVE-2010-4755"
},
{
"cvssv2": 7.5,
"description": "bypass authentication check via crafted values",
"name": "CVE-2010-4478"
}
],
"enc": [
{
"algorithm": "aes128-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "aes192-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7"
]
}
},
{
"algorithm": "aes256-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "arcfour256",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 4.2"
]
}
},
{
"algorithm": "arcfour128",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 4.2"
]
}
},
{
"algorithm": "aes128-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "3des-cbc",
"notes": {
"fail": [
"using broken & deprecated 3DES cipher"
],
"info": [
"available since OpenSSH 1.2.2, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "blowfish-cbc",
"notes": {
"fail": [
"using weak & deprecated Blowfish cipher"
],
"info": [
"available since OpenSSH 1.2.2, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "cast128-cbc",
"notes": {
"fail": [
"using weak & deprecated CAST cipher"
],
"info": [
"available since OpenSSH 2.1.0"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "aes192-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "aes256-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0, Dropbear SSH 0.47"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "arcfour",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 2.1.0"
]
}
},
{
"algorithm": "rijndael-cbc@lysator.liu.se",
"notes": {
"fail": [
"using deprecated & non-standardized Rijndael cipher"
],
"info": [
"disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0",
"available since OpenSSH 2.3.0"
],
"warn": [
"using weak cipher mode"
]
}
}
],
"fingerprints": [
{
"hash": "nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244",
"hash_alg": "SHA256",
"hostkey": "ssh-rsa"
},
{
"hash": "18:e2:51:fe:21:6c:78:d0:b8:cf:32:d4:bd:56:42:e1",
"hash_alg": "MD5",
"hostkey": "ssh-rsa"
}
],
"kex": [
{
"algorithm": "diffie-hellman-group-exchange-sha256",
"keysize": 1024,
"notes": {
"fail": [
"using small 1024-bit modulus"
],
"info": [
"available since OpenSSH 4.4"
]
}
},
{
"algorithm": "diffie-hellman-group-exchange-sha1",
"keysize": 1024,
"notes": {
"fail": [
"using small 1024-bit modulus"
],
"info": [
"available since OpenSSH 2.3.0"
]
}
},
{
"algorithm": "diffie-hellman-group14-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 3.9, Dropbear SSH 0.53"
],
"warn": [
"2048-bit modulus only provides 112-bits of symmetric strength"
]
}
},
{
"algorithm": "diffie-hellman-group1-sha1",
"notes": {
"fail": [
"using small 1024-bit modulus",
"vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)",
"using broken SHA-1 hash algorithm"
],
"info": [
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
]
}
}
],
"key": [
{
"algorithm": "ssh-rsa",
"keysize": 3072,
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8",
"available since OpenSSH 2.5.0, Dropbear SSH 0.28"
]
}
},
{
"algorithm": "ssh-rsa-cert-v01@openssh.com",
"ca_algorithm": "ssh-rsa",
"casize": 1024,
"keysize": 3072,
"notes": {
"fail": [
"using broken SHA-1 hash algorithm",
"using small 1024-bit CA key modulus"
],
"info": [
"deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8",
"available since OpenSSH 5.6"
]
}
}
],
"mac": [
{
"algorithm": "hmac-md5",
"notes": {
"fail": [
"using broken MD5 hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "umac-64@openssh.com",
"notes": {
"info": [
"available since OpenSSH 4.7"
],
"warn": [
"using encrypt-and-MAC mode",
"using small 64-bit tag size"
]
}
},
{
"algorithm": "hmac-ripemd160",
"notes": {
"fail": [
"using deprecated RIPEMD hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-ripemd160@openssh.com",
"notes": {
"fail": [
"using deprecated RIPEMD hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha1-96",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0, Dropbear SSH 0.47"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-md5-96",
"notes": {
"fail": [
"using broken MD5 hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
}
],
"recommendations": {
"critical": {
"chg": {
"kex": [
{
"name": "diffie-hellman-group-exchange-sha256",
"notes": "increase modulus size to 3072 bits or larger"
}
]
},
"del": {
"enc": [
{
"name": "3des-cbc",
"notes": ""
},
{
"name": "arcfour128",
"notes": ""
},
{
"name": "arcfour",
"notes": ""
},
{
"name": "arcfour256",
"notes": ""
},
{
"name": "blowfish-cbc",
"notes": ""
},
{
"name": "cast128-cbc",
"notes": ""
},
{
"name": "rijndael-cbc@lysator.liu.se",
"notes": ""
}
],
"kex": [
{
"name": "diffie-hellman-group14-sha1",
"notes": ""
},
{
"name": "diffie-hellman-group1-sha1",
"notes": ""
},
{
"name": "diffie-hellman-group-exchange-sha1",
"notes": ""
}
],
"key": [
{
"name": "ssh-rsa",
"notes": ""
},
{
"name": "ssh-rsa-cert-v01@openssh.com",
"notes": ""
}
],
"mac": [
{
"name": "hmac-md5",
"notes": ""
},
{
"name": "hmac-md5-96",
"notes": ""
},
{
"name": "hmac-ripemd160",
"notes": ""
},
{
"name": "hmac-ripemd160@openssh.com",
"notes": ""
},
{
"name": "hmac-sha1",
"notes": ""
},
{
"name": "hmac-sha1-96",
"notes": ""
}
]
}
},
"warning": {
"del": {
"enc": [
{
"name": "aes128-cbc",
"notes": ""
},
{
"name": "aes192-cbc",
"notes": ""
},
{
"name": "aes256-cbc",
"notes": ""
}
],
"mac": [
{
"name": "umac-64@openssh.com",
"notes": ""
}
]
}
}
},
"target": "localhost:2222"
}

View File

@ -5,7 +5,10 @@
(gen) compression: enabled (zlib@openssh.com) (gen) compression: enabled (zlib@openssh.com)
# security # security
(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepencies (cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers
(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepancies
(cve) CVE-2017-15906 -- (CVSSv2: 5.3) readonly bypass via sftp
(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response
(cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data (cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data
(cve) CVE-2016-1907 -- (CVSSv2: 5.0) cause DoS via crafted network traffic (out of bounds read) (cve) CVE-2016-1907 -- (CVSSv2: 5.0) cause DoS via crafted network traffic (out of bounds read)
(cve) CVE-2015-6564 -- (CVSSv2: 6.9) privilege escalation via leveraging sshd uid (cve) CVE-2015-6564 -- (CVSSv2: 6.9) privilege escalation via leveraging sshd uid
@ -22,112 +25,87 @@
(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus
`- [info] available since OpenSSH 4.4 `- [info] available since OpenSSH 4.4
(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing algorithm (kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53 `- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus
 `- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm  `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)
 `- [fail] disabled (in client) since OpenSSH 7.0, logjam attack  `- [fail] using broken SHA-1 hash algorithm
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
# host-key algorithms # host-key algorithms
(key) ssh-rsa (3072-bit) -- [fail] using weak hashing algorithm (key) ssh-rsa (3072-bit) -- [fail] using broken SHA-1 hash algorithm
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2 `- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
(key) ssh-rsa-cert-v01@openssh.com (3072-bit cert/1024-bit CA) -- [fail] using weak hashing algorithm (key) ssh-rsa-cert-v01@openssh.com (3072-bit cert/1024-bit RSA CA) -- [fail] using broken SHA-1 hash algorithm
 `- [fail] using small 1024-bit modulus  `- [fail] using small 1024-bit CA key modulus
`- [info] available since OpenSSH 5.6 `- [info] available since OpenSSH 5.6
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2 `- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
# encryption algorithms (ciphers) # encryption algorithms (ciphers)
(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes192-ctr -- [info] available since OpenSSH 3.7 (enc) aes192-ctr -- [info] available since OpenSSH 3.7
(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) arcfour256 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour256 -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 4.2 `- [info] available since OpenSSH 4.2
(enc) arcfour128 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour128 -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 4.2 `- [info] available since OpenSSH 4.2
(enc) aes128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes128-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
(enc) 3des-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) 3des-cbc -- [fail] using broken & deprecated 3DES cipher
 `- [warn] disabled (in client) since OpenSSH 7.4, unsafe algorithm
 `- [warn] using weak cipher
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28 `- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
(enc) blowfish-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) blowfish-cbc -- [fail] using weak & deprecated Blowfish cipher
 `- [fail] disabled since Dropbear SSH 0.53
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28 `- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
(enc) cast128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) cast128-cbc -- [fail] using weak & deprecated CAST cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(enc) aes192-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes192-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
(enc) aes256-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes256-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47
(enc) arcfour -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(enc) rijndael-cbc@lysator.liu.se -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) rijndael-cbc@lysator.liu.se -- [fail] using deprecated & non-standardized Rijndael cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
# message authentication code algorithms # message authentication code algorithms
(mac) hmac-md5 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-md5 -- [fail] using broken MD5 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode (mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] using weak hashing algorithm  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
(mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode (mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode
 `- [warn] using small 64-bit tag size  `- [warn] using small 64-bit tag size
`- [info] available since OpenSSH 4.7 `- [info] available since OpenSSH 4.7
(mac) hmac-ripemd160 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-ripemd160 -- [fail] using deprecated RIPEMD hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.5.0 `- [info] available since OpenSSH 2.5.0
(mac) hmac-ripemd160@openssh.com -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-ripemd160@openssh.com -- [fail] using deprecated RIPEMD hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(mac) hmac-sha1-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-sha1-96 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47
(mac) hmac-md5-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-md5-96 -- [fail] using broken MD5 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.5.0 `- [info] available since OpenSSH 2.5.0
# fingerprints # fingerprints
(fin) ssh-rsa: SHA256:nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244 (fin) ssh-rsa: SHA256:nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244
# algorithm recommendations (for OpenSSH 5.6) # algorithm recommendations (for OpenSSH 5.6)
(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 2048 bits or larger)  (rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 3072 bits or larger) 
(rec) -3des-cbc -- enc algorithm to remove  (rec) -3des-cbc -- enc algorithm to remove 
(rec) -aes128-cbc -- enc algorithm to remove 
(rec) -aes192-cbc -- enc algorithm to remove 
(rec) -aes256-cbc -- enc algorithm to remove 
(rec) -arcfour -- enc algorithm to remove  (rec) -arcfour -- enc algorithm to remove 
(rec) -arcfour128 -- enc algorithm to remove  (rec) -arcfour128 -- enc algorithm to remove 
(rec) -arcfour256 -- enc algorithm to remove  (rec) -arcfour256 -- enc algorithm to remove 
@ -135,16 +113,19 @@
(rec) -cast128-cbc -- enc algorithm to remove  (rec) -cast128-cbc -- enc algorithm to remove 
(rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove  (rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove 
(rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove  (rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove 
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove 
(rec) -hmac-md5 -- mac algorithm to remove  (rec) -hmac-md5 -- mac algorithm to remove 
(rec) -hmac-md5-96 -- mac algorithm to remove  (rec) -hmac-md5-96 -- mac algorithm to remove 
(rec) -hmac-ripemd160 -- mac algorithm to remove  (rec) -hmac-ripemd160 -- mac algorithm to remove 
(rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove  (rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove 
(rec) -hmac-sha1-96 -- mac algorithm to remove  (rec) -hmac-sha1-96 -- mac algorithm to remove 
(rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove  (rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove 
(rec) -ssh-rsa -- key algorithm to remove  (rec) -ssh-rsa -- key algorithm to remove 
(rec) -ssh-rsa-cert-v01@openssh.com -- key algorithm to remove  (rec) -ssh-rsa-cert-v01@openssh.com -- key algorithm to remove 
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove  (rec) -aes128-cbc -- enc algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove  (rec) -aes192-cbc -- enc algorithm to remove 
(rec) -aes256-cbc -- enc algorithm to remove 
(rec) -umac-64@openssh.com -- mac algorithm to remove  (rec) -umac-64@openssh.com -- mac algorithm to remove 
# additional info # additional info

View File

@ -1 +1,554 @@
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_5.6", "software": "OpenSSH_5.6"}, "compression": ["none", "zlib@openssh.com"], "enc": ["aes128-ctr", "aes192-ctr", "aes256-ctr", "arcfour256", "arcfour128", "aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "aes192-cbc", "aes256-cbc", "arcfour", "rijndael-cbc@lysator.liu.se"], "fingerprints": [{"hash": "nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244", "hash_alg": "SHA256", "hostkey": "ssh-rsa"}, {"hash": "18:e2:51:fe:21:6c:78:d0:b8:cf:32:d4:bd:56:42:e1", "hash_alg": "MD5", "hostkey": "ssh-rsa"}], "kex": [{"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 1024}, {"algorithm": "diffie-hellman-group-exchange-sha1", "keysize": 1024}, {"algorithm": "diffie-hellman-group14-sha1"}, {"algorithm": "diffie-hellman-group1-sha1"}], "key": [{"algorithm": "ssh-rsa", "keysize": 3072}, {"algorithm": "ssh-rsa-cert-v01@openssh.com", "casize": 3072, "keysize": 3072}], "mac": ["hmac-md5", "hmac-sha1", "umac-64@openssh.com", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"} {
"banner": {
"comments": null,
"protocol": "2.0",
"raw": "SSH-2.0-OpenSSH_5.6",
"software": "OpenSSH_5.6"
},
"compression": [
"none",
"zlib@openssh.com"
],
"cves": [
{
"cvssv2": 7.8,
"description": "command injection via anomalous argument transfers",
"name": "CVE-2020-15778"
},
{
"cvssv2": 5.3,
"description": "enumerate usernames due to timing discrepancies",
"name": "CVE-2018-15473"
},
{
"cvssv2": 5.3,
"description": "readonly bypass via sftp",
"name": "CVE-2017-15906"
},
{
"cvssv2": 5.3,
"description": "enumerate usernames via challenge response",
"name": "CVE-2016-20012"
},
{
"cvssv2": 5.5,
"description": "bypass command restrictions via crafted X11 forwarding data",
"name": "CVE-2016-3115"
},
{
"cvssv2": 5.0,
"description": "cause DoS via crafted network traffic (out of bounds read)",
"name": "CVE-2016-1907"
},
{
"cvssv2": 6.9,
"description": "privilege escalation via leveraging sshd uid",
"name": "CVE-2015-6564"
},
{
"cvssv2": 1.9,
"description": "conduct impersonation attack",
"name": "CVE-2015-6563"
},
{
"cvssv2": 5.8,
"description": "bypass environment restrictions via specific string before wildcard",
"name": "CVE-2014-2532"
},
{
"cvssv2": 7.5,
"description": "cause DoS via triggering error condition (memory corruption)",
"name": "CVE-2014-1692"
},
{
"cvssv2": 3.5,
"description": "leak data via debug messages",
"name": "CVE-2012-0814"
},
{
"cvssv2": 3.5,
"description": "cause DoS via large value in certain length field (memory consumption)",
"name": "CVE-2011-5000"
},
{
"cvssv2": 5.0,
"description": "cause DoS via large number of connections (slot exhaustion)",
"name": "CVE-2010-5107"
},
{
"cvssv2": 4.0,
"description": "cause DoS via crafted glob expression (CPU and memory consumption)",
"name": "CVE-2010-4755"
},
{
"cvssv2": 7.5,
"description": "bypass authentication check via crafted values",
"name": "CVE-2010-4478"
}
],
"enc": [
{
"algorithm": "aes128-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "aes192-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7"
]
}
},
{
"algorithm": "aes256-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "arcfour256",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 4.2"
]
}
},
{
"algorithm": "arcfour128",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 4.2"
]
}
},
{
"algorithm": "aes128-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "3des-cbc",
"notes": {
"fail": [
"using broken & deprecated 3DES cipher"
],
"info": [
"available since OpenSSH 1.2.2, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "blowfish-cbc",
"notes": {
"fail": [
"using weak & deprecated Blowfish cipher"
],
"info": [
"available since OpenSSH 1.2.2, Dropbear SSH 0.28"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "cast128-cbc",
"notes": {
"fail": [
"using weak & deprecated CAST cipher"
],
"info": [
"available since OpenSSH 2.1.0"
],
"warn": [
"using weak cipher mode",
"using small 64-bit block size"
]
}
},
{
"algorithm": "aes192-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "aes256-cbc",
"notes": {
"info": [
"available since OpenSSH 2.3.0, Dropbear SSH 0.47"
],
"warn": [
"using weak cipher mode"
]
}
},
{
"algorithm": "arcfour",
"notes": {
"fail": [
"using broken RC4 cipher"
],
"info": [
"available since OpenSSH 2.1.0"
]
}
},
{
"algorithm": "rijndael-cbc@lysator.liu.se",
"notes": {
"fail": [
"using deprecated & non-standardized Rijndael cipher"
],
"info": [
"disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0",
"available since OpenSSH 2.3.0"
],
"warn": [
"using weak cipher mode"
]
}
}
],
"fingerprints": [
{
"hash": "nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244",
"hash_alg": "SHA256",
"hostkey": "ssh-rsa"
},
{
"hash": "18:e2:51:fe:21:6c:78:d0:b8:cf:32:d4:bd:56:42:e1",
"hash_alg": "MD5",
"hostkey": "ssh-rsa"
}
],
"kex": [
{
"algorithm": "diffie-hellman-group-exchange-sha256",
"keysize": 1024,
"notes": {
"fail": [
"using small 1024-bit modulus"
],
"info": [
"available since OpenSSH 4.4"
]
}
},
{
"algorithm": "diffie-hellman-group-exchange-sha1",
"keysize": 1024,
"notes": {
"fail": [
"using small 1024-bit modulus"
],
"info": [
"available since OpenSSH 2.3.0"
]
}
},
{
"algorithm": "diffie-hellman-group14-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 3.9, Dropbear SSH 0.53"
],
"warn": [
"2048-bit modulus only provides 112-bits of symmetric strength"
]
}
},
{
"algorithm": "diffie-hellman-group1-sha1",
"notes": {
"fail": [
"using small 1024-bit modulus",
"vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)",
"using broken SHA-1 hash algorithm"
],
"info": [
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
]
}
}
],
"key": [
{
"algorithm": "ssh-rsa",
"keysize": 3072,
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8",
"available since OpenSSH 2.5.0, Dropbear SSH 0.28"
]
}
},
{
"algorithm": "ssh-rsa-cert-v01@openssh.com",
"ca_algorithm": "ssh-rsa",
"casize": 3072,
"keysize": 3072,
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8",
"available since OpenSSH 5.6"
]
}
}
],
"mac": [
{
"algorithm": "hmac-md5",
"notes": {
"fail": [
"using broken MD5 hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "umac-64@openssh.com",
"notes": {
"info": [
"available since OpenSSH 4.7"
],
"warn": [
"using encrypt-and-MAC mode",
"using small 64-bit tag size"
]
}
},
{
"algorithm": "hmac-ripemd160",
"notes": {
"fail": [
"using deprecated RIPEMD hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-ripemd160@openssh.com",
"notes": {
"fail": [
"using deprecated RIPEMD hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha1-96",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0, Dropbear SSH 0.47"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-md5-96",
"notes": {
"fail": [
"using broken MD5 hash algorithm"
],
"info": [
"available since OpenSSH 2.5.0"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
}
],
"recommendations": {
"critical": {
"chg": {
"kex": [
{
"name": "diffie-hellman-group-exchange-sha256",
"notes": "increase modulus size to 3072 bits or larger"
}
]
},
"del": {
"enc": [
{
"name": "3des-cbc",
"notes": ""
},
{
"name": "arcfour128",
"notes": ""
},
{
"name": "arcfour",
"notes": ""
},
{
"name": "arcfour256",
"notes": ""
},
{
"name": "blowfish-cbc",
"notes": ""
},
{
"name": "cast128-cbc",
"notes": ""
},
{
"name": "rijndael-cbc@lysator.liu.se",
"notes": ""
}
],
"kex": [
{
"name": "diffie-hellman-group14-sha1",
"notes": ""
},
{
"name": "diffie-hellman-group1-sha1",
"notes": ""
},
{
"name": "diffie-hellman-group-exchange-sha1",
"notes": ""
}
],
"key": [
{
"name": "ssh-rsa",
"notes": ""
},
{
"name": "ssh-rsa-cert-v01@openssh.com",
"notes": ""
}
],
"mac": [
{
"name": "hmac-md5",
"notes": ""
},
{
"name": "hmac-md5-96",
"notes": ""
},
{
"name": "hmac-ripemd160",
"notes": ""
},
{
"name": "hmac-ripemd160@openssh.com",
"notes": ""
},
{
"name": "hmac-sha1",
"notes": ""
},
{
"name": "hmac-sha1-96",
"notes": ""
}
]
}
},
"warning": {
"del": {
"enc": [
{
"name": "aes128-cbc",
"notes": ""
},
{
"name": "aes192-cbc",
"notes": ""
},
{
"name": "aes256-cbc",
"notes": ""
}
],
"mac": [
{
"name": "umac-64@openssh.com",
"notes": ""
}
]
}
}
},
"target": "localhost:2222"
}

View File

@ -5,7 +5,10 @@
(gen) compression: enabled (zlib@openssh.com) (gen) compression: enabled (zlib@openssh.com)
# security # security
(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepencies (cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers
(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepancies
(cve) CVE-2017-15906 -- (CVSSv2: 5.3) readonly bypass via sftp
(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response
(cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data (cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data
(cve) CVE-2016-1907 -- (CVSSv2: 5.0) cause DoS via crafted network traffic (out of bounds read) (cve) CVE-2016-1907 -- (CVSSv2: 5.0) cause DoS via crafted network traffic (out of bounds read)
(cve) CVE-2015-6564 -- (CVSSv2: 6.9) privilege escalation via leveraging sshd uid (cve) CVE-2015-6564 -- (CVSSv2: 6.9) privilege escalation via leveraging sshd uid
@ -22,111 +25,86 @@
(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus
`- [info] available since OpenSSH 4.4 `- [info] available since OpenSSH 4.4
(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing algorithm (kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53 `- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus (kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus
 `- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm  `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)
 `- [fail] disabled (in client) since OpenSSH 7.0, logjam attack  `- [fail] using broken SHA-1 hash algorithm
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
# host-key algorithms # host-key algorithms
(key) ssh-rsa (3072-bit) -- [fail] using weak hashing algorithm (key) ssh-rsa (3072-bit) -- [fail] using broken SHA-1 hash algorithm
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2 `- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
(key) ssh-rsa-cert-v01@openssh.com (3072-bit cert/3072-bit CA) -- [fail] using weak hashing algorithm (key) ssh-rsa-cert-v01@openssh.com (3072-bit cert/3072-bit RSA CA) -- [fail] using broken SHA-1 hash algorithm
`- [info] available since OpenSSH 5.6 `- [info] available since OpenSSH 5.6
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2 `- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
# encryption algorithms (ciphers) # encryption algorithms (ciphers)
(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes192-ctr -- [info] available since OpenSSH 3.7 (enc) aes192-ctr -- [info] available since OpenSSH 3.7
(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) arcfour256 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour256 -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 4.2 `- [info] available since OpenSSH 4.2
(enc) arcfour128 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour128 -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 4.2 `- [info] available since OpenSSH 4.2
(enc) aes128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes128-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
(enc) 3des-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) 3des-cbc -- [fail] using broken & deprecated 3DES cipher
 `- [warn] disabled (in client) since OpenSSH 7.4, unsafe algorithm
 `- [warn] using weak cipher
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28 `- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
(enc) blowfish-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) blowfish-cbc -- [fail] using weak & deprecated Blowfish cipher
 `- [fail] disabled since Dropbear SSH 0.53
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28 `- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
(enc) cast128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) cast128-cbc -- [fail] using weak & deprecated CAST cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
 `- [warn] using small 64-bit block size  `- [warn] using small 64-bit block size
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(enc) aes192-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes192-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
(enc) aes256-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) aes256-cbc -- [warn] using weak cipher mode
 `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47 `- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47
(enc) arcfour -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) arcfour -- [fail] using broken RC4 cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(enc) rijndael-cbc@lysator.liu.se -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (enc) rijndael-cbc@lysator.liu.se -- [fail] using deprecated & non-standardized Rijndael cipher
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using weak cipher mode  `- [warn] using weak cipher mode
`- [info] available since OpenSSH 2.3.0 `- [info] available since OpenSSH 2.3.0
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
# message authentication code algorithms # message authentication code algorithms
(mac) hmac-md5 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-md5 -- [fail] using broken MD5 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode (mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] using weak hashing algorithm  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
(mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode (mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode
 `- [warn] using small 64-bit tag size  `- [warn] using small 64-bit tag size
`- [info] available since OpenSSH 4.7 `- [info] available since OpenSSH 4.7
(mac) hmac-ripemd160 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-ripemd160 -- [fail] using deprecated RIPEMD hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.5.0 `- [info] available since OpenSSH 2.5.0
(mac) hmac-ripemd160@openssh.com -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-ripemd160@openssh.com -- [fail] using deprecated RIPEMD hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.1.0 `- [info] available since OpenSSH 2.1.0
(mac) hmac-sha1-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-sha1-96 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47
(mac) hmac-md5-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm (mac) hmac-md5-96 -- [fail] using broken MD5 hash algorithm
 `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm
 `- [warn] using encrypt-and-MAC mode  `- [warn] using encrypt-and-MAC mode
 `- [warn] using weak hashing algorithm
`- [info] available since OpenSSH 2.5.0 `- [info] available since OpenSSH 2.5.0
# fingerprints # fingerprints
(fin) ssh-rsa: SHA256:nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244 (fin) ssh-rsa: SHA256:nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244
# algorithm recommendations (for OpenSSH 5.6) # algorithm recommendations (for OpenSSH 5.6)
(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 2048 bits or larger)  (rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 3072 bits or larger) 
(rec) -3des-cbc -- enc algorithm to remove  (rec) -3des-cbc -- enc algorithm to remove 
(rec) -aes128-cbc -- enc algorithm to remove 
(rec) -aes192-cbc -- enc algorithm to remove 
(rec) -aes256-cbc -- enc algorithm to remove 
(rec) -arcfour -- enc algorithm to remove  (rec) -arcfour -- enc algorithm to remove 
(rec) -arcfour128 -- enc algorithm to remove  (rec) -arcfour128 -- enc algorithm to remove 
(rec) -arcfour256 -- enc algorithm to remove  (rec) -arcfour256 -- enc algorithm to remove 
@ -134,16 +112,19 @@
(rec) -cast128-cbc -- enc algorithm to remove  (rec) -cast128-cbc -- enc algorithm to remove 
(rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove  (rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove 
(rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove  (rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove 
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove 
(rec) -hmac-md5 -- mac algorithm to remove  (rec) -hmac-md5 -- mac algorithm to remove 
(rec) -hmac-md5-96 -- mac algorithm to remove  (rec) -hmac-md5-96 -- mac algorithm to remove 
(rec) -hmac-ripemd160 -- mac algorithm to remove  (rec) -hmac-ripemd160 -- mac algorithm to remove 
(rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove  (rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove 
(rec) -hmac-sha1-96 -- mac algorithm to remove  (rec) -hmac-sha1-96 -- mac algorithm to remove 
(rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove  (rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove 
(rec) -ssh-rsa -- key algorithm to remove  (rec) -ssh-rsa -- key algorithm to remove 
(rec) -ssh-rsa-cert-v01@openssh.com -- key algorithm to remove  (rec) -ssh-rsa-cert-v01@openssh.com -- key algorithm to remove 
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove  (rec) -aes128-cbc -- enc algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove  (rec) -aes192-cbc -- enc algorithm to remove 
(rec) -aes256-cbc -- enc algorithm to remove 
(rec) -umac-64@openssh.com -- mac algorithm to remove  (rec) -umac-64@openssh.com -- mac algorithm to remove 
# additional info # additional info

View File

@ -1 +1,31 @@
{"errors": [], "host": "localhost", "passed": true, "policy": "Hardened OpenSSH Server v8.0 (version 1)"} {
"errors": [
{
"actual": [
"3072"
],
"expected_optional": [
""
],
"expected_required": [
"4096"
],
"mismatched_field": "Host key (rsa-sha2-256) sizes"
},
{
"actual": [
"3072"
],
"expected_optional": [
""
],
"expected_required": [
"4096"
],
"mismatched_field": "Host key (rsa-sha2-512) sizes"
}
],
"host": "localhost",
"passed": false,
"policy": "Hardened OpenSSH Server v8.0 (version 3)"
}

View File

@ -1,3 +1,13 @@
Host: localhost:2222 Host: localhost:2222
Policy: Hardened OpenSSH Server v8.0 (version 1) Policy: Hardened OpenSSH Server v8.0 (version 3)
Result: ✔ Passed Result: ❌ Failed!

Errors:
* Host key (rsa-sha2-256) sizes did not match.
- Expected: 4096
- Actual: 3072
* Host key (rsa-sha2-512) sizes did not match.
- Expected: 4096
- Actual: 3072


View File

@ -1 +1,54 @@
{"errors": [{"actual": ["umac-64-etm@openssh.com", "umac-128-etm@openssh.com", "hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "hmac-sha1-etm@openssh.com", "umac-64@openssh.com", "umac-128@openssh.com", "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1"], "expected_optional": [""], "expected_required": ["hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "umac-128-etm@openssh.com"], "mismatched_field": "MACs"}], "host": "localhost", "passed": false, "policy": "Hardened OpenSSH Server v8.0 (version 1)"} {
"errors": [
{
"actual": [
"3072"
],
"expected_optional": [
""
],
"expected_required": [
"4096"
],
"mismatched_field": "Host key (rsa-sha2-256) sizes"
},
{
"actual": [
"3072"
],
"expected_optional": [
""
],
"expected_required": [
"4096"
],
"mismatched_field": "Host key (rsa-sha2-512) sizes"
},
{
"actual": [
"umac-64-etm@openssh.com",
"umac-128-etm@openssh.com",
"hmac-sha2-256-etm@openssh.com",
"hmac-sha2-512-etm@openssh.com",
"hmac-sha1-etm@openssh.com",
"umac-64@openssh.com",
"umac-128@openssh.com",
"hmac-sha2-256",
"hmac-sha2-512",
"hmac-sha1"
],
"expected_optional": [
""
],
"expected_required": [
"hmac-sha2-256-etm@openssh.com",
"hmac-sha2-512-etm@openssh.com",
"umac-128-etm@openssh.com"
],
"mismatched_field": "MACs"
}
],
"host": "localhost",
"passed": false,
"policy": "Hardened OpenSSH Server v8.0 (version 3)"
}

View File

@ -1,8 +1,16 @@
Host: localhost:2222 Host: localhost:2222
Policy: Hardened OpenSSH Server v8.0 (version 1) Policy: Hardened OpenSSH Server v8.0 (version 3)
Result: ❌ Failed! Result: ❌ Failed!
 
Errors: Errors:
* Host key (rsa-sha2-256) sizes did not match.
- Expected: 4096
- Actual: 3072
* Host key (rsa-sha2-512) sizes did not match.
- Expected: 4096
- Actual: 3072
* MACs did not match. * MACs did not match.
- Expected: hmac-sha2-256-etm@openssh.com, hmac-sha2-512-etm@openssh.com, umac-128-etm@openssh.com - Expected: hmac-sha2-256-etm@openssh.com, hmac-sha2-512-etm@openssh.com, umac-128-etm@openssh.com
- Actual: umac-64-etm@openssh.com, umac-128-etm@openssh.com, hmac-sha2-256-etm@openssh.com, hmac-sha2-512-etm@openssh.com, hmac-sha1-etm@openssh.com, umac-64@openssh.com, umac-128@openssh.com, hmac-sha2-256, hmac-sha2-512, hmac-sha1 - Actual: umac-64-etm@openssh.com, umac-128-etm@openssh.com, hmac-sha2-256-etm@openssh.com, hmac-sha2-512-etm@openssh.com, hmac-sha1-etm@openssh.com, umac-64@openssh.com, umac-128@openssh.com, hmac-sha2-256, hmac-sha2-512, hmac-sha1

View File

@ -1 +1,6 @@
{"errors": [], "host": "localhost", "passed": true, "policy": "Docker policy: test11 (version 1)"} {
"errors": [],
"host": "localhost",
"passed": true,
"policy": "Docker policy: test11 (version 1)"
}

View File

@ -1,3 +1,12 @@
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
Host: localhost:2222 Host: localhost:2222
Policy: Docker policy: test11 (version 1) Policy: Docker policy: test11 (version 1)
Result: ✔ Passed Result: ✔ Passed

View File

@ -1 +1,43 @@
{"errors": [{"actual": ["3072"], "expected_optional": [""], "expected_required": ["4096"], "mismatched_field": "RSA host key (rsa-sha2-256) sizes"}, {"actual": ["3072"], "expected_optional": [""], "expected_required": ["4096"], "mismatched_field": "RSA host key (rsa-sha2-512) sizes"}, {"actual": ["3072"], "expected_optional": [""], "expected_required": ["4096"], "mismatched_field": "RSA host key (ssh-rsa) sizes"}], "host": "localhost", "passed": false, "policy": "Docker policy: test12 (version 1)"} {
"errors": [
{
"actual": [
"3072"
],
"expected_optional": [
""
],
"expected_required": [
"4096"
],
"mismatched_field": "Host key (rsa-sha2-256) sizes"
},
{
"actual": [
"3072"
],
"expected_optional": [
""
],
"expected_required": [
"4096"
],
"mismatched_field": "Host key (rsa-sha2-512) sizes"
},
{
"actual": [
"3072"
],
"expected_optional": [
""
],
"expected_required": [
"4096"
],
"mismatched_field": "Host key (ssh-rsa) sizes"
}
],
"host": "localhost",
"passed": false,
"policy": "Docker policy: test12 (version 1)"
}

View File

@ -1,17 +1,26 @@
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
Host: localhost:2222 Host: localhost:2222
Policy: Docker policy: test12 (version 1) Policy: Docker policy: test12 (version 1)
Result: ❌ Failed! Result: ❌ Failed!
 
Errors: Errors:
* RSA host key (rsa-sha2-256) sizes did not match. * Host key (rsa-sha2-256) sizes did not match.
- Expected: 4096 - Expected: 4096
- Actual: 3072 - Actual: 3072
* RSA host key (rsa-sha2-512) sizes did not match. * Host key (rsa-sha2-512) sizes did not match.
- Expected: 4096 - Expected: 4096
- Actual: 3072 - Actual: 3072
* RSA host key (ssh-rsa) sizes did not match. * Host key (ssh-rsa) sizes did not match.
- Expected: 4096 - Expected: 4096
- Actual: 3072 - Actual: 3072
 

View File

@ -1 +1,6 @@
{"errors": [], "host": "localhost", "passed": true, "policy": "Docker policy: test13 (version 1)"} {
"errors": [],
"host": "localhost",
"passed": true,
"policy": "Docker policy: test13 (version 1)"
}

View File

@ -1,3 +1,15 @@
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
Host: localhost:2222 Host: localhost:2222
Policy: Docker policy: test13 (version 1) Policy: Docker policy: test13 (version 1)
Result: ✔ Passed Result: ✔ Passed

View File

@ -1 +1,19 @@
{"errors": [{"actual": ["2048"], "expected_optional": [""], "expected_required": ["4096"], "mismatched_field": "Group exchange (diffie-hellman-group-exchange-sha256) modulus sizes"}], "host": "localhost", "passed": false, "policy": "Docker policy: test14 (version 1)"} {
"errors": [
{
"actual": [
"4096"
],
"expected_optional": [
""
],
"expected_required": [
"8192"
],
"mismatched_field": "Group exchange (diffie-hellman-group-exchange-sha256) modulus sizes"
}
],
"host": "localhost",
"passed": false,
"policy": "Docker policy: test14 (version 1)"
}

View File

@ -1,9 +1,21 @@
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
Host: localhost:2222 Host: localhost:2222
Policy: Docker policy: test14 (version 1) Policy: Docker policy: test14 (version 1)
Result: ❌ Failed! Result: ❌ Failed!
 
Errors: Errors:
* Group exchange (diffie-hellman-group-exchange-sha256) modulus sizes did not match. * Group exchange (diffie-hellman-group-exchange-sha256) modulus sizes did not match.
- Expected: 4096 - Expected: 8192
- Actual: 2048 - Actual: 4096
 

View File

@ -1 +1,6 @@
{"errors": [], "host": "localhost", "passed": true, "policy": "Docker policy: test6 (version 1)"} {
"errors": [],
"host": "localhost",
"passed": true,
"policy": "Docker policy: test6 (version 1)"
}

View File

@ -1 +1,450 @@
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_8.0", "software": "OpenSSH_8.0"}, "compression": ["none", "zlib@openssh.com"], "enc": ["chacha20-poly1305@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "aes256-gcm@openssh.com"], "fingerprints": [{"hash": "UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU", "hash_alg": "SHA256", "hostkey": "ssh-ed25519"}, {"hash": "1e:0c:7b:34:73:bf:52:41:b0:f9:d1:a9:ab:98:c7:c9", "hash_alg": "MD5", "hostkey": "ssh-ed25519"}, {"hash": "nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244", "hash_alg": "SHA256", "hostkey": "ssh-rsa"}, {"hash": "18:e2:51:fe:21:6c:78:d0:b8:cf:32:d4:bd:56:42:e1", "hash_alg": "MD5", "hostkey": "ssh-rsa"}], "kex": [{"algorithm": "curve25519-sha256"}, {"algorithm": "curve25519-sha256@libssh.org"}, {"algorithm": "ecdh-sha2-nistp256"}, {"algorithm": "ecdh-sha2-nistp384"}, {"algorithm": "ecdh-sha2-nistp521"}, {"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 2048}, {"algorithm": "diffie-hellman-group16-sha512"}, {"algorithm": "diffie-hellman-group18-sha512"}, {"algorithm": "diffie-hellman-group14-sha256"}, {"algorithm": "diffie-hellman-group14-sha1"}], "key": [{"algorithm": "rsa-sha2-512", "keysize": 3072}, {"algorithm": "rsa-sha2-256", "keysize": 3072}, {"algorithm": "ssh-rsa", "keysize": 3072}, {"algorithm": "ecdsa-sha2-nistp256"}, {"algorithm": "ssh-ed25519"}], "mac": ["umac-64-etm@openssh.com", "umac-128-etm@openssh.com", "hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "hmac-sha1-etm@openssh.com", "umac-64@openssh.com", "umac-128@openssh.com", "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1"], "target": "localhost"} {
"banner": {
"comments": null,
"protocol": "2.0",
"raw": "SSH-2.0-OpenSSH_8.0",
"software": "OpenSSH_8.0"
},
"compression": [
"none",
"zlib@openssh.com"
],
"cves": [
{
"cvssv2": 7.0,
"description": "privilege escalation via supplemental groups",
"name": "CVE-2021-41617"
},
{
"cvssv2": 7.8,
"description": "command injection via anomalous argument transfers",
"name": "CVE-2020-15778"
},
{
"cvssv2": 7.8,
"description": "memory corruption and local code execution via pre-authentication integer overflow",
"name": "CVE-2019-16905"
},
{
"cvssv2": 5.3,
"description": "enumerate usernames via challenge response",
"name": "CVE-2016-20012"
}
],
"enc": [
{
"algorithm": "chacha20-poly1305@openssh.com",
"notes": {
"info": [
"default cipher since OpenSSH 6.9",
"available since OpenSSH 6.5"
]
}
},
{
"algorithm": "aes128-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "aes192-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7"
]
}
},
{
"algorithm": "aes256-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "aes128-gcm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
]
}
},
{
"algorithm": "aes256-gcm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
]
}
}
],
"fingerprints": [
{
"hash": "UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU",
"hash_alg": "SHA256",
"hostkey": "ssh-ed25519"
},
{
"hash": "1e:0c:7b:34:73:bf:52:41:b0:f9:d1:a9:ab:98:c7:c9",
"hash_alg": "MD5",
"hostkey": "ssh-ed25519"
},
{
"hash": "nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244",
"hash_alg": "SHA256",
"hostkey": "ssh-rsa"
},
{
"hash": "18:e2:51:fe:21:6c:78:d0:b8:cf:32:d4:bd:56:42:e1",
"hash_alg": "MD5",
"hostkey": "ssh-rsa"
}
],
"kex": [
{
"algorithm": "curve25519-sha256",
"notes": {
"info": [
"default key exchange since OpenSSH 6.4",
"available since OpenSSH 7.4, Dropbear SSH 2018.76"
]
}
},
{
"algorithm": "curve25519-sha256@libssh.org",
"notes": {
"info": [
"default key exchange since OpenSSH 6.4",
"available since OpenSSH 6.4, Dropbear SSH 2013.62"
]
}
},
{
"algorithm": "ecdh-sha2-nistp256",
"notes": {
"fail": [
"using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency"
],
"info": [
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
]
}
},
{
"algorithm": "ecdh-sha2-nistp384",
"notes": {
"fail": [
"using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency"
],
"info": [
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
]
}
},
{
"algorithm": "ecdh-sha2-nistp521",
"notes": {
"fail": [
"using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency"
],
"info": [
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
]
}
},
{
"algorithm": "diffie-hellman-group-exchange-sha256",
"keysize": 4096,
"notes": {
"info": [
"OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).",
"available since OpenSSH 4.4"
]
}
},
{
"algorithm": "diffie-hellman-group16-sha512",
"notes": {
"info": [
"available since OpenSSH 7.3, Dropbear SSH 2016.73"
]
}
},
{
"algorithm": "diffie-hellman-group18-sha512",
"notes": {
"info": [
"available since OpenSSH 7.3"
]
}
},
{
"algorithm": "diffie-hellman-group14-sha256",
"notes": {
"info": [
"available since OpenSSH 7.3, Dropbear SSH 2016.73"
],
"warn": [
"2048-bit modulus only provides 112-bits of symmetric strength"
]
}
},
{
"algorithm": "diffie-hellman-group14-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 3.9, Dropbear SSH 0.53"
],
"warn": [
"2048-bit modulus only provides 112-bits of symmetric strength"
]
}
}
],
"key": [
{
"algorithm": "rsa-sha2-512",
"keysize": 3072,
"notes": {
"info": [
"available since OpenSSH 7.2"
]
}
},
{
"algorithm": "rsa-sha2-256",
"keysize": 3072,
"notes": {
"info": [
"available since OpenSSH 7.2"
]
}
},
{
"algorithm": "ssh-rsa",
"keysize": 3072,
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8",
"available since OpenSSH 2.5.0, Dropbear SSH 0.28"
]
}
},
{
"algorithm": "ecdsa-sha2-nistp256",
"notes": {
"fail": [
"using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency"
],
"info": [
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
],
"warn": [
"using weak random number generator could reveal the key"
]
}
},
{
"algorithm": "ssh-ed25519",
"notes": {
"info": [
"available since OpenSSH 6.5"
]
}
}
],
"mac": [
{
"algorithm": "umac-64-etm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
],
"warn": [
"using small 64-bit tag size"
]
}
},
{
"algorithm": "umac-128-etm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
]
}
},
{
"algorithm": "hmac-sha2-256-etm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
]
}
},
{
"algorithm": "hmac-sha2-512-etm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
]
}
},
{
"algorithm": "hmac-sha1-etm@openssh.com",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 6.2"
]
}
},
{
"algorithm": "umac-64@openssh.com",
"notes": {
"info": [
"available since OpenSSH 4.7"
],
"warn": [
"using encrypt-and-MAC mode",
"using small 64-bit tag size"
]
}
},
{
"algorithm": "umac-128@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha2-256",
"notes": {
"info": [
"available since OpenSSH 5.9, Dropbear SSH 2013.56"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha2-512",
"notes": {
"info": [
"available since OpenSSH 5.9, Dropbear SSH 2013.56"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
}
],
"recommendations": {
"critical": {
"del": {
"kex": [
{
"name": "diffie-hellman-group14-sha1",
"notes": ""
},
{
"name": "ecdh-sha2-nistp256",
"notes": ""
},
{
"name": "ecdh-sha2-nistp384",
"notes": ""
},
{
"name": "ecdh-sha2-nistp521",
"notes": ""
}
],
"key": [
{
"name": "ecdsa-sha2-nistp256",
"notes": ""
},
{
"name": "ssh-rsa",
"notes": ""
}
],
"mac": [
{
"name": "hmac-sha1",
"notes": ""
},
{
"name": "hmac-sha1-etm@openssh.com",
"notes": ""
}
]
}
},
"warning": {
"del": {
"kex": [
{
"name": "diffie-hellman-group14-sha256",
"notes": ""
}
],
"mac": [
{
"name": "hmac-sha2-256",
"notes": ""
},
{
"name": "hmac-sha2-512",
"notes": ""
},
{
"name": "umac-128@openssh.com",
"notes": ""
},
{
"name": "umac-64-etm@openssh.com",
"notes": ""
},
{
"name": "umac-64@openssh.com",
"notes": ""
}
]
}
}
},
"target": "localhost:2222"
}

View File

@ -4,36 +4,47 @@
(gen) compatibility: OpenSSH 7.4+, Dropbear SSH 2018.76+ (gen) compatibility: OpenSSH 7.4+, Dropbear SSH 2018.76+
(gen) compression: enabled (zlib@openssh.com) (gen) compression: enabled (zlib@openssh.com)
# security
(cve) CVE-2021-41617 -- (CVSSv2: 7.0) privilege escalation via supplemental groups
(cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers
(cve) CVE-2019-16905 -- (CVSSv2: 7.8) memory corruption and local code execution via pre-authentication integer overflow
(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response
# key exchange algorithms # key exchange algorithms
(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76 (kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.5, Dropbear SSH 2013.62  `- [info] default key exchange since OpenSSH 6.4
(kex) ecdh-sha2-nistp256 -- [fail] using weak elliptic curves (kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
 `- [info] default key exchange since OpenSSH 6.4
(kex) ecdh-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62 `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) ecdh-sha2-nistp384 -- [fail] using weak elliptic curves (kex) ecdh-sha2-nistp384 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62 `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) ecdh-sha2-nistp521 -- [fail] using weak elliptic curves (kex) ecdh-sha2-nistp521 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62 `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) diffie-hellman-group-exchange-sha256 (2048-bit) -- [info] available since OpenSSH 4.4 (kex) diffie-hellman-group-exchange-sha256 (4096-bit) -- [info] available since OpenSSH 4.4
 `- [info] OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).
(kex) diffie-hellman-group16-sha512 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73 (kex) diffie-hellman-group16-sha512 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
(kex) diffie-hellman-group18-sha512 -- [info] available since OpenSSH 7.3 (kex) diffie-hellman-group18-sha512 -- [info] available since OpenSSH 7.3
(kex) diffie-hellman-group14-sha256 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73 (kex) diffie-hellman-group14-sha256 -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength
(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing algorithm `- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53 `- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
# host-key algorithms # host-key algorithms
(key) rsa-sha2-512 (3072-bit) -- [info] available since OpenSSH 7.2 (key) rsa-sha2-512 (3072-bit) -- [info] available since OpenSSH 7.2
(key) rsa-sha2-256 (3072-bit) -- [info] available since OpenSSH 7.2 (key) rsa-sha2-256 (3072-bit) -- [info] available since OpenSSH 7.2
(key) ssh-rsa (3072-bit) -- [fail] using weak hashing algorithm (key) ssh-rsa (3072-bit) -- [fail] using broken SHA-1 hash algorithm
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2 `- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
(key) ecdsa-sha2-nistp256 -- [fail] using weak elliptic curves (key) ecdsa-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
 `- [warn] using weak random number generator could reveal the key  `- [warn] using weak random number generator could reveal the key
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62 `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(key) ssh-ed25519 -- [info] available since OpenSSH 6.5 (key) ssh-ed25519 -- [info] available since OpenSSH 6.5
# encryption algorithms (ciphers) # encryption algorithms (ciphers)
(enc) chacha20-poly1305@openssh.com -- [info] available since OpenSSH 6.5 (enc) chacha20-poly1305@openssh.com -- [info] available since OpenSSH 6.5
`- [info] default cipher since OpenSSH 6.9.  `- [info] default cipher since OpenSSH 6.9
(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes192-ctr -- [info] available since OpenSSH 3.7 (enc) aes192-ctr -- [info] available since OpenSSH 3.7
(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
@ -46,7 +57,7 @@
(mac) umac-128-etm@openssh.com -- [info] available since OpenSSH 6.2 (mac) umac-128-etm@openssh.com -- [info] available since OpenSSH 6.2
(mac) hmac-sha2-256-etm@openssh.com -- [info] available since OpenSSH 6.2 (mac) hmac-sha2-256-etm@openssh.com -- [info] available since OpenSSH 6.2
(mac) hmac-sha2-512-etm@openssh.com -- [info] available since OpenSSH 6.2 (mac) hmac-sha2-512-etm@openssh.com -- [info] available since OpenSSH 6.2
(mac) hmac-sha1-etm@openssh.com -- [warn] using weak hashing algorithm (mac) hmac-sha1-etm@openssh.com -- [fail] using broken SHA-1 hash algorithm
`- [info] available since OpenSSH 6.2 `- [info] available since OpenSSH 6.2
(mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode (mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode
 `- [warn] using small 64-bit tag size  `- [warn] using small 64-bit tag size
@ -57,8 +68,8 @@
`- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56 `- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56
(mac) hmac-sha2-512 -- [warn] using encrypt-and-MAC mode (mac) hmac-sha2-512 -- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56 `- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56
(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode (mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] using weak hashing algorithm  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
# fingerprints # fingerprints
@ -66,14 +77,15 @@
(fin) ssh-rsa: SHA256:nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244 (fin) ssh-rsa: SHA256:nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244
# algorithm recommendations (for OpenSSH 8.0) # algorithm recommendations (for OpenSSH 8.0)
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove 
(rec) -ecdh-sha2-nistp256 -- kex algorithm to remove  (rec) -ecdh-sha2-nistp256 -- kex algorithm to remove 
(rec) -ecdh-sha2-nistp384 -- kex algorithm to remove  (rec) -ecdh-sha2-nistp384 -- kex algorithm to remove 
(rec) -ecdh-sha2-nistp521 -- kex algorithm to remove  (rec) -ecdh-sha2-nistp521 -- kex algorithm to remove 
(rec) -ecdsa-sha2-nistp256 -- key algorithm to remove  (rec) -ecdsa-sha2-nistp256 -- key algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove 
(rec) -hmac-sha1-etm@openssh.com -- mac algorithm to remove 
(rec) -ssh-rsa -- key algorithm to remove  (rec) -ssh-rsa -- key algorithm to remove 
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove  (rec) -diffie-hellman-group14-sha256 -- kex algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove 
(rec) -hmac-sha1-etm@openssh.com -- mac algorithm to remove 
(rec) -hmac-sha2-256 -- mac algorithm to remove  (rec) -hmac-sha2-256 -- mac algorithm to remove 
(rec) -hmac-sha2-512 -- mac algorithm to remove  (rec) -hmac-sha2-512 -- mac algorithm to remove 
(rec) -umac-128@openssh.com -- mac algorithm to remove  (rec) -umac-128@openssh.com -- mac algorithm to remove 

View File

@ -1 +1,409 @@
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_8.0", "software": "OpenSSH_8.0"}, "compression": ["none", "zlib@openssh.com"], "enc": ["chacha20-poly1305@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "aes256-gcm@openssh.com"], "fingerprints": [{"hash": "UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU", "hash_alg": "SHA256", "hostkey": "ssh-ed25519"}, {"hash": "1e:0c:7b:34:73:bf:52:41:b0:f9:d1:a9:ab:98:c7:c9", "hash_alg": "MD5", "hostkey": "ssh-ed25519"}], "kex": [{"algorithm": "curve25519-sha256"}, {"algorithm": "curve25519-sha256@libssh.org"}, {"algorithm": "ecdh-sha2-nistp256"}, {"algorithm": "ecdh-sha2-nistp384"}, {"algorithm": "ecdh-sha2-nistp521"}, {"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 2048}, {"algorithm": "diffie-hellman-group16-sha512"}, {"algorithm": "diffie-hellman-group18-sha512"}, {"algorithm": "diffie-hellman-group14-sha256"}, {"algorithm": "diffie-hellman-group14-sha1"}], "key": [{"algorithm": "ssh-ed25519"}, {"algorithm": "ssh-ed25519-cert-v01@openssh.com"}], "mac": ["umac-64-etm@openssh.com", "umac-128-etm@openssh.com", "hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "hmac-sha1-etm@openssh.com", "umac-64@openssh.com", "umac-128@openssh.com", "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1"], "target": "localhost"} {
"banner": {
"comments": null,
"protocol": "2.0",
"raw": "SSH-2.0-OpenSSH_8.0",
"software": "OpenSSH_8.0"
},
"compression": [
"none",
"zlib@openssh.com"
],
"cves": [
{
"cvssv2": 7.0,
"description": "privilege escalation via supplemental groups",
"name": "CVE-2021-41617"
},
{
"cvssv2": 7.8,
"description": "command injection via anomalous argument transfers",
"name": "CVE-2020-15778"
},
{
"cvssv2": 7.8,
"description": "memory corruption and local code execution via pre-authentication integer overflow",
"name": "CVE-2019-16905"
},
{
"cvssv2": 5.3,
"description": "enumerate usernames via challenge response",
"name": "CVE-2016-20012"
}
],
"enc": [
{
"algorithm": "chacha20-poly1305@openssh.com",
"notes": {
"info": [
"default cipher since OpenSSH 6.9",
"available since OpenSSH 6.5"
]
}
},
{
"algorithm": "aes128-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "aes192-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7"
]
}
},
{
"algorithm": "aes256-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "aes128-gcm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
]
}
},
{
"algorithm": "aes256-gcm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
]
}
}
],
"fingerprints": [
{
"hash": "UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU",
"hash_alg": "SHA256",
"hostkey": "ssh-ed25519"
},
{
"hash": "1e:0c:7b:34:73:bf:52:41:b0:f9:d1:a9:ab:98:c7:c9",
"hash_alg": "MD5",
"hostkey": "ssh-ed25519"
}
],
"kex": [
{
"algorithm": "curve25519-sha256",
"notes": {
"info": [
"default key exchange since OpenSSH 6.4",
"available since OpenSSH 7.4, Dropbear SSH 2018.76"
]
}
},
{
"algorithm": "curve25519-sha256@libssh.org",
"notes": {
"info": [
"default key exchange since OpenSSH 6.4",
"available since OpenSSH 6.4, Dropbear SSH 2013.62"
]
}
},
{
"algorithm": "ecdh-sha2-nistp256",
"notes": {
"fail": [
"using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency"
],
"info": [
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
]
}
},
{
"algorithm": "ecdh-sha2-nistp384",
"notes": {
"fail": [
"using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency"
],
"info": [
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
]
}
},
{
"algorithm": "ecdh-sha2-nistp521",
"notes": {
"fail": [
"using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency"
],
"info": [
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
]
}
},
{
"algorithm": "diffie-hellman-group-exchange-sha256",
"keysize": 4096,
"notes": {
"info": [
"OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).",
"available since OpenSSH 4.4"
]
}
},
{
"algorithm": "diffie-hellman-group16-sha512",
"notes": {
"info": [
"available since OpenSSH 7.3, Dropbear SSH 2016.73"
]
}
},
{
"algorithm": "diffie-hellman-group18-sha512",
"notes": {
"info": [
"available since OpenSSH 7.3"
]
}
},
{
"algorithm": "diffie-hellman-group14-sha256",
"notes": {
"info": [
"available since OpenSSH 7.3, Dropbear SSH 2016.73"
],
"warn": [
"2048-bit modulus only provides 112-bits of symmetric strength"
]
}
},
{
"algorithm": "diffie-hellman-group14-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 3.9, Dropbear SSH 0.53"
],
"warn": [
"2048-bit modulus only provides 112-bits of symmetric strength"
]
}
}
],
"key": [
{
"algorithm": "ssh-ed25519",
"notes": {
"info": [
"available since OpenSSH 6.5"
]
}
},
{
"algorithm": "ssh-ed25519-cert-v01@openssh.com",
"ca_algorithm": "ssh-ed25519",
"casize": 256,
"notes": {
"info": [
"available since OpenSSH 6.5"
]
}
}
],
"mac": [
{
"algorithm": "umac-64-etm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
],
"warn": [
"using small 64-bit tag size"
]
}
},
{
"algorithm": "umac-128-etm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
]
}
},
{
"algorithm": "hmac-sha2-256-etm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
]
}
},
{
"algorithm": "hmac-sha2-512-etm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
]
}
},
{
"algorithm": "hmac-sha1-etm@openssh.com",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 6.2"
]
}
},
{
"algorithm": "umac-64@openssh.com",
"notes": {
"info": [
"available since OpenSSH 4.7"
],
"warn": [
"using encrypt-and-MAC mode",
"using small 64-bit tag size"
]
}
},
{
"algorithm": "umac-128@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha2-256",
"notes": {
"info": [
"available since OpenSSH 5.9, Dropbear SSH 2013.56"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha2-512",
"notes": {
"info": [
"available since OpenSSH 5.9, Dropbear SSH 2013.56"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
},
{
"algorithm": "hmac-sha1",
"notes": {
"fail": [
"using broken SHA-1 hash algorithm"
],
"info": [
"available since OpenSSH 2.1.0, Dropbear SSH 0.28"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
}
],
"recommendations": {
"critical": {
"del": {
"kex": [
{
"name": "diffie-hellman-group14-sha1",
"notes": ""
},
{
"name": "ecdh-sha2-nistp256",
"notes": ""
},
{
"name": "ecdh-sha2-nistp384",
"notes": ""
},
{
"name": "ecdh-sha2-nistp521",
"notes": ""
}
],
"mac": [
{
"name": "hmac-sha1",
"notes": ""
},
{
"name": "hmac-sha1-etm@openssh.com",
"notes": ""
}
]
}
},
"informational": {
"add": {
"key": [
{
"name": "rsa-sha2-256",
"notes": ""
},
{
"name": "rsa-sha2-512",
"notes": ""
}
]
}
},
"warning": {
"del": {
"kex": [
{
"name": "diffie-hellman-group14-sha256",
"notes": ""
}
],
"mac": [
{
"name": "hmac-sha2-256",
"notes": ""
},
{
"name": "hmac-sha2-512",
"notes": ""
},
{
"name": "umac-128@openssh.com",
"notes": ""
},
{
"name": "umac-64-etm@openssh.com",
"notes": ""
},
{
"name": "umac-64@openssh.com",
"notes": ""
}
]
}
}
},
"target": "localhost:2222"
}

View File

@ -4,29 +4,40 @@
(gen) compatibility: OpenSSH 7.4+, Dropbear SSH 2018.76+ (gen) compatibility: OpenSSH 7.4+, Dropbear SSH 2018.76+
(gen) compression: enabled (zlib@openssh.com) (gen) compression: enabled (zlib@openssh.com)
# security
(cve) CVE-2021-41617 -- (CVSSv2: 7.0) privilege escalation via supplemental groups
(cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers
(cve) CVE-2019-16905 -- (CVSSv2: 7.8) memory corruption and local code execution via pre-authentication integer overflow
(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response
# key exchange algorithms # key exchange algorithms
(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76 (kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.5, Dropbear SSH 2013.62  `- [info] default key exchange since OpenSSH 6.4
(kex) ecdh-sha2-nistp256 -- [fail] using weak elliptic curves (kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
 `- [info] default key exchange since OpenSSH 6.4
(kex) ecdh-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62 `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) ecdh-sha2-nistp384 -- [fail] using weak elliptic curves (kex) ecdh-sha2-nistp384 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62 `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) ecdh-sha2-nistp521 -- [fail] using weak elliptic curves (kex) ecdh-sha2-nistp521 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62 `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) diffie-hellman-group-exchange-sha256 (2048-bit) -- [info] available since OpenSSH 4.4 (kex) diffie-hellman-group-exchange-sha256 (4096-bit) -- [info] available since OpenSSH 4.4
 `- [info] OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).
(kex) diffie-hellman-group16-sha512 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73 (kex) diffie-hellman-group16-sha512 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
(kex) diffie-hellman-group18-sha512 -- [info] available since OpenSSH 7.3 (kex) diffie-hellman-group18-sha512 -- [info] available since OpenSSH 7.3
(kex) diffie-hellman-group14-sha256 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73 (kex) diffie-hellman-group14-sha256 -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength
(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing algorithm `- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53 `- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
# host-key algorithms # host-key algorithms
(key) ssh-ed25519 -- [info] available since OpenSSH 6.5 (key) ssh-ed25519 -- [info] available since OpenSSH 6.5
(key) ssh-ed25519-cert-v01@openssh.com -- [info] available since OpenSSH 6.5 (key) ssh-ed25519-cert-v01@openssh.com (256-bit cert/256-bit ssh-ed25519 CA) -- [info] available since OpenSSH 6.5
# encryption algorithms (ciphers) # encryption algorithms (ciphers)
(enc) chacha20-poly1305@openssh.com -- [info] available since OpenSSH 6.5 (enc) chacha20-poly1305@openssh.com -- [info] available since OpenSSH 6.5
`- [info] default cipher since OpenSSH 6.9.  `- [info] default cipher since OpenSSH 6.9
(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes192-ctr -- [info] available since OpenSSH 3.7 (enc) aes192-ctr -- [info] available since OpenSSH 3.7
(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
@ -39,7 +50,7 @@
(mac) umac-128-etm@openssh.com -- [info] available since OpenSSH 6.2 (mac) umac-128-etm@openssh.com -- [info] available since OpenSSH 6.2
(mac) hmac-sha2-256-etm@openssh.com -- [info] available since OpenSSH 6.2 (mac) hmac-sha2-256-etm@openssh.com -- [info] available since OpenSSH 6.2
(mac) hmac-sha2-512-etm@openssh.com -- [info] available since OpenSSH 6.2 (mac) hmac-sha2-512-etm@openssh.com -- [info] available since OpenSSH 6.2
(mac) hmac-sha1-etm@openssh.com -- [warn] using weak hashing algorithm (mac) hmac-sha1-etm@openssh.com -- [fail] using broken SHA-1 hash algorithm
`- [info] available since OpenSSH 6.2 `- [info] available since OpenSSH 6.2
(mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode (mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode
 `- [warn] using small 64-bit tag size  `- [warn] using small 64-bit tag size
@ -50,22 +61,23 @@
`- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56 `- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56
(mac) hmac-sha2-512 -- [warn] using encrypt-and-MAC mode (mac) hmac-sha2-512 -- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56 `- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56
(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode (mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm
 `- [warn] using weak hashing algorithm  `- [warn] using encrypt-and-MAC mode
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
# fingerprints # fingerprints
(fin) ssh-ed25519: SHA256:UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU (fin) ssh-ed25519: SHA256:UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU
# algorithm recommendations (for OpenSSH 8.0) # algorithm recommendations (for OpenSSH 8.0)
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove 
(rec) -ecdh-sha2-nistp256 -- kex algorithm to remove  (rec) -ecdh-sha2-nistp256 -- kex algorithm to remove 
(rec) -ecdh-sha2-nistp384 -- kex algorithm to remove  (rec) -ecdh-sha2-nistp384 -- kex algorithm to remove 
(rec) -ecdh-sha2-nistp521 -- kex algorithm to remove  (rec) -ecdh-sha2-nistp521 -- kex algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove 
(rec) -hmac-sha1-etm@openssh.com -- mac algorithm to remove 
(rec) +rsa-sha2-256 -- key algorithm to append  (rec) +rsa-sha2-256 -- key algorithm to append 
(rec) +rsa-sha2-512 -- key algorithm to append  (rec) +rsa-sha2-512 -- key algorithm to append 
(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove  (rec) -diffie-hellman-group14-sha256 -- kex algorithm to remove 
(rec) -hmac-sha1 -- mac algorithm to remove 
(rec) -hmac-sha1-etm@openssh.com -- mac algorithm to remove 
(rec) -hmac-sha2-256 -- mac algorithm to remove  (rec) -hmac-sha2-256 -- mac algorithm to remove 
(rec) -hmac-sha2-512 -- mac algorithm to remove  (rec) -hmac-sha2-512 -- mac algorithm to remove 
(rec) -umac-128@openssh.com -- mac algorithm to remove  (rec) -umac-128@openssh.com -- mac algorithm to remove 

View File

@ -1 +1,190 @@
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_8.0", "software": "OpenSSH_8.0"}, "compression": ["none", "zlib@openssh.com"], "enc": ["chacha20-poly1305@openssh.com", "aes256-gcm@openssh.com", "aes128-gcm@openssh.com", "aes256-ctr", "aes192-ctr", "aes128-ctr"], "fingerprints": [{"hash": "UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU", "hash_alg": "SHA256", "hostkey": "ssh-ed25519"}, {"hash": "1e:0c:7b:34:73:bf:52:41:b0:f9:d1:a9:ab:98:c7:c9", "hash_alg": "MD5", "hostkey": "ssh-ed25519"}], "kex": [{"algorithm": "curve25519-sha256"}, {"algorithm": "curve25519-sha256@libssh.org"}, {"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 2048}], "key": [{"algorithm": "ssh-ed25519"}], "mac": ["hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "umac-128-etm@openssh.com"], "target": "localhost"} {
"banner": {
"comments": null,
"protocol": "2.0",
"raw": "SSH-2.0-OpenSSH_8.0",
"software": "OpenSSH_8.0"
},
"compression": [
"none",
"zlib@openssh.com"
],
"cves": [
{
"cvssv2": 7.0,
"description": "privilege escalation via supplemental groups",
"name": "CVE-2021-41617"
},
{
"cvssv2": 7.8,
"description": "command injection via anomalous argument transfers",
"name": "CVE-2020-15778"
},
{
"cvssv2": 7.8,
"description": "memory corruption and local code execution via pre-authentication integer overflow",
"name": "CVE-2019-16905"
},
{
"cvssv2": 5.3,
"description": "enumerate usernames via challenge response",
"name": "CVE-2016-20012"
}
],
"enc": [
{
"algorithm": "chacha20-poly1305@openssh.com",
"notes": {
"info": [
"default cipher since OpenSSH 6.9",
"available since OpenSSH 6.5"
]
}
},
{
"algorithm": "aes256-gcm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
]
}
},
{
"algorithm": "aes128-gcm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
]
}
},
{
"algorithm": "aes256-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
},
{
"algorithm": "aes192-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7"
]
}
},
{
"algorithm": "aes128-ctr",
"notes": {
"info": [
"available since OpenSSH 3.7, Dropbear SSH 0.52"
]
}
}
],
"fingerprints": [
{
"hash": "UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU",
"hash_alg": "SHA256",
"hostkey": "ssh-ed25519"
},
{
"hash": "1e:0c:7b:34:73:bf:52:41:b0:f9:d1:a9:ab:98:c7:c9",
"hash_alg": "MD5",
"hostkey": "ssh-ed25519"
}
],
"kex": [
{
"algorithm": "curve25519-sha256",
"notes": {
"info": [
"default key exchange since OpenSSH 6.4",
"available since OpenSSH 7.4, Dropbear SSH 2018.76"
]
}
},
{
"algorithm": "curve25519-sha256@libssh.org",
"notes": {
"info": [
"default key exchange since OpenSSH 6.4",
"available since OpenSSH 6.4, Dropbear SSH 2013.62"
]
}
},
{
"algorithm": "diffie-hellman-group-exchange-sha256",
"keysize": 4096,
"notes": {
"info": [
"OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).",
"available since OpenSSH 4.4"
]
}
}
],
"key": [
{
"algorithm": "ssh-ed25519",
"notes": {
"info": [
"available since OpenSSH 6.5"
]
}
}
],
"mac": [
{
"algorithm": "hmac-sha2-256-etm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
]
}
},
{
"algorithm": "hmac-sha2-512-etm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
]
}
},
{
"algorithm": "umac-128-etm@openssh.com",
"notes": {
"info": [
"available since OpenSSH 6.2"
]
}
}
],
"recommendations": {
"informational": {
"add": {
"kex": [
{
"name": "diffie-hellman-group16-sha512",
"notes": ""
},
{
"name": "diffie-hellman-group18-sha512",
"notes": ""
}
],
"key": [
{
"name": "rsa-sha2-256",
"notes": ""
},
{
"name": "rsa-sha2-512",
"notes": ""
}
]
}
}
},
"target": "localhost:2222"
}

View File

@ -4,17 +4,26 @@
(gen) compatibility: OpenSSH 7.4+, Dropbear SSH 2018.76+ (gen) compatibility: OpenSSH 7.4+, Dropbear SSH 2018.76+
(gen) compression: enabled (zlib@openssh.com) (gen) compression: enabled (zlib@openssh.com)
# security
(cve) CVE-2021-41617 -- (CVSSv2: 7.0) privilege escalation via supplemental groups
(cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers
(cve) CVE-2019-16905 -- (CVSSv2: 7.8) memory corruption and local code execution via pre-authentication integer overflow
(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response
# key exchange algorithms # key exchange algorithms
(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76 (kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.5, Dropbear SSH 2013.62  `- [info] default key exchange since OpenSSH 6.4
(kex) diffie-hellman-group-exchange-sha256 (2048-bit) -- [info] available since OpenSSH 4.4 (kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
 `- [info] default key exchange since OpenSSH 6.4
(kex) diffie-hellman-group-exchange-sha256 (4096-bit) -- [info] available since OpenSSH 4.4
 `- [info] OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).
# host-key algorithms # host-key algorithms
(key) ssh-ed25519 -- [info] available since OpenSSH 6.5 (key) ssh-ed25519 -- [info] available since OpenSSH 6.5
# encryption algorithms (ciphers) # encryption algorithms (ciphers)
(enc) chacha20-poly1305@openssh.com -- [info] available since OpenSSH 6.5 (enc) chacha20-poly1305@openssh.com -- [info] available since OpenSSH 6.5
`- [info] default cipher since OpenSSH 6.9.  `- [info] default cipher since OpenSSH 6.9
(enc) aes256-gcm@openssh.com -- [info] available since OpenSSH 6.2 (enc) aes256-gcm@openssh.com -- [info] available since OpenSSH 6.2
(enc) aes128-gcm@openssh.com -- [info] available since OpenSSH 6.2 (enc) aes128-gcm@openssh.com -- [info] available since OpenSSH 6.2
(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
@ -30,7 +39,6 @@
(fin) ssh-ed25519: SHA256:UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU (fin) ssh-ed25519: SHA256:UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU
# algorithm recommendations (for OpenSSH 8.0) # algorithm recommendations (for OpenSSH 8.0)
(rec) +diffie-hellman-group14-sha256 -- kex algorithm to append 
(rec) +diffie-hellman-group16-sha512 -- kex algorithm to append  (rec) +diffie-hellman-group16-sha512 -- kex algorithm to append 
(rec) +diffie-hellman-group18-sha512 -- kex algorithm to append  (rec) +diffie-hellman-group18-sha512 -- kex algorithm to append 
(rec) +rsa-sha2-256 -- key algorithm to append  (rec) +rsa-sha2-256 -- key algorithm to append 

View File

@ -1 +1,92 @@
{"banner": {"comments": "", "protocol": [2, 0], "raw": "", "software": "tinyssh_noversion"}, "compression": ["none"], "enc": ["chacha20-poly1305@openssh.com"], "fingerprints": [{"hash": "89ocln1x7KNqnMgWffGoYtD70ksJ4FrH7BMJHa7SrwU", "hash_alg": "SHA256", "hostkey": "ssh-ed25519"}, {"hash": "dd:9c:6d:f9:b0:8c:af:fa:c2:65:81:5d:5d:56:f8:21", "hash_alg": "MD5", "hostkey": "ssh-ed25519"}], "kex": [{"algorithm": "curve25519-sha256"}, {"algorithm": "curve25519-sha256@libssh.org"}, {"algorithm": "sntrup4591761x25519-sha512@tinyssh.org"}], "key": [{"algorithm": "ssh-ed25519"}], "mac": ["hmac-sha2-256"], "target": "localhost"} {
"banner": {
"comments": "",
"protocol": "2.0",
"raw": "",
"software": "tinyssh_noversion"
},
"compression": [
"none"
],
"cves": [],
"enc": [
{
"algorithm": "chacha20-poly1305@openssh.com",
"notes": {
"info": [
"default cipher since OpenSSH 6.9",
"available since OpenSSH 6.5"
]
}
}
],
"fingerprints": [
{
"hash": "89ocln1x7KNqnMgWffGoYtD70ksJ4FrH7BMJHa7SrwU",
"hash_alg": "SHA256",
"hostkey": "ssh-ed25519"
},
{
"hash": "dd:9c:6d:f9:b0:8c:af:fa:c2:65:81:5d:5d:56:f8:21",
"hash_alg": "MD5",
"hostkey": "ssh-ed25519"
}
],
"kex": [
{
"algorithm": "curve25519-sha256",
"notes": {
"info": [
"default key exchange since OpenSSH 6.4",
"available since OpenSSH 7.4, Dropbear SSH 2018.76"
]
}
},
{
"algorithm": "curve25519-sha256@libssh.org",
"notes": {
"info": [
"default key exchange since OpenSSH 6.4",
"available since OpenSSH 6.4, Dropbear SSH 2013.62"
]
}
},
{
"algorithm": "sntrup4591761x25519-sha512@tinyssh.org",
"notes": {
"info": [
"the sntrup4591761 algorithm was withdrawn, as it may not provide strong post-quantum security",
"available since OpenSSH 8.0"
],
"warn": [
"using experimental algorithm"
]
}
}
],
"key": [
{
"algorithm": "ssh-ed25519",
"notes": {
"info": [
"available since OpenSSH 6.5"
]
}
}
],
"mac": [
{
"algorithm": "hmac-sha2-256",
"notes": {
"info": [
"available since OpenSSH 5.9, Dropbear SSH 2013.56"
],
"warn": [
"using encrypt-and-MAC mode"
]
}
}
],
"recommendations": {},
"target": "localhost:2222"
}

View File

@ -5,16 +5,19 @@
# key exchange algorithms # key exchange algorithms
(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76 (kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.5, Dropbear SSH 2013.62  `- [info] default key exchange since OpenSSH 6.4
(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
 `- [info] default key exchange since OpenSSH 6.4
(kex) sntrup4591761x25519-sha512@tinyssh.org -- [warn] using experimental algorithm (kex) sntrup4591761x25519-sha512@tinyssh.org -- [warn] using experimental algorithm
`- [info] available since OpenSSH 8.0 `- [info] available since OpenSSH 8.0
`- [info] the sntrup4591761 algorithm was withdrawn, as it may not provide strong post-quantum security
# host-key algorithms # host-key algorithms
(key) ssh-ed25519 -- [info] available since OpenSSH 6.5 (key) ssh-ed25519 -- [info] available since OpenSSH 6.5
# encryption algorithms (ciphers) # encryption algorithms (ciphers)
(enc) chacha20-poly1305@openssh.com -- [info] available since OpenSSH 6.5 (enc) chacha20-poly1305@openssh.com -- [info] available since OpenSSH 6.5
`- [info] default cipher since OpenSSH 6.9.  `- [info] default cipher since OpenSSH 6.9
# message authentication code algorithms # message authentication code algorithms
(mac) hmac-sha2-256 -- [warn] using encrypt-and-MAC mode (mac) hmac-sha2-256 -- [warn] using encrypt-and-MAC mode

View File

@ -23,7 +23,7 @@ hostkey_size_rsa-sha2-512 = 3072
hostkey_size_ssh-rsa = 3072 hostkey_size_ssh-rsa = 3072
# Group exchange DH modulus sizes. # Group exchange DH modulus sizes.
dh_modulus_size_diffie-hellman-group-exchange-sha256 = 2048 dh_modulus_size_diffie-hellman-group-exchange-sha256 = 4096
# The host key types that must match exactly (order matters). # The host key types that must match exactly (order matters).
host keys = rsa-sha2-512, rsa-sha2-256, ssh-rsa, ecdsa-sha2-nistp256, ssh-ed25519 host keys = rsa-sha2-512, rsa-sha2-256, ssh-rsa, ecdsa-sha2-nistp256, ssh-ed25519

View File

@ -23,7 +23,7 @@ hostkey_size_rsa-sha2-512 = 3072
hostkey_size_ssh-rsa = 3072 hostkey_size_ssh-rsa = 3072
# Group exchange DH modulus sizes. # Group exchange DH modulus sizes.
dh_modulus_size_diffie-hellman-group-exchange-sha256 = 4096 dh_modulus_size_diffie-hellman-group-exchange-sha256 = 8192
# The host key types that must match exactly (order matters). # The host key types that must match exactly (order matters).
host keys = rsa-sha2-512, rsa-sha2-256, ssh-rsa, ecdsa-sha2-nistp256, ssh-ed25519 host keys = rsa-sha2-512, rsa-sha2-256, ssh-rsa, ecdsa-sha2-nistp256, ssh-ed25519

View File

@ -7,7 +7,7 @@ class TestAuditConf:
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def init(self, ssh_audit): def init(self, ssh_audit):
self.AuditConf = ssh_audit.AuditConf self.AuditConf = ssh_audit.AuditConf
self.OutputBuffer = ssh_audit.OutputBuffer self.OutputBuffer = ssh_audit.OutputBuffer()
self.usage = ssh_audit.usage self.usage = ssh_audit.usage
self.process_commandline = process_commandline self.process_commandline = process_commandline

View File

@ -1,6 +1,7 @@
import os import os
import pytest import pytest
from ssh_audit.outputbuffer import OutputBuffer
from ssh_audit.ssh2_kex import SSH2_Kex from ssh_audit.ssh2_kex import SSH2_Kex
from ssh_audit.ssh2_kexparty import SSH2_KexParty from ssh_audit.ssh2_kexparty import SSH2_KexParty
@ -13,7 +14,7 @@ def kex(ssh_audit):
enc, mac, compression, languages = [], [], ['none'], [] enc, mac, compression, languages = [], [], ['none'], []
srv = SSH2_KexParty(enc, mac, compression, languages) srv = SSH2_KexParty(enc, mac, compression, languages)
cookie = os.urandom(16) cookie = os.urandom(16)
kex = SSH2_Kex(cookie, kex_algs, key_algs, cli, srv, 0) kex = SSH2_Kex(OutputBuffer, cookie, kex_algs, key_algs, cli, srv, 0)
return kex return kex
@ -25,17 +26,17 @@ def test_prevent_runtime_error_regression(ssh_audit, kex):
keys, and an error occurred when iterating and modifying them at the keys, and an error occurred when iterating and modifying them at the
same time. same time.
""" """
kex.set_host_key("ssh-rsa", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00") kex.set_host_key("ssh-rsa", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
kex.set_host_key("ssh-rsa1", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00") kex.set_host_key("ssh-rsa1", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
kex.set_host_key("ssh-rsa2", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00") kex.set_host_key("ssh-rsa2", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
kex.set_host_key("ssh-rsa3", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00") kex.set_host_key("ssh-rsa3", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
kex.set_host_key("ssh-rsa4", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00") kex.set_host_key("ssh-rsa4", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
kex.set_host_key("ssh-rsa5", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00") kex.set_host_key("ssh-rsa5", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
kex.set_host_key("ssh-rsa6", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00") kex.set_host_key("ssh-rsa6", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
kex.set_host_key("ssh-rsa7", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00") kex.set_host_key("ssh-rsa7", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
kex.set_host_key("ssh-rsa8", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00") kex.set_host_key("ssh-rsa8", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
rv = ssh_audit.build_struct('localhost', banner=None, kex=kex) rv = ssh_audit.build_struct('localhost', None, [], kex=kex)
assert len(rv["fingerprints"]) == (9 * 2) # Each host key generates two hash fingerprints: one using SHA256, and one using MD5. assert len(rv["fingerprints"]) == (9 * 2) # Each host key generates two hash fingerprints: one using SHA256, and one using MD5.

View File

@ -2,6 +2,7 @@ import hashlib
import pytest import pytest
from datetime import date from datetime import date
from ssh_audit.outputbuffer import OutputBuffer
from ssh_audit.policy import Policy from ssh_audit.policy import Policy
from ssh_audit.ssh2_kex import SSH2_Kex from ssh_audit.ssh2_kex import SSH2_Kex
from ssh_audit.writebuf import WriteBuf from ssh_audit.writebuf import WriteBuf
@ -10,6 +11,7 @@ from ssh_audit.writebuf import WriteBuf
class TestPolicy: class TestPolicy:
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def init(self, ssh_audit): def init(self, ssh_audit):
self.OutputBuffer = OutputBuffer
self.Policy = Policy self.Policy = Policy
self.wbuf = WriteBuf self.wbuf = WriteBuf
self.ssh2_kex = SSH2_Kex self.ssh2_kex = SSH2_Kex
@ -32,7 +34,7 @@ class TestPolicy:
w.write_list(['']) w.write_list([''])
w.write_byte(False) w.write_byte(False)
w.write_int(0) w.write_int(0)
return self.ssh2_kex.parse(w.write_flush()) return self.ssh2_kex.parse(self.OutputBuffer, w.write_flush())
def test_builtin_policy_consistency(self): def test_builtin_policy_consistency(self):
@ -41,15 +43,91 @@ class TestPolicy:
for policy_name in Policy.BUILTIN_POLICIES: for policy_name in Policy.BUILTIN_POLICIES:
# Ensure that the policy name ends with " (version X)", where X is the 'version' field. # Ensure that the policy name ends with " (version X)", where X is the 'version' field.
version_str = " (version %s)" % Policy.BUILTIN_POLICIES[policy_name]['version'] version_str = " (version %s)" % Policy.BUILTIN_POLICIES[policy_name]['version']
assert(policy_name.endswith(version_str)) assert policy_name.endswith(version_str)
# Ensure that all required fields are present.
required_fields = ['version', 'banner', 'compressions', 'host_keys', 'optional_host_keys', 'kex', 'ciphers', 'macs', 'hostkey_sizes', 'dh_modulus_sizes', 'server_policy']
for field in required_fields:
assert field in Policy.BUILTIN_POLICIES[policy_name]
# Ensure no extra fields are present.
assert len(required_fields) == len(Policy.BUILTIN_POLICIES[policy_name])
# Ensure that at least one host key is defined.
assert type(Policy.BUILTIN_POLICIES[policy_name]['host_keys']) is list
assert len(Policy.BUILTIN_POLICIES[policy_name]['host_keys']) > 0
# Ensure that at least one key exchange is defined.
assert type(Policy.BUILTIN_POLICIES[policy_name]['kex']) is list
assert len(Policy.BUILTIN_POLICIES[policy_name]['kex']) > 0
# Ensure that at least one cipher is defined.
assert type(Policy.BUILTIN_POLICIES[policy_name]['ciphers']) is list
assert len(Policy.BUILTIN_POLICIES[policy_name]['ciphers']) > 0
# Ensure that at least one MAC is defined
assert type(Policy.BUILTIN_POLICIES[policy_name]['macs']) is list
assert len(Policy.BUILTIN_POLICIES[policy_name]['macs']) > 0
# These tests apply to server policies only.
if Policy.BUILTIN_POLICIES[policy_name]['server_policy']:
assert type(Policy.BUILTIN_POLICIES[policy_name]['hostkey_sizes']) is dict
assert len(Policy.BUILTIN_POLICIES[policy_name]['hostkey_sizes']) > 0
# Examine all the hostkey_sizes entries...
for hostkey_type in Policy.BUILTIN_POLICIES[policy_name]['hostkey_sizes']:
hostkey_data = Policy.BUILTIN_POLICIES[policy_name]['hostkey_sizes'][hostkey_type]
# Ensure that 'hostkey_size' is always included and that it is an integer.
assert 'hostkey_size' in hostkey_data
assert type(hostkey_data['hostkey_size']) is int
# If this is an ed25519 host key, ensure its size is fixed at 256. If its an RSA host key, ensure the size is 4096.
if hostkey_type.find('ed25519') != -1:
assert int(hostkey_data['hostkey_size']) == 256
elif hostkey_type.startswith('rsa-'):
assert int(hostkey_data['hostkey_size']) == 4096
else: # Catch unexpected host key types.
assert False
# Ensure either that 'ca_key_type' and 'ca_key_size' are both present, or neither are. Fail cases when only one of the fields are present.
assert (('ca_key_type' in hostkey_data) and ('ca_key_size' in hostkey_data)) or (('ca_key_type' not in hostkey_data) and ('ca_key_size' not in hostkey_data))
# Ensure that the ca_key_type is either ssh-rsa or ssh-ed25519.
if 'ca_key_type' in hostkey_data:
assert hostkey_data['ca_key_type'] in ['ssh-rsa', 'ssh-ed25519']
# Ensure RSA CA key sizes are fixed at 4096. Ensure ED25519 CA keys are 256.
if 'ca_key_size' in hostkey_data:
if 'ca_key_type' == 'ssh-rsa':
assert hostkey_data['ca_key_size'] == 4096
elif 'ca_key_type' == 'ssh-ed25519':
assert hostkey_data['ca_key_size'] == 256
# Ensure that the 'dh_modulus_size' field is a dict.
assert type(Policy.BUILTIN_POLICIES[policy_name]['dh_modulus_sizes']) is dict
# The 'dh_modulus_size' field should have either one entry, or be empty.
assert len(Policy.BUILTIN_POLICIES[policy_name]['dh_modulus_sizes']) in range(0, 2) # The endpoint in range() is not inclusive
# If 'diffie-hellman-group-exchange-sha256' is in the kex list, ensure that it exists in the 'dh_modulus_sizes' entry. That entry must be defined for 2048 bits or larger.
if 'diffie-hellman-group-exchange-sha256' in Policy.BUILTIN_POLICIES[policy_name]['kex']:
assert 'diffie-hellman-group-exchange-sha256' in Policy.BUILTIN_POLICIES[policy_name]['dh_modulus_sizes']
assert int(Policy.BUILTIN_POLICIES[policy_name]['dh_modulus_sizes']['diffie-hellman-group-exchange-sha256']) >= 2048
else: # Client-specific tests.
# These must be set to None for client policies, since they have no meaning otherwise.
assert Policy.BUILTIN_POLICIES[policy_name]['hostkey_sizes'] is None
assert Policy.BUILTIN_POLICIES[policy_name]['dh_modulus_sizes'] is None
# Ensure that each built-in policy can be loaded with Policy.load_builtin_policy(). # Ensure that each built-in policy can be loaded with Policy.load_builtin_policy().
assert(Policy.load_builtin_policy(policy_name) is not None) assert Policy.load_builtin_policy(policy_name) is not None
# Ensure that both server and client policy names are returned. # Ensure that both server and client policy names are returned.
server_policy_names, client_policy_names = Policy.list_builtin_policies() server_policy_names, client_policy_names = Policy.list_builtin_policies()
assert(len(server_policy_names) > 0) assert len(server_policy_names) > 0
assert(len(client_policy_names) > 0) assert len(client_policy_names) > 0
def test_policy_basic(self): def test_policy_basic(self):
@ -66,7 +144,7 @@ ciphers = cipher_alg1, cipher_alg2, cipher_alg3
macs = mac_alg1, mac_alg2, mac_alg3''' macs = mac_alg1, mac_alg2, mac_alg3'''
policy = self.Policy(policy_data=policy_data) policy = self.Policy(policy_data=policy_data)
assert str(policy) == "Name: [Test Policy]\nVersion: [1]\nBanner: {undefined}\nCompressions: comp_alg1\nHost Keys: key_alg1\nOptional Host Keys: {undefined}\nKey Exchanges: kex_alg1, kex_alg2\nCiphers: cipher_alg1, cipher_alg2, cipher_alg3\nMACs: mac_alg1, mac_alg2, mac_alg3\nHost Key Sizes: {undefined}\nCA Key Sizes: {undefined}\nDH Modulus Sizes: {undefined}\nServer Policy: True" assert str(policy) == "Name: [Test Policy]\nVersion: [1]\nBanner: {undefined}\nCompressions: comp_alg1\nHost Keys: key_alg1\nOptional Host Keys: {undefined}\nKey Exchanges: kex_alg1, kex_alg2\nCiphers: cipher_alg1, cipher_alg2, cipher_alg3\nMACs: mac_alg1, mac_alg2, mac_alg3\nHost Key Sizes: {undefined}\nDH Modulus Sizes: {undefined}\nServer Policy: True"
def test_policy_invalid_1(self): def test_policy_invalid_1(self):

View File

@ -22,12 +22,12 @@ class TestResolve:
vsocket.gsock.addrinfodata['localhost#22'] = socket.gaierror(8, 'hostname nor servname provided, or not known') vsocket.gsock.addrinfodata['localhost#22'] = socket.gaierror(8, 'hostname nor servname provided, or not known')
conf = self._conf() conf = self._conf()
s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference) s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference)
output_spy.begin() # output_spy.begin()
with pytest.raises(SystemExit): with pytest.raises(socket.gaierror):
list(s._resolve()) list(s._resolve())
lines = output_spy.flush() # lines = output_spy.flush()
assert len(lines) == 1 # assert len(lines) == 1
assert 'hostname nor servname provided' in lines[-1] # assert 'hostname nor servname provided' in lines[-1]
def test_resolve_hostname_without_records(self, output_spy, virtual_socket): def test_resolve_hostname_without_records(self, output_spy, virtual_socket):
vsocket = virtual_socket vsocket = virtual_socket

View File

@ -138,7 +138,7 @@ class TestSSH1:
self.audit(out, self._conf()) self.audit(out, self._conf())
out.write() out.write()
lines = output_spy.flush() lines = output_spy.flush()
assert len(lines) == 17 assert len(lines) == 21
def test_ssh1_server_invalid_first_packet(self, output_spy, virtual_socket): def test_ssh1_server_invalid_first_packet(self, output_spy, virtual_socket):
vsocket = virtual_socket vsocket = virtual_socket
@ -153,7 +153,7 @@ class TestSSH1:
out.write() out.write()
assert ret != 0 assert ret != 0
lines = output_spy.flush() lines = output_spy.flush()
assert len(lines) == 10 assert len(lines) == 14
assert 'unknown message' in lines[-1] assert 'unknown message' in lines[-1]
def test_ssh1_server_invalid_checksum(self, output_spy, virtual_socket): def test_ssh1_server_invalid_checksum(self, output_spy, virtual_socket):

View File

@ -61,8 +61,25 @@ class TestSSH2:
w.write_int(0) w.write_int(0)
return w.write_flush() return w.write_flush()
def _kex_payload_with_gss(self):
w = self.wbuf()
w.write(b'\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff')
w.write_list(['gss-gex-sha1-dZuIebMjgUqaxvbF7hDbAw==', 'gss-gex-sha1-vz8J1E9PzLr8b1K+0remTg==', 'gss-group14-sha1-dZuIebMjgUqaxvbF7hDbAw==', 'gss-group14-sha1-vz8J1E9PzLr8b1K+0remTg==', 'gss-group14-sha256-dZuIebMjgUqaxvbF7hDbAw==', 'gss-group14-sha256-vz8J1E9PzLr8b1K+0remTg==', 'gss-group16-sha512-dZuIebMjgUqaxvbF7hDbAw==', 'gss-group16-sha512-vz8J1E9PzLr8b1K+0remTg==', 'gss-group18-sha512-dZuIebMjgUqaxvbF7hDbAw==', 'gss-group18-sha512-vz8J1E9PzLr8b1K+0remTg==', 'gss-group1-sha1-dZuIebMjgUqaxvbF7hDbAw==', 'gss-group1-sha1-vz8J1E9PzLr8b1K+0remTg==', 'gss-curve448-sha512-XXX'])
w.write_list(['ssh-ed25519'])
w.write_list(['chacha20-poly1305@openssh.com'])
w.write_list(['chacha20-poly1305@openssh.com'])
w.write_list(['hmac-sha2-512-etm@openssh.com'])
w.write_list(['hmac-sha2-512-etm@openssh.com'])
w.write_list(['none', 'zlib@openssh.com'])
w.write_list(['none', 'zlib@openssh.com'])
w.write_list([''])
w.write_list([''])
w.write_byte(False)
w.write_int(0)
return w.write_flush()
def test_kex_read(self): def test_kex_read(self):
kex = self.ssh2_kex.parse(self._kex_payload()) kex = self.ssh2_kex.parse(self.OutputBuffer, self._kex_payload())
assert kex is not None assert kex is not None
assert kex.cookie == b'\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff' assert kex.cookie == b'\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff'
assert kex.kex_algorithms == ['bogus_kex1', 'bogus_kex2'] assert kex.kex_algorithms == ['bogus_kex1', 'bogus_kex2']
@ -88,7 +105,7 @@ class TestSSH2:
srv = self.ssh2_kexparty(enc, mac, compression, languages) srv = self.ssh2_kexparty(enc, mac, compression, languages)
if cookie is None: if cookie is None:
cookie = os.urandom(16) cookie = os.urandom(16)
kex = self.ssh2_kex(cookie, kex_algs, key_algs, cli, srv, 0) kex = self.ssh2_kex(self.OutputBuffer, cookie, kex_algs, key_algs, cli, srv, 0)
return kex return kex
def _get_kex_variat1(self): def _get_kex_variat1(self):
@ -132,7 +149,7 @@ class TestSSH2:
def test_key_payload(self): def test_key_payload(self):
kex1 = self._get_kex_variat1() kex1 = self._get_kex_variat1()
kex2 = self.ssh2_kex.parse(self._kex_payload()) kex2 = self.ssh2_kex.parse(self.OutputBuffer, self._kex_payload())
assert kex1.payload == kex2.payload assert kex1.payload == kex2.payload
def test_ssh2_server_simple(self, output_spy, virtual_socket): def test_ssh2_server_simple(self, output_spy, virtual_socket):
@ -161,5 +178,24 @@ class TestSSH2:
out.write() out.write()
assert ret != 0 assert ret != 0
lines = output_spy.flush() lines = output_spy.flush()
assert len(lines) == 5 assert len(lines) == 9
assert 'unknown message' in lines[-1] assert 'unknown message' in lines[-1]
def test_ssh2_gss_kex(self, output_spy, virtual_socket):
'''Ensure that GSS kex algorithms are properly parsed.'''
vsocket = virtual_socket
w = self.wbuf()
w.write_byte(self.protocol.MSG_KEXINIT)
w.write(self._kex_payload_with_gss()) # Use the kex with GSS algorithms.
vsocket.rdata.append(b'SSH-2.0-OpenSSH_7.3 ssh-audit-test\r\n')
vsocket.rdata.append(self._create_ssh2_packet(w.write_flush()))
output_spy.begin()
out = self.OutputBuffer()
self.audit(out, self._conf())
out.write()
lines = output_spy.flush()
# Ensure that none of the lines are reported as "unknown algorithm".
for line in lines:
assert line.find('unknown algorithm') == -1

35
test/test_ssh2_kexdb.py Normal file
View File

@ -0,0 +1,35 @@
import pytest
from ssh_audit.ssh2_kexdb import SSH2_KexDB
class Test_SSH2_KexDB:
@pytest.fixture(autouse=True)
def init(self):
self.db = SSH2_KexDB.get_db()
def test_ssh2_kexdb(self):
'''Ensures that the SSH2_KexDB.ALGORITHMS dictionary is in the right format.'''
db_keys = list(self.db.keys())
db_keys.sort()
# Ensure only these keys exist in the database.
assert db_keys == ['enc', 'kex', 'key', 'mac']
# For 'enc', 'kex', etc...
for alg_type in self.db:
# Iterate over algorithms within this type (i.e.: all 'enc' algorithms, all 'kex' algorithms, etc).
for alg_name in self.db[alg_type]:
# Get the list of failures, warnings, etc., for this algorithm.
alg_data = self.db[alg_type][alg_name]
# This list must be between 1 and 4 entries long.
assert 1 <= len(alg_data) <= 4
# The first entry denotes the versions when this algorithm was added to OpenSSH, Dropbear, and/or libssh, followed by when it was deprecated, and finally when it was removed. Hence it must have between 0 and 3 entries.
added_entry = alg_data[0]
assert 0 <= len(added_entry) <= 3

34
tox.ini
View File

@ -1,19 +1,19 @@
[tox] [tox]
envlist = envlist =
py{py3}-{test,pylint,flake8,vulture} py{py3}-{test,pylint,flake8,vulture}
py{36,37,38,39}-{test,mypy,pylint,flake8,vulture} py{37,38,39,310,311}-{test,mypy,pylint,flake8,vulture}
cov cov
skip_missing_interpreters = true skip_missing_interpreters = true
[testenv] [testenv]
deps = deps =
test: pytest<6.0 test: pytest
test,cov: {[testenv:cov]deps} test,cov: {[testenv:cov]deps}
test,py{36,37,38,39}-{type,mypy}: colorama test,py{37,38,39,310,311}-{type,mypy}: colorama
py{36,37,38,39}-{type,mypy}: {[testenv:mypy]deps} py{37,38,39,310,311}-{type,mypy}: {[testenv:mypy]deps}
py{py3,36,37,38,39}-{lint,pylint},lint: {[testenv:pylint]deps} py{py3,37,38,39,310,311}-{lint,pylint},lint: {[testenv:pylint]deps}
py{py3,36,37,38,39}-{lint,flake8},lint: {[testenv:flake8]deps} py{py3,37,38,39,310,311}-{lint,flake8},lint: {[testenv:flake8]deps}
py{py3,36,37,38,39}-{lint,vulture},lint: {[testenv:vulture]deps} py{py3,37,38,39,310,311}-{lint,vulture},lint: {[testenv:vulture]deps}
setenv = setenv =
SSHAUDIT = {toxinidir}/src SSHAUDIT = {toxinidir}/src
test: COVERAGE_FILE = {toxinidir}/.coverage.{envname} test: COVERAGE_FILE = {toxinidir}/.coverage.{envname}
@ -25,10 +25,10 @@ commands =
test: coverage combine test: coverage combine
test: coverage report --show-missing test: coverage report --show-missing
test: coverage html -d {toxinidir}/reports/html/coverage.{envname} test: coverage html -d {toxinidir}/reports/html/coverage.{envname}
py{36,37,38,39}-{type,mypy}: {[testenv:mypy]commands} py{37,38,39,310,311}-{type,mypy}: {[testenv:mypy]commands}
py{py3,36,37,38,39}-{lint,pylint},lint: {[testenv:pylint]commands} py{py3,37,38,39,310,311}-{lint,pylint},lint: {[testenv:pylint]commands}
py{py3,36,37,38,39}-{lint,flake8},lint: {[testenv:flake8]commands} py{py3,37,38,39,310,311}-{lint,flake8},lint: {[testenv:flake8]commands}
py{py3,36,37,38,39}-{lint,vulture},lint: {[testenv:vulture]commands} py{py3,37,38,39,310,311}-{lint,vulture},lint: {[testenv:vulture]commands}
#ignore_outcome = #ignore_outcome =
# type: true # type: true
# lint: true # lint: true
@ -91,14 +91,12 @@ reports = no
#output-format = colorized #output-format = colorized
indent-string = " " indent-string = " "
disable = disable =
bad-continuation,
broad-except, broad-except,
duplicate-code, duplicate-code,
fixme, fixme,
invalid-name, invalid-name,
line-too-long, line-too-long,
missing-docstring, missing-docstring,
mixed-indentation,
no-else-raise, no-else-raise,
no-else-return, no-else-return,
super-with-arguments, # Can be re-factored, at some point. super-with-arguments, # Can be re-factored, at some point.
@ -109,7 +107,7 @@ disable =
too-many-lines, too-many-lines,
too-many-locals, too-many-locals,
too-many-statements, too-many-statements,
unsubscriptable-object # This seems to be a local issue on the maintainer's machine only. Could be removed, perhaps, in Jan 2021. consider-using-f-string
max-complexity = 15 max-complexity = 15
max-args = 8 max-args = 8
max-locals = 20 max-locals = 20
@ -127,10 +125,10 @@ ignore-long-lines = ^\s*(#\s+type:\s+.*|[A-Z0-9_]+\s+=\s+.*|('.*':\s+)?\[.*\],?|
max-module-lines = 2500 max-module-lines = 2500
[flake8] [flake8]
ignore = # E241 = multiple spaces after operator; should be kept for tabular data
E241, # multiple spaces after operator; should be kept for tabular data # E303 = too many blank lines
E303, # too many blank lines # E501 = line too long
E501, # line too long ignore = E241, E303, E501
[pytest] [pytest]
junit_family = xunit1 junit_family = xunit1

View File

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
# #
# The MIT License (MIT) # The MIT License (MIT)
@ -45,7 +45,7 @@
# #
################################################################################ ################################################################################
function usage { usage() {
echo >&2 "Usage: $0 [-m <path-to-man-page>] [-g <path-to-globals.py>] [-h]" echo >&2 "Usage: $0 [-m <path-to-man-page>] [-g <path-to-globals.py>] [-h]"
echo >&2 " -m Specify an alternate man page path (default: ./ssh-audit.1)" echo >&2 " -m Specify an alternate man page path (default: ./ssh-audit.1)"
echo >&2 " -g Specify an alternate globals.py path (default: ./src/ssh_audit/globals.py)" echo >&2 " -g Specify an alternate globals.py path (default: ./src/ssh_audit/globals.py)"
@ -55,9 +55,10 @@ function usage {
PLATFORM="$(uname -s)" PLATFORM="$(uname -s)"
# This script is intended for use on Linux and Cygwin only. # This script is intended for use on Linux and Cygwin only.
case "$PLATFORM" in case "${PLATFORM}" in
Linux | CYGWIN*) ;; Linux | CYGWIN*) ;;
*) echo "Platform not supported: $PLATFORM" *)
echo "Platform not supported: ${PLATFORM}"
exit 1 exit 1
;; ;;
esac esac
@ -65,14 +66,13 @@ esac
MAN_PAGE=./ssh-audit.1 MAN_PAGE=./ssh-audit.1
GLOBALS_PY=./src/ssh_audit/globals.py GLOBALS_PY=./src/ssh_audit/globals.py
while getopts "m: g: h" OPTION while getopts "m: g: h" OPTION; do
do case "${OPTION}" in
case "$OPTION" in
m) m)
MAN_PAGE="$OPTARG" MAN_PAGE="${OPTARG}"
;; ;;
g) g)
GLOBALS_PY="$OPTARG" GLOBALS_PY="${OPTARG}"
;; ;;
h) h)
usage usage
@ -87,11 +87,11 @@ do
done done
# Check that the specified files exist. # Check that the specified files exist.
[ -f "$MAN_PAGE" ] || { echo >&2 "man page file not found: $MAN_PAGE"; exit 1; } [[ -f "$MAN_PAGE" ]] || { echo >&2 "man page file not found: $MAN_PAGE"; exit 1; }
[ -f "$GLOBALS_PY" ] || { echo >&2 "globals.py file not found: $GLOBALS_PY"; exit 1; } [[ -f "${GLOBALS_PY}" ]] || { echo >&2 "globals.py file not found: ${GLOBALS_PY}"; exit 1; }
# Check that the 'ul' (do underlining) binary exists. # Check that the 'ul' (do underlining) binary exists.
if [[ "$PLATFORM" = Linux ]]; then if [[ "${PLATFORM}" == "Linux" ]]; then
command -v ul >/dev/null 2>&1 || { echo >&2 "ul not found."; exit 1; } command -v ul >/dev/null 2>&1 || { echo >&2 "ul not found."; exit 1; }
fi fi
@ -99,10 +99,10 @@ fi
command -v sed >/dev/null 2>&1 || { echo >&2 "sed not found."; exit 1; } command -v sed >/dev/null 2>&1 || { echo >&2 "sed not found."; exit 1; }
# Reset the globals.py file, in case it was modified from a prior run. # Reset the globals.py file, in case it was modified from a prior run.
git checkout $GLOBALS_PY > /dev/null 2>&1 git checkout "${GLOBALS_PY}" > /dev/null 2>&1
# Remove the Windows man page placeholder from 'globals.py'. # Remove the Windows man page placeholder from 'globals.py'.
sed -i '/^WINDOWS_MAN_PAGE/d' "$GLOBALS_PY" sed -i '/^WINDOWS_MAN_PAGE/d' "${GLOBALS_PY}"
echo "Processing man page at ${MAN_PAGE} and placing output into ${GLOBALS_PY}..." echo "Processing man page at ${MAN_PAGE} and placing output into ${GLOBALS_PY}..."
@ -116,15 +116,15 @@ echo "Processing man page at ${MAN_PAGE} and placing output into ${GLOBALS_PY}..
# escape sequence. Not required under Cygwin because man outputs ANSI escape # escape sequence. Not required under Cygwin because man outputs ANSI escape
# codes automatically. # codes automatically.
echo WINDOWS_MAN_PAGE = '"""' >> "$GLOBALS_PY" echo WINDOWS_MAN_PAGE = '"""' >> "${GLOBALS_PY}"
if [[ "$PLATFORM" = CYGWIN* ]]; then if [[ "${PLATFORM}" == CYGWIN* ]]; then
MANWIDTH=80 MAN_KEEP_FORMATTING=1 man "$MAN_PAGE" | sed $'s/\u2010/-/g' >> "$GLOBALS_PY" MANWIDTH=80 MAN_KEEP_FORMATTING=1 man "${MAN_PAGE}" | sed $'s/\u2010/-/g' >> "${GLOBALS_PY}"
else else
MANWIDTH=80 MAN_KEEP_FORMATTING=1 man "$MAN_PAGE" | ul | sed $'s/\u2010/-/g' >> "$GLOBALS_PY" MANWIDTH=80 MAN_KEEP_FORMATTING=1 man "${MAN_PAGE}" | ul | sed $'s/\u2010/-/g' >> "${GLOBALS_PY}"
fi fi
echo '"""' >> "$GLOBALS_PY" echo '"""' >> "${GLOBALS_PY}"
echo "Done." echo "Done."
exit 0 exit 0