Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ssh-audit for openSUSE:Factory checked in at 2021-09-02 23:20:19 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ssh-audit (Old) and /work/SRC/openSUSE:Factory/.ssh-audit.new.1899 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ssh-audit" Thu Sep 2 23:20:19 2021 rev:5 rq:915764 version:2.5.0 Changes: -------- --- /work/SRC/openSUSE:Factory/ssh-audit/ssh-audit.changes 2021-03-03 18:35:07.467388522 +0100 +++ /work/SRC/openSUSE:Factory/.ssh-audit.new.1899/ssh-audit.changes 2021-09-02 23:20:39.348578990 +0200 @@ -1,0 +2,30 @@ +Mon Aug 30 10:11:06 UTC 2021 - Martin Hauke <mar...@gmx.de> + +- Require correct python version + +------------------------------------------------------------------- +Thu Aug 26 20:12:17 UTC 2021 - Martin Hauke <mar...@gmx.de> + +- Update to version 2.5.0 + * Fixed crash when running host key tests. + * Handles server connection failures more gracefully. + * Now prints JSON with indents when -jj is used (useful for + debugging). + * Added MD5 fingerprints to verbose output. + * Added -d/--debug option for getting debugging output. + * Updated JSON output to include MD5 fingerprints. Note that + this results in a breaking change in the 'fingerprints' + dictionary format. + * Updated OpenSSH 8.1 (and earlier) policies to include + rsa-sha2-512 and rsa-sha2-256. + * Added OpenSSH v8.6 & v8.7 policies. + * Added 3 new key exchanges: + + gss-gex-sha1-eipGX3TCiQSrx573bT1o1Q== + + gss-group1-sha1-eipGX3TCiQSrx573bT1o1Q== + + gss-group14-sha1-eipGX3TCiQSrx573bT1o1Q== + * Added 3 new MACs: + + hmac-ripemd160-96 + + AEAD_AES_128_GCM + + AEAD_AES_256_GCM + +------------------------------------------------------------------- Old: ---- ssh-audit-2.4.0.tar.gz ssh-audit-2.4.0.tar.gz.sig New: ---- ssh-audit-2.5.0.tar.gz ssh-audit-2.5.0.tar.gz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ssh-audit.spec ++++++ --- /var/tmp/diff_new_pack.UCh7Zn/_old 2021-09-02 23:20:39.924579708 +0200 +++ /var/tmp/diff_new_pack.UCh7Zn/_new 2021-09-02 23:20:39.928579712 +0200 @@ -17,7 +17,7 @@ Name: ssh-audit -Version: 2.4.0 +Version: 2.5.0 Release: 0 Summary: SSH server auditing License: MIT @@ -30,7 +30,7 @@ BuildRequires: python3-pytest BuildRequires: python3-rpm-macros BuildRequires: python3-setuptools -Requires: python >= 3 +Requires: python3 BuildArch: noarch %description ++++++ ssh-audit-2.4.0.tar.gz -> ssh-audit-2.5.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/.github/workflows/tox.yaml new/ssh-audit-2.5.0/.github/workflows/tox.yaml --- old/ssh-audit-2.4.0/.github/workflows/tox.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/ssh-audit-2.5.0/.github/workflows/tox.yaml 2021-08-26 21:24:34.000000000 +0200 @@ -0,0 +1,24 @@ +name: ssh-audit +on: [push, pull_request] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.6, 3.7, 3.8, 3.9] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install codecov coveralls flake8 mypy pylint tox vulture + - name: Run Tox + run: | + tox diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/.travis.yml new/ssh-audit-2.5.0/.travis.yml --- old/ssh-audit-2.4.0/.travis.yml 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/.travis.yml 2021-08-26 21:24:34.000000000 +0200 @@ -10,6 +10,7 @@ - "3.7" - "3.8" - "3.9" + - "3.10" cache: - pip diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/CONTRIBUTING.md new/ssh-audit-2.5.0/CONTRIBUTING.md --- old/ssh-audit-2.4.0/CONTRIBUTING.md 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/CONTRIBUTING.md 2021-08-26 21:24:34.000000000 +0200 @@ -11,26 +11,8 @@ 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/). -### Running tests on Ubuntu 18.04 and later - 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. -### Running tests on Ubuntu 16.04 - -For Ubuntu 16.04 (which is still supported until April 2021), a newer version of tox is needed. The easiest way is to use virtualenv: -``` -$ sudo apt install python3-virtualenv -$ virtualenv -p /usr/bin/python3 ~/venv_ssh-audit -$ source ~/venv_ssh-audit/bin/activate -$ pip install tox -``` -Then, to run the tox tests: -``` -$ source ~/venv_ssh-audit/bin/activate -$ cd path/to/ssh-audit -$ tox -``` - ## Docker Tests diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/PACKAGING.md new/ssh-audit-2.5.0/PACKAGING.md --- old/ssh-audit-2.4.0/PACKAGING.md 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/PACKAGING.md 2021-08-26 21:24:34.000000000 +0200 @@ -2,8 +2,6 @@ An executable can only be made on a Windows host because the PyInstaller tool (https://www.pyinstaller.org/) does not support cross-compilation. -On a Windows machine, do the following: - 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. 2.) Using pip, install pyinstaller and colorama: @@ -12,14 +10,15 @@ pip install pyinstaller colorama ``` -3.) Create the executable with: +3.) Install Cygwin (https://www.cygwin.com/). + +4.) Create the executable with: ``` - cd src\ssh_audit - rename ssh_audit.py ssh-audit.py - pyinstaller -F --icon ..\..\windows_icon.ico ssh-audit.py + $ ./build_windows_executable.sh ``` + # PyPI To create package and upload to test server: @@ -38,7 +37,7 @@ $ pip3 install --index-url https://test.pypi.org/simple ssh-audit ``` -To upload to production server (hint: use username '__token__' and API token): +To upload to production server (hint: use username '\_\_token\_\_' and API token): ``` $ make -f Makefile.pypi uploadprod @@ -60,7 +59,7 @@ ``` $ sudo apt install make snapcraft - $ sudo snap install review-tools + $ sudo snap install review-tools lxd ``` Initialize LXD (leave all options default): @@ -91,8 +90,8 @@ $ make -f Makefile.docker ``` -Then upload them to Dockerhub with: +Then upload it to Dockerhub with: ``` $ make -f Makefile.docker upload -``` \ No newline at end of file +``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/README.md new/ssh-audit-2.5.0/README.md --- old/ssh-audit-2.4.0/README.md 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/README.md 2021-08-26 21:24:34.000000000 +0200 @@ -1,14 +1,25 @@ # ssh-audit -[](https://travis-ci.org/jtesta/ssh-audit) -<!-- -[](https://ci.appveyor.com/project/arthepsy/ssh-audit) -[](https://codecov.io/gh/arthepsy/ssh-audit) -[](https://sq.evolutiongaming.com/dashboard?id=arthepsy-github%3Assh-audit%3Adevelop) ---> +[](https://github.com/jtesta/ssh-audit/blob/master/LICENSE) +[](https://pypi.org/project/ssh-audit/) +[](https://hub.docker.com/r/positronsecurity/ssh-audit) +[](https://github.com/jtesta/ssh-audit/actions) +[](https://github.com/jtesta/ssh-audit/blob/master/CONTRIBUTING.md) + **ssh-audit** is a tool for ssh server & client configuration auditing. [jtesta/ssh-audit](https://github.com/jtesta/ssh-audit/) (v2.0+) is the updated and maintained version of ssh-audit forked from [arthepsy/ssh-audit](https://github.com/arthepsy/ssh-audit) (v1.x) due to inactivity. +- [Features](#features) +- [Usage](#usage) +- [Screenshots](#screenshots) + - [Server Standard Audit Example](#server-standard-audit-example) + - [Server Policy Audit Example](#server-policy-audit-example) + - [Client Standard Audit Example](#client-standard-audit-example) +- [Hardening Guides](#hardening-guides) +- [Pre-Built Packages](#pre-built-packages) +- [Web Front-End](#web-front-end) +- [ChangeLog](#changelog) + ## Features - SSH1 and SSH2 protocol server support; - analyze SSH client configuration; @@ -37,7 +48,8 @@ -c, --client-audit starts a server on port 2222 to audit client software config (use -p to change port; use -t to change timeout) - -j, --json JSON output + -d, --debug Enable debug output. + -j, --json JSON output (use -jj to enable indents) -l, --level=<level> minimum output level (info|warn|fail) -L, --list-policies list all the official, built-in policies --lookup=<alg1,alg2,...> looks up an algorithm(s) without @@ -115,6 +127,8 @@ ssh-audit -M new_policy.txt targetserver ``` +## Screenshots + ### Server Standard Audit Example Below is a screen shot of the standard server-auditing output when connecting to an unhardened OpenSSH v5.3 service:  @@ -130,10 +144,10 @@ Below is a screen shot of the client-auditing output when an unhardened OpenSSH v7.2 client connects:  -### Hardening Guides +## Hardening Guides 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. To install from PyPI: @@ -157,10 +171,22 @@ ``` (Then run with: `docker run -it -p 2222:2222 positronsecurity/ssh-audit 10.1.1.1`) -### 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/). ## ChangeLog +### v2.5.0 (2021-08-26) + - Fixed crash when running host key tests. + - Handles server connection failures more gracefully. + - Now prints JSON with indents when `-jj` is used (useful for debugging). + - Added MD5 fingerprints to verbose output. + - Added `-d`/`--debug` option for getting debugging output; credit [Adam Russell](https://github.com/thecliguy). + - Updated JSON output to include MD5 fingerprints. Note that this results in a breaking change in the 'fingerprints' dictionary format. + - Updated OpenSSH 8.1 (and earlier) policies to include `rsa-sha2-512` and `rsa-sha2-256`. + - Added OpenSSH v8.6 & v8.7 policies. + - Added 3 new key exchanges: `gss-gex-sha1-eipGX3TCiQSrx573bT1o1Q==`, `gss-group1-sha1-eipGX3TCiQSrx573bT1o1Q==`, and `gss-group14-sha1-eipGX3TCiQSrx573bT1o1Q==`. + - Added 3 new MACs: `hmac-ripemd160-96`, `AEAD_AES_128_GCM`, and `AEAD_AES_256_GCM`. + ### v2.4.0 (2021-02-23) - Added multi-threaded scanning support. - Added built-in Windows manual page (see `-m`/`--manual`); credit [Adam Russell](https://github.com/thecliguy). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/build_windows_executable.sh new/ssh-audit-2.5.0/build_windows_executable.sh --- old/ssh-audit-2.4.0/build_windows_executable.sh 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/build_windows_executable.sh 2021-08-26 21:24:34.000000000 +0200 @@ -58,6 +58,29 @@ exit 1 fi +# Prompt for the version to release. +echo -n "Enter the version to release, using format 'vX.X.X': " +read -r version + +# Ensure that entered version fits required format. +if [[ ! $version =~ ^v[0-9]\.[0-9]\.[0-9]$ ]]; then + echo "Error: version string does not match format vX.X.X!" + exit 1 +fi + +# Verify that version is correct. +echo -n "Version will be set to '${version}'. Is this correct? (y/n): " +read -r yn +echo + +if [[ $yn != "y" ]]; then + echo "Build cancelled." + exit 1 +fi + +# Reset any local changes made to globals.py from a previous run. +git checkout src/ssh_audit/globals.py 2> /dev/null + # Update the man page. ./update_windows_man_page.sh if [[ $? != 0 ]]; then @@ -68,12 +91,14 @@ # Do all operations from this point from the main source directory. pushd src/ssh_audit > /dev/null -# Delete the executable if it exists from a prior run. -if [[ -f dist/ssh-audit.exe ]]; then - rm dist/ssh-audit.exe -fi +# Delete the existing VERSION variable and add the value that the user entered, above. +sed -i '/^VERSION/d' globals.py +echo "VERSION = '$version'" >> globals.py -# Create a link from ssh_audit.py to ssh-audit.py. +# Delete cached files if they exist from a prior run. +rm -rf dist/ build/ ssh-audit.spec + +# Create a hard link from ssh_audit.py to ssh-audit.py. if [[ ! -f ssh-audit.py ]]; then ln ssh_audit.py ssh-audit.py fi @@ -83,10 +108,23 @@ if [[ -f dist/ssh-audit.exe ]]; then echo -e "\nExecutable created in $(pwd)/dist/ssh-audit.exe\n" +else + echo -e "\nFAILED to create $(pwd)/dist/ssh-audit.exe!\n" + exit 1 +fi + +# 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 +if [[ $? == 0 ]]; then + echo -e "\nError: executable's version number includes '-dev'." + exit 1 fi -# Remove the link we created, above. -rm ssh-audit.py +# Remove the cache files created during the build process, along with the link we created, above. +rm -rf build/ ssh-audit.spec ssh-audit.py + +# Reset the changes we made to globals.py. +git checkout globals.py 2> /dev/null popd > /dev/null exit 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/docker_test.sh new/ssh-audit-2.5.0/docker_test.sh --- old/ssh-audit-2.4.0/docker_test.sh 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/docker_test.sh 2021-08-26 21:24:34.000000000 +0200 @@ -700,10 +700,10 @@ run_custom_policy_test 'config2' 'test14' $PROGRAM_RETVAL_FAILURE # Passing test for built-in OpenSSH 8.0p1 server policy. -run_builtin_policy_test "Hardened OpenSSH Server v8.0 (version 1)" "8.0p1" "test1" "-o HostKeyAlgorithms=ssh-ed25519 -o KexAlgorithms=curve25519-sha256,curve25519-sha...@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1...@openssh.com,aes256-...@openssh.com,aes128-...@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr -o MACs=hmac-sha2-256-...@openssh.com,hmac-sha2-512-...@openssh.com,umac-128-...@openssh.com" $PROGRAM_RETVAL_GOOD +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-sha...@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1...@openssh.com,aes256-...@openssh.com,aes128-...@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr -o MACs=hmac-sha2-256-...@openssh.com,hmac-sha2-512-...@openssh.com,umac-128-...@openssh.com" $PROGRAM_RETVAL_GOOD # 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=ssh-ed25519 -o KexAlgorithms=curve25519-sha256,curve25519-sha...@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1...@openssh.com,aes256-...@openssh.com,aes128-...@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr" $PROGRAM_RETVAL_FAILURE +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-sha...@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1...@openssh.com,aes256-...@openssh.com,aes128-...@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr" $PROGRAM_RETVAL_FAILURE if [[ $num_failures == 0 ]]; then diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/src/ssh_audit/algorithms.py new/ssh-audit-2.5.0/src/ssh_audit/algorithms.py --- old/ssh-audit-2.4.0/src/ssh_audit/algorithms.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/src/ssh_audit/algorithms.py 2021-08-26 21:24:34.000000000 +0200 @@ -1,7 +1,7 @@ """ The MIT License (MIT) - Copyright (C) 2017-2020 Joe Testa (jte...@positronsecurity.com) + Copyright (C) 2017-2021 Joe Testa (jte...@positronsecurity.com) Copyright (C) 2017 Andris Raugulis (m...@arthepsy.eu) Permission is hereby granted, free of charge, to any person obtaining a copy @@ -55,7 +55,7 @@ if self.ssh1kex is None: return None item = Algorithms.Item(1, SSH1_KexDB.ALGORITHMS) - item.add('key', [u'ssh-rsa1']) + item.add('key', ['ssh-rsa1']) item.add('enc', self.ssh1kex.supported_ciphers) item.add('aut', self.ssh1kex.supported_authentications) return item diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/src/ssh_audit/auditconf.py new/ssh-audit-2.5.0/src/ssh_audit/auditconf.py --- old/ssh-audit-2.4.0/src/ssh_audit/auditconf.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/src/ssh_audit/auditconf.py 2021-08-26 21:24:34.000000000 +0200 @@ -1,7 +1,7 @@ """ The MIT License (MIT) - Copyright (C) 2017-2020 Joe Testa (jte...@positronsecurity.com) + Copyright (C) 2017-2021 Joe Testa (jte...@positronsecurity.com) Copyright (C) 2017 Andris Raugulis (m...@arthepsy.eu) Permission is hereby granted, free of charge, to any person obtaining a copy @@ -41,6 +41,7 @@ self.client_audit = False self.colors = True self.json = False + self.json_print_indent = False self.verbose = False self.level = 'info' self.ip_version_preference: List[int] = [] # Holds only 5 possible values: [] (no preference), [4] (use IPv4 only), [6] (use IPv6 only), [46] (use both IPv4 and IPv6, but prioritize v4), and [64] (use both IPv4 and IPv6, but prioritize v6). @@ -57,10 +58,11 @@ self.list_policies = False self.lookup = '' self.manual = False + self.debug = False def __setattr__(self, name: str, value: Union[str, int, float, bool, Sequence[int]]) -> None: valid = False - if name in ['batch', 'client_audit', 'colors', 'json', 'list_policies', 'manual', 'make_policy', 'ssh1', 'ssh2', 'timeout_set', 'verbose']: + if name in ['batch', 'client_audit', 'colors', 'json', 'json_print_indent', 'list_policies', 'manual', 'make_policy', 'ssh1', 'ssh2', 'timeout_set', 'verbose', 'debug']: valid, value = True, bool(value) elif name in ['ipv4', 'ipv6']: valid, value = True, bool(value) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/src/ssh_audit/fingerprint.py new/ssh-audit-2.5.0/src/ssh_audit/fingerprint.py --- old/ssh-audit-2.4.0/src/ssh_audit/fingerprint.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/src/ssh_audit/fingerprint.py 2021-08-26 21:24:34.000000000 +0200 @@ -1,7 +1,7 @@ """ The MIT License (MIT) - Copyright (C) 2017-2020 Joe Testa (jte...@positronsecurity.com) + Copyright (C) 2017-2021 Joe Testa (jte...@positronsecurity.com) Copyright (C) 2017 Andris Raugulis (m...@arthepsy.eu) Permission is hereby granted, free of charge, to any person obtaining a copy @@ -33,11 +33,11 @@ @property def md5(self) -> str: h = hashlib.md5(self.__fpd).hexdigest() - r = u':'.join(h[i:i + 2] for i in range(0, len(h), 2)) - return u'MD5:{}'.format(r) + r = ':'.join(h[i:i + 2] for i in range(0, len(h), 2)) + return 'MD5:{}'.format(r) @property def sha256(self) -> str: h = base64.b64encode(hashlib.sha256(self.__fpd).digest()) r = h.decode('ascii').rstrip('=') - return u'SHA256:{}'.format(r) + return 'SHA256:{}'.format(r) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/src/ssh_audit/gextest.py new/ssh-audit-2.5.0/src/ssh_audit/gextest.py --- old/ssh-audit-2.4.0/src/ssh_audit/gextest.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/src/ssh_audit/gextest.py 2021-08-26 21:24:34.000000000 +0200 @@ -26,10 +26,13 @@ from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401 from typing import Callable, Optional, Union, Any # noqa: F401 +import traceback + from ssh_audit.kexdh import KexGroupExchange_SHA1, KexGroupExchange_SHA256 from ssh_audit.ssh2_kexdb import SSH2_KexDB from ssh_audit.ssh2_kex import SSH2_Kex from ssh_audit.ssh_socket import SSH_Socket +from ssh_audit.outputbuffer import OutputBuffer # Performs DH group exchanges to find what moduli are supported, and checks @@ -38,16 +41,18 @@ # Creates a new connection to the server. Returns True on success, or False. @staticmethod - def reconnect(s: 'SSH_Socket', kex: 'SSH2_Kex', gex_alg: str) -> bool: + def reconnect(out: 'OutputBuffer', s: 'SSH_Socket', kex: 'SSH2_Kex', gex_alg: str) -> bool: if s.is_connected(): return True err = s.connect() if err is not None: + out.v(err, write_now=True) return False _, _, err = s.get_banner() if err is not None: + out.v(err, write_now=True) s.close() return False @@ -55,15 +60,19 @@ # server's own values. s.send_kexinit(key_exchanges=[gex_alg], hostkeys=kex.key_algorithms, ciphers=kex.server.encryption, macs=kex.server.mac, compressions=kex.server.compression, languages=kex.server.languages) - # Parse the server's KEX. - _, payload = s.read_packet(2) - SSH2_Kex.parse(payload) + try: + # Parse the server's KEX. + _, payload = s.read_packet(2) + SSH2_Kex.parse(payload) + except Exception: + out.v("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc()), write_now=True) + return False return True # Runs the DH moduli test against the specified target. @staticmethod - def run(s: 'SSH_Socket', kex: 'SSH2_Kex') -> None: + def run(out: 'OutputBuffer', s: 'SSH_Socket', kex: 'SSH2_Kex') -> None: GEX_ALGS = { 'diffie-hellman-group-exchange-sha1': KexGroupExchange_SHA1, 'diffie-hellman-group-exchange-sha256': KexGroupExchange_SHA256, @@ -77,13 +86,14 @@ # Check if the server supports any of the group-exchange # algorithms. If so, test each one. - for gex_alg in GEX_ALGS: + for gex_alg, kex_group_class in GEX_ALGS.items(): if gex_alg in kex.kex_algorithms: + out.d('Preparing to perform DH group exchange using ' + gex_alg + '...', write_now=True) - if GEXTest.reconnect(s, kex, gex_alg) is False: + if GEXTest.reconnect(out, s, kex, gex_alg) is False: break - kex_group = GEX_ALGS[gex_alg]() + kex_group = kex_group_class() smallest_modulus = -1 # First try a range of weak sizes. @@ -110,7 +120,9 @@ if bits >= smallest_modulus > 0: break - if GEXTest.reconnect(s, kex, gex_alg) is False: + out.d('Preparing to perform DH group exchange using ' + gex_alg + ' with modulus size ' + str(bits) + '...', write_now=True) + + if GEXTest.reconnect(out, s, kex, gex_alg) is False: reconnect_failed = True break diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/src/ssh_audit/globals.py new/ssh-audit-2.5.0/src/ssh_audit/globals.py --- old/ssh-audit-2.4.0/src/ssh_audit/globals.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/src/ssh_audit/globals.py 2021-08-26 21:24:34.000000000 +0200 @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -VERSION = 'v2.4.0' +VERSION = 'v2.5.0' SSH_HEADER = 'SSH-{0}-OpenSSH_8.2' # SSH software to impersonate GITHUB_ISSUES_URL = 'https://github.com/jtesta/ssh-audit/issues' # The URL to the Github issues tracker. WINDOWS_MAN_PAGE = '' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/src/ssh_audit/hostkeytest.py new/ssh-audit-2.5.0/src/ssh_audit/hostkeytest.py --- old/ssh-audit-2.4.0/src/ssh_audit/hostkeytest.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/src/ssh_audit/hostkeytest.py 2021-08-26 21:24:34.000000000 +0200 @@ -26,10 +26,13 @@ from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401 from typing import Callable, Optional, Union, Any # noqa: F401 +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.ssh2_kex import SSH2_Kex from ssh_audit.ssh2_kexdb import SSH2_KexDB from ssh_audit.ssh_socket import SSH_Socket +from ssh_audit.outputbuffer import OutputBuffer # Obtains host keys, checks their size, and derives their fingerprints. @@ -52,7 +55,7 @@ } @staticmethod - def run(s: 'SSH_Socket', server_kex: 'SSH2_Kex') -> None: + def run(out: 'OutputBuffer', s: 'SSH_Socket', server_kex: 'SSH2_Kex') -> None: KEX_TO_DHGROUP = { 'diffie-hellman-group1-sha1': KexGroup1, 'diffie-hellman-group14-sha1': KexGroup14_SHA1, @@ -80,10 +83,10 @@ break if kex_str is not None and kex_group is not None: - HostKeyTest.perform_test(s, server_kex, kex_str, kex_group, HostKeyTest.HOST_KEY_TYPES) + HostKeyTest.perform_test(out, s, server_kex, kex_str, kex_group, HostKeyTest.HOST_KEY_TYPES) @staticmethod - def perform_test(s: 'SSH_Socket', server_kex: 'SSH2_Kex', kex_str: str, kex_group: 'KexDH', host_key_types: Dict[str, Dict[str, bool]]) -> None: + def perform_test(out: 'OutputBuffer', s: 'SSH_Socket', server_kex: 'SSH2_Kex', kex_str: str, kex_group: 'KexDH', host_key_types: Dict[str, Dict[str, bool]]) -> None: hostkey_modulus_size = 0 ca_modulus_size = 0 @@ -101,6 +104,8 @@ # If this host key type is supported by the server, we test it. if host_key_type in server_kex.key_algorithms: + out.d('Preparing to obtain ' + host_key_type + ' host key...', write_now=True) + cert = host_key_types[host_key_type]['cert'] variable_key_len = host_key_types[host_key_type]['variable_key_len'] @@ -108,20 +113,25 @@ if not s.is_connected(): err = s.connect() if err is not None: + out.v(err, write_now=True) return _, _, err = s.get_banner() if err is not None: + out.v(err, write_now=True) s.close() return # Send our KEX using the specified group-exchange and most of the server's own values. s.send_kexinit(key_exchanges=[kex_str], hostkeys=[host_key_type], ciphers=server_kex.server.encryption, macs=server_kex.server.mac, compressions=server_kex.server.compression, languages=server_kex.server.languages) - # Parse the server's KEX. - _, payload = s.read_packet() - SSH2_Kex.parse(payload) - + try: + # Parse the server's KEX. + _, payload = s.read_packet() + SSH2_Kex.parse(payload) + except Exception: + out.v("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc()), write_now=True) + return # 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. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/src/ssh_audit/kexdh.py new/ssh-audit-2.5.0/src/ssh_audit/kexdh.py --- old/ssh-audit-2.4.0/src/ssh_audit/kexdh.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/src/ssh_audit/kexdh.py 2021-08-26 21:24:34.000000000 +0200 @@ -1,7 +1,7 @@ """ The MIT License (MIT) - Copyright (C) 2017-2020 Joe Testa (jte...@positronsecurity.com) + Copyright (C) 2017-2021 Joe Testa (jte...@positronsecurity.com) Copyright (C) 2017 Andris Raugulis (m...@arthepsy.eu) Permission is hereby granted, free of charge, to any person obtaining a copy @@ -37,8 +37,8 @@ class KexDH: # pragma: nocover def __init__(self, kex_name: str, hash_alg: str, g: int, p: int) -> None: - self.__kex_name = kex_name - self.__hash_alg = hash_alg + self.__kex_name = kex_name # pylint: disable=unused-private-member + self.__hash_alg = hash_alg # pylint: disable=unused-private-member self.__g = 0 self.__p = 0 self.__q = 0 @@ -46,10 +46,10 @@ self.__e = 0 self.set_params(g, p) - self.__ed25519_pubkey: Optional[bytes] = None + self.__ed25519_pubkey: Optional[bytes] = None # pylint: disable=unused-private-member self.__hostkey_type: Optional[bytes] = None - self.__hostkey_e = 0 - self.__hostkey_n = 0 + self.__hostkey_e = 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.__ca_n_len = 0 # Length of the CA key modulus (if hostkey is a cert). @@ -121,11 +121,11 @@ # The public key exponent. hostkey_e, hostkey_e_len, ptr = KexDH.__get_bytes(hostkey, ptr) - self.__hostkey_e = int(binascii.hexlify(hostkey_e), 16) + self.__hostkey_e = int(binascii.hexlify(hostkey_e), 16) # pylint: disable=unused-private-member # 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) - self.__hostkey_n = int(binascii.hexlify(hostkey_n), 16) + 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 # key. @@ -327,7 +327,7 @@ s.send_packet() packet_type, payload = s.read_packet(2) - if (packet_type != Protocol.MSG_KEXDH_GEX_GROUP) and (packet_type != Protocol.MSG_DEBUG): # pylint: disable=consider-using-in + if packet_type not in [Protocol.MSG_KEXDH_GEX_GROUP, Protocol.MSG_DEBUG]: # TODO: replace with a better exception type. raise Exception('Expected MSG_KEXDH_GEX_REPLY (%d), but got %d instead.' % (Protocol.MSG_KEXDH_GEX_REPLY, packet_type)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/src/ssh_audit/outputbuffer.py new/ssh-audit-2.5.0/src/ssh_audit/outputbuffer.py --- old/ssh-audit-2.4.0/src/ssh_audit/outputbuffer.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/src/ssh_audit/outputbuffer.py 2021-08-26 21:24:34.000000000 +0200 @@ -47,6 +47,7 @@ self.section: List[str] = [] self.batch = False self.verbose = False + self.debug = False self.use_colors = True self.json = False self.__level = 0 @@ -167,7 +168,16 @@ def v(self, s: str, write_now: bool = False) -> 'OutputBuffer': '''Prints a message if verbose output is enabled.''' - if self.verbose: + if self.verbose or self.debug: + self.info(s) + if write_now: + self.write() + + return self + + def d(self, s: str, write_now: bool = False) -> 'OutputBuffer': + '''Prints a message if verbose output is enabled.''' + if self.debug: self.info(s) if write_now: self.write() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/src/ssh_audit/policy.py new/ssh-audit-2.5.0/src/ssh_audit/policy.py --- old/ssh-audit-2.4.0/src/ssh_audit/policy.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/src/ssh_audit/policy.py 2021-08-26 21:24:34.000000000 +0200 @@ -1,7 +1,7 @@ """ The MIT License (MIT) - Copyright (C) 2020 Joe Testa (jte...@positronsecurity.com) + Copyright (C) 2020-2021 Joe Testa (jte...@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 @@ -49,15 +49,15 @@ # Generic OpenSSH Server policies - 'Hardened OpenSSH Server v7.7 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-...@openssh.com', 'rsa-sha2-256-cert-...@openssh.com', 'rsa-sha2-512-cert-...@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha...@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1...@openssh.com', 'aes256-...@openssh.com', 'aes128-...@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-...@openssh.com', 'hmac-sha2-512-...@openssh.com', 'umac-128-...@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 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-...@openssh.com', 'rsa-sha2-256-cert-...@openssh.com', 'rsa-sha2-512-cert-...@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha...@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1...@openssh.com', 'aes256-...@openssh.com', 'aes128-...@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-...@openssh.com', 'hmac-sha2-512-...@openssh.com', 'umac-128-...@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 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-...@openssh.com', 'rsa-sha2-256-cert-...@openssh.com', 'rsa-sha2-512-cert-...@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha...@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1...@openssh.com', 'aes256-...@openssh.com', 'aes128-...@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-...@openssh.com', 'hmac-sha2-512-...@openssh.com', 'umac-128-...@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 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-...@openssh.com', 'rsa-sha2-256-cert-...@openssh.com', 'rsa-sha2-512-cert-...@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha...@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1...@openssh.com', 'aes256-...@openssh.com', 'aes128-...@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-...@openssh.com', 'hmac-sha2-512-...@openssh.com', 'umac-128-...@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 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-...@openssh.com', 'rsa-sha2-256-cert-...@openssh.com', 'rsa-sha2-512-cert-...@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha...@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1...@openssh.com', 'aes256-...@openssh.com', 'aes128-...@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-...@openssh.com', 'hmac-sha2-512-...@openssh.com', 'umac-128-...@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 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-...@openssh.com', 'rsa-sha2-256-cert-...@openssh.com', 'rsa-sha2-512-cert-...@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha...@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1...@openssh.com', 'aes256-...@openssh.com', 'aes128-...@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-...@openssh.com', 'hmac-sha2-512-...@openssh.com', 'umac-128-...@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 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-...@openssh.com', 'rsa-sha2-256-cert-...@openssh.com', 'rsa-sha2-512-cert-...@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha...@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1...@openssh.com', 'aes256-...@openssh.com', 'aes128-...@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-...@openssh.com', 'hmac-sha2-512-...@openssh.com', 'umac-128-...@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 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-...@openssh.com', 'rsa-sha2-256-cert-...@openssh.com', 'rsa-sha2-512-cert-...@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha...@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1...@openssh.com', 'aes256-...@openssh.com', 'aes128-...@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-...@openssh.com', 'hmac-sha2-512-...@openssh.com', 'umac-128-...@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 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25...@openssh.com', 'ssh-ed25519-cert-...@openssh.com', 'sk-ssh-ed25519-cert-...@openssh.com', 'rsa-sha2-256-cert-...@openssh.com', 'rsa-sha2-512-cert-...@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha...@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1...@openssh.com', 'aes256-...@openssh.com', 'aes128-...@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-...@openssh.com', 'hmac-sha2-512-...@openssh.com', 'umac-128-...@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 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25...@openssh.com', 'ssh-ed25519-cert-...@openssh.com', 'sk-ssh-ed25519-cert-...@openssh.com', 'rsa-sha2-256-cert-...@openssh.com', 'rsa-sha2-512-cert-...@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha...@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1...@openssh.com', 'aes256-...@openssh.com', 'aes128-...@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-...@openssh.com', 'hmac-sha2-512-...@openssh.com', 'umac-128-...@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, '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-ed25...@openssh.com', 'ssh-ed25519-cert-...@openssh.com', 'sk-ssh-ed25519-cert-...@openssh.com', 'rsa-sha2-256-cert-...@openssh.com', 'rsa-sha2-512-cert-...@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha...@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1...@openssh.com', 'aes256-...@openssh.com', 'aes128-...@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-...@openssh.com', 'hmac-sha2-512-...@openssh.com', 'umac-128-...@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-...@openssh.com': 4096, 'rsa-sha2-512-cert-...@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exch ange-sha256': 2048}, 'server_policy': True}, @@ -67,6 +67,10 @@ '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-ed25...@openssh.com', 'ssh-ed25519-cert-...@openssh.com', 'sk-ssh-ed25519-cert-...@openssh.com', 'rsa-sha2-256-cert-...@openssh.com', 'rsa-sha2-512-cert-...@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha...@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1...@openssh.com', 'aes256-...@openssh.com', 'aes128-...@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-...@openssh.com', 'hmac-sha2-512-...@openssh.com', 'umac-128-...@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-...@openssh.com': 4096, 'rsa-sha2-512-cert-...@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exch ange-sha256': 2048}, '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-ed25...@openssh.com', 'ssh-ed25519-cert-...@openssh.com', 'sk-ssh-ed25519-cert-...@openssh.com', 'rsa-sha2-256-cert-...@openssh.com', 'rsa-sha2-512-cert-...@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha...@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1...@openssh.com', 'aes256-...@openssh.com', 'aes128-...@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-...@openssh.com', 'hmac-sha2-512-...@openssh.com', 'umac-128-...@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-...@openssh.com': 4096, 'rsa-sha2-512-cert-...@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exch ange-sha256': 2048}, '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-ed25...@openssh.com', 'ssh-ed25519-cert-...@openssh.com', 'sk-ssh-ed25519-cert-...@openssh.com', 'rsa-sha2-256-cert-...@openssh.com', 'rsa-sha2-512-cert-...@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha...@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1...@openssh.com', 'aes256-...@openssh.com', 'aes128-...@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-...@openssh.com', 'hmac-sha2-512-...@openssh.com', 'umac-128-...@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-...@openssh.com': 4096, 'rsa-sha2-512-cert-...@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exch ange-sha256': 2048}, 'server_policy': True}, + # Ubuntu Client policies @@ -113,7 +117,7 @@ if policy_file is not None: try: - with open(policy_file, "r") as f: + with open(policy_file, "r", encoding='utf-8') as f: policy_data = f.read() except FileNotFoundError: print("Error: policy file not found: %s" % policy_file) @@ -421,8 +425,8 @@ server_policy_names = [] client_policy_names = [] - for policy_name in Policy.BUILTIN_POLICIES: - if Policy.BUILTIN_POLICIES[policy_name]['server_policy']: + for policy_name, policy in Policy.BUILTIN_POLICIES.items(): + if policy['server_policy']: server_policy_names.append(policy_name) else: client_policy_names.append(policy_name) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/src/ssh_audit/ssh1_publickeymessage.py new/ssh-audit-2.5.0/src/ssh_audit/ssh1_publickeymessage.py --- old/ssh-audit-2.4.0/src/ssh_audit/ssh1_publickeymessage.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/src/ssh_audit/ssh1_publickeymessage.py 2021-08-26 21:24:34.000000000 +0200 @@ -90,7 +90,7 @@ @property def supported_ciphers(self) -> List[str]: ciphers = [] - for i in range(len(SSH1.CIPHERS)): + for i in range(len(SSH1.CIPHERS)): # pylint: disable=consider-using-enumerate if self.__supported_ciphers_mask & (1 << i) != 0: ciphers.append(Utils.to_text(SSH1.CIPHERS[i])) return ciphers diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/src/ssh_audit/ssh2_kexdb.py new/ssh-audit-2.5.0/src/ssh_audit/ssh2_kexdb.py --- old/ssh-audit-2.4.0/src/ssh_audit/ssh2_kexdb.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/src/ssh_audit/ssh2_kexdb.py 2021-08-26 21:24:34.000000000 +0200 @@ -1,7 +1,7 @@ """ The MIT License (MIT) - Copyright (C) 2017-2020 Joe Testa (jte...@positronsecurity.com) + Copyright (C) 2017-2021 Joe Testa (jte...@positronsecurity.com) Copyright (C) 2017 Andris Raugulis (m...@arthepsy.eu) Permission is hereby granted, free of charge, to any person obtaining a copy @@ -66,10 +66,13 @@ '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]], 'gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g==': [[], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH67_UNSAFE, FAIL_OPENSSH70_LOGJAM], [WARN_HASH_WEAK]], + 'gss-gex-sha1-eipGX3TCiQSrx573bT1o1Q==': [[], [], [WARN_HASH_WEAK]], 'gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==': [[], [], [WARN_HASH_WEAK]], 'gss-gex-sha1-': [[], [], [WARN_HASH_WEAK]], + 'gss-group1-sha1-eipGX3TCiQSrx573bT1o1Q==': [[], [FAIL_1024BIT_MODULUS], [WARN_HASH_WEAK]], 'gss-group1-sha1-': [[], [FAIL_1024BIT_MODULUS], [WARN_HASH_WEAK]], 'gss-group14-sha1-': [[], [], [WARN_HASH_WEAK]], + 'gss-group14-sha1-eipGX3TCiQSrx573bT1o1Q==': [[], [], [WARN_HASH_WEAK]], 'gss-group14-sha1-toWM5Slw5Ew8Mqkay+al2g==': [[], [], [WARN_HASH_WEAK]], 'gss-group14-sha256-': [[]], 'gss-group14-sha256-toWM5Slw5Ew8Mqkay+al2g==': [[]], @@ -250,6 +253,7 @@ 'hmac-md5-96': [['2.5.0', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC, WARN_HASH_WEAK]], 'hmac-ripemd': [[], [FAIL_DEPRECATED_MAC], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC]], 'hmac-ripemd160': [['2.5.0', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC]], + 'hmac-ripemd160-96': [[], [FAIL_DEPRECATED_MAC], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]], 'hmac-ripemd...@openssh.com': [['2.1.0', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC]], 'umac...@openssh.com': [['4.7'], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]], 'umac-...@openssh.com': [['6.2'], [], [WARN_ENCRYPT_AND_MAC]], @@ -270,5 +274,7 @@ 'aes256-gcm': [[]], 'chacha20-poly1...@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. 'crypticore-...@ssh.com': [[], [FAIL_UNPROVEN]], + 'AEAD_AES_128_GCM': [[]], + 'AEAD_AES_256_GCM': [[]], } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/src/ssh_audit/ssh_audit.py new/ssh-audit-2.5.0/src/ssh_audit/ssh_audit.py --- old/ssh-audit-2.4.0/src/ssh_audit/ssh_audit.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/src/ssh_audit/ssh_audit.py 2021-08-26 21:24:34.000000000 +0200 @@ -84,7 +84,8 @@ uout.info(' -6, --ipv6 enable IPv6 (order of precedence)') 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(' -j, --json JSON output') + uout.info(' -d, --debug debug output') + 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, --list-policies list all the official, built-in policies') uout.info(' --lookup=<alg1,alg2,...> looks up an algorithm(s) without\n connecting to a server') @@ -263,7 +264,7 @@ out.sep() -def output_fingerprints(out: OutputBuffer, algs: Algorithms, is_json_output: bool, sha256: bool = True) -> None: +def output_fingerprints(out: OutputBuffer, algs: Algorithms, is_json_output: bool) -> None: with out: fps = [] if algs.ssh1kex is not None: @@ -290,10 +291,12 @@ fps = sorted(fps) for fpp in fps: name, fp = fpp - fpo = fp.sha256 if sha256 else fp.md5 - # p = '' if out.batch else ' ' * (padlen - len(name)) - # out.good('(fin) {0}{1} -- {2} {3}'.format(name, p, bits, fpo)) - out.good('(fin) {}: {}'.format(name, fpo)) + out.good('(fin) {}: {}'.format(name, fp.sha256)) + + # Output the MD5 hash too if verbose mode is enabled. + if out.verbose: + out.info('(fin) {}: {} -- [info] do not rely on MD5 fingerprints for server identification; it is insecure for this use case'.format(name, fp.md5)) + if not out.is_section_empty() and not is_json_output: out.head('# fingerprints') out.flush_section() @@ -467,14 +470,14 @@ 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' program_retval = output_algorithms(out, title, adb, atype, kex.server.mac, unknown_algorithms, aconf.json, program_retval, maxlen) - output_fingerprints(out, algs, aconf.json, True) + output_fingerprints(out, algs, aconf.json) perfect_config = output_recommendations(out, algs, software, aconf.json, maxlen) output_info(out, software, client_audit, not perfect_config, aconf.json) if aconf.json: out.reset() # Build & write the JSON struct. - out.info(json.dumps(build_struct(aconf.host, banner, kex=kex, client_host=client_host), sort_keys=True)) + 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)) 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 (jte...@positronsecurity.com), or create a Github issue at <https://github.com/jtesta/ssh-audit/issues>.\n" % ','.join(unknown_algorithms)) @@ -489,7 +492,7 @@ passed, error_struct, error_str = aconf.policy.evaluate(banner, kex) if aconf.json: json_struct = {'host': aconf.host, 'policy': aconf.policy.get_name_and_version(), 'passed': passed, 'errors': error_struct} - out.info(json.dumps(json_struct, sort_keys=True)) + out.info(json.dumps(json_struct, indent=4 if aconf.json_print_indent else None, sort_keys=True)) else: spacing = '' if aconf.client_audit: @@ -560,7 +563,7 @@ # Open with mode 'x' (creates the file, or fails if it already exist). succeeded = True try: - with open(aconf.policy_file, 'x') as f: + with open(aconf.policy_file, 'x', encoding='utf-8') as f: f.write(policy_data) except FileExistsError: succeeded = False @@ -575,8 +578,8 @@ # pylint: disable=too-many-branches aconf = AuditConf() try: - sopts = 'h1246M:p:P:jbcnvl:t:T:Lm' - 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'] + sopts = 'h1246M:p:P:jbcnvl:t:T:Lmd' + 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'] opts, args = getopt.gnu_getopt(args, sopts, lopts) except getopt.GetoptError as err: usage_cb(str(err)) @@ -606,7 +609,10 @@ aconf.colors = False out.use_colors = False elif o in ('-j', '--json'): - aconf.json = True + if aconf.json: # If specified twice, enable indent printing. + aconf.json_print_indent = True + else: + aconf.json = True elif o in ('-v', '--verbose'): aconf.verbose = True out.verbose = True @@ -632,6 +638,9 @@ aconf.lookup = a elif o in ('-m', '--manual'): aconf.manual = True + elif o in ('-d', '--debug'): + aconf.debug = True + out.debug = True 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() @@ -672,7 +681,7 @@ # If a file containing a list of targets was given, read it. if aconf.target_file is not None: - with open(aconf.target_file, 'r') as f: + with open(aconf.target_file, 'r', encoding='utf-8') as f: aconf.target_list = f.readlines() # Strip out whitespace from each line in target file, and skip empty lines. @@ -783,11 +792,18 @@ # Skip over certificate host types (or we would return invalid fingerprints). if '-cert-' in host_key_type: continue - entry = { - 'type': host_key_type, - 'fp': fp.sha256, - } - res['fingerprints'].append(entry) + + # Add the SHA256 and MD5 fingerprints. + res['fingerprints'].append({ + 'hostkey': host_key_type, + 'hash_alg': 'SHA256', + 'hash': fp.sha256[7:] + }) + res['fingerprints'].append({ + 'hostkey': host_key_type, + 'hash_alg': 'MD5', + 'hash': fp.md5[4:] + }) else: pkm_supported_ciphers = None pkm_supported_authentications = None @@ -813,15 +829,18 @@ program_retval = exitcodes.GOOD out.batch = aconf.batch out.verbose = aconf.verbose + out.debug = aconf.debug out.level = aconf.level out.use_colors = aconf.colors - s = SSH_Socket(aconf.host, aconf.port, aconf.ip_version_preference, aconf.timeout, aconf.timeout_set) + s = SSH_Socket(out, aconf.host, aconf.port, aconf.ip_version_preference, aconf.timeout, aconf.timeout_set) + if aconf.client_audit: out.v("Listening for client connection on port %d..." % aconf.port, write_now=True) s.listen_and_accept() else: - out.v("Connecting to %s:%d..." % ('[%s]' % aconf.host if Utils.is_ipv6_address(aconf.host) else aconf.host, aconf.port), write_now=True) + out.v("Starting audit of %s:%d..." % ('[%s]' % aconf.host if Utils.is_ipv6_address(aconf.host) else aconf.host, aconf.port), write_now=True) err = s.connect() + if err is not None: out.fail(err) @@ -850,10 +869,10 @@ if len(payload) > 0: payload_txt = payload.decode('utf-8') else: - payload_txt = u'empty' + payload_txt = 'empty' except UnicodeDecodeError: - payload_txt = u'"{}"'.format(repr(payload).lstrip('b')[1:-1]) - if payload_txt == u'Protocol major versions differ.': + payload_txt = '"{}"'.format(repr(payload).lstrip('b')[1:-1]) + if payload_txt == 'Protocol major versions differ.': if sshv == 2 and aconf.ssh1: ret = audit(out, aconf, 1) out.write() @@ -876,10 +895,15 @@ if sshv == 1: program_retval = output(out, aconf, banner, header, pkm=SSH1_PublicKeyMessage.parse(payload)) elif sshv == 2: - kex = SSH2_Kex.parse(payload) + try: + kex = SSH2_Kex.parse(payload) + except Exception: + out.fail("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc())) + return exitcodes.CONNECTION_ERROR + if aconf.client_audit is False: - HostKeyTest.run(s, kex) - GEXTest.run(s, kex) + HostKeyTest.run(out, s, kex) + GEXTest.run(out, s, kex) # This is a standard audit scan. if (aconf.policy is None) and (aconf.make_policy is False): @@ -948,8 +972,8 @@ similar_algorithms = [ alg_unknown + " --> (" + alg_type + ") " + alg_name for alg_unknown in algorithms_not_found - for alg_type in adb - for alg_name in adb[alg_type] + for alg_type, alg_names in adb.items() + for alg_name in alg_names # Perform a case-insensitive comparison using 'casefold' # and match substrings using the 'in' operator. if alg_unknown.casefold() in alg_name.casefold() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/src/ssh_audit/ssh_socket.py new/ssh-audit-2.5.0/src/ssh_audit/ssh_socket.py --- old/ssh-audit-2.4.0/src/ssh_audit/ssh_socket.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/src/ssh_audit/ssh_socket.py 2021-08-26 21:24:34.000000000 +0200 @@ -52,8 +52,9 @@ SM_BANNER_SENT = 1 - def __init__(self, host: Optional[str], port: int, ip_version_preference: List[int] = [], timeout: Union[int, float] = 5, timeout_set: bool = False) -> None: # pylint: disable=dangerous-default-value + def __init__(self, outputbuffer: 'OutputBuffer', host: Optional[str], port: int, ip_version_preference: List[int] = [], timeout: Union[int, float] = 5, timeout_set: bool = False) -> None: # pylint: disable=dangerous-default-value super(SSH_Socket, self).__init__() + self.__outputbuffer = outputbuffer self.__sock: Optional[socket.socket] = None self.__sock_map: Dict[int, socket.socket] = {} self.__block_size = 8 @@ -90,7 +91,7 @@ if socktype == socket.SOCK_STREAM: yield af, addr except socket.error as e: - OutputBuffer().fail('[exception] {}'.format(e)).write() + self.__outputbuffer.fail('[exception] {}'.format(e)).write() sys.exit(exitcodes.CONNECTION_ERROR) # Listens on a server socket and accepts one connection (used for @@ -156,6 +157,7 @@ try: s = socket.socket(af, socket.SOCK_STREAM) 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) s.connect(addr) self.__sock = s return None @@ -170,6 +172,8 @@ return '[exception] {}'.format(errm) def get_banner(self, sshv: int = 2) -> Tuple[Optional['Banner'], List[str], Optional[str]]: + self.__outputbuffer.d('Getting banner...', write_now=True) + if self.__sock is None: return self.__banner, self.__header, 'not connected' if self.__banner is not None: @@ -229,6 +233,8 @@ def send_kexinit(self, key_exchanges: List[str] = ['curve25519-sha256', 'curve25519-sha...@libssh.org', 'ecdh-sha2-nistp256', 'ecdh-sha2-nistp384', 'ecdh-sha2-nistp521', 'diffie-hellman-group-exchange-sha256', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group14-sha256'], hostkeys: List[str] = ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ssh-ed25519'], ciphers: List[str] = ['chacha20-poly1...@openssh.com', 'aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-...@openssh.com', 'aes256-...@openssh.com'], macs: List[str] = ['umac-64-...@openssh.com', 'umac-128-...@openssh.com', 'hmac-sha2-256-...@openssh.com', 'hmac-sha2-512-...@openssh.com', 'hmac-sha1-...@openssh.com', 'umac...@openssh.com', 'umac-...@openssh.com', 'hmac-sha2-256', 'hmac-sha2-512', 'hmac-sha1'], compressions: List[str] = ['none', 'z...@openssh.com'], languages: List[str] = ['']) -> None: # pylint: disable=dangerous-default-value '''Sends the list of supported host keys, key exchanges, ciphers, and MACs. Emulates OpenSSH v8.2.''' + self.__outputbuffer.d('KEX initialisation...', write_now=True) + kexparty = SSH2_KexParty(ciphers, macs, compressions, languages) kex = SSH2_Kex(os.urandom(16), key_exchanges, hostkeys, kexparty, kexparty, False, 0) @@ -268,7 +274,7 @@ payload_length = packet_length - padding_length - 1 check_size = 4 + 1 + payload_length + padding_length if check_size % self.__block_size != 0: - OutputBuffer().fail('[exception] invalid ssh packet (block size)').write() + self.__outputbuffer.fail('[exception] invalid ssh packet (block size)').write() sys.exit(exitcodes.CONNECTION_ERROR) self.ensure_read(payload_length) if sshv == 1: @@ -283,7 +289,7 @@ if sshv == 1: rcrc = SSH1.crc32(padding + payload) if crc != rcrc: - OutputBuffer().fail('[exception] packet checksum CRC32 mismatch.').write() + self.__outputbuffer.fail('[exception] packet checksum CRC32 mismatch.').write() sys.exit(exitcodes.CONNECTION_ERROR) else: self.ensure_read(padding_length) @@ -332,6 +338,6 @@ def __cleanup(self) -> None: self._close_socket(self.__sock) - for fd in self.__sock_map: - self._close_socket(self.__sock_map[fd]) + for sock in self.__sock_map.values(): + self._close_socket(sock) self.__sock = None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/src/ssh_audit/writebuf.py new/ssh-audit-2.5.0/src/ssh_audit/writebuf.py --- old/ssh-audit-2.4.0/src/ssh_audit/writebuf.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/src/ssh_audit/writebuf.py 2021-08-26 21:24:34.000000000 +0200 @@ -54,7 +54,7 @@ return self.write(v) def write_list(self, v: List[str]) -> 'WriteBuf': - return self.write_string(u','.join(v)) + return self.write_string(','.join(v)) @classmethod def _bitlength(cls, n: int) -> int: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/ssh-audit.1 new/ssh-audit-2.5.0/ssh-audit.1 --- old/ssh-audit-2.4.0/ssh-audit.1 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/ssh-audit.1 2021-08-26 21:24:34.000000000 +0200 @@ -1,4 +1,4 @@ -.TH SSH-AUDIT 1 "February 7, 2021" +.TH SSH-AUDIT 1 "March 2, 2021" .SH NAME \fBssh-audit\fP \- SSH server & client configuration auditor .SH SYNOPSIS @@ -47,9 +47,14 @@ Starts a server on port 2222 to audit client software configuration. Use -p/--port=<port> to change port and -t/--timeout=<secs> to change listen timeout. .TP +.B -d, \-\-debug +.br +Enable debug output. + +.TP .B -j, \-\-json .br -Output results in JSON format. +Output results in JSON format. Specify twice (-jj) to enable indent printing (useful for debugging). .TP .B -l, \-\-level=<info|warn|fail> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/test/docker/expected_results/dropbear_2019.78_test1.json new/ssh-audit-2.5.0/test/docker/expected_results/dropbear_2019.78_test1.json --- old/ssh-audit-2.4.0/test/docker/expected_results/dropbear_2019.78_test1.json 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/test/docker/expected_results/dropbear_2019.78_test1.json 2021-08-26 21:24:34.000000000 +0200 @@ -1 +1 @@ -{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-dropbear_2019.78", "software": "dropbear_2019.78"}, "compression": ["z...@openssh.com", "none"], "enc": ["aes128-ctr", "aes256-ctr", "aes128-cbc", "aes256-cbc", "3des-ctr", "3des-cbc"], "fingerprints": [{"fp": "SHA256:CDfAU12pjQS7/91kg7gYacza0U/6PDbE04Ic3IpYxkM", "type": "ssh-rsa"}], "kex": [{"algorithm": "curve25519-sha256"}, {"algorithm": "curve25519-sha...@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": "kexgue...@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": ["z...@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-sha...@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": "kexgue...@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": "l ocalhost"} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/test/docker/expected_results/openssh_4.0p1_test1.json new/ssh-audit-2.5.0/test/docker/expected_results/openssh_4.0p1_test1.json --- old/ssh-audit-2.4.0/test/docker/expected_results/openssh_4.0p1_test1.json 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/test/docker/expected_results/openssh_4.0p1_test1.json 2021-08-26 21:24:34.000000000 +0200 @@ -1 +1 @@ -{"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-...@lysator.liu.se", "aes128-ctr", "aes192-ctr", "aes256-ctr"], "fingerprints": [{"fp": "SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4", "type": "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-ripemd...@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"], "enc": ["aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "arcfour", "aes192-cbc", "aes256-cbc", "rijndael-...@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-ripemd...@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/test/docker/expected_results/openssh_5.6p1_test1.json new/ssh-audit-2.5.0/test/docker/expected_results/openssh_5.6p1_test1.json --- old/ssh-audit-2.4.0/test/docker/expected_results/openssh_5.6p1_test1.json 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/test/docker/expected_results/openssh_5.6p1_test1.json 2021-08-26 21:24:34.000000000 +0200 @@ -1 +1 @@ -{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_5.6", "software": "OpenSSH_5.6"}, "compression": ["none", "z...@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-...@lysator.liu.se"], "fingerprints": [{"fp": "SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4", "type": "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...@openssh.com", "hmac-ripemd160", "hmac-ripemd...@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", "z...@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-...@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...@openssh.com", "hmac-ripemd160", "hmac-ripemd160@openssh .com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/test/docker/expected_results/openssh_5.6p1_test2.json new/ssh-audit-2.5.0/test/docker/expected_results/openssh_5.6p1_test2.json --- old/ssh-audit-2.4.0/test/docker/expected_results/openssh_5.6p1_test2.json 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/test/docker/expected_results/openssh_5.6p1_test2.json 2021-08-26 21:24:34.000000000 +0200 @@ -1 +1 @@ -{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_5.6", "software": "OpenSSH_5.6"}, "compression": ["none", "z...@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-...@lysator.liu.se"], "fingerprints": [{"fp": "SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4", "type": "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-...@openssh.com", "casize": 1024, "keysize": 1024}], "mac": ["hmac-md5", "hmac-sha1", "umac...@openssh.com", "hmac-ripemd160", "hmac-ripemd...@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", "z...@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-...@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-...@openssh.com", "casize": 1024, "keysize": 1024}], "mac": ["hmac-md5", "hmac-sha1", "umac-64@o penssh.com", "hmac-ripemd160", "hmac-ripemd...@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/test/docker/expected_results/openssh_5.6p1_test3.json new/ssh-audit-2.5.0/test/docker/expected_results/openssh_5.6p1_test3.json --- old/ssh-audit-2.4.0/test/docker/expected_results/openssh_5.6p1_test3.json 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/test/docker/expected_results/openssh_5.6p1_test3.json 2021-08-26 21:24:34.000000000 +0200 @@ -1 +1 @@ -{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_5.6", "software": "OpenSSH_5.6"}, "compression": ["none", "z...@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-...@lysator.liu.se"], "fingerprints": [{"fp": "SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4", "type": "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-...@openssh.com", "casize": 3072, "keysize": 1024}], "mac": ["hmac-md5", "hmac-sha1", "umac...@openssh.com", "hmac-ripemd160", "hmac-ripemd...@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", "z...@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-...@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-...@openssh.com", "casize": 3072, "keysize": 1024}], "mac": ["hmac-md5", "hmac-sha1", "umac-64@o penssh.com", "hmac-ripemd160", "hmac-ripemd...@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/test/docker/expected_results/openssh_5.6p1_test4.json new/ssh-audit-2.5.0/test/docker/expected_results/openssh_5.6p1_test4.json --- old/ssh-audit-2.4.0/test/docker/expected_results/openssh_5.6p1_test4.json 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/test/docker/expected_results/openssh_5.6p1_test4.json 2021-08-26 21:24:34.000000000 +0200 @@ -1 +1 @@ -{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_5.6", "software": "OpenSSH_5.6"}, "compression": ["none", "z...@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-...@lysator.liu.se"], "fingerprints": [{"fp": "SHA256:nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244", "type": "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-...@openssh.com", "casize": 1024, "keysize": 3072}], "mac": ["hmac-md5", "hmac-sha1", "umac...@openssh.com", "hmac-ripemd160", "hmac-ripemd...@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", "z...@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-...@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-...@openssh.com", "casize": 1024, "keysize": 3072}], "mac": ["hmac-md5", "hmac-sha1", "umac-64@o penssh.com", "hmac-ripemd160", "hmac-ripemd...@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/test/docker/expected_results/openssh_5.6p1_test5.json new/ssh-audit-2.5.0/test/docker/expected_results/openssh_5.6p1_test5.json --- old/ssh-audit-2.4.0/test/docker/expected_results/openssh_5.6p1_test5.json 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/test/docker/expected_results/openssh_5.6p1_test5.json 2021-08-26 21:24:34.000000000 +0200 @@ -1 +1 @@ -{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_5.6", "software": "OpenSSH_5.6"}, "compression": ["none", "z...@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-...@lysator.liu.se"], "fingerprints": [{"fp": "SHA256:nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244", "type": "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-...@openssh.com", "casize": 3072, "keysize": 3072}], "mac": ["hmac-md5", "hmac-sha1", "umac...@openssh.com", "hmac-ripemd160", "hmac-ripemd...@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", "z...@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-...@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-...@openssh.com", "casize": 3072, "keysize": 3072}], "mac": ["hmac-md5", "hmac-sha1", "umac-64@o penssh.com", "hmac-ripemd160", "hmac-ripemd...@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/test/docker/expected_results/openssh_8.0p1_test1.json new/ssh-audit-2.5.0/test/docker/expected_results/openssh_8.0p1_test1.json --- old/ssh-audit-2.4.0/test/docker/expected_results/openssh_8.0p1_test1.json 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/test/docker/expected_results/openssh_8.0p1_test1.json 2021-08-26 21:24:34.000000000 +0200 @@ -1 +1 @@ -{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_8.0", "software": "OpenSSH_8.0"}, "compression": ["none", "z...@openssh.com"], "enc": ["chacha20-poly1...@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-...@openssh.com", "aes256-...@openssh.com"], "fingerprints": [{"fp": "SHA256:UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU", "type": "ssh-ed25519"}, {"fp": "SHA256:nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244", "type": "ssh-rsa"}], "kex": [{"algorithm": "curve25519-sha256"}, {"algorithm": "curve25519-sha...@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}, {"a lgorithm": "rsa-sha2-256", "keysize": 3072}, {"algorithm": "ssh-rsa", "keysize": 3072}, {"algorithm": "ecdsa-sha2-nistp256"}, {"algorithm": "ssh-ed25519"}], "mac": ["umac-64-...@openssh.com", "umac-128-...@openssh.com", "hmac-sha2-256-...@openssh.com", "hmac-sha2-512-...@openssh.com", "hmac-sha1-...@openssh.com", "umac...@openssh.com", "umac-...@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", "z...@openssh.com"], "enc": ["chacha20-poly1...@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-...@openssh.com", "aes256-...@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-sha...@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-...@openssh.com", "umac-128-...@openssh.com", "hmac-sha2-256-...@openssh.com", "hmac-sha2-512-...@openssh.com", "hmac-sha1-...@openssh.com", "umac...@openssh.com", "umac-...@openssh.com", "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1"], "target": "localhost"} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/test/docker/expected_results/openssh_8.0p1_test2.json new/ssh-audit-2.5.0/test/docker/expected_results/openssh_8.0p1_test2.json --- old/ssh-audit-2.4.0/test/docker/expected_results/openssh_8.0p1_test2.json 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/test/docker/expected_results/openssh_8.0p1_test2.json 2021-08-26 21:24:34.000000000 +0200 @@ -1 +1 @@ -{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_8.0", "software": "OpenSSH_8.0"}, "compression": ["none", "z...@openssh.com"], "enc": ["chacha20-poly1...@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-...@openssh.com", "aes256-...@openssh.com"], "fingerprints": [{"fp": "SHA256:UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU", "type": "ssh-ed25519"}], "kex": [{"algorithm": "curve25519-sha256"}, {"algorithm": "curve25519-sha...@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-...@openssh.com"}], "mac": ["umac-64-...@openssh.com", "umac-128-etm@o penssh.com", "hmac-sha2-256-...@openssh.com", "hmac-sha2-512-...@openssh.com", "hmac-sha1-...@openssh.com", "umac...@openssh.com", "umac-...@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", "z...@openssh.com"], "enc": ["chacha20-poly1...@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-...@openssh.com", "aes256-...@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-sha...@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": [{"algo rithm": "ssh-ed25519"}, {"algorithm": "ssh-ed25519-cert-...@openssh.com"}], "mac": ["umac-64-...@openssh.com", "umac-128-...@openssh.com", "hmac-sha2-256-...@openssh.com", "hmac-sha2-512-...@openssh.com", "hmac-sha1-...@openssh.com", "umac...@openssh.com", "umac-...@openssh.com", "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1"], "target": "localhost"} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/test/docker/expected_results/openssh_8.0p1_test3.json new/ssh-audit-2.5.0/test/docker/expected_results/openssh_8.0p1_test3.json --- old/ssh-audit-2.4.0/test/docker/expected_results/openssh_8.0p1_test3.json 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/test/docker/expected_results/openssh_8.0p1_test3.json 2021-08-26 21:24:34.000000000 +0200 @@ -1 +1 @@ -{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_8.0", "software": "OpenSSH_8.0"}, "compression": ["none", "z...@openssh.com"], "enc": ["chacha20-poly1...@openssh.com", "aes256-...@openssh.com", "aes128-...@openssh.com", "aes256-ctr", "aes192-ctr", "aes128-ctr"], "fingerprints": [{"fp": "SHA256:UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU", "type": "ssh-ed25519"}], "kex": [{"algorithm": "curve25519-sha256"}, {"algorithm": "curve25519-sha...@libssh.org"}, {"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 2048}], "key": [{"algorithm": "ssh-ed25519"}], "mac": ["hmac-sha2-256-...@openssh.com", "hmac-sha2-512-...@openssh.com", "umac-128-...@openssh.com"], "target": "localhost"} +{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_8.0", "software": "OpenSSH_8.0"}, "compression": ["none", "z...@openssh.com"], "enc": ["chacha20-poly1...@openssh.com", "aes256-...@openssh.com", "aes128-...@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-sha...@libssh.org"}, {"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 2048}], "key": [{"algorithm": "ssh-ed25519"}], "mac": ["hmac-sha2-256-...@openssh.com", "hmac-sha2-512-...@openssh.com", "umac-128-...@openssh.com"], "target": "localhost"} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/test/docker/expected_results/tinyssh_20190101_test1.json new/ssh-audit-2.5.0/test/docker/expected_results/tinyssh_20190101_test1.json --- old/ssh-audit-2.4.0/test/docker/expected_results/tinyssh_20190101_test1.json 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/test/docker/expected_results/tinyssh_20190101_test1.json 2021-08-26 21:24:34.000000000 +0200 @@ -1 +1 @@ -{"banner": {"comments": "", "protocol": [2, 0], "raw": "", "software": "tinyssh_noversion"}, "compression": ["none"], "enc": ["chacha20-poly1...@openssh.com"], "fingerprints": [{"fp": "SHA256:89ocln1x7KNqnMgWffGoYtD70ksJ4FrH7BMJHa7SrwU", "type": "ssh-ed25519"}], "kex": [{"algorithm": "curve25519-sha256"}, {"algorithm": "curve25519-sha...@libssh.org"}, {"algorithm": "sntrup4591761x25519-sha...@tinyssh.org"}], "key": [{"algorithm": "ssh-ed25519"}], "mac": ["hmac-sha2-256"], "target": "localhost"} +{"banner": {"comments": "", "protocol": [2, 0], "raw": "", "software": "tinyssh_noversion"}, "compression": ["none"], "enc": ["chacha20-poly1...@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-sha...@libssh.org"}, {"algorithm": "sntrup4591761x25519-sha...@tinyssh.org"}], "key": [{"algorithm": "ssh-ed25519"}], "mac": ["hmac-sha2-256"], "target": "localhost"} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/test/test_build_struct.py new/ssh-audit-2.5.0/test/test_build_struct.py --- old/ssh-audit-2.4.0/test/test_build_struct.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/test/test_build_struct.py 2021-08-26 21:24:34.000000000 +0200 @@ -37,7 +37,7 @@ rv = ssh_audit.build_struct('localhost', banner=None, kex=kex) - assert len(rv["fingerprints"]) == 9 + assert len(rv["fingerprints"]) == (9 * 2) # Each host key generates two hash fingerprints: one using SHA256, and one using MD5. for key in ['banner', 'compression', 'enc', 'fingerprints', 'kex', 'key', 'mac']: assert key in rv diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/test/test_resolve.py new/ssh-audit-2.5.0/test/test_resolve.py --- old/ssh-audit-2.4.0/test/test_resolve.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/test/test_resolve.py 2021-08-26 21:24:34.000000000 +0200 @@ -8,6 +8,7 @@ def init(self, ssh_audit): self.AuditConf = ssh_audit.AuditConf self.audit = ssh_audit.audit + self.OutputBuffer = ssh_audit.OutputBuffer self.ssh_socket = ssh_audit.SSH_Socket def _conf(self): @@ -20,7 +21,7 @@ vsocket = virtual_socket vsocket.gsock.addrinfodata['localhost#22'] = socket.gaierror(8, 'hostname nor servname provided, or not known') conf = self._conf() - s = self.ssh_socket('localhost', 22, conf.ip_version_preference) + s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference) output_spy.begin() with pytest.raises(SystemExit): list(s._resolve()) @@ -32,7 +33,7 @@ vsocket = virtual_socket vsocket.gsock.addrinfodata['localhost#22'] = [] conf = self._conf() - s = self.ssh_socket('localhost', 22, conf.ip_version_preference) + s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference) output_spy.begin() r = list(s._resolve()) assert len(r) == 0 @@ -40,7 +41,7 @@ def test_resolve_ipv4(self, virtual_socket): conf = self._conf() conf.ipv4 = True - s = self.ssh_socket('localhost', 22, conf.ip_version_preference) + s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference) r = list(s._resolve()) assert len(r) == 1 assert r[0] == (socket.AF_INET, ('127.0.0.1', 22)) @@ -48,14 +49,14 @@ def test_resolve_ipv6(self, virtual_socket): conf = self._conf() conf.ipv6 = True - s = self.ssh_socket('localhost', 22, conf.ip_version_preference) + s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference) r = list(s._resolve()) assert len(r) == 1 assert r[0] == (socket.AF_INET6, ('::1', 22)) def test_resolve_ipv46_both(self, virtual_socket): conf = self._conf() - s = self.ssh_socket('localhost', 22, conf.ip_version_preference) + s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference) r = list(s._resolve()) assert len(r) == 2 assert r[0] == (socket.AF_INET, ('127.0.0.1', 22)) @@ -65,7 +66,7 @@ conf = self._conf() conf.ipv4 = True conf.ipv6 = True - s = self.ssh_socket('localhost', 22, conf.ip_version_preference) + s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference) r = list(s._resolve()) assert len(r) == 2 assert r[0] == (socket.AF_INET, ('127.0.0.1', 22)) @@ -73,7 +74,7 @@ conf = self._conf() conf.ipv6 = True conf.ipv4 = True - s = self.ssh_socket('localhost', 22, conf.ip_version_preference) + s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference) r = list(s._resolve()) assert len(r) == 2 assert r[0] == (socket.AF_INET6, ('::1', 22)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/test/test_socket.py new/ssh-audit-2.5.0/test/test_socket.py --- old/ssh-audit-2.4.0/test/test_socket.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/test/test_socket.py 2021-08-26 21:24:34.000000000 +0200 @@ -1,5 +1,6 @@ import pytest +from ssh_audit.outputbuffer import OutputBuffer from ssh_audit.ssh_socket import SSH_Socket @@ -7,24 +8,25 @@ class TestSocket: @pytest.fixture(autouse=True) def init(self, ssh_audit): + self.OutputBuffer = OutputBuffer self.ssh_socket = SSH_Socket def test_invalid_host(self, virtual_socket): with pytest.raises(ValueError): - self.ssh_socket(None, 22) + self.ssh_socket(self.OutputBuffer(), None, 22) def test_invalid_port(self, virtual_socket): with pytest.raises(ValueError): - self.ssh_socket('localhost', 'abc') + self.ssh_socket(self.OutputBuffer(), 'localhost', 'abc') with pytest.raises(ValueError): - self.ssh_socket('localhost', -1) + self.ssh_socket(self.OutputBuffer(), 'localhost', -1) with pytest.raises(ValueError): - self.ssh_socket('localhost', 0) + self.ssh_socket(self.OutputBuffer(), 'localhost', 0) with pytest.raises(ValueError): - self.ssh_socket('localhost', 65536) + self.ssh_socket(self.OutputBuffer(), 'localhost', 65536) def test_not_connected_socket(self, virtual_socket): - sock = self.ssh_socket('localhost', 22) + sock = self.ssh_socket(self.OutputBuffer(), 'localhost', 22) banner, header, err = sock.get_banner() assert banner is None assert len(header) == 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ssh-audit-2.4.0/test/test_ssh1.py new/ssh-audit-2.5.0/test/test_ssh1.py --- old/ssh-audit-2.4.0/test/test_ssh1.py 2021-02-24 02:39:18.000000000 +0100 +++ new/ssh-audit-2.5.0/test/test_ssh1.py 2021-08-26 21:24:34.000000000 +0200 @@ -138,7 +138,7 @@ self.audit(out, self._conf()) out.write() lines = output_spy.flush() - assert len(lines) == 16 + assert len(lines) == 17 def test_ssh1_server_invalid_first_packet(self, output_spy, virtual_socket): vsocket = virtual_socket