mirror of
https://github.com/jtesta/ssh-audit.git
synced 2025-12-16 12:01:48 +01:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f9a630de4 | ||
|
|
f821565ff9 | ||
|
|
062a1f3cb4 | ||
|
|
c900874406 | ||
|
|
0382cf9b2d | ||
|
|
d8d90a3a89 | ||
|
|
aaa7d24565 | ||
|
|
d3b1551520 | ||
|
|
970d747dcb | ||
|
|
1c0d3d5df1 | ||
|
|
4845a8fdee | ||
|
|
11a902cb14 | ||
|
|
b456bb31b9 | ||
|
|
32085b2fa5 | ||
|
|
5ddd8cca5b | ||
|
|
b90db2c1af | ||
|
|
68c827c239 | ||
|
|
e318787a5c | ||
|
|
d9c703c777 | ||
|
|
28a1e23986 | ||
|
|
a01baadfa8 | ||
|
|
45abc3aaf4 | ||
|
|
99c64787d9 | ||
|
|
3fa62c3ac5 | ||
|
|
d7fff591fa | ||
|
|
84647ecb32 |
2
.github/workflows/tox.yaml
vendored
2
.github/workflows/tox.yaml
vendored
@@ -7,7 +7,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
|
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (C) 2017-2024 Joe Testa (jtesta@positronsecurity.com)
|
Copyright (C) 2017-2025 Joe Testa (jtesta@positronsecurity.com)
|
||||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
18
PACKAGING.md
18
PACKAGING.md
@@ -15,10 +15,10 @@ An executable can only be made on a Windows host because the PyInstaller tool (h
|
|||||||
|
|
||||||
# PyPI
|
# PyPI
|
||||||
|
|
||||||
To create package and upload to test server (hint: use username '\_\_token\_\_' and API token for test.pypi.org):
|
To create package and upload to test server (hint: use API token for test.pypi.org):
|
||||||
|
|
||||||
```
|
```
|
||||||
$ sudo apt install python3-virtualenv python3.10-venv
|
$ sudo apt install python3-virtualenv python3.12-venv
|
||||||
$ make -f Makefile.pypi
|
$ make -f Makefile.pypi
|
||||||
$ make -f Makefile.pypi uploadtest
|
$ make -f Makefile.pypi uploadtest
|
||||||
```
|
```
|
||||||
@@ -26,12 +26,12 @@ To create package and upload to test server (hint: use username '\_\_token\_\_'
|
|||||||
To download from test server and verify:
|
To download from test server and verify:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ virtualenv -p /usr/bin/python3 /tmp/pypi_test
|
$ virtualenv /tmp/pypi_test
|
||||||
$ cd /tmp/pypi_test; source bin/activate
|
$ cd /tmp/pypi_test; source bin/activate
|
||||||
$ pip3 install --index-url https://test.pypi.org/simple ssh-audit
|
$ pip3 install --index-url https://test.pypi.org/simple ssh-audit
|
||||||
```
|
```
|
||||||
|
|
||||||
To upload to production server (hint: use username '\_\_token\_\_' and API token for production pypi.org):
|
To upload to production server (hint: use API token for production pypi.org):
|
||||||
|
|
||||||
```
|
```
|
||||||
$ make -f Makefile.pypi uploadprod
|
$ make -f Makefile.pypi uploadprod
|
||||||
@@ -40,7 +40,7 @@ To upload to production server (hint: use username '\_\_token\_\_' and API token
|
|||||||
To download from production server and verify:
|
To download from production server and verify:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ virtualenv -p /usr/bin/python3 /tmp/pypi_prod
|
$ virtualenv /tmp/pypi_prod
|
||||||
$ cd /tmp/pypi_prod; source bin/activate
|
$ cd /tmp/pypi_prod; source bin/activate
|
||||||
$ pip3 install ssh-audit
|
$ pip3 install ssh-audit
|
||||||
```
|
```
|
||||||
@@ -48,14 +48,14 @@ To download from production server and verify:
|
|||||||
|
|
||||||
# Snap
|
# Snap
|
||||||
|
|
||||||
To create the snap package, run a fully-updated Ubuntu Server 22.04 VM.
|
To create the Snap package, run a fully-updated Ubuntu Server 24.04 VM.
|
||||||
|
|
||||||
Create the snap package with:
|
Create the Snap package with:
|
||||||
```
|
```
|
||||||
$ ./build_snap.sh
|
$ ./build_snap.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Upload the snap with:
|
Upload the Snap with:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ snapcraft export-login ~/snap_creds.txt
|
$ snapcraft export-login ~/snap_creds.txt
|
||||||
@@ -68,7 +68,7 @@ Upload the snap with:
|
|||||||
|
|
||||||
# Docker
|
# Docker
|
||||||
|
|
||||||
Ensure that the buildx plugin is available by following the installation instructions available at: https://docs.docker.com/engine/install/ubuntu/
|
Ensure that the `buildx` plugin is available by following the installation instructions available at: https://docs.docker.com/engine/install/ubuntu/
|
||||||
|
|
||||||
Build a local image with:
|
Build a local image with:
|
||||||
|
|
||||||
|
|||||||
153
README.md
153
README.md
@@ -26,8 +26,7 @@
|
|||||||
- [ChangeLog](#changelog)
|
- [ChangeLog](#changelog)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- SSH1 and SSH2 protocol server support;
|
- analyze SSH both server and client configuration;
|
||||||
- analyze SSH client configuration;
|
|
||||||
- grab banner, recognize device or software and operating system, detect compression;
|
- grab banner, recognize device or software and operating system, detect compression;
|
||||||
- gather key-exchange, host-key, encryption and message authentication code algorithms;
|
- gather key-exchange, host-key, encryption and message authentication code algorithms;
|
||||||
- output algorithm security information (available since, removed/disabled, unsafe/weak/legacy, etc);
|
- output algorithm security information (available since, removed/disabled, unsafe/weak/legacy, etc);
|
||||||
@@ -36,69 +35,100 @@
|
|||||||
- historical information from OpenSSH, Dropbear SSH and libssh;
|
- historical information from OpenSSH, Dropbear SSH and libssh;
|
||||||
- policy scans to ensure adherence to a hardened/standard configuration;
|
- policy scans to ensure adherence to a hardened/standard configuration;
|
||||||
- runs on Linux and Windows;
|
- runs on Linux and Windows;
|
||||||
- supports Python 3.8 - 3.13;
|
- supports Python 3.9 - 3.13;
|
||||||
- no dependencies
|
- no dependencies
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
```
|
```
|
||||||
usage: ssh-audit.py [options] <host>
|
usage: ssh-audit.py [-h] [-4] [-6] [-b] [-c] [-d]
|
||||||
|
[-g <min1:pref1:max1[,min2:pref2:max2,...]> / <x-y[:step]>]
|
||||||
|
[-j] [-l {info,warn,fail}] [-L] [-M custom_policy.txt]
|
||||||
|
[-m] [-n] [-P "Built-In Policy Name" / custom_policy.txt]
|
||||||
|
[-p N] [-T targets.txt] [-t N] [-v]
|
||||||
|
[--conn-rate-test N[:max_rate]] [--dheat N[:kex[:e_len]]]
|
||||||
|
[--get-hardening-guide platform] [--list-hardening-guides]
|
||||||
|
[--lookup alg1[,alg2,...]] [--skip-rate-test]
|
||||||
|
[--threads N]
|
||||||
|
[host]
|
||||||
|
|
||||||
-h, --help print this help
|
# ssh-audit.py v3.4.0-dev, https://github.com/jtesta/ssh-audit
|
||||||
-1, --ssh1 force ssh version 1 only
|
|
||||||
-2, --ssh2 force ssh version 2 only
|
positional arguments:
|
||||||
|
host target hostname or IPv4/IPv6 address
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
-4, --ipv4 enable IPv4 (order of precedence)
|
-4, --ipv4 enable IPv4 (order of precedence)
|
||||||
-6, --ipv6 enable IPv6 (order of precedence)
|
-6, --ipv6 enable IPv6 (order of precedence)
|
||||||
-b, --batch batch output
|
-b, --batch batch output
|
||||||
-c, --client-audit starts a server on port 2222 to audit client
|
-c, --client-audit starts a server on port 2222 to audit client software
|
||||||
software config (use -p to change port;
|
config (use -p to change port; use -t to change
|
||||||
use -t to change timeout)
|
timeout)
|
||||||
--conn-rate-test=N[:max_rate] perform a connection rate test (useful
|
-d, --debug enable debugging output
|
||||||
for collecting metrics related to
|
-g <min1:pref1:max1[,min2:pref2:max2,...]> / <x-y[:step]>, --gex-test <min1:pref1:max1[,min2:pref2:max2,...]> / <x-y[:step]>
|
||||||
susceptibility of the DHEat vuln).
|
conducts a very customized Diffie-Hellman GEX modulus
|
||||||
Testing is conducted with N concurrent
|
size test. Tests an array of minimum, preferred, and
|
||||||
sockets with an optional maximum rate
|
maximum values, or a range of values with an optional
|
||||||
of connections per second.
|
incremental step amount
|
||||||
-d, --debug Enable debug output.
|
-j, --json enable JSON output (use -jj to enable indentation for
|
||||||
--dheat=N[:kex[:e_len]] continuously perform the DHEat DoS attack
|
better readability)
|
||||||
(CVE-2002-20001) against the target using N
|
-l {info,warn,fail}, --level {info,warn,fail}
|
||||||
concurrent sockets. Optionally, a specific
|
minimum output level (default: info)
|
||||||
key exchange algorithm can be specified
|
-L, --list-policies list all the official, built-in policies. Combine with
|
||||||
instead of allowing it to be automatically
|
-v to view policy change logs
|
||||||
chosen. Additionally, a small length of
|
-M custom_policy.txt, --make-policy custom_policy.txt
|
||||||
the fake e value sent to the server can
|
creates a policy based on the target server (i.e.: the
|
||||||
be chosen for a more efficient attack (such
|
target server has the ideal configuration that other
|
||||||
as 4).
|
servers should adhere to), and stores it in the file
|
||||||
-g, --gex-test=<x[,y,...]> dh gex modulus size test
|
path specified
|
||||||
<min1:pref1:max1[,min2:pref2:max2,...]>
|
|
||||||
<x-y[:step]>
|
|
||||||
-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. Use with -v
|
|
||||||
to view policy change logs.
|
|
||||||
--lookup=<alg1,alg2,...> looks up an algorithm(s) without
|
|
||||||
connecting to a server
|
|
||||||
-m, --manual print the man page (Docker, PyPI, Snap, and Windows
|
-m, --manual print the man page (Docker, PyPI, Snap, and Windows
|
||||||
builds only)
|
builds only)
|
||||||
-M, --make-policy=<policy.txt> creates a policy based on the target server
|
-n, --no-colors disable colors (automatic when the NO_COLOR
|
||||||
(i.e.: the target server has the ideal
|
environment variable is set)
|
||||||
configuration that other servers should
|
-P "Built-In Policy Name" / custom_policy.txt, --policy "Built-In Policy Name" / custom_policy.txt
|
||||||
adhere to)
|
run a policy test using the specified policy (use -L
|
||||||
-n, --no-colors disable colors
|
to see built-in policies, or specify filesystem path
|
||||||
-p, --port=<port> port to connect
|
to custom policy created by -M)
|
||||||
-P, --policy=<"policy name" | policy.txt> run a policy test using the
|
-p N, --port N the TCP port to connect to (or to listen on when -c is
|
||||||
specified policy
|
used)
|
||||||
--skip-rate-test skip the connection rate test during standard audits
|
-T targets.txt, --targets targets.txt
|
||||||
(used to safely infer whether the DHEat attack
|
a file containing a list of target hosts (one per
|
||||||
is viable)
|
line, format HOST[:PORT]). Use -p/--port to set the
|
||||||
-t, --timeout=<secs> timeout (in seconds) for connection and reading
|
default port for all hosts. Use --threads to control
|
||||||
|
concurrent scans
|
||||||
|
-t N, --timeout N timeout (in seconds) for connection and reading
|
||||||
(default: 5)
|
(default: 5)
|
||||||
-T, --targets=<hosts.txt> a file containing a list of target hosts (one
|
-v, --verbose enable verbose output
|
||||||
per line, format HOST[:PORT]). Use -p/--port
|
--conn-rate-test N[:max_rate]
|
||||||
to set the default port for all hosts. Use
|
perform a connection rate test (useful for collecting
|
||||||
--threads to control concurrent scans.
|
metrics related to susceptibility of the DHEat vuln).
|
||||||
--threads=<threads> number of threads to use when scanning multiple
|
Testing is conducted with N concurrent sockets with an
|
||||||
|
optional maximum rate of connections per second
|
||||||
|
--dheat N[:kex[:e_len]]
|
||||||
|
continuously perform the DHEat DoS attack
|
||||||
|
(CVE-2002-20001) against the target using N concurrent
|
||||||
|
sockets. Optionally, a specific key exchange algorithm
|
||||||
|
can be specified instead of allowing it to be
|
||||||
|
automatically chosen. Additionally, a small length of
|
||||||
|
the fake e value sent to the server can be chosen for
|
||||||
|
a more efficient attack (such as 4).
|
||||||
|
--get-hardening-guide platform
|
||||||
|
retrieves the hardening guide for the specified
|
||||||
|
platform name (use --list-hardening-guides to see list
|
||||||
|
of available guides).
|
||||||
|
--list-hardening-guides
|
||||||
|
list all official, built-in hardening guides for
|
||||||
|
common systems. Their full names can then be passed to
|
||||||
|
--get-hardening-guide. Add -v to this option to view
|
||||||
|
hardening guide change logs and prior versions.
|
||||||
|
--lookup alg1[,alg2,...]
|
||||||
|
looks up an algorithm(s) without connecting to a
|
||||||
|
server.
|
||||||
|
--skip-rate-test skip the connection rate test during standard audits
|
||||||
|
(used to safely infer whether the DHEat attack is
|
||||||
|
viable)
|
||||||
|
--threads N number of threads to use when scanning multiple
|
||||||
targets (-T/--targets) (default: 32)
|
targets (-T/--targets) (default: 32)
|
||||||
-v, --verbose verbose output
|
|
||||||
```
|
```
|
||||||
* if both IPv4 and IPv6 are used, order of precedence can be set by using either `-46` or `-64`.
|
* if both IPv4 and IPv6 are used, order of precedence can be set by using either `-46` or `-64`.
|
||||||
* batch flag `-b` will output sections without header and without empty lines (implies verbose flag).
|
* batch flag `-b` will output sections without header and without empty lines (implies verbose flag).
|
||||||
@@ -189,7 +219,7 @@ Below is a screen shot of the client-auditing output when an unhardened OpenSSH
|
|||||||

|

|
||||||
|
|
||||||
## 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)
|
Guides to harden server & client configuration are built into the tool (see `--list-hardening-guides` and `--get-hardening-guide` options). Additionally, they are also available online at: [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](https://github.com/jtesta/ssh-audit/releases) page), PyPI, Snap, and Docker:
|
Pre-built packages are available for Windows (see the [Releases](https://github.com/jtesta/ssh-audit/releases) page), PyPI, Snap, and Docker:
|
||||||
@@ -219,6 +249,21 @@ For convenience, a web front-end on top of the command-line tool is available at
|
|||||||
|
|
||||||
## ChangeLog
|
## ChangeLog
|
||||||
|
|
||||||
|
### v3.4.0-dev
|
||||||
|
- BIG THANKS to [realmiwi](https://github.com/realmiwi) for being the project's *very first sponsor!!*
|
||||||
|
- Dropped support for Python 3.8, as it reached end-of-life in October 2024.
|
||||||
|
- Added warning to all key exchanges that do not include protections against quantum attacks due to the Harvest Now, Decrypt Later strategy (see https://en.wikipedia.org/wiki/Harvest_now,_decrypt_later).
|
||||||
|
- Removed SSHv1 support (rationale is documented in: https://github.com/jtesta/ssh-audit/issues/298).
|
||||||
|
- Added hardening guides (see `--list-hardening-guides` and `--get-hardening-guide`). Previously, they were only available at <https://ssh-audit.com/hardening_guides.html>, but now they are built-in for convenience; partial credit [oam7575](https://github.com/oam7575).
|
||||||
|
- Added `allow_hostkey_subset_and_reordering` policy option to allow targets to have a more stringent list of host keys and/or a different ordering of them.
|
||||||
|
- Migrated from deprecated `getopt` module to `argparse`; partial credit [oam7575](https://github.com/oam7575).
|
||||||
|
- When running against multiple hosts, now prints each target host regardless of output level.
|
||||||
|
- Batch mode (`-b`) no longer automatically enables verbose mode, due to sometimes confusing results; users can still explicitly enable verbose mode using the `-v` flag.
|
||||||
|
- Added built-in policy for OpenSSH 10.0.
|
||||||
|
- Added hardening guides and policies for Debian 13.
|
||||||
|
- Added 2 new key exchanges: `mlkem768nistp256-sha256`, `mlkem1024nistp384-sha384`.
|
||||||
|
- Added 2 new ciphers: `AEAD_CAMELLIA_128_GCM`, `AEAD_CAMELLIA_256_GCM`.
|
||||||
|
|
||||||
### v3.3.0 (2024-10-15)
|
### v3.3.0 (2024-10-15)
|
||||||
- Added Python 3.13 support.
|
- Added Python 3.13 support.
|
||||||
- Added built-in policies for Ubuntu 24.04 LTS server & client, OpenSSH 9.8, and OpenSSH 9.9.
|
- Added built-in policies for Ubuntu 24.04 LTS server & client, OpenSSH 9.8, and OpenSSH 9.9.
|
||||||
|
|||||||
@@ -111,18 +111,9 @@ echo "Processing man page at ${MAN_PAGE} and placing output into ${GLOBALS_PY}..
|
|||||||
# * 'MAN_KEEP_FORMATTING' preserves the backspace-overwrite sequence when
|
# * 'MAN_KEEP_FORMATTING' preserves the backspace-overwrite sequence when
|
||||||
# redirected to a file or a pipe.
|
# redirected to a file or a pipe.
|
||||||
# * sed converts unicode hyphens into an ASCI equivalent.
|
# * sed converts unicode hyphens into an ASCI equivalent.
|
||||||
# * The 'ul' command converts the backspace-overwrite sequence to an ANSI
|
|
||||||
# escape sequence. Not required under Cygwin because man outputs ANSI escape
|
|
||||||
# codes automatically.
|
|
||||||
|
|
||||||
echo BUILTIN_MAN_PAGE = '"""' >> "${GLOBALS_PY}"
|
echo BUILTIN_MAN_PAGE = '"""' >> "${GLOBALS_PY}"
|
||||||
|
MANWIDTH=80 MAN_KEEP_FORMATTING=1 man "${MAN_PAGE}" | sed $'s/\u2010/-/g' >> "${GLOBALS_PY}"
|
||||||
if [[ "${PLATFORM}" == CYGWIN* ]]; then
|
|
||||||
MANWIDTH=80 MAN_KEEP_FORMATTING=1 man "${MAN_PAGE}" | sed $'s/\u2010/-/g' >> "${GLOBALS_PY}"
|
|
||||||
else
|
|
||||||
MANWIDTH=80 MAN_KEEP_FORMATTING=1 man "${MAN_PAGE}" | ul | sed $'s/\u2010/-/g' >> "${GLOBALS_PY}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo '"""' >> "${GLOBALS_PY}"
|
echo '"""' >> "${GLOBALS_PY}"
|
||||||
|
|
||||||
echo "Done."
|
echo "Done."
|
||||||
|
|||||||
@@ -793,6 +793,9 @@ run_custom_policy_test "config2" "test16" "${PROGRAM_RETVAL_FAILURE}"
|
|||||||
# Passing test with larger key matching.
|
# Passing test with larger key matching.
|
||||||
run_custom_policy_test "config2" "test17" "${PROGRAM_RETVAL_GOOD}"
|
run_custom_policy_test "config2" "test17" "${PROGRAM_RETVAL_GOOD}"
|
||||||
|
|
||||||
|
# Passing test with host key subset matching.
|
||||||
|
run_custom_policy_test "config2" "test18" "${PROGRAM_RETVAL_GOOD}"
|
||||||
|
|
||||||
# Failing test for built-in OpenSSH 8.0p1 server policy (RSA host key size is 3072 instead of 4096).
|
# Failing test for built-in OpenSSH 8.0p1 server policy (RSA host key size is 3072 instead of 4096).
|
||||||
run_builtin_policy_test "Hardened OpenSSH Server v8.0 (version 4)" "8.0p1" "test1" "-o HostKeyAlgorithms=rsa-sha2-512,rsa-sha2-256,ssh-ed25519 -o KexAlgorithms=curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr -o MACs=hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com" "${PROGRAM_RETVAL_FAILURE}"
|
run_builtin_policy_test "Hardened OpenSSH Server v8.0 (version 4)" "8.0p1" "test1" "-o HostKeyAlgorithms=rsa-sha2-512,rsa-sha2-256,ssh-ed25519 -o KexAlgorithms=curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr -o MACs=hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com" "${PROGRAM_RETVAL_FAILURE}"
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ classifiers =
|
|||||||
License :: OSI Approved :: MIT License
|
License :: OSI Approved :: MIT License
|
||||||
Operating System :: OS Independent
|
Operating System :: OS Independent
|
||||||
Programming Language :: Python :: 3
|
Programming Language :: Python :: 3
|
||||||
Programming Language :: Python :: 3.8
|
|
||||||
Programming Language :: Python :: 3.9
|
Programming Language :: Python :: 3.9
|
||||||
Programming Language :: Python :: 3.10
|
Programming Language :: Python :: 3.10
|
||||||
Programming Language :: Python :: 3.11
|
Programming Language :: Python :: 3.11
|
||||||
@@ -34,7 +33,7 @@ classifiers =
|
|||||||
packages = find:
|
packages = find:
|
||||||
package_dir =
|
package_dir =
|
||||||
= src
|
= src
|
||||||
python_requires = >=3.8,<4
|
python_requires = >=3.9,<4
|
||||||
|
|
||||||
[options.packages.find]
|
[options.packages.find]
|
||||||
where = src
|
where = src
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (C) 2017-2021 Joe Testa (jtesta@positronsecurity.com)
|
Copyright (C) 2017-2025 Joe Testa (jtesta@positronsecurity.com)
|
||||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@@ -29,8 +29,6 @@ from typing import Callable, Optional, Union, Any # noqa: F401
|
|||||||
from ssh_audit.algorithm import Algorithm
|
from ssh_audit.algorithm import Algorithm
|
||||||
from ssh_audit.product import Product
|
from ssh_audit.product import Product
|
||||||
from ssh_audit.software import Software
|
from ssh_audit.software import Software
|
||||||
from ssh_audit.ssh1_kexdb import SSH1_KexDB
|
|
||||||
from ssh_audit.ssh1_publickeymessage import SSH1_PublicKeyMessage
|
|
||||||
from ssh_audit.ssh2_kex import SSH2_Kex
|
from ssh_audit.ssh2_kex import SSH2_Kex
|
||||||
from ssh_audit.ssh2_kexdb import SSH2_KexDB
|
from ssh_audit.ssh2_kexdb import SSH2_KexDB
|
||||||
from ssh_audit.timeframe import Timeframe
|
from ssh_audit.timeframe import Timeframe
|
||||||
@@ -38,28 +36,13 @@ from ssh_audit.utils import Utils
|
|||||||
|
|
||||||
|
|
||||||
class Algorithms:
|
class Algorithms:
|
||||||
def __init__(self, pkm: Optional[SSH1_PublicKeyMessage], kex: Optional[SSH2_Kex]) -> None:
|
def __init__(self, kex: Optional[SSH2_Kex]) -> None:
|
||||||
self.__ssh1kex = pkm
|
|
||||||
self.__ssh2kex = kex
|
self.__ssh2kex = kex
|
||||||
|
|
||||||
@property
|
|
||||||
def ssh1kex(self) -> Optional[SSH1_PublicKeyMessage]:
|
|
||||||
return self.__ssh1kex
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ssh2kex(self) -> Optional[SSH2_Kex]:
|
def ssh2kex(self) -> Optional[SSH2_Kex]:
|
||||||
return self.__ssh2kex
|
return self.__ssh2kex
|
||||||
|
|
||||||
@property
|
|
||||||
def ssh1(self) -> Optional['Algorithms.Item']:
|
|
||||||
if self.ssh1kex is None:
|
|
||||||
return None
|
|
||||||
item = Algorithms.Item(1, SSH1_KexDB.get_db())
|
|
||||||
item.add('key', ['ssh-rsa1'])
|
|
||||||
item.add('enc', self.ssh1kex.supported_ciphers)
|
|
||||||
item.add('aut', self.ssh1kex.supported_authentications)
|
|
||||||
return item
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ssh2(self) -> Optional['Algorithms.Item']:
|
def ssh2(self) -> Optional['Algorithms.Item']:
|
||||||
if self.ssh2kex is None:
|
if self.ssh2kex is None:
|
||||||
@@ -73,7 +56,7 @@ class Algorithms:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def values(self) -> Iterable['Algorithms.Item']:
|
def values(self) -> Iterable['Algorithms.Item']:
|
||||||
for item in [self.ssh1, self.ssh2]:
|
for item in [self.ssh2]:
|
||||||
if item is not None:
|
if item is not None:
|
||||||
yield item
|
yield item
|
||||||
|
|
||||||
@@ -82,10 +65,6 @@ class Algorithms:
|
|||||||
def _ml(items: Sequence[str]) -> int:
|
def _ml(items: Sequence[str]) -> int:
|
||||||
return max(len(i) for i in items)
|
return max(len(i) for i in items)
|
||||||
maxlen = 0
|
maxlen = 0
|
||||||
if self.ssh1kex is not None:
|
|
||||||
maxlen = max(_ml(self.ssh1kex.supported_ciphers),
|
|
||||||
_ml(self.ssh1kex.supported_authentications),
|
|
||||||
maxlen)
|
|
||||||
if self.ssh2kex is not None:
|
if self.ssh2kex is not None:
|
||||||
maxlen = max(_ml(self.ssh2kex.kex_algorithms),
|
maxlen = max(_ml(self.ssh2kex.kex_algorithms),
|
||||||
_ml(self.ssh2kex.key_algorithms),
|
_ml(self.ssh2kex.key_algorithms),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (C) 2017-2024 Joe Testa (jtesta@positronsecurity.com)
|
Copyright (C) 2017-2025 Joe Testa (jtesta@positronsecurity.com)
|
||||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@@ -35,8 +35,6 @@ class AuditConf:
|
|||||||
def __init__(self, host: str = '', port: int = 22) -> None:
|
def __init__(self, host: str = '', port: int = 22) -> None:
|
||||||
self.host = host
|
self.host = host
|
||||||
self.port = port
|
self.port = port
|
||||||
self.ssh1 = True
|
|
||||||
self.ssh2 = True
|
|
||||||
self.batch = False
|
self.batch = False
|
||||||
self.client_audit = False
|
self.client_audit = False
|
||||||
self.colors = True
|
self.colors = True
|
||||||
@@ -73,7 +71,7 @@ class AuditConf:
|
|||||||
|
|
||||||
def __setattr__(self, name: str, value: Union[str, int, float, bool, Sequence[int]]) -> None:
|
def __setattr__(self, name: str, value: Union[str, int, float, bool, Sequence[int]]) -> None:
|
||||||
valid = False
|
valid = False
|
||||||
if name in ['batch', 'client_audit', 'colors', 'json', 'json_print_indent', 'list_policies', 'manual', 'make_policy', 'ssh1', 'ssh2', 'timeout_set', 'verbose', 'debug', 'skip_rate_test']:
|
if name in ['batch', 'client_audit', 'colors', 'json', 'json_print_indent', 'list_policies', 'manual', 'make_policy', 'timeout_set', 'verbose', 'debug', 'skip_rate_test']:
|
||||||
valid, value = True, bool(value)
|
valid, value = True, bool(value)
|
||||||
elif name in ['ipv4', 'ipv6']:
|
elif name in ['ipv4', 'ipv6']:
|
||||||
valid, value = True, bool(value)
|
valid, value = True, bool(value)
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ BUILTIN_POLICIES: Dict[str, Dict[str, Union[Optional[str], Optional[List[str]],
|
|||||||
|
|
||||||
'Hardened Debian 12 (version 2)': {'version': '2', 'changelog': 'Re-ordered host keys to prioritize ED25519 due to efficiency. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'rsa-sha2-512', 'rsa-sha2-256'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'kex-strict-s-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-gcm@openssh.com', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 3072}, 'server_policy': True},
|
'Hardened Debian 12 (version 2)': {'version': '2', 'changelog': 'Re-ordered host keys to prioritize ED25519 due to efficiency. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'rsa-sha2-512', 'rsa-sha2-256'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'kex-strict-s-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-gcm@openssh.com', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 3072}, 'server_policy': True},
|
||||||
|
|
||||||
|
'Hardened Debian 13 (version 1)': {'version': '1', 'changelog': 'Initial revision. As compared to the Debian 12 guide, the following changes were made: 1.) all non-post-quantum key exchanges were removed, and mlkem768x25519-sha256 and sntrup761x25519-sha512 were added, 2.) editing the /etc/ssh/moduli file is no longer done, as we no longer use any group-exchange algorithms (none of them currently protect against quantum attacks), 3.) editing the sshd_config file is no longer done, in order to make system upgrades easier for users, 4.) network-level connection throttling is no longer done, as OpenSSH prevents the DHEat attack by default now.', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'rsa-sha2-512', 'rsa-sha2-256'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['mlkem768x25519-sha256', 'sntrup761x25519-sha512', 'sntrup761x25519-sha512@openssh.com', 'ext-info-s', 'kex-strict-s-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-gcm@openssh.com', 'aes128-ctr'], 'macs': ['hmac-sha2-512-etm@openssh.com', 'hmac-sha2-256-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 3072}, "allow_hostkey_subset_and_reordering": True, 'server_policy': True},
|
||||||
|
|
||||||
|
|
||||||
# Rocky Linux 9
|
# Rocky Linux 9
|
||||||
'Hardened Rocky Linux 9 (version 1)': {'version': '1', 'changelog': 'Initial version', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'kex-strict-s-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 3072}, 'server_policy': True},
|
'Hardened Rocky Linux 9 (version 1)': {'version': '1', 'changelog': 'Initial version', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'kex-strict-s-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 3072}, 'server_policy': True},
|
||||||
@@ -57,6 +59,8 @@ BUILTIN_POLICIES: Dict[str, Dict[str, Union[Optional[str], Optional[List[str]],
|
|||||||
|
|
||||||
'Hardened Ubuntu Server 22.04 LTS (version 6)': {'version': '6', 'changelog': 'Re-ordered host keys to prioritize ED25519 due to efficiency. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'rsa-sha2-512', 'rsa-sha2-256'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'kex-strict-s-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-gcm@openssh.com', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 3072}, 'server_policy': True},
|
'Hardened Ubuntu Server 22.04 LTS (version 6)': {'version': '6', 'changelog': 'Re-ordered host keys to prioritize ED25519 due to efficiency. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'rsa-sha2-512', 'rsa-sha2-256'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'kex-strict-s-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-gcm@openssh.com', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 3072}, 'server_policy': True},
|
||||||
|
|
||||||
|
'Hardened Ubuntu Server 24.04 LTS (version 2)': {'version': '2', 'changelog': 'Removed commands directly editing sshd_config to make system updates easier for users.', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'rsa-sha2-512', 'rsa-sha2-256'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'diffie-hellman-group16-sha512', 'ext-info-s', 'kex-strict-s-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-gcm@openssh.com', 'aes128-ctr'], 'macs': ['hmac-sha2-512-etm@openssh.com', 'hmac-sha2-256-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 3072}, "allow_hostkey_subset_and_reordering": True, "server_policy": True},
|
||||||
|
|
||||||
'Hardened Ubuntu Server 24.04 LTS (version 1)': {'version': '1', 'changelog': 'Initial version.', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'rsa-sha2-512', 'rsa-sha2-256'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'diffie-hellman-group16-sha512', 'ext-info-s', 'kex-strict-s-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-gcm@openssh.com', 'aes128-ctr'], 'macs': ['hmac-sha2-512-etm@openssh.com', 'hmac-sha2-256-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 3072}, 'server_policy': True},
|
'Hardened Ubuntu Server 24.04 LTS (version 1)': {'version': '1', 'changelog': 'Initial version.', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'rsa-sha2-512', 'rsa-sha2-256'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'diffie-hellman-group16-sha512', 'ext-info-s', 'kex-strict-s-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-gcm@openssh.com', 'aes128-ctr'], 'macs': ['hmac-sha2-512-etm@openssh.com', 'hmac-sha2-256-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 3072}, 'server_policy': True},
|
||||||
|
|
||||||
# Generic OpenSSH Server policies
|
# Generic OpenSSH Server policies
|
||||||
@@ -107,6 +111,8 @@ BUILTIN_POLICIES: Dict[str, Dict[str, Union[Optional[str], Optional[List[str]],
|
|||||||
|
|
||||||
'Hardened OpenSSH Server v9.9 (version 1)': {'version': '1', 'changelog': 'Initial version.', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512', 'sntrup761x25519-sha512@openssh.com', 'mlkem768x25519-sha256', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-s', 'kex-strict-s-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 3072}, 'server_policy': True},
|
'Hardened OpenSSH Server v9.9 (version 1)': {'version': '1', 'changelog': 'Initial version.', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512', 'sntrup761x25519-sha512@openssh.com', 'mlkem768x25519-sha256', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-s', 'kex-strict-s-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 3072}, 'server_policy': True},
|
||||||
|
|
||||||
|
'Hardened OpenSSH Server v10.0 (version 1)': {'version': '1', 'changelog': 'Initial version.', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['mlkem768x25519-sha256', 'sntrup761x25519-sha512', 'sntrup761x25519-sha512@openssh.com', 'ext-info-s', 'kex-strict-s-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-gcm@openssh.com', 'aes128-ctr'], 'macs': ['hmac-sha2-512-etm@openssh.com', 'hmac-sha2-256-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {}, 'server_policy': True},
|
||||||
|
|
||||||
# Amazon Linux Policies
|
# Amazon Linux Policies
|
||||||
|
|
||||||
'Hardened Amazon Linux Client 2023 (version 1)': {'version': '1', 'changelog': 'Initial version.', 'banner': None, 'compressions': None, 'host_keys': ['sk-ssh-ed25519-cert-v01@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'sk-ssh-ed25519@openssh.com', 'ssh-ed25519', 'rsa-sha2-512', 'rsa-sha2-256'], 'optional_host_keys': None, 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c', 'kex-strict-c-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
|
'Hardened Amazon Linux Client 2023 (version 1)': {'version': '1', 'changelog': 'Initial version.', 'banner': None, 'compressions': None, 'host_keys': ['sk-ssh-ed25519-cert-v01@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'sk-ssh-ed25519@openssh.com', 'ssh-ed25519', 'rsa-sha2-512', 'rsa-sha2-256'], 'optional_host_keys': None, 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c', 'kex-strict-c-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
|
||||||
@@ -120,6 +126,8 @@ BUILTIN_POLICIES: Dict[str, Dict[str, Union[Optional[str], Optional[List[str]],
|
|||||||
|
|
||||||
'Hardened Debian Client 12 (version 2)': {'version': '2', 'changelog': 'Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', 'banner': None, 'compressions': None, 'host_keys': ['sk-ssh-ed25519-cert-v01@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'sk-ssh-ed25519@openssh.com', 'ssh-ed25519', 'rsa-sha2-512', 'rsa-sha2-256'], 'optional_host_keys': None, 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c', 'kex-strict-c-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-gcm@openssh.com', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
|
'Hardened Debian Client 12 (version 2)': {'version': '2', 'changelog': 'Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', 'banner': None, 'compressions': None, 'host_keys': ['sk-ssh-ed25519-cert-v01@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'sk-ssh-ed25519@openssh.com', 'ssh-ed25519', 'rsa-sha2-512', 'rsa-sha2-256'], 'optional_host_keys': None, 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c', 'kex-strict-c-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-gcm@openssh.com', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
|
||||||
|
|
||||||
|
'Hardened Debian Client 13 (version 1)': {'version': '1', 'changelog': 'Initial revision. As compared to the Debian 12 guide, the following changes were made: all non-post-quantum key exchanges were removed, and mlkem768x25519-sha256 and sntrup761x25519-sha512 were added.', 'banner': None, 'compressions': None, 'host_keys': ['sk-ssh-ed25519-cert-v01@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'sk-ssh-ed25519@openssh.com', 'ssh-ed25519', 'rsa-sha2-512', 'rsa-sha2-256'], 'optional_host_keys': None, 'kex': ['mlkem768x25519-sha256', 'sntrup761x25519-sha512', 'sntrup761x25519-sha512@openssh.com', 'ext-info-c', 'kex-strict-c-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-gcm@openssh.com', 'aes128-ctr'], 'macs': ['hmac-sha2-512-etm@openssh.com', 'hmac-sha2-256-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
|
||||||
|
|
||||||
|
|
||||||
# Rocky Linux Policies
|
# Rocky Linux Policies
|
||||||
|
|
||||||
|
|||||||
@@ -759,9 +759,9 @@ class DHEat:
|
|||||||
r = socket.getaddrinfo(host, 0, family, socket.SOCK_STREAM)
|
r = socket.getaddrinfo(host, 0, family, socket.SOCK_STREAM)
|
||||||
for address_family, socktype, _, _, addr in r:
|
for address_family, socktype, _, _, addr in r:
|
||||||
if socktype == socket.SOCK_STREAM:
|
if socktype == socket.SOCK_STREAM:
|
||||||
return address_family, addr[0]
|
return int(address_family), str(addr[0])
|
||||||
|
|
||||||
return -1, ''
|
return int(socket.AF_UNSPEC), ''
|
||||||
|
|
||||||
|
|
||||||
def _run(self) -> bool:
|
def _run(self) -> bool:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
|
Copyright (C) 2017-2025 Joe Testa (jtesta@positronsecurity.com)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -30,6 +30,7 @@ from typing import Callable, Optional, Union, Any # noqa: F401
|
|||||||
|
|
||||||
from ssh_audit.banner import Banner
|
from ssh_audit.banner import Banner
|
||||||
from ssh_audit.kexdh import KexDHException, KexGroupExchange, KexGroupExchange_SHA1, KexGroupExchange_SHA256
|
from ssh_audit.kexdh import KexDHException, KexGroupExchange, KexGroupExchange_SHA1, KexGroupExchange_SHA256
|
||||||
|
from ssh_audit.software import Software
|
||||||
from ssh_audit.ssh2_kexdb import SSH2_KexDB
|
from ssh_audit.ssh2_kexdb import SSH2_KexDB
|
||||||
from ssh_audit.ssh2_kex import SSH2_Kex
|
from ssh_audit.ssh2_kex import SSH2_Kex
|
||||||
from ssh_audit.ssh_socket import SSH_Socket
|
from ssh_audit.ssh_socket import SSH_Socket
|
||||||
@@ -64,7 +65,7 @@ class GEXTest:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Parse the server's KEX.
|
# Parse the server's KEX.
|
||||||
_, payload = s.read_packet(2)
|
_, payload = s.read_packet()
|
||||||
SSH2_Kex.parse(out, payload)
|
SSH2_Kex.parse(out, payload)
|
||||||
except (KexDHException, struct.error):
|
except (KexDHException, struct.error):
|
||||||
out.v("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc()), write_now=True)
|
out.v("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc()), write_now=True)
|
||||||
@@ -158,9 +159,22 @@ class GEXTest:
|
|||||||
|
|
||||||
smallest_modulus, reconnect_failed = GEXTest._send_init(out, s, kex_group, kex, gex_alg, bits, bits, bits)
|
smallest_modulus, reconnect_failed = GEXTest._send_init(out, s, kex_group, kex, gex_alg, bits, bits, bits)
|
||||||
|
|
||||||
# If the smallest modulus is 2048 and the server is OpenSSH, then we may have triggered the fallback mechanism, which tends to happen in testing scenarios such as this but not in most real-world conditions (see X). To better test this condition, we will do an additional check to see if the server supports sizes between 2048 and 4096, and consider this the definitive result.
|
# If the banner exists, then parse it into a Software object. Next, if the target host is OpenSSH, check if its version is 9.9 or less; these versions are known to have a GEX fallback mechanism.
|
||||||
|
software = None if banner is None else Software.parse(banner)
|
||||||
|
is_openssh = False
|
||||||
|
has_fallback_mechanism = False
|
||||||
|
if (software is not None) and (software.product == "OpenSSH"):
|
||||||
|
is_openssh = True
|
||||||
|
try:
|
||||||
|
if float(software.version) <= 9.9:
|
||||||
|
has_fallback_mechanism = True
|
||||||
|
out.d(f"Found version of OpenSSH that includes GEX fallback mechanism: {software}")
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# If the smallest modulus is 2048 and the server is OpenSSH v9.9 or less, then we may have triggered the fallback mechanism, which tends to happen in testing scenarios such as this but not in most real-world conditions. To better test this condition, we will do an additional check to see if the server supports sizes between 2048 and 4096, and consider this the definitive result.
|
||||||
openssh_test_updated = False
|
openssh_test_updated = False
|
||||||
if (smallest_modulus == 2048) and (banner is not None) and (banner.software is not None) and (banner.software.find('OpenSSH') != -1):
|
if (smallest_modulus == 2048) and is_openssh and has_fallback_mechanism:
|
||||||
out.d('First pass found a minimum GEX modulus of 2048 against OpenSSH server. Performing a second pass to get a more accurate result...')
|
out.d('First pass found a minimum GEX modulus of 2048 against OpenSSH server. Performing a second pass to get a more accurate result...')
|
||||||
smallest_modulus, _ = GEXTest._send_init(out, s, kex_group, kex, gex_alg, 2048, 3072, 4096)
|
smallest_modulus, _ = GEXTest._send_init(out, s, kex_group, kex, gex_alg, 2048, 3072, 4096)
|
||||||
out.d('Modulus size returned by server during second pass: %d bits' % smallest_modulus, write_now=True)
|
out.d('Modulus size returned by server during second pass: %d bits' % smallest_modulus, write_now=True)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
"""
|
"""
|
||||||
# The version to display.
|
# The version to display.
|
||||||
VERSION = 'v3.3.0'
|
VERSION = 'v3.4.0-dev'
|
||||||
|
|
||||||
# SSH software to impersonate
|
# SSH software to impersonate
|
||||||
SSH_HEADER = 'SSH-{0}-OpenSSH_8.2'
|
SSH_HEADER = 'SSH-{0}-OpenSSH_8.2'
|
||||||
|
|||||||
687
src/ssh_audit/hardening_guides.py
Normal file
687
src/ssh_audit/hardening_guides.py
Normal file
@@ -0,0 +1,687 @@
|
|||||||
|
"""
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (C) 2025 Joe Testa (jtesta@positronsecurity.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
"""
|
||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
from ssh_audit.outputbuffer import OutputBuffer
|
||||||
|
|
||||||
|
|
||||||
|
class Hardening_Guides:
|
||||||
|
|
||||||
|
HARDENING_GUIDES: Dict[str, Any] = {
|
||||||
|
"Amazon Linux 2023": [
|
||||||
|
{
|
||||||
|
"server_guide": True,
|
||||||
|
"version": 3,
|
||||||
|
"version_date": "2024-10-01",
|
||||||
|
"change_log": "Re-ordered host keys to prioritize ED25519 due to efficiency. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.",
|
||||||
|
"notes": "all commands below are to be executed as the root user.",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Re-generate the RSA and ED25519 keys",
|
||||||
|
"comment": "",
|
||||||
|
"command": "rm -f /etc/ssh/ssh_host_*\nssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N \"\"\nssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N \"\""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Enable the ED25519 and RSA keys",
|
||||||
|
"comment": "Enable the ED25519 and RSA HostKey directives in the /etc/ssh/sshd_config file:",
|
||||||
|
"command": "echo -e \"\\nHostKey /etc/ssh/ssh_host_ed25519_key\\nHostKey /etc/ssh/ssh_host_rsa_key\" >> /etc/ssh/sshd_config"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Remove small Diffie-Hellman moduli",
|
||||||
|
"comment": "",
|
||||||
|
"command": "awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe\nmv -f /etc/ssh/moduli.safe /etc/ssh/moduli"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restrict supported key exchange, cipher, and MAC algorithms",
|
||||||
|
"comment": "",
|
||||||
|
"command": "echo -e \"# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com hardening guide.\\nKexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,gss-curve25519-sha256-,diffie-hellman-group16-sha512,gss-group16-sha512-,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\\n\\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\\n\\nMACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\\n\\nHostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nCASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nGSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\\n\\nHostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\nPubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n\" > /etc/crypto-policies/back-ends/opensshserver.config"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restart OpenSSH server",
|
||||||
|
"comment": "",
|
||||||
|
"command": "systemctl restart sshd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Implement connection rate throttling",
|
||||||
|
"comment": "Connection rate throttling is needed in order to protect against the DHEat denial-of-service attack. A complete and flexible solution is to use iptables to allow up to 10 connections every 10 seconds from any one source address. An alternate solution is to set OpenSSH's PerSourceMaxStartups directive to 1 (note, however, that this can cause incomplete results during ssh-audit scans, as well as other client failures when bursts of connections are made).",
|
||||||
|
"command": "dnf install -y iptables\niptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set\niptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP\nip6tables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set\nip6tables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP\ndnf install -y iptables-services\niptables-save > /etc/sysconfig/iptables\nip6tables-save > /etc/sysconfig/ip6tables\nsystemctl enable iptables\nsystemctl enable ip6tables\nsystemctl start iptables\nsystemctl start ip6tables"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": True,
|
||||||
|
"version": 2,
|
||||||
|
"version_date": "2024-04-22",
|
||||||
|
"change_log": "Added connection throttling instructions to counteract the DHEat denial-of-service attack.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [] # Commands for this older version are not tracked here.
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": True,
|
||||||
|
"version": 1,
|
||||||
|
"version_date": "2024-03-15",
|
||||||
|
"change_log": "Initial revision.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [] # Commands for this older version are not tracked here.
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": False,
|
||||||
|
"version": 3,
|
||||||
|
"version_date": "2024-10-01",
|
||||||
|
"change_log": "Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Run the following in a terminal to harden the SSH client for the local user:",
|
||||||
|
"comment": "",
|
||||||
|
"command": "mkdir -p -m 0700 ~/.ssh; echo -e \"\\nHost *\\n Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\\n\\n KexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,gss-group16-sha512-,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\\n\\n MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\\n\\n HostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n CASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\\n\\n HostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\n PubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\n\" >> ~/.ssh/config"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": False,
|
||||||
|
"version": 2,
|
||||||
|
"version_date": "2024-04-22",
|
||||||
|
"change_log": "added connection throttling instructions to counteract the DHEat denial-of-service attack.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [] # Commands for this older version are not tracked here.
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": False,
|
||||||
|
"version": 1,
|
||||||
|
"version_date": "2024-03-15",
|
||||||
|
"change_log": "Initial revision.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [] # Commands for this older version are not tracked here.
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
"Debian 11": [
|
||||||
|
{
|
||||||
|
"server_guide": True,
|
||||||
|
"version": 1,
|
||||||
|
"version_date": "2021-09-17",
|
||||||
|
"change_log": "Latest version.",
|
||||||
|
"notes": "all commands below are to be executed as the root user.",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Re-generate the RSA and ED25519 keys",
|
||||||
|
"comment": "",
|
||||||
|
"command": "rm -f /etc/ssh/ssh_host_*\nssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N \"\"\nssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N \"\""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Enable the RSA and ED25519 keys",
|
||||||
|
"comment": "Enable the RSA and ED25519 HostKey directives in the /etc/ssh/sshd_config file:",
|
||||||
|
"command": "sed -i 's/^\\#HostKey \\/etc\\/ssh\\/ssh_host_\\(rsa\\|ed25519\\)_key$/HostKey \\/etc\\/ssh\\/ssh_host_\\1_key/g' /etc/ssh/sshd_config"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Remove small Diffie-Hellman moduli",
|
||||||
|
"comment": "",
|
||||||
|
"command": "awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe\nmv -f /etc/ssh/moduli.safe /etc/ssh/moduli"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restrict supported key exchange, cipher, and MAC algorithms",
|
||||||
|
"comment": "",
|
||||||
|
"command": "echo -e \"\\n# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com\\n# hardening guide.\\nKexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr\\nMACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\\nHostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com\" > /etc/ssh/sshd_config.d/ssh-audit_hardening.conf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restart OpenSSH server",
|
||||||
|
"comment": "",
|
||||||
|
"command": "service ssh restart"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
"Debian 12": [
|
||||||
|
{
|
||||||
|
"server_guide": True,
|
||||||
|
"version": 3,
|
||||||
|
"version_date": "2025-04-18",
|
||||||
|
"change_log": "Added sntrup761x25519-sha512 to KexAlgorithms.",
|
||||||
|
"notes": "all commands below are to be executed as the root user.",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Re-generate the RSA and ED25519 keys",
|
||||||
|
"comment": "",
|
||||||
|
"command": "rm /etc/ssh/ssh_host_*\nssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N \"\"\nssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N \"\""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Enable the ED25519 and RSA keys",
|
||||||
|
"comment": "Enable the ED25519 and RSA HostKey directives in the /etc/ssh/sshd_config file:",
|
||||||
|
"command": "echo -e \"\\nHostKey /etc/ssh/ssh_host_ed25519_key\\nHostKey /etc/ssh/ssh_host_rsa_key\" >> /etc/ssh/sshd_config"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Remove small Diffie-Hellman moduli",
|
||||||
|
"comment": "",
|
||||||
|
"command": "awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe\nmv /etc/ssh/moduli.safe /etc/ssh/moduli"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restrict supported key exchange, cipher, and MAC algorithms",
|
||||||
|
"comment": "",
|
||||||
|
"command": "echo -e \"# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com\\n# hardening guide.\\n KexAlgorithms sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,gss-curve25519-sha256-,diffie-hellman-group16-sha512,gss-group16-sha512-,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\\n\\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\\n\\nMACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\\n\\nHostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nRequiredRSASize 3072\\n\\nCASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nGSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\\n\\nHostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\nPubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\n\" > /etc/ssh/sshd_config.d/ssh-audit_hardening.conf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restart OpenSSH server",
|
||||||
|
"comment": "",
|
||||||
|
"command": "service ssh restart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Implement connection rate throttling",
|
||||||
|
"comment": "Connection rate throttling is needed in order to protect against the DHEat denial-of-service attack. A complete and flexible solution is to use iptables to allow up to 10 connections every 10 seconds from any one source address. An alternate solution is to set OpenSSH's PerSourceMaxStartups directive to 1 (note, however, that this can cause incomplete results during ssh-audit scans, as well as other client failures when bursts of connections are made).",
|
||||||
|
"command": "apt update\nDEBIAN_FRONTEND=noninteractive apt install -q -y iptables netfilter-persistent iptables-persistent\niptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set\niptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP\nip6tables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set\nip6tables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP\nservice netfilter-persistent save"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": True,
|
||||||
|
"version": 2,
|
||||||
|
"version_date": "2024-10-01",
|
||||||
|
"change_log": "Re-ordered host keys to prioritize ED25519 due to efficiency. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [] # Commands for this older version are not tracked here.
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": True,
|
||||||
|
"version": 1,
|
||||||
|
"version_date": "2024-04-24",
|
||||||
|
"change_log": "Added connection throttling instructions to counteract the DHEat denial-of-service attack.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [] # Commands for this older version are not tracked here.
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": False,
|
||||||
|
"version": 2,
|
||||||
|
"version_date": "2024-10-01",
|
||||||
|
"change_log": "Added RequiredRSASize directive to enforce a minimum of 3072-bit user and host-based authentication keys. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Run the following in a terminal to harden the SSH client for the local user:",
|
||||||
|
"comment": "",
|
||||||
|
"command": "mkdir -p -m 0700 ~/.ssh; echo -e \"\\nHost *\\n Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\\n\\n KexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,gss-group16-sha512-,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\\n\\n MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\\n\\n RequiredRSASize 3072\\n\\n HostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n CASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\\n\\n HostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\n PubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\n\" >> ~/.ssh/config"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": False,
|
||||||
|
"version": 1,
|
||||||
|
"version_date": "2024-03-15",
|
||||||
|
"change_log": "Initial revision.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [] # Commands for this older version are not tracked here.
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
"Debian 13": [
|
||||||
|
{
|
||||||
|
"server_guide": True,
|
||||||
|
"version": 1,
|
||||||
|
"version_date": "2025-09-01",
|
||||||
|
"change_log": "Initial revision. As compared to the Debian 12 guide, the following changes were made: 1.) all non-post-quantum key exchanges were removed, and mlkem768x25519-sha256 and sntrup761x25519-sha512 were added, 2.) editing the /etc/ssh/moduli file is no longer done, as we no longer use any group-exchange algorithms (none of them currently protect against quantum attacks), 3.) editing the sshd_config file is no longer done, in order to make system upgrades easier for users, 4.) network-level connection throttling is no longer done, as OpenSSH prevents the DHEat attack by default now.",
|
||||||
|
"notes": "all commands below are to be executed as the root user.",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Re-generate the ED25519 and RSA keys",
|
||||||
|
"comment": "",
|
||||||
|
"command": "rm /etc/ssh/ssh_host_*\nssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N \"\"\nssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N \"\""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restrict supported key exchange, cipher, and MAC algorithms",
|
||||||
|
"comment": "",
|
||||||
|
"command": "echo -e \"# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com\\n# hardening guide.\\nKexAlgorithms mlkem768x25519-sha256,sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com\\n\\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\\n\\nMACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com\\n\\nRequiredRSASize 3072\\n\\nHostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nCASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nGSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\\n\\nHostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nPubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\" > /etc/ssh/sshd_config.d/debian13_ssh-audit_hardening.conf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restart OpenSSH server",
|
||||||
|
"comment": "",
|
||||||
|
"command": "service ssh restart"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": False,
|
||||||
|
"version": 1,
|
||||||
|
"version_date": "2025-09-01",
|
||||||
|
"change_log": "Initial revision. As compared to the Debian 12 guide, the following changes were made: all non-post-quantum key exchanges were removed.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Run the following in a terminal to harden the SSH client for the local user:",
|
||||||
|
"comment": "",
|
||||||
|
"command": "mkdir -p -m 0700 ~/.ssh; echo -e \"\\nHost *\\n Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\\n\\n KexAlgorithms mlkem768x25519-sha256,sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com\\n\\n MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com\\n\\n RequiredRSASize 3072\\n\\n HostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n CASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\\n\\n HostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\n PubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\n\" >> ~/.ssh/config"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
"Rocky Linux 9": [
|
||||||
|
{
|
||||||
|
"server_guide": True,
|
||||||
|
"version": 2,
|
||||||
|
"version_date": "2024-10-01",
|
||||||
|
"change_log": "Re-ordered host keys to prioritize ED25519 due to efficiency. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.",
|
||||||
|
"notes": "all commands below are to be executed as the root user.",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Re-generate the RSA and ED25519 keys",
|
||||||
|
"comment": "",
|
||||||
|
"command": "rm -f /etc/ssh/ssh_host_*\nssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N \"\"\nssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N \"\""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Enable the ED25519 and RSA keys",
|
||||||
|
"comment": "Enable the ED25519 and RSA HostKey directives in the /etc/ssh/sshd_config file:",
|
||||||
|
"command": "echo -e \"\\nHostKey /etc/ssh/ssh_host_ed25519_key\\nHostKey /etc/ssh/ssh_host_rsa_key\" >> /etc/ssh/sshd_config"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Remove small Diffie-Hellman moduli",
|
||||||
|
"comment": "",
|
||||||
|
"command": "awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe\nmv -f /etc/ssh/moduli.safe /etc/ssh/moduli"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restrict supported key exchange, cipher, and MAC algorithms",
|
||||||
|
"comment": "",
|
||||||
|
"command": "echo -e \"# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com\\n# hardening guide.\\nKexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,gss-curve25519-sha256-,diffie-hellman-group16-sha512,gss-group16-sha512-,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\\n\\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\\n\\nMACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\\n\\nHostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nRequiredRSASize 3072\\n\\nCASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nGSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\\n\\nHostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\nPubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n\" > /etc/crypto-policies/back-ends/opensshserver.config"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restart OpenSSH server",
|
||||||
|
"comment": "",
|
||||||
|
"command": "systemctl restart sshd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Implement connection rate throttling",
|
||||||
|
"comment": "Connection rate throttling is needed in order to protect against the DHEat denial-of-service attack. A complete and flexible solution is to use iptables/firewalld to allow up to 10 connections every 10 seconds from any one source address. An alternate solution is to set OpenSSH's PerSourceMaxStartups directive to 1 (note, however, that this can cause incomplete results during ssh-audit scans, as well as other client failures when bursts of connections are made).",
|
||||||
|
"command": "firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 22 -m state --state NEW -m recent --set\nfirewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 1 -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP\nfirewall-cmd --permanent --direct --add-rule ipv6 filter INPUT 0 -p tcp --dport 22 -m state --state NEW -m recent --set\nfirewall-cmd --permanent --direct --add-rule ipv6 filter INPUT 1 -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP\nsystemctl reload firewalld"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": True,
|
||||||
|
"version": 1,
|
||||||
|
"version_date": "2024-04-24",
|
||||||
|
"change_log": "Added connection throttling instructions to counteract the DHEat denial-of-service attack.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [] # Commands for this older version are not tracked here.
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": False,
|
||||||
|
"version": 2,
|
||||||
|
"version_date": "2024-10-01",
|
||||||
|
"change_log": "Added RequiredRSASize directive to enforce a minimum of 3072-bit user and host-based authentication keys. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Run the following in a terminal to harden the SSH client for the local user:",
|
||||||
|
"comment": "",
|
||||||
|
"command": "mkdir -p -m 0700 ~/.ssh; echo -e \"\\nHost *\\n Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\\n\\n KexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,gss-group16-sha512-,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\\n\\n MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\\n\\n RequiredRSASize 3072\\n\\n HostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n CASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\\n\\n HostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\n PubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\n\" >> ~/.ssh/config"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": False,
|
||||||
|
"version": 1,
|
||||||
|
"version_date": "2024-03-15",
|
||||||
|
"change_log": "Initial revision.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [] # Commands for this older version are not tracked here.
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
"Ubuntu 22.04": [
|
||||||
|
{
|
||||||
|
"server_guide": True,
|
||||||
|
"version": 2,
|
||||||
|
"version_date": "2024-10-01",
|
||||||
|
"change_log": "Re-ordered host keys to prioritize ED25519 due to efficiency. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.",
|
||||||
|
"notes": "all commands below are to be executed as the root user.",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Re-generate the RSA and ED25519 keys",
|
||||||
|
"comment": "",
|
||||||
|
"command": "rm /etc/ssh/ssh_host_*\nssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N \"\"\nssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N \"\""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Enable the ED25519 and RSA keys",
|
||||||
|
"comment": "Enable the ED25519 and RSA HostKey directives in the /etc/ssh/sshd_config file:",
|
||||||
|
"command": "echo -e \"\\nHostKey /etc/ssh/ssh_host_ed25519_key\\nHostKey /etc/ssh/ssh_host_rsa_key\" >> /etc/ssh/sshd_config"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Remove small Diffie-Hellman moduli",
|
||||||
|
"comment": "",
|
||||||
|
"command": "awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe\nmv /etc/ssh/moduli.safe /etc/ssh/moduli"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restrict supported key exchange, cipher, and MAC algorithms",
|
||||||
|
"comment": "",
|
||||||
|
"command": "echo -e \"# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com\\n# hardening guide.\\nKexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,gss-curve25519-sha256-,diffie-hellman-group16-sha512,gss-group16-sha512-,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\\n\\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\\n\\nMACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\\n\\nHostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nCASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nGSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\\n\\nHostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\nPubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\" > /etc/ssh/sshd_config.d/ssh-audit_hardening.conf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Implement connection rate throttling",
|
||||||
|
"comment": "Connection rate throttling is needed in order to protect against the DHEat denial-of-service attack. A complete and flexible solution is to use iptables to allow up to 10 connections every 10 seconds from any one source address. An alternate solution is to set OpenSSH's PerSourceMaxStartups directive to 1 (note, however, that this can cause incomplete results during ssh-audit scans, as well as other client failures when bursts of connections are made).",
|
||||||
|
"command": "iptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set\niptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP\nip6tables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set\nip6tables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP\nDEBIAN_FRONTEND=noninteractive apt install -q -y netfilter-persistent iptables-persistent\nservice netfilter-persistent save"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restart OpenSSH server",
|
||||||
|
"comment": "",
|
||||||
|
"command": "service ssh restart"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": True,
|
||||||
|
"version": 1,
|
||||||
|
"version_date": "2024-04-22",
|
||||||
|
"change_log": "Added connection throttling instructions to counteract the DHEat denial-of-service attack.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [] # Commands for this older version are not tracked here.
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": False,
|
||||||
|
"version": 1,
|
||||||
|
"version_date": "2024-10-01",
|
||||||
|
"change_log": "Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Run the following in a terminal to harden the SSH client for the local user:",
|
||||||
|
"comment": "",
|
||||||
|
"command": "mkdir -p -m 0700 ~/.ssh; echo -e \"\\nHost *\\n Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\\n\\n KexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,gss-group16-sha512-,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\\n\\n MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\\n\\n HostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n CASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\\n\\n HostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\n PubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\n\" >> ~/.ssh/config"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
"Ubuntu 24.04": [
|
||||||
|
{
|
||||||
|
"server_guide": True,
|
||||||
|
"version": 3,
|
||||||
|
"version_date": "2025-09-01",
|
||||||
|
"change_log": "Removed commands directly editing sshd_config to make system updates easier for users.",
|
||||||
|
"notes": "all commands below are to be executed as the root user.",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Re-generate the ED25519 and RSA keys",
|
||||||
|
"comment": "",
|
||||||
|
"command": "rm /etc/ssh/ssh_host_*\nssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N \"\"\nssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N \"\""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Remove small Diffie-Hellman moduli",
|
||||||
|
"comment": "",
|
||||||
|
"command": "awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe\nmv /etc/ssh/moduli.safe /etc/ssh/moduli"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restrict supported key exchange, cipher, and MAC algorithms",
|
||||||
|
"comment": "",
|
||||||
|
"command": "echo -e \"# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com\\n# hardening guide.\\nKexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256,gss-group16-sha512-,diffie-hellman-group16-sha512\\n\\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\\n\\nMACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com\\n\\nRequiredRSASize 3072\\n\\nHostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nCASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nGSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\\n\\nHostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nPubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\" > /etc/ssh/sshd_config.d/ssh-audit_hardening.conf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restart OpenSSH server",
|
||||||
|
"comment": "",
|
||||||
|
"command": "service ssh restart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Implement connection rate throttling",
|
||||||
|
"comment": "Connection rate throttling is needed in order to protect against the DHEat denial-of-service attack. A complete and flexible solution is to use iptables to allow up to 10 connections every 10 seconds from any one source address. An alternate solution is to set OpenSSH's PerSourceMaxStartups directive to 1 (note, however, that this can cause incomplete results during ssh-audit scans, as well as other client failures when bursts of connections are made).",
|
||||||
|
"command": "iptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set\niptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP\nip6tables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set\nip6tables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP\nDEBIAN_FRONTEND=noninteractive apt install -q -y netfilter-persistent iptables-persistent\nservice netfilter-persistent save"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": True,
|
||||||
|
"version": 2,
|
||||||
|
"version_date": "2024-10-01",
|
||||||
|
"change_log": "Added RequiredRSASize directive to enforce a minimum of 3072-bit user and host-based authentication keys.",
|
||||||
|
"notes": "all commands below are to be executed as the root user.",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Re-generate the ED25519 and RSA keys",
|
||||||
|
"comment": "",
|
||||||
|
"command": "rm /etc/ssh/ssh_host_*\nssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N \"\"\nssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N \"\""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Remove small Diffie-Hellman moduli",
|
||||||
|
"comment": "",
|
||||||
|
"command": "awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe\nmv /etc/ssh/moduli.safe /etc/ssh/moduli"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Enable the ED25519 and RSA keys",
|
||||||
|
"comment": "Enable the ED25519 and RSA HostKey directives in the /etc/ssh/sshd_config file:",
|
||||||
|
"command": "echo -e \"\\nHostKey /etc/ssh/ssh_host_ed25519_key\\nHostKey /etc/ssh/ssh_host_rsa_key\" >> /etc/ssh/sshd_config"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restrict supported key exchange, cipher, and MAC algorithms",
|
||||||
|
"comment": "",
|
||||||
|
"command": "echo -e \"# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com\\n# hardening guide.\\nKexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256,gss-group16-sha512-,diffie-hellman-group16-sha512\\n\\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\\n\\nMACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com\\n\\nRequiredRSASize 3072\\n\\nHostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nCASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nGSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\\n\\nHostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\nPubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\" > /etc/ssh/sshd_config.d/ssh-audit_hardening.conf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Restart OpenSSH server",
|
||||||
|
"comment": "",
|
||||||
|
"command": "service ssh restart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"heading": "Implement connection rate throttling",
|
||||||
|
"comment": "Connection rate throttling is needed in order to protect against the DHEat denial-of-service attack. A complete and flexible solution is to use iptables to allow up to 10 connections every 10 seconds from any one source address. An alternate solution is to set OpenSSH's PerSourceMaxStartups directive to 1 (note, however, that this can cause incomplete results during ssh-audit scans, as well as other client failures when bursts of connections are made).",
|
||||||
|
"command": "iptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set\niptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP\nip6tables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set\nip6tables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP\nDEBIAN_FRONTEND=noninteractive apt install -q -y netfilter-persistent iptables-persistent\nservice netfilter-persistent save"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": True,
|
||||||
|
"version": 1,
|
||||||
|
"version_date": "2024-04-29",
|
||||||
|
"change_log": "Initial revision. In comparison to Ubuntu 22.04 LTS guide, the following changes were made: 1.) For key exchanges, diffie-hellman-group18-sha512 and diffie-hellman-group-exchange-sha256 were prioritized over diffie-hellman-group16-sha512 due to greater security strength; GSS algorithms were prioritized over their non-GSS equivalents in order to match the client guide, 2.) For ciphers, 256-bit AES ciphers were prioritized over 192 and 128-bit AES ciphers due to their increased resistence against quantum computing attacks (previously, weaker GCM ciphers had priority over CTR ciphers), 3.) The HostbasedAcceptedAlgorithms and PubkeyAcceptedAlgorithms settings are now the same as HostKeyAlgorithms setting, 4.) The hmac-sha2-512-etm@openssh.com MAC was increased in priority due to its increased resistence against quantum computing attacks, and 5.) The ED25519 host keys were given priority over RSA host keys due to their greater efficiency.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [] # Commands for this older version are not tracked here.
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": False,
|
||||||
|
"version": 2,
|
||||||
|
"version_date": "2024-10-01",
|
||||||
|
"change_log": "Added RequiredRSASize directive to enforce a minimum of 3072-bit user and host-based authentication keys.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Run the following in a terminal to harden the SSH client for the local user:",
|
||||||
|
"comment": "",
|
||||||
|
"command": "mkdir -p -m 0700 ~/.ssh; echo -e \"\\nHost *\\n Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\\n\\n KexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256,gss-group16-sha512-,diffie-hellman-group16-sha512\\n\\n MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com\\n\\n RequiredRSASize 3072\\n\\n HostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n CASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\\n\\n HostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n PubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n\" >> ~/.ssh/config"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": False,
|
||||||
|
"version": 1,
|
||||||
|
"version_date": "2024-04-29",
|
||||||
|
"change_log": "Initial revision. In comparison to Ubuntu 22.04 LTS Client guide, the following changes were made: 1.) For key exchanges, diffie-hellman-group18-sha512 and diffie-hellman-group-exchange-sha256 were prioritized over diffie-hellman-group16-sha512 due to greater security strength, 2.) For ciphers, 256-bit AES ciphers were prioritized over 192 and 128-bit AES ciphers due to their increased resistence against quantum computing attacks (previously, weaker GCM ciphers had priority over CTR ciphers), 3.) The HostbasedAcceptedAlgorithms and PubkeyAcceptedAlgorithms settings are now the same as HostKeyAlgorithms setting, and 4.) The hmac-sha2-512-etm@openssh.com MAC was increased in priority due to its increased resistence against quantum computing attacks.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [] # Commands for this older version are not tracked here.
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
"Linux Mint 21": [
|
||||||
|
{
|
||||||
|
"server_guide": False,
|
||||||
|
"version": 1,
|
||||||
|
"version_date": "2024-10-01",
|
||||||
|
"change_log": "Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Run the following in a terminal to harden the SSH client for the local user:",
|
||||||
|
"comment": "",
|
||||||
|
"command": "mkdir -p -m 0700 ~/.ssh; echo -e \"\\nHost *\\n Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\\n\\n KexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,gss-group16-sha512-,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\\n\\n MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\\n\\n HostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n CASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\\n\\n HostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\n PubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\\n\\n\" >> ~/.ssh/config"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
"Linux Mint 22": [
|
||||||
|
{
|
||||||
|
"server_guide": False,
|
||||||
|
"version": 2,
|
||||||
|
"version_date": "2024-10-01",
|
||||||
|
"change_log": "Added RequiredRSASize directive to enforce a minimum of 3072-bit user and host-based authentication keys.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"heading": "Run the following in a terminal to harden the SSH client for the local user:",
|
||||||
|
"comment": "",
|
||||||
|
"command": "mkdir -p -m 0700 ~/.ssh; echo -e \"\\nHost *\\n Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\\n\\n KexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256,gss-group16-sha512-,diffie-hellman-group16-sha512\\n\\n MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com\\n\\n RequiredRSASize 3072\\n\\n HostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n CASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\\n\\n HostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n PubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\\n\\n\" >> ~/.ssh/config"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"server_guide": False,
|
||||||
|
"version": 1,
|
||||||
|
"version_date": "2024-04-29",
|
||||||
|
"change_log": "Initial revision. In comparison to Ubuntu 22.04 LTS Client guide, the following changes were made: 1.) For key exchanges, diffie-hellman-group18-sha512 and diffie-hellman-group-exchange-sha256 were prioritized over diffie-hellman-group16-sha512 due to greater security strength, 2.) For ciphers, 256-bit AES ciphers were prioritized over 192 and 128-bit AES ciphers due to their increased resistence against quantum computing attacks (previously, weaker GCM ciphers had priority over CTR ciphers), 3.) The HostbasedAcceptedAlgorithms and PubkeyAcceptedAlgorithms settings are now the same as HostKeyAlgorithms setting, and 4.) The hmac-sha2-512-etm@openssh.com MAC was increased in priority due to its increased resistence against quantum computing attacks.",
|
||||||
|
"notes": "",
|
||||||
|
"commands": [] # Commands for this older version are not tracked here.
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def list_guides(out: OutputBuffer, verbose: bool) -> None:
|
||||||
|
'''Print all the server and client hardening guides.'''
|
||||||
|
|
||||||
|
|
||||||
|
server_guide_names = []
|
||||||
|
client_guide_names = []
|
||||||
|
|
||||||
|
# Iterate through the guides, and record a list of server guide names, along with a separate list for client guide names.
|
||||||
|
for name, guides in Hardening_Guides.HARDENING_GUIDES.items():
|
||||||
|
for guide in guides:
|
||||||
|
version = guide["version"]
|
||||||
|
version_date = guide["version_date"]
|
||||||
|
change_log = guide["change_log"]
|
||||||
|
if guide["server_guide"]:
|
||||||
|
full_name = f"{name} Server" if not verbose else f"{name} Server (version {version}): {version_date}: {change_log}"
|
||||||
|
if full_name not in server_guide_names:
|
||||||
|
server_guide_names.append(full_name)
|
||||||
|
else:
|
||||||
|
full_name = f"{name} Client" if not verbose else f"{name} Client (version {version}): {version_date}: {change_log}"
|
||||||
|
if full_name not in client_guide_names:
|
||||||
|
client_guide_names.append(full_name)
|
||||||
|
|
||||||
|
# Sort the names.
|
||||||
|
server_guide_names.sort()
|
||||||
|
client_guide_names.sort()
|
||||||
|
|
||||||
|
# Print the lists.
|
||||||
|
out.head("\nServer hardening guides:\n")
|
||||||
|
out.info(" * %s" % "\n * ".join(server_guide_names))
|
||||||
|
|
||||||
|
out.head("\nClient hardening guides:\n")
|
||||||
|
out.info(" * %s" % "\n * ".join(client_guide_names))
|
||||||
|
out.info("\n")
|
||||||
|
|
||||||
|
if not verbose:
|
||||||
|
out.info("Hint: add -v to --list-hardening-guides in order to see change log messages and prior versions. Prior versions of hardening guides can be retrieved as well with --get-hardening-guide (i.e.: --get-hardening-guide \"Ubuntu 24.04 Server (version 1)\").\n")
|
||||||
|
out.write()
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def print_hardening_guide(out: OutputBuffer, platform: str) -> None:
|
||||||
|
'''Prints a hardening guide for the specified platform.'''
|
||||||
|
|
||||||
|
|
||||||
|
platform_orig = platform
|
||||||
|
invalid_guide_name_error = "Invalid guide name. Run --list-hardening-guides to see list of valid guide names."
|
||||||
|
|
||||||
|
# If the user provided a version with the platform name, parse the version number they're interested in.
|
||||||
|
use_latest_version = True
|
||||||
|
use_version = 0
|
||||||
|
pos = platform.find(" (version ")
|
||||||
|
if pos != -1:
|
||||||
|
use_latest_version = False
|
||||||
|
end_pos = platform.find(")", pos)
|
||||||
|
try:
|
||||||
|
use_version = int(platform[pos + 10:end_pos])
|
||||||
|
except ValueError:
|
||||||
|
out.fail(invalid_guide_name_error, write_now=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
platform = platform[0:pos]
|
||||||
|
|
||||||
|
last_space_pos = platform.rfind(" ")
|
||||||
|
if last_space_pos == -1:
|
||||||
|
out.fail(invalid_guide_name_error, write_now=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# From input such as "Ubuntu 24.04 Server", parse the OS name ("Ubuntu 24.04") and last word ("Server").
|
||||||
|
os_name = platform[0:last_space_pos]
|
||||||
|
last_word = platform[last_space_pos + 1:]
|
||||||
|
|
||||||
|
# Determine if this is a server or client guide.
|
||||||
|
is_server = False
|
||||||
|
if last_word == "Server":
|
||||||
|
is_server = True
|
||||||
|
elif last_word != "Client":
|
||||||
|
out.fail(invalid_guide_name_error, write_now=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Ensure that this OS exists in the database.
|
||||||
|
if os_name not in Hardening_Guides.HARDENING_GUIDES:
|
||||||
|
out.fail(invalid_guide_name_error, write_now=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Pull all guides for this OS name.
|
||||||
|
guides = Hardening_Guides.HARDENING_GUIDES[os_name]
|
||||||
|
|
||||||
|
# Iterate over guides until we find the type (server/client) we need, as well as the version of the guide we need.
|
||||||
|
selected_guide = None
|
||||||
|
latest_version = 0
|
||||||
|
for guide in guides:
|
||||||
|
if guide["server_guide"] == is_server:
|
||||||
|
version = guide["version"]
|
||||||
|
if use_latest_version and (version > latest_version):
|
||||||
|
selected_guide = guide
|
||||||
|
latest_version = version
|
||||||
|
elif use_latest_version is False and use_version == version:
|
||||||
|
selected_guide = guide
|
||||||
|
|
||||||
|
# Ensure we found a guide from above.
|
||||||
|
if selected_guide is None:
|
||||||
|
out.fail(invalid_guide_name_error, write_now=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Now print the guide.
|
||||||
|
version_header = f"\n#\n# Hardening guide for {platform_orig}\n#\n" if not use_latest_version else f"\n#\n# Hardening guide for {platform_orig} (version {latest_version})\n#\n"
|
||||||
|
out.info(version_header)
|
||||||
|
|
||||||
|
commands = selected_guide["commands"]
|
||||||
|
for command_dict in commands:
|
||||||
|
heading = command_dict["heading"]
|
||||||
|
comment = command_dict["comment"]
|
||||||
|
command = command_dict["command"]
|
||||||
|
if heading != "":
|
||||||
|
out.info(f"# {heading}")
|
||||||
|
|
||||||
|
if comment != "":
|
||||||
|
out.info(f"# {comment}")
|
||||||
|
|
||||||
|
out.info(f"{command}")
|
||||||
|
out.info(s="")
|
||||||
|
|
||||||
|
out.write()
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
|
Copyright (C) 2017-2025 Joe Testa (jtesta@positronsecurity.com)
|
||||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@@ -88,11 +88,11 @@ class KexDH: # pragma: nocover
|
|||||||
self.__ca_key_type = ''
|
self.__ca_key_type = ''
|
||||||
self.__ca_n_len = 0
|
self.__ca_n_len = 0
|
||||||
|
|
||||||
packet_type, payload = s.read_packet(2)
|
packet_type, payload = s.read_packet()
|
||||||
|
|
||||||
# Skip any & all MSG_DEBUG messages.
|
# Skip any & all MSG_DEBUG messages.
|
||||||
while packet_type == Protocol.MSG_DEBUG:
|
while packet_type == Protocol.MSG_DEBUG:
|
||||||
packet_type, payload = s.read_packet(2)
|
packet_type, payload = s.read_packet()
|
||||||
|
|
||||||
if packet_type != -1 and packet_type not in [Protocol.MSG_KEXDH_REPLY, Protocol.MSG_KEXDH_GEX_REPLY]: # pylint: disable=no-else-raise
|
if packet_type != -1 and packet_type not in [Protocol.MSG_KEXDH_REPLY, Protocol.MSG_KEXDH_GEX_REPLY]: # pylint: disable=no-else-raise
|
||||||
raise KexDHException('Expected MSG_KEXDH_REPLY (%d) or MSG_KEXDH_GEX_REPLY (%d), but got %d instead.' % (Protocol.MSG_KEXDH_REPLY, Protocol.MSG_KEXDH_GEX_REPLY, packet_type))
|
raise KexDHException('Expected MSG_KEXDH_REPLY (%d) or MSG_KEXDH_GEX_REPLY (%d), but got %d instead.' % (Protocol.MSG_KEXDH_REPLY, Protocol.MSG_KEXDH_GEX_REPLY, packet_type))
|
||||||
@@ -380,13 +380,13 @@ class KexGroupExchange(KexDH):
|
|||||||
s.write_int(maxbits)
|
s.write_int(maxbits)
|
||||||
s.send_packet()
|
s.send_packet()
|
||||||
|
|
||||||
packet_type, payload = s.read_packet(2)
|
packet_type, payload = s.read_packet()
|
||||||
if packet_type not in [Protocol.MSG_KEXDH_GEX_GROUP, Protocol.MSG_DEBUG]:
|
if packet_type not in [Protocol.MSG_KEXDH_GEX_GROUP, Protocol.MSG_DEBUG]:
|
||||||
raise KexDHException('Expected MSG_KEXDH_GEX_REPLY (%d), but got %d instead.' % (Protocol.MSG_KEXDH_GEX_REPLY, packet_type))
|
raise KexDHException('Expected MSG_KEXDH_GEX_REPLY (%d), but got %d instead.' % (Protocol.MSG_KEXDH_GEX_REPLY, packet_type))
|
||||||
|
|
||||||
# Skip any & all MSG_DEBUG messages.
|
# Skip any & all MSG_DEBUG messages.
|
||||||
while packet_type == Protocol.MSG_DEBUG:
|
while packet_type == Protocol.MSG_DEBUG:
|
||||||
packet_type, payload = s.read_packet(2)
|
packet_type, payload = s.read_packet()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Parse the modulus (p) and generator (g) values from the server.
|
# Parse the modulus (p) and generator (g) values from the server.
|
||||||
|
|||||||
@@ -54,11 +54,11 @@ class OutputBuffer:
|
|||||||
self.__is_color_supported = ('colorama' in sys.modules) or (os.name == 'posix')
|
self.__is_color_supported = ('colorama' in sys.modules) or (os.name == 'posix')
|
||||||
self.line_ended = True
|
self.line_ended = True
|
||||||
|
|
||||||
def _print(self, level: str, s: str = '', line_ended: bool = True) -> None:
|
def _print(self, level: str, s: str = '', line_ended: bool = True, always_print: bool = False) -> None:
|
||||||
'''Saves output to buffer (if in buffered mode), or immediately prints to stdout otherwise.'''
|
'''Saves output to buffer (if in buffered mode), or immediately prints to stdout otherwise.'''
|
||||||
|
|
||||||
# If we're logging only 'warn' or above, and this is an 'info', ignore message.
|
# If we're logging only 'warn' or above, and this is an 'info', ignore message, unless always_print is True (useful for printing informational lines regardless of the level setting).
|
||||||
if self.get_level(level) < self.__level:
|
if (always_print is False) and (self.get_level(level) < self.__level):
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.use_colors and self.colors_supported and len(s) > 0 and level != 'info':
|
if self.use_colors and self.colors_supported and len(s) > 0 and level != 'info':
|
||||||
@@ -145,20 +145,22 @@ class OutputBuffer:
|
|||||||
self._print('head', s, line_ended)
|
self._print('head', s, line_ended)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def fail(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
|
def fail(self, s: str, line_ended: bool = True, write_now: bool = False, always_print: bool = False) -> 'OutputBuffer':
|
||||||
self._print('fail', s, line_ended)
|
self._print('fail', s, line_ended, always_print=always_print)
|
||||||
|
if write_now:
|
||||||
|
self.write()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def warn(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
|
def warn(self, s: str, line_ended: bool = True, always_print: bool = False) -> 'OutputBuffer':
|
||||||
self._print('warn', s, line_ended)
|
self._print('warn', s, line_ended, always_print=always_print)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def info(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
|
def info(self, s: str, line_ended: bool = True, always_print: bool = False) -> 'OutputBuffer':
|
||||||
self._print('info', s, line_ended)
|
self._print('info', s, line_ended, always_print=always_print)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def good(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
|
def good(self, s: str, line_ended: bool = True, always_print: bool = False) -> 'OutputBuffer':
|
||||||
self._print('good', s, line_ended)
|
self._print('good', s, line_ended, always_print=always_print)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def sep(self) -> 'OutputBuffer':
|
def sep(self) -> 'OutputBuffer':
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (C) 2020-2024 Joe Testa (jtesta@positronsecurity.com)
|
Copyright (C) 2020-2025 Joe Testa (jtesta@positronsecurity.com)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -55,6 +55,7 @@ class Policy:
|
|||||||
self._dh_modulus_sizes: Optional[Dict[str, int]] = None
|
self._dh_modulus_sizes: Optional[Dict[str, int]] = None
|
||||||
self._server_policy = True
|
self._server_policy = True
|
||||||
self._allow_algorithm_subset_and_reordering = False
|
self._allow_algorithm_subset_and_reordering = False
|
||||||
|
self._allow_hostkey_subset_and_reordering = False
|
||||||
self._allow_larger_keys = False
|
self._allow_larger_keys = False
|
||||||
self._errors: List[Any] = []
|
self._errors: List[Any] = []
|
||||||
self._updated_builtin_policy_available = False # If True, an outdated built-in policy was loaded.
|
self._updated_builtin_policy_available = False # If True, an outdated built-in policy was loaded.
|
||||||
@@ -116,7 +117,7 @@ class Policy:
|
|||||||
key = key.strip()
|
key = key.strip()
|
||||||
val = val.strip()
|
val = val.strip()
|
||||||
|
|
||||||
if key not in ['name', 'version', 'banner', 'compressions', 'host keys', 'optional host keys', 'key exchanges', 'ciphers', 'macs', 'client policy', 'host_key_sizes', 'dh_modulus_sizes', 'allow_algorithm_subset_and_reordering', 'allow_larger_keys'] and not key.startswith('hostkey_size_') and not key.startswith('cakey_size_') and not key.startswith('dh_modulus_size_'):
|
if key not in ['name', 'version', 'banner', 'compressions', 'host keys', 'optional host keys', 'key exchanges', 'ciphers', 'macs', 'client policy', 'host_key_sizes', 'dh_modulus_sizes', 'allow_algorithm_subset_and_reordering', 'allow_hostkey_subset_and_reordering', 'allow_larger_keys'] and not key.startswith('hostkey_size_') and not key.startswith('cakey_size_') and not key.startswith('dh_modulus_size_'):
|
||||||
raise ValueError("invalid field found in policy: %s" % line)
|
raise ValueError("invalid field found in policy: %s" % line)
|
||||||
|
|
||||||
if key in ['name', 'banner']:
|
if key in ['name', 'banner']:
|
||||||
@@ -211,6 +212,9 @@ class Policy:
|
|||||||
self._server_policy = False
|
self._server_policy = False
|
||||||
elif key == 'allow_algorithm_subset_and_reordering' and val.lower() == 'true':
|
elif key == 'allow_algorithm_subset_and_reordering' and val.lower() == 'true':
|
||||||
self._allow_algorithm_subset_and_reordering = True
|
self._allow_algorithm_subset_and_reordering = True
|
||||||
|
self._allow_hostkey_subset_and_reordering = True # We force subsets/reorderings of the host keys as well in this case.
|
||||||
|
elif key == 'allow_hostkey_subset_and_reordering' and val.lower() == 'true':
|
||||||
|
self._allow_hostkey_subset_and_reordering = True
|
||||||
elif key == 'allow_larger_keys' and val.lower() == 'true':
|
elif key == 'allow_larger_keys' and val.lower() == 'true':
|
||||||
self._allow_larger_keys = True
|
self._allow_larger_keys = True
|
||||||
|
|
||||||
@@ -300,9 +304,12 @@ name = "Custom Policy (based on %s on %s)"
|
|||||||
# The version of this policy (displayed in the output during scans). Not parsed, and may be any value, including strings.
|
# The version of this policy (displayed in the output during scans). Not parsed, and may be any value, including strings.
|
||||||
version = 1
|
version = 1
|
||||||
|
|
||||||
# When false, host keys, kex, ciphers, and MAC lists must match exactly. When true, the target host may support a subset of the specified algorithms and/or algorithms may appear in a different order; this feature is useful for specifying a baseline and allowing some hosts the option to implement stricter controls.
|
# When false, host keys, kex, ciphers, and MAC lists must match exactly. When true, the target host may support a subset of the specified algorithms and/or algorithms may appear in a different order; this feature is useful for specifying a baseline and allowing some hosts the option to implement stricter controls. A value of true automatically sets "allow_hostkey_subset_and_reordering" to true as well.
|
||||||
allow_algorithm_subset_and_reordering = false
|
allow_algorithm_subset_and_reordering = false
|
||||||
|
|
||||||
|
# When false, the host key list must match exactly. When true, the target host may support a subset of the specified host keys and/or the keys may appear in a different order.
|
||||||
|
allow_hostkey_subset_and_reordering = true
|
||||||
|
|
||||||
# When false, host keys, CA keys, and Diffie-Hellman key sizes must exactly match what's specified in this policy. When true, target systems are allowed to have larger keys; this feature is useful for specifying a baseline and allowing some hosts the option to implement stricter controls.
|
# When false, host keys, CA keys, and Diffie-Hellman key sizes must exactly match what's specified in this policy. When true, target systems are allowed to have larger keys; this feature is useful for specifying a baseline and allowing some hosts the option to implement stricter controls.
|
||||||
allow_larger_keys = false
|
allow_larger_keys = false
|
||||||
|
|
||||||
@@ -358,7 +365,7 @@ macs = %s
|
|||||||
# Check host keys.
|
# Check host keys.
|
||||||
if self._host_keys is not None:
|
if self._host_keys is not None:
|
||||||
# If the policy allows subsets and re-ordered algorithms...
|
# If the policy allows subsets and re-ordered algorithms...
|
||||||
if self._allow_algorithm_subset_and_reordering:
|
if self._allow_hostkey_subset_and_reordering:
|
||||||
for hostkey_t in kex.key_algorithms:
|
for hostkey_t in kex.key_algorithms:
|
||||||
if hostkey_t not in self._host_keys:
|
if hostkey_t not in self._host_keys:
|
||||||
ret = False
|
ret = False
|
||||||
@@ -467,11 +474,18 @@ macs = %s
|
|||||||
def _get_errors(self) -> Tuple[List[Any], str]:
|
def _get_errors(self) -> Tuple[List[Any], str]:
|
||||||
'''Returns the list of errors, along with the string representation of those errors.'''
|
'''Returns the list of errors, along with the string representation of those errors.'''
|
||||||
|
|
||||||
subset_and_reordering_semicolon = "; subset and/or reordering allowed" if self._allow_algorithm_subset_and_reordering else "; exact match"
|
all_subset_and_reordering_semicolon = "; subset and/or reordering allowed" if self._allow_algorithm_subset_and_reordering else "; exact match"
|
||||||
subset_and_reordering_parens = " (subset and/or reordering allowed)" if self._allow_algorithm_subset_and_reordering else ""
|
all_subset_and_reordering_parens = " (subset and/or reordering allowed)" if self._allow_algorithm_subset_and_reordering else ""
|
||||||
|
hostkey_subset_and_reordering_semicolon = "; subset and/or reordering allowed" if self._allow_hostkey_subset_and_reordering else "; exact match"
|
||||||
|
hostkey_subset_and_reordering_parens = " (subset and/or reordering allowed)" if self._allow_hostkey_subset_and_reordering else ""
|
||||||
|
|
||||||
error_list = []
|
error_list = []
|
||||||
spacer = ''
|
spacer = ''
|
||||||
for e in self._errors:
|
for e in self._errors:
|
||||||
|
|
||||||
|
subset_and_reordering_semicolon = hostkey_subset_and_reordering_semicolon if e["mismatched_field"] == "Host keys" else all_subset_and_reordering_semicolon
|
||||||
|
subset_and_reordering_parens = hostkey_subset_and_reordering_parens if e["mismatched_field"] == "Host keys" else all_subset_and_reordering_parens
|
||||||
|
|
||||||
e_str = " * %s did not match.\n" % e['mismatched_field']
|
e_str = " * %s did not match.\n" % e['mismatched_field']
|
||||||
|
|
||||||
if ('expected_optional' in e) and (e['expected_optional'] != ['']):
|
if ('expected_optional' in e) and (e['expected_optional'] != ['']):
|
||||||
@@ -579,6 +593,7 @@ macs = %s
|
|||||||
p._dh_modulus_sizes = cast(Optional[Dict[str, int]], policy_struct['dh_modulus_sizes']) # pylint: disable=protected-access
|
p._dh_modulus_sizes = cast(Optional[Dict[str, int]], policy_struct['dh_modulus_sizes']) # pylint: disable=protected-access
|
||||||
p._server_policy = cast(bool, policy_struct['server_policy']) # pylint: disable=protected-access
|
p._server_policy = cast(bool, policy_struct['server_policy']) # pylint: disable=protected-access
|
||||||
p._name_and_version = "%s (version %s)" % (p._name, p._version) # pylint: disable=protected-access
|
p._name_and_version = "%s (version %s)" % (p._name, p._version) # pylint: disable=protected-access
|
||||||
|
p._allow_hostkey_subset_and_reordering = cast(bool, policy_struct['allow_hostkey_subset_and_reordering']) if 'allow_hostkey_subset_and_reordering' in policy_struct else False # pylint: disable=protected-access
|
||||||
|
|
||||||
# Ensure this struct has all the necessary fields.
|
# Ensure this struct has all the necessary fields.
|
||||||
p._normalize_hostkey_sizes() # pylint: disable=protected-access
|
p._normalize_hostkey_sizes() # pylint: disable=protected-access
|
||||||
@@ -646,7 +661,7 @@ macs = %s
|
|||||||
if self._dh_modulus_sizes is not None:
|
if self._dh_modulus_sizes is not None:
|
||||||
dh_modulus_sizes_str = str(self._dh_modulus_sizes)
|
dh_modulus_sizes_str = str(self._dh_modulus_sizes)
|
||||||
|
|
||||||
return "Name: %s\nVersion: %s\nAllow Algorithm Subset and/or Reordering: %r\nBanner: %s\nCompressions: %s\nHost Keys: %s\nOptional Host Keys: %s\nKey Exchanges: %s\nCiphers: %s\nMACs: %s\nHost Key Sizes: %s\nDH Modulus Sizes: %s\nServer Policy: %r" % (name, version, self._allow_algorithm_subset_and_reordering, banner, compressions_str, host_keys_str, optional_host_keys_str, kex_str, ciphers_str, macs_str, hostkey_sizes_str, dh_modulus_sizes_str, self._server_policy)
|
return "Name: %s\nVersion: %s\nAllow Algorithm Subset and/or Reordering: %r\nAllow Host Key Subset and/or Reordering: %r\nBanner: %s\nCompressions: %s\nHost Keys: %s\nOptional Host Keys: %s\nKey Exchanges: %s\nCiphers: %s\nMACs: %s\nHost Key Sizes: %s\nDH Modulus Sizes: %s\nServer Policy: %r" % (name, version, self._allow_algorithm_subset_and_reordering, self._allow_hostkey_subset_and_reordering, banner, compressions_str, host_keys_str, optional_host_keys_str, kex_str, ciphers_str, macs_str, hostkey_sizes_str, dh_modulus_sizes_str, self._server_policy)
|
||||||
|
|
||||||
|
|
||||||
def __getstate__(self) -> Dict[str, Any]:
|
def __getstate__(self) -> Dict[str, Any]:
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
"""
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
# pylint: disable=unused-import
|
|
||||||
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
|
|
||||||
from typing import Callable, Optional, Union, Any # noqa: F401
|
|
||||||
|
|
||||||
from ssh_audit.ssh1_crc32 import SSH1_CRC32
|
|
||||||
|
|
||||||
|
|
||||||
class SSH1:
|
|
||||||
_crc32: Optional[SSH1_CRC32] = None
|
|
||||||
CIPHERS = ['none', 'idea', 'des', '3des', 'tss', 'rc4', 'blowfish']
|
|
||||||
AUTHS = ['none', 'rhosts', 'rsa', 'password', 'rhosts_rsa', 'tis', 'kerberos']
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def crc32(cls, v: bytes) -> int:
|
|
||||||
if cls._crc32 is None:
|
|
||||||
cls._crc32 = SSH1_CRC32()
|
|
||||||
return cls._crc32.calc(v)
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
"""
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
# pylint: disable=unused-import
|
|
||||||
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
|
|
||||||
from typing import Callable, Optional, Union, Any # noqa: F401
|
|
||||||
|
|
||||||
|
|
||||||
class SSH1_CRC32:
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self._table = [0] * 256
|
|
||||||
for i in range(256):
|
|
||||||
crc = 0
|
|
||||||
n = i
|
|
||||||
for _ in range(8):
|
|
||||||
x = (crc ^ n) & 1
|
|
||||||
crc = (crc >> 1) ^ (x * 0xedb88320)
|
|
||||||
n = n >> 1
|
|
||||||
self._table[i] = crc
|
|
||||||
|
|
||||||
def calc(self, v: bytes) -> int:
|
|
||||||
crc, length = 0, len(v)
|
|
||||||
for i in range(length):
|
|
||||||
n = ord(v[i:i + 1])
|
|
||||||
n = n ^ (crc & 0xff)
|
|
||||||
crc = (crc >> 8) ^ self._table[n]
|
|
||||||
return crc
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
"""
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
# pylint: disable=unused-import
|
|
||||||
import copy
|
|
||||||
import threading
|
|
||||||
|
|
||||||
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
|
|
||||||
from typing import Callable, Optional, Union, Any # noqa: F401
|
|
||||||
|
|
||||||
|
|
||||||
class SSH1_KexDB: # pylint: disable=too-few-public-methods
|
|
||||||
|
|
||||||
FAIL_PLAINTEXT = 'no encryption/integrity'
|
|
||||||
FAIL_OPENSSH37_REMOVE = 'removed since OpenSSH 3.7'
|
|
||||||
FAIL_NA_BROKEN = 'not implemented in OpenSSH, broken algorithm'
|
|
||||||
FAIL_NA_UNSAFE = 'not implemented in OpenSSH (server), unsafe algorithm'
|
|
||||||
TEXT_CIPHER_IDEA = 'cipher used by commercial SSH'
|
|
||||||
|
|
||||||
DB_PER_THREAD: Dict[int, Dict[str, Dict[str, List[List[Optional[str]]]]]] = {}
|
|
||||||
|
|
||||||
MASTER_DB: Dict[str, Dict[str, List[List[Optional[str]]]]] = {
|
|
||||||
'key': {
|
|
||||||
'ssh-rsa1': [['1.2.2']],
|
|
||||||
},
|
|
||||||
'enc': {
|
|
||||||
'none': [['1.2.2'], [FAIL_PLAINTEXT]],
|
|
||||||
'idea': [[None], [], [], [TEXT_CIPHER_IDEA]],
|
|
||||||
'des': [['2.3.0C'], [FAIL_NA_UNSAFE]],
|
|
||||||
'3des': [['1.2.2']],
|
|
||||||
'tss': [[''], [FAIL_NA_BROKEN]],
|
|
||||||
'rc4': [[], [FAIL_NA_BROKEN]],
|
|
||||||
'blowfish': [['1.2.2']],
|
|
||||||
},
|
|
||||||
'aut': {
|
|
||||||
'rhosts': [['1.2.2', '3.6'], [FAIL_OPENSSH37_REMOVE]],
|
|
||||||
'rsa': [['1.2.2']],
|
|
||||||
'password': [['1.2.2']],
|
|
||||||
'rhosts_rsa': [['1.2.2']],
|
|
||||||
'tis': [['1.2.2']],
|
|
||||||
'kerberos': [['1.2.2', '3.6'], [FAIL_OPENSSH37_REMOVE]],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_db() -> Dict[str, Dict[str, List[List[Optional[str]]]]]:
|
|
||||||
'''Returns a copy of the MASTER_DB that is private to the calling thread. This prevents multiple threads from polluting the results of other threads.'''
|
|
||||||
calling_thread_id = threading.get_ident()
|
|
||||||
|
|
||||||
if calling_thread_id not in SSH1_KexDB.DB_PER_THREAD:
|
|
||||||
SSH1_KexDB.DB_PER_THREAD[calling_thread_id] = copy.deepcopy(SSH1_KexDB.MASTER_DB)
|
|
||||||
|
|
||||||
return SSH1_KexDB.DB_PER_THREAD[calling_thread_id]
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def thread_exit() -> None:
|
|
||||||
'''Deletes the calling thread's copy of the MASTER_DB. This is needed because, in rare circumstances, a terminated thread's ID can be re-used by new threads.'''
|
|
||||||
|
|
||||||
calling_thread_id = threading.get_ident()
|
|
||||||
|
|
||||||
if calling_thread_id in SSH1_KexDB.DB_PER_THREAD:
|
|
||||||
del SSH1_KexDB.DB_PER_THREAD[calling_thread_id]
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
"""
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
# pylint: disable=unused-import
|
|
||||||
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
|
|
||||||
from typing import Callable, Optional, Union, Any # noqa: F401
|
|
||||||
|
|
||||||
from ssh_audit.ssh1 import SSH1
|
|
||||||
from ssh_audit.readbuf import ReadBuf
|
|
||||||
from ssh_audit.utils import Utils
|
|
||||||
from ssh_audit.writebuf import WriteBuf
|
|
||||||
|
|
||||||
|
|
||||||
class SSH1_PublicKeyMessage:
|
|
||||||
def __init__(self, cookie: bytes, skey: Tuple[int, int, int], hkey: Tuple[int, int, int], pflags: int, cmask: int, amask: int) -> None:
|
|
||||||
if len(skey) != 3:
|
|
||||||
raise ValueError('invalid server key pair: {}'.format(skey))
|
|
||||||
if len(hkey) != 3:
|
|
||||||
raise ValueError('invalid host key pair: {}'.format(hkey))
|
|
||||||
self.__cookie = cookie
|
|
||||||
self.__server_key = skey
|
|
||||||
self.__host_key = hkey
|
|
||||||
self.__protocol_flags = pflags
|
|
||||||
self.__supported_ciphers_mask = cmask
|
|
||||||
self.__supported_authentications_mask = amask
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cookie(self) -> bytes:
|
|
||||||
return self.__cookie
|
|
||||||
|
|
||||||
@property
|
|
||||||
def server_key_bits(self) -> int:
|
|
||||||
return self.__server_key[0]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def server_key_public_exponent(self) -> int:
|
|
||||||
return self.__server_key[1]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def server_key_public_modulus(self) -> int:
|
|
||||||
return self.__server_key[2]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def host_key_bits(self) -> int:
|
|
||||||
return self.__host_key[0]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def host_key_public_exponent(self) -> int:
|
|
||||||
return self.__host_key[1]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def host_key_public_modulus(self) -> int:
|
|
||||||
return self.__host_key[2]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def host_key_fingerprint_data(self) -> bytes:
|
|
||||||
# pylint: disable=protected-access
|
|
||||||
mod = WriteBuf._create_mpint(self.host_key_public_modulus, False)
|
|
||||||
e = WriteBuf._create_mpint(self.host_key_public_exponent, False)
|
|
||||||
return mod + e
|
|
||||||
|
|
||||||
@property
|
|
||||||
def protocol_flags(self) -> int:
|
|
||||||
return self.__protocol_flags
|
|
||||||
|
|
||||||
@property
|
|
||||||
def supported_ciphers_mask(self) -> int:
|
|
||||||
return self.__supported_ciphers_mask
|
|
||||||
|
|
||||||
@property
|
|
||||||
def supported_ciphers(self) -> List[str]:
|
|
||||||
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
|
|
||||||
|
|
||||||
@property
|
|
||||||
def supported_authentications_mask(self) -> int:
|
|
||||||
return self.__supported_authentications_mask
|
|
||||||
|
|
||||||
@property
|
|
||||||
def supported_authentications(self) -> List[str]:
|
|
||||||
auths = []
|
|
||||||
for i in range(1, len(SSH1.AUTHS)):
|
|
||||||
if self.__supported_authentications_mask & (1 << i) != 0:
|
|
||||||
auths.append(Utils.to_text(SSH1.AUTHS[i]))
|
|
||||||
return auths
|
|
||||||
|
|
||||||
def write(self, wbuf: 'WriteBuf') -> None:
|
|
||||||
wbuf.write(self.cookie)
|
|
||||||
wbuf.write_int(self.server_key_bits)
|
|
||||||
wbuf.write_mpint1(self.server_key_public_exponent)
|
|
||||||
wbuf.write_mpint1(self.server_key_public_modulus)
|
|
||||||
wbuf.write_int(self.host_key_bits)
|
|
||||||
wbuf.write_mpint1(self.host_key_public_exponent)
|
|
||||||
wbuf.write_mpint1(self.host_key_public_modulus)
|
|
||||||
wbuf.write_int(self.protocol_flags)
|
|
||||||
wbuf.write_int(self.supported_ciphers_mask)
|
|
||||||
wbuf.write_int(self.supported_authentications_mask)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def payload(self) -> bytes:
|
|
||||||
wbuf = WriteBuf()
|
|
||||||
self.write(wbuf)
|
|
||||||
return wbuf.write_flush()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def parse(cls, payload: bytes) -> 'SSH1_PublicKeyMessage':
|
|
||||||
buf = ReadBuf(payload)
|
|
||||||
cookie = buf.read(8)
|
|
||||||
server_key_bits = buf.read_int()
|
|
||||||
server_key_exponent = buf.read_mpint1()
|
|
||||||
server_key_modulus = buf.read_mpint1()
|
|
||||||
skey = (server_key_bits, server_key_exponent, server_key_modulus)
|
|
||||||
host_key_bits = buf.read_int()
|
|
||||||
host_key_exponent = buf.read_mpint1()
|
|
||||||
host_key_modulus = buf.read_mpint1()
|
|
||||||
hkey = (host_key_bits, host_key_exponent, host_key_modulus)
|
|
||||||
pflags = buf.read_int()
|
|
||||||
cmask = buf.read_int()
|
|
||||||
amask = buf.read_int()
|
|
||||||
pkm = cls(cookie, skey, hkey, pflags, cmask, amask)
|
|
||||||
return pkm
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (C) 2017-2024 Joe Testa (jtesta@positronsecurity.com)
|
Copyright (C) 2017-2025 Joe Testa (jtesta@positronsecurity.com)
|
||||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@@ -57,6 +57,7 @@ class SSH2_KexDB: # pylint: disable=too-few-public-methods
|
|||||||
WARN_CIPHER_MODE = 'using weak cipher mode'
|
WARN_CIPHER_MODE = 'using weak cipher mode'
|
||||||
WARN_ENCRYPT_AND_MAC = 'using encrypt-and-MAC mode'
|
WARN_ENCRYPT_AND_MAC = 'using encrypt-and-MAC mode'
|
||||||
WARN_EXPERIMENTAL = 'using experimental algorithm'
|
WARN_EXPERIMENTAL = 'using experimental algorithm'
|
||||||
|
WARN_NOT_PQ_SAFE = 'does not provide protection against post-quantum attacks'
|
||||||
WARN_RNDSIG_KEY = 'using weak random number generator could reveal the key'
|
WARN_RNDSIG_KEY = 'using weak random number generator could reveal the key'
|
||||||
WARN_TAG_SIZE = 'using small 64-bit tag size'
|
WARN_TAG_SIZE = 'using small 64-bit tag size'
|
||||||
WARN_TAG_SIZE_96 = 'using small 96-bit tag size'
|
WARN_TAG_SIZE_96 = 'using small 96-bit tag size'
|
||||||
@@ -65,12 +66,14 @@ class SSH2_KexDB: # pylint: disable=too-few-public-methods
|
|||||||
INFO_DEFAULT_OPENSSH_KEX_65_TO_73 = 'default key exchange from OpenSSH 6.5 to 7.3'
|
INFO_DEFAULT_OPENSSH_KEX_65_TO_73 = 'default key exchange from OpenSSH 6.5 to 7.3'
|
||||||
INFO_DEFAULT_OPENSSH_KEX_74_TO_89 = 'default key exchange from OpenSSH 7.4 to 8.9'
|
INFO_DEFAULT_OPENSSH_KEX_74_TO_89 = 'default key exchange from OpenSSH 7.4 to 8.9'
|
||||||
INFO_DEFAULT_OPENSSH_KEX_90_TO_98 = 'default key exchange from OpenSSH 9.0 to 9.8'
|
INFO_DEFAULT_OPENSSH_KEX_90_TO_98 = 'default key exchange from OpenSSH 9.0 to 9.8'
|
||||||
INFO_DEFAULT_OPENSSH_KEX_99 = 'default key exchange since OpenSSH 9.9'
|
INFO_DEFAULT_OPENSSH_KEX_99 = 'default key exchange in OpenSSH 9.9'
|
||||||
|
INFO_DEFAULT_OPENSSH_KEX_100 = 'default key exchange since OpenSSH 10.0'
|
||||||
INFO_DEPRECATED_IN_OPENSSH88 = 'deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8'
|
INFO_DEPRECATED_IN_OPENSSH88 = 'deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8'
|
||||||
INFO_DISABLED_IN_DBEAR67 = 'disabled in Dropbear SSH 2015.67'
|
INFO_DISABLED_IN_DBEAR67 = 'disabled in Dropbear SSH 2015.67'
|
||||||
INFO_DISABLED_IN_OPENSSH70 = 'disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0'
|
INFO_DISABLED_IN_OPENSSH70 = 'disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0'
|
||||||
INFO_NEVER_IMPLEMENTED_IN_OPENSSH = 'despite the @openssh.com tag, this was never implemented in OpenSSH'
|
INFO_NEVER_IMPLEMENTED_IN_OPENSSH = 'despite the @openssh.com tag, this was never implemented in OpenSSH'
|
||||||
INFO_HYBRID_PQ_X25519_KEX = 'hybrid key exchange based on post-quantum resistant algorithm and proven conventional X25519 algorithm'
|
INFO_HYBRID_PQ_X25519_KEX = 'hybrid key exchange based on post-quantum resistant algorithm and proven conventional X25519 algorithm'
|
||||||
|
INFO_HYBRID_PQ_NISTP_KEX = 'hybrid key exchange based on post-quantum resistant algorithm and a suspected back-doored NIST P-curve'
|
||||||
INFO_REMOVED_IN_OPENSSH61 = 'removed since OpenSSH 6.1, removed from specification'
|
INFO_REMOVED_IN_OPENSSH61 = 'removed since OpenSSH 6.1, removed from specification'
|
||||||
INFO_REMOVED_IN_OPENSSH69 = 'removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9'
|
INFO_REMOVED_IN_OPENSSH69 = 'removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9'
|
||||||
INFO_REMOVED_IN_OPENSSH70 = 'removed in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0'
|
INFO_REMOVED_IN_OPENSSH70 = 'removed in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0'
|
||||||
@@ -84,117 +87,119 @@ class SSH2_KexDB: # pylint: disable=too-few-public-methods
|
|||||||
MASTER_DB: Dict[str, Dict[str, List[List[Optional[str]]]]] = {
|
MASTER_DB: Dict[str, Dict[str, List[List[Optional[str]]]]] = {
|
||||||
# Format: 'algorithm_name': [['version_first_appeared_in'], [reason_for_failure1, reason_for_failure2, ...], [warning1, warning2, ...], [info1, info2, ...]]
|
# Format: 'algorithm_name': [['version_first_appeared_in'], [reason_for_failure1, reason_for_failure2, ...], [warning1, warning2, ...], [info1, info2, ...]]
|
||||||
'kex': {
|
'kex': {
|
||||||
'Curve25519SHA256': [[]],
|
'Curve25519SHA256': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'curve25519-sha256': [['7.4,d2018.76'], [], [], [INFO_DEFAULT_OPENSSH_KEX_74_TO_89]],
|
'curve25519-sha256': [['7.4,d2018.76'], [], [WARN_NOT_PQ_SAFE], [INFO_DEFAULT_OPENSSH_KEX_74_TO_89]],
|
||||||
'curve25519-sha256@libssh.org': [['6.4,d2013.62,l10.6.0'], [], [], [INFO_DEFAULT_OPENSSH_KEX_65_TO_73]],
|
'curve25519-sha256@libssh.org': [['6.4,d2013.62,l10.6.0'], [], [WARN_NOT_PQ_SAFE], [INFO_DEFAULT_OPENSSH_KEX_65_TO_73]],
|
||||||
'curve448-sha512': [[]],
|
'curve448-sha512': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'curve448-sha512@libssh.org': [[]],
|
'curve448-sha512@libssh.org': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group14-sha1': [['3.9,d0.53,l10.6.0'], [FAIL_SHA1], [WARN_2048BIT_MODULUS]],
|
'diffie-hellman-group14-sha1': [['3.9,d0.53,l10.6.0'], [FAIL_SHA1], [WARN_2048BIT_MODULUS, WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group14-sha224@ssh.com': [[]],
|
'diffie-hellman-group14-sha224@ssh.com': [[], [], [WARN_2048BIT_MODULUS, WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group14-sha256': [['7.3,d2016.73'], [], [WARN_2048BIT_MODULUS]],
|
'diffie-hellman-group14-sha256': [['7.3,d2016.73'], [], [WARN_2048BIT_MODULUS, WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group14-sha256@ssh.com': [[], [], [WARN_2048BIT_MODULUS]],
|
'diffie-hellman-group14-sha256@ssh.com': [[], [], [WARN_2048BIT_MODULUS, WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group15-sha256': [[]],
|
'diffie-hellman-group15-sha256': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group15-sha256@ssh.com': [[]],
|
'diffie-hellman-group15-sha256@ssh.com': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group15-sha384@ssh.com': [[]],
|
'diffie-hellman-group15-sha384@ssh.com': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group15-sha512': [[]],
|
'diffie-hellman-group15-sha512': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group16-sha256': [[]],
|
'diffie-hellman-group16-sha256': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group16-sha384@ssh.com': [[]],
|
'diffie-hellman-group16-sha384@ssh.com': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group16-sha512': [['7.3,d2016.73']],
|
'diffie-hellman-group16-sha512': [['7.3,d2016.73'], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group16-sha512@ssh.com': [[]],
|
'diffie-hellman-group16-sha512@ssh.com': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group17-sha512': [[]],
|
'diffie-hellman-group17-sha512': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman_group17-sha512': [[]],
|
'diffie-hellman_group17-sha512': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group18-sha512': [['7.3']],
|
'diffie-hellman-group18-sha512': [['7.3'], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group18-sha512@ssh.com': [[]],
|
'diffie-hellman-group18-sha512@ssh.com': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group1-sha1': [['2.3.0,d0.28,l10.2', '6.6', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1], [], [INFO_REMOVED_IN_OPENSSH69]],
|
'diffie-hellman-group1-sha1': [['2.3.0,d0.28,l10.2', '6.6', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1], [WARN_NOT_PQ_SAFE], [INFO_REMOVED_IN_OPENSSH69]],
|
||||||
'diffie-hellman-group1-sha256': [[], [FAIL_1024BIT_MODULUS]],
|
'diffie-hellman-group1-sha256': [[], [FAIL_1024BIT_MODULUS], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group-exchange-sha1': [['2.3.0', '6.6', None], [FAIL_SHA1]],
|
'diffie-hellman-group-exchange-sha1': [['2.3.0', '6.6', None], [FAIL_SHA1], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group-exchange-sha224@ssh.com': [[]],
|
'diffie-hellman-group-exchange-sha224@ssh.com': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group-exchange-sha256': [['4.4']],
|
'diffie-hellman-group-exchange-sha256': [['4.4'], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group-exchange-sha256@ssh.com': [[]],
|
'diffie-hellman-group-exchange-sha256@ssh.com': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group-exchange-sha384@ssh.com': [[]],
|
'diffie-hellman-group-exchange-sha384@ssh.com': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'diffie-hellman-group-exchange-sha512@ssh.com': [[]],
|
'diffie-hellman-group-exchange-sha512@ssh.com': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
'ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
||||||
'ecdh-nistp384-kyber-768r3-sha384-d00@openquantumsafe.org': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
'ecdh-nistp384-kyber-768r3-sha384-d00@openquantumsafe.org': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
||||||
'ecdh-nistp521-kyber-1024r3-sha512-d00@openquantumsafe.org': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
'ecdh-nistp521-kyber-1024r3-sha512-d00@openquantumsafe.org': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
||||||
'ecdh-sha2-1.2.840.10045.3.1.1': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # NIST P-192 / secp192r1
|
'ecdh-sha2-1.2.840.10045.3.1.1': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]], # NIST P-192 / secp192r1
|
||||||
'ecdh-sha2-1.2.840.10045.3.1.7': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-256 / secp256r1
|
'ecdh-sha2-1.2.840.10045.3.1.7': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]], # NIST P-256 / secp256r1
|
||||||
'ecdh-sha2-1.3.132.0.10': [[]], # ECDH over secp256k1 (i.e.: the Bitcoin curve)
|
'ecdh-sha2-1.3.132.0.10': [[], [], [WARN_NOT_PQ_SAFE]], # ECDH over secp256k1 (i.e.: the Bitcoin curve)
|
||||||
'ecdh-sha2-1.3.132.0.16': [[], [FAIL_UNPROVEN]], # sect283k1
|
'ecdh-sha2-1.3.132.0.16': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]], # sect283k1
|
||||||
'ecdh-sha2-1.3.132.0.1': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]], # sect163k1
|
'ecdh-sha2-1.3.132.0.1': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_NOT_PQ_SAFE]], # sect163k1
|
||||||
'ecdh-sha2-1.3.132.0.26': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]], # sect233k1
|
'ecdh-sha2-1.3.132.0.26': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_NOT_PQ_SAFE]], # sect233k1
|
||||||
'ecdh-sha2-1.3.132.0.27': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # sect233r1
|
'ecdh-sha2-1.3.132.0.27': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]], # sect233r1
|
||||||
'ecdh-sha2-1.3.132.0.33': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # NIST P-224 / secp224r1
|
'ecdh-sha2-1.3.132.0.33': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]], # NIST P-224 / secp224r1
|
||||||
'ecdh-sha2-1.3.132.0.34': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-384 / secp384r1
|
'ecdh-sha2-1.3.132.0.34': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]], # NIST P-384 / secp384r1
|
||||||
'ecdh-sha2-1.3.132.0.35': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-521 / secp521r1
|
'ecdh-sha2-1.3.132.0.35': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]], # NIST P-521 / secp521r1
|
||||||
'ecdh-sha2-1.3.132.0.36': [[], [FAIL_UNPROVEN]], # sect409k1
|
'ecdh-sha2-1.3.132.0.36': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]], # sect409k1
|
||||||
'ecdh-sha2-1.3.132.0.37': [[], [FAIL_NSA_BACKDOORED_CURVE]], # sect409r1
|
'ecdh-sha2-1.3.132.0.37': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]], # sect409r1
|
||||||
'ecdh-sha2-1.3.132.0.38': [[], [FAIL_UNPROVEN]], # sect571k1
|
'ecdh-sha2-1.3.132.0.38': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]], # sect571k1
|
||||||
|
|
||||||
# Note: the base64 strings, according to draft 6 of RFC5656, is Base64(MD5(DER(OID))). The final RFC5656 dropped the base64 strings in favor of plain OID concatenation, but apparently some SSH servers implement them anyway. See: https://datatracker.ietf.org/doc/html/draft-green-secsh-ecc-06#section-9.2
|
# Note: the base64 strings, according to draft 6 of RFC5656, is Base64(MD5(DER(OID))). The final RFC5656 dropped the base64 strings in favor of plain OID concatenation, but apparently some SSH servers implement them anyway. See: https://datatracker.ietf.org/doc/html/draft-green-secsh-ecc-06#section-9.2
|
||||||
'ecdh-sha2-4MHB+NBt3AlaSRQ7MnB4cg==': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]], # sect163k1
|
'ecdh-sha2-4MHB+NBt3AlaSRQ7MnB4cg==': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_NOT_PQ_SAFE]], # sect163k1
|
||||||
'ecdh-sha2-5pPrSUQtIaTjUSt5VZNBjg==': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # NIST P-192 / secp192r1
|
'ecdh-sha2-5pPrSUQtIaTjUSt5VZNBjg==': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]], # NIST P-192 / secp192r1
|
||||||
'ecdh-sha2-9UzNcgwTlEnSCECZa7V1mw==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-256 / secp256r1
|
'ecdh-sha2-9UzNcgwTlEnSCECZa7V1mw==': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]], # NIST P-256 / secp256r1
|
||||||
'ecdh-sha2-brainpoolp256r1@genua.de': [[], [FAIL_UNPROVEN]],
|
'ecdh-sha2-brainpoolp256r1@genua.de': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-brainpoolp384r1@genua.de': [[], [FAIL_UNPROVEN]],
|
'ecdh-sha2-brainpoolp384r1@genua.de': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-brainpoolp521r1@genua.de': [[], [FAIL_UNPROVEN]],
|
'ecdh-sha2-brainpoolp521r1@genua.de': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-curve25519': [[], []],
|
'ecdh-sha2-curve25519': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-D3FefCjYoJ/kfXgAyLddYA==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # sect409r1
|
'ecdh-sha2-D3FefCjYoJ/kfXgAyLddYA==': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]], # sect409r1
|
||||||
'ecdh-sha2-h/SsxnLCtRBh7I9ATyeB3A==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-521 / secp521r1
|
'ecdh-sha2-h/SsxnLCtRBh7I9ATyeB3A==': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]], # NIST P-521 / secp521r1
|
||||||
'ecdh-sha2-m/FtSAmrV4j/Wy6RVUaK7A==': [[], [FAIL_UNPROVEN]], # sect409k1
|
'ecdh-sha2-m/FtSAmrV4j/Wy6RVUaK7A==': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]], # sect409k1
|
||||||
'ecdh-sha2-mNVwCXAoS1HGmHpLvBC94w==': [[], [FAIL_UNPROVEN]], # sect571k1
|
'ecdh-sha2-mNVwCXAoS1HGmHpLvBC94w==': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]], # sect571k1
|
||||||
'ecdh-sha2-nistb233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]],
|
'ecdh-sha2-nistb233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-nistb409': [[], [FAIL_UNPROVEN]],
|
'ecdh-sha2-nistb409': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-nistk163': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]],
|
'ecdh-sha2-nistk163': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-nistk233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]],
|
'ecdh-sha2-nistk233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-nistk283': [[], [FAIL_UNPROVEN]],
|
'ecdh-sha2-nistk283': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-nistk409': [[], [FAIL_UNPROVEN]],
|
'ecdh-sha2-nistk409': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-nistp192': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
'ecdh-sha2-nistp192': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-nistp224': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
'ecdh-sha2-nistp224': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-nistp256': [['5.7,d2013.62,l10.6.0'], [FAIL_NSA_BACKDOORED_CURVE]],
|
'ecdh-sha2-nistp256': [['5.7,d2013.62,l10.6.0'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-nistp384': [['5.7,d2013.62'], [FAIL_NSA_BACKDOORED_CURVE]],
|
'ecdh-sha2-nistp384': [['5.7,d2013.62'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-nistp521': [['5.7,d2013.62'], [FAIL_NSA_BACKDOORED_CURVE]],
|
'ecdh-sha2-nistp521': [['5.7,d2013.62'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-nistt571': [[], [FAIL_UNPROVEN]],
|
'ecdh-sha2-nistt571': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]],
|
||||||
'ecdh-sha2-qCbG5Cn/jjsZ7nBeR7EnOA==': [[FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # sect233r1
|
'ecdh-sha2-qCbG5Cn/jjsZ7nBeR7EnOA==': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]], # sect233r1
|
||||||
'ecdh-sha2-qcFQaMAMGhTziMT0z+Tuzw==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-384 / secp384r1
|
'ecdh-sha2-qcFQaMAMGhTziMT0z+Tuzw==': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]], # NIST P-384 / secp384r1
|
||||||
'ecdh-sha2-VqBg4QRPjxx1EXZdV0GdWQ==': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_SMALL_ECC_MODULUS]], # NIST P-224 / secp224r1
|
'ecdh-sha2-VqBg4QRPjxx1EXZdV0GdWQ==': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_SMALL_ECC_MODULUS], [WARN_NOT_PQ_SAFE]], # NIST P-224 / secp224r1
|
||||||
'ecdh-sha2-wiRIU8TKjMZ418sMqlqtvQ==': [[], [FAIL_UNPROVEN]], # sect283k1
|
'ecdh-sha2-wiRIU8TKjMZ418sMqlqtvQ==': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]], # sect283k1
|
||||||
'ecdh-sha2-zD/b3hu/71952ArpUG4OjQ==': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]], # sect233k1
|
'ecdh-sha2-zD/b3hu/71952ArpUG4OjQ==': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_NOT_PQ_SAFE]], # sect233k1
|
||||||
'ecmqv-sha2': [[], [FAIL_UNPROVEN]],
|
'ecmqv-sha2': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]],
|
||||||
'ext-info-c': [['7.2'], [], [], [INFO_EXTENSION_NEGOTIATION]], # Extension negotiation (RFC 8308)
|
'ext-info-c': [['7.2'], [], [], [INFO_EXTENSION_NEGOTIATION]], # Extension negotiation (RFC 8308)
|
||||||
'ext-info-s': [['9.6'], [], [], [INFO_EXTENSION_NEGOTIATION]], # Extension negotiation (RFC 8308)
|
'ext-info-s': [['9.6'], [], [], [INFO_EXTENSION_NEGOTIATION]], # Extension negotiation (RFC 8308)
|
||||||
'kex-strict-c-v00@openssh.com': [[], [], [], [INFO_STRICT_KEX]], # Strict KEX marker (countermeasure for CVE-2023-48795).
|
'kex-strict-c-v00@openssh.com': [[], [], [], [INFO_STRICT_KEX]], # Strict KEX marker (countermeasure for CVE-2023-48795).
|
||||||
'kex-strict-s-v00@openssh.com': [[], [], [], [INFO_STRICT_KEX]], # Strict KEX marker (countermeasure for CVE-2023-48795).
|
'kex-strict-s-v00@openssh.com': [[], [], [], [INFO_STRICT_KEX]], # Strict KEX marker (countermeasure for CVE-2023-48795).
|
||||||
|
|
||||||
# The GSS kex algorithms get special wildcard handling, since they include variable base64 data after their standard prefixes.
|
# The GSS kex algorithms get special wildcard handling, since they include variable base64 data after their standard prefixes.
|
||||||
'gss-13.3.132.0.10-sha256-*': [[], [FAIL_UNKNOWN]],
|
'gss-13.3.132.0.10-sha256-*': [[], [FAIL_UNKNOWN], [WARN_NOT_PQ_SAFE]],
|
||||||
'gss-curve25519-sha256-*': [[]],
|
'gss-curve25519-sha256-*': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'gss-curve448-sha512-*': [[]],
|
'gss-curve448-sha512-*': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'gss-gex-sha1-*': [[], [FAIL_SHA1]],
|
'gss-gex-sha1-*': [[], [FAIL_SHA1], [WARN_NOT_PQ_SAFE]],
|
||||||
'gss-gex-sha256-*': [[]],
|
'gss-gex-sha256-*': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'gss-group14-sha1-*': [[], [FAIL_SHA1], [WARN_2048BIT_MODULUS]],
|
'gss-group14-sha1-*': [[], [FAIL_SHA1], [WARN_2048BIT_MODULUS, WARN_NOT_PQ_SAFE]],
|
||||||
'gss-group14-sha256-*': [[], [], [WARN_2048BIT_MODULUS]],
|
'gss-group14-sha256-*': [[], [], [WARN_2048BIT_MODULUS, WARN_NOT_PQ_SAFE]],
|
||||||
'gss-group15-sha512-*': [[]],
|
'gss-group15-sha512-*': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'gss-group16-sha512-*': [[]],
|
'gss-group16-sha512-*': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'gss-group17-sha512-*': [[]],
|
'gss-group17-sha512-*': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'gss-group18-sha512-*': [[]],
|
'gss-group18-sha512-*': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'gss-group1-sha1-*': [[], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1]],
|
'gss-group1-sha1-*': [[], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1], [WARN_NOT_PQ_SAFE]],
|
||||||
'gss-nistp256-sha256-*': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
'gss-nistp256-sha256-*': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]],
|
||||||
'gss-nistp384-sha256-*': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
'gss-nistp384-sha256-*': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]],
|
||||||
'gss-nistp384-sha384-*': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
'gss-nistp384-sha384-*': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]],
|
||||||
'gss-nistp521-sha512-*': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
'gss-nistp521-sha512-*': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]],
|
||||||
'kexAlgoCurve25519SHA256': [[]],
|
'kexAlgoCurve25519SHA256': [[], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'kexAlgoDH14SHA1': [[], [FAIL_SHA1], [WARN_2048BIT_MODULUS]],
|
'kexAlgoDH14SHA1': [[], [FAIL_SHA1], [WARN_2048BIT_MODULUS, WARN_NOT_PQ_SAFE]],
|
||||||
'kexAlgoDH1SHA1': [[], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1]],
|
'kexAlgoDH1SHA1': [[], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1], [WARN_NOT_PQ_SAFE]],
|
||||||
'kexAlgoECDH256': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
'kexAlgoECDH256': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]],
|
||||||
'kexAlgoECDH384': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
'kexAlgoECDH384': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]],
|
||||||
'kexAlgoECDH521': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
'kexAlgoECDH521': [[], [FAIL_NSA_BACKDOORED_CURVE], [WARN_NOT_PQ_SAFE]],
|
||||||
'kexguess2@matt.ucc.asn.au': [['d2013.57']],
|
'kexguess2@matt.ucc.asn.au': [['d2013.57'], [], [WARN_NOT_PQ_SAFE]],
|
||||||
'm383-sha384@libassh.org': [[], [FAIL_UNPROVEN]],
|
'm383-sha384@libassh.org': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]],
|
||||||
'm511-sha512@libassh.org': [[], [FAIL_UNPROVEN]],
|
'm511-sha512@libassh.org': [[], [FAIL_UNPROVEN], [WARN_NOT_PQ_SAFE]],
|
||||||
'mlkem768x25519-sha256': [['9.9'], [], [], [INFO_HYBRID_PQ_X25519_KEX]],
|
'mlkem768x25519-sha256': [['9.9'], [], [], [INFO_DEFAULT_OPENSSH_KEX_100, INFO_HYBRID_PQ_X25519_KEX]],
|
||||||
'rsa1024-sha1': [[], [FAIL_1024BIT_MODULUS, FAIL_SHA1]],
|
'mlkem768nistp256-sha256': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [INFO_HYBRID_PQ_NISTP_KEX]],
|
||||||
'rsa2048-sha256': [[], [], [WARN_2048BIT_MODULUS]],
|
'mlkem1024nistp384-sha384': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [INFO_HYBRID_PQ_NISTP_KEX]],
|
||||||
'sm2kep-sha2-nistp256': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_UNTRUSTED]],
|
'rsa1024-sha1': [[], [FAIL_1024BIT_MODULUS, FAIL_SHA1], [WARN_NOT_PQ_SAFE]],
|
||||||
|
'rsa2048-sha256': [[], [], [WARN_2048BIT_MODULUS, WARN_NOT_PQ_SAFE]],
|
||||||
|
'sm2kep-sha2-nistp256': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_UNTRUSTED], [WARN_NOT_PQ_SAFE]],
|
||||||
'sntrup4591761x25519-sha512@tinyssh.org': [['8.0', '8.4'], [], [WARN_EXPERIMENTAL], [INFO_WITHDRAWN_PQ_ALG]],
|
'sntrup4591761x25519-sha512@tinyssh.org': [['8.0', '8.4'], [], [WARN_EXPERIMENTAL], [INFO_WITHDRAWN_PQ_ALG]],
|
||||||
'sntrup761x25519-sha512': [['9.9'], [], [], [INFO_DEFAULT_OPENSSH_KEX_99, INFO_HYBRID_PQ_X25519_KEX]],
|
'sntrup761x25519-sha512': [['9.9'], [], [], [INFO_DEFAULT_OPENSSH_KEX_99, INFO_HYBRID_PQ_X25519_KEX]],
|
||||||
'sntrup761x25519-sha512@openssh.com': [['8.5'], [], [], [INFO_DEFAULT_OPENSSH_KEX_90_TO_98, INFO_HYBRID_PQ_X25519_KEX]],
|
'sntrup761x25519-sha512@openssh.com': [['8.5'], [], [], [INFO_DEFAULT_OPENSSH_KEX_90_TO_98, INFO_HYBRID_PQ_X25519_KEX]],
|
||||||
@@ -297,6 +302,8 @@ class SSH2_KexDB: # pylint: disable=too-few-public-methods
|
|||||||
'3des-ofb': [[], [FAIL_3DES], [WARN_CIPHER_MODE]],
|
'3des-ofb': [[], [FAIL_3DES], [WARN_CIPHER_MODE]],
|
||||||
'AEAD_AES_128_GCM': [[]],
|
'AEAD_AES_128_GCM': [[]],
|
||||||
'AEAD_AES_256_GCM': [[]],
|
'AEAD_AES_256_GCM': [[]],
|
||||||
|
'AEAD_CAMELLIA_128_GCM': [[]],
|
||||||
|
'AEAD_CAMELLIA_256_GCM': [[]],
|
||||||
'aes128-cbc': [['2.3.0,d0.28,l10.2', '6.6', None], [], [WARN_CIPHER_MODE]],
|
'aes128-cbc': [['2.3.0,d0.28,l10.2', '6.6', None], [], [WARN_CIPHER_MODE]],
|
||||||
'aes128-ctr': [['3.7,d0.52,l10.4.1']],
|
'aes128-ctr': [['3.7,d0.52,l10.4.1']],
|
||||||
'aes128-gcm': [[]],
|
'aes128-gcm': [[]],
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"""
|
"""
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (C) 2017-2024 Joe Testa (jtesta@positronsecurity.com)
|
Copyright (C) 2017-2025 Joe Testa (jtesta@positronsecurity.com)
|
||||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@@ -23,9 +23,9 @@
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
"""
|
"""
|
||||||
|
import argparse
|
||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
import copy
|
import copy
|
||||||
import getopt # pylint: disable=deprecated-module
|
|
||||||
import json
|
import json
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
@@ -33,6 +33,7 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=unused-import
|
# pylint: disable=unused-import
|
||||||
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
|
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
|
||||||
from typing import cast, Callable, Optional, Union, Any # noqa: F401
|
from typing import cast, Callable, Optional, Union, Any # noqa: F401
|
||||||
@@ -52,11 +53,10 @@ from ssh_audit.gextest import GEXTest
|
|||||||
from ssh_audit.hostkeytest import HostKeyTest
|
from ssh_audit.hostkeytest import HostKeyTest
|
||||||
from ssh_audit.outputbuffer import OutputBuffer
|
from ssh_audit.outputbuffer import OutputBuffer
|
||||||
from ssh_audit.policy import Policy
|
from ssh_audit.policy import Policy
|
||||||
|
from ssh_audit.hardening_guides import Hardening_Guides
|
||||||
from ssh_audit.product import Product
|
from ssh_audit.product import Product
|
||||||
from ssh_audit.protocol import Protocol
|
from ssh_audit.protocol import Protocol
|
||||||
from ssh_audit.software import Software
|
from ssh_audit.software import Software
|
||||||
from ssh_audit.ssh1_kexdb import SSH1_KexDB
|
|
||||||
from ssh_audit.ssh1_publickeymessage import SSH1_PublicKeyMessage
|
|
||||||
from ssh_audit.ssh2_kex import SSH2_Kex
|
from ssh_audit.ssh2_kex import SSH2_Kex
|
||||||
from ssh_audit.ssh2_kexdb import SSH2_KexDB
|
from ssh_audit.ssh2_kexdb import SSH2_KexDB
|
||||||
from ssh_audit.ssh_socket import SSH_Socket
|
from ssh_audit.ssh_socket import SSH_Socket
|
||||||
@@ -82,61 +82,6 @@ if sys.platform == 'win32':
|
|||||||
# no_idna_workaround = True
|
# no_idna_workaround = True
|
||||||
|
|
||||||
|
|
||||||
def usage(uout: OutputBuffer, err: Optional[str] = None) -> None:
|
|
||||||
retval = exitcodes.GOOD
|
|
||||||
p = os.path.basename(sys.argv[0])
|
|
||||||
uout.head('# {} {}, https://github.com/jtesta/ssh-audit\n'.format(p, VERSION))
|
|
||||||
if err is not None and len(err) > 0:
|
|
||||||
uout.fail(err + '\n')
|
|
||||||
retval = exitcodes.UNKNOWN_ERROR
|
|
||||||
uout.info('usage: {0} [options] <host>\n'.format(p))
|
|
||||||
uout.info(' -h, --help print this help')
|
|
||||||
uout.info(' -1, --ssh1 force ssh version 1 only')
|
|
||||||
uout.info(' -2, --ssh2 force ssh version 2 only')
|
|
||||||
uout.info(' -4, --ipv4 enable IPv4 (order of precedence)')
|
|
||||||
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(' --conn-rate-test=N[:max_rate] perform a connection rate test (useful')
|
|
||||||
uout.info(' for collecting metrics related to')
|
|
||||||
uout.info(' susceptibility of the DHEat vuln).')
|
|
||||||
uout.info(' Testing is conducted with N concurrent')
|
|
||||||
uout.info(' sockets with an optional maximum rate')
|
|
||||||
uout.info(' of connections per second.')
|
|
||||||
uout.info(' -d, --debug debug output')
|
|
||||||
uout.info(' --dheat=N[:kex[:e_len]] continuously perform the DHEat DoS attack')
|
|
||||||
uout.info(' (CVE-2002-20001) against the target using N')
|
|
||||||
uout.info(' concurrent sockets. Optionally, a specific')
|
|
||||||
uout.info(' key exchange algorithm can be specified')
|
|
||||||
uout.info(' instead of allowing it to be automatically')
|
|
||||||
uout.info(' chosen. Additionally, a small length of')
|
|
||||||
uout.info(' the fake e value sent to the server can')
|
|
||||||
uout.info(' be chosen for a more efficient attack (such')
|
|
||||||
uout.info(' as 4).')
|
|
||||||
uout.info(' -g, --gex-test=<x[,y,...]> dh gex modulus size test')
|
|
||||||
uout.info(' <min1:pref1:max1[,min2:pref2:max2,...]>')
|
|
||||||
uout.info(' <x-y[:step]>')
|
|
||||||
uout.info(' -j, --json JSON output (use -jj to enable indents)')
|
|
||||||
uout.info(' -l, --level=<level> minimum output level (info|warn|fail)')
|
|
||||||
uout.info(' -L, --list-policies list all the official, built-in policies. Use with -v')
|
|
||||||
uout.info(' to view policy change logs.')
|
|
||||||
uout.info(' --lookup=<alg1,alg2,...> looks up an algorithm(s) without\n connecting to a server')
|
|
||||||
uout.info(' -M, --make-policy=<policy.txt> creates a policy based on the target server\n (i.e.: the target server has the ideal\n configuration that other servers should\n adhere to)')
|
|
||||||
uout.info(' -m, --manual print the man page (Windows only)')
|
|
||||||
uout.info(' -n, --no-colors disable colors (automatic when the NO_COLOR')
|
|
||||||
uout.info(' environment variable is set)')
|
|
||||||
uout.info(' -p, --port=<port> port to connect')
|
|
||||||
uout.info(' -P, --policy=<policy.txt> run a policy test using the specified policy')
|
|
||||||
uout.info(' --skip-rate-test skip the connection rate test during standard audits\n (used to safely infer whether the DHEat attack\n is viable)')
|
|
||||||
uout.info(' -t, --timeout=<secs> timeout (in seconds) for connection and reading\n (default: 5)')
|
|
||||||
uout.info(' -T, --targets=<hosts.txt> a file containing a list of target hosts (one\n per line, format HOST[:PORT]). Use -p/--port\n to set the default port for all hosts. Use\n --threads to control concurrent scans.')
|
|
||||||
uout.info(' --threads=<threads> number of threads to use when scanning multiple\n targets (-T/--targets) (default: 32)')
|
|
||||||
uout.info(' -v, --verbose verbose output')
|
|
||||||
uout.sep()
|
|
||||||
uout.write()
|
|
||||||
sys.exit(retval)
|
|
||||||
|
|
||||||
|
|
||||||
def output_algorithms(out: OutputBuffer, title: str, alg_db: Dict[str, Dict[str, List[List[Optional[str]]]]], alg_type: str, algorithms: List[str], unknown_algs: List[str], is_json_output: bool, program_retval: int, maxlen: int = 0, host_keys: Optional[Dict[str, Dict[str, Union[bytes, str, int]]]] = None, dh_modulus_sizes: Optional[Dict[str, int]] = None) -> int: # pylint: disable=too-many-arguments
|
def output_algorithms(out: OutputBuffer, title: str, alg_db: Dict[str, Dict[str, List[List[Optional[str]]]]], alg_type: str, algorithms: List[str], unknown_algs: List[str], is_json_output: bool, program_retval: int, maxlen: int = 0, host_keys: Optional[Dict[str, Dict[str, Union[bytes, str, int]]]] = None, dh_modulus_sizes: Optional[Dict[str, int]] = None) -> int: # pylint: disable=too-many-arguments
|
||||||
with out:
|
with out:
|
||||||
for algorithm in algorithms:
|
for algorithm in algorithms:
|
||||||
@@ -288,11 +233,6 @@ def output_security(out: OutputBuffer, banner: Optional[Banner], padlen: int, is
|
|||||||
def output_fingerprints(out: OutputBuffer, algs: Algorithms, is_json_output: bool) -> None:
|
def output_fingerprints(out: OutputBuffer, algs: Algorithms, is_json_output: bool) -> None:
|
||||||
with out:
|
with out:
|
||||||
fps = {}
|
fps = {}
|
||||||
if algs.ssh1kex is not None:
|
|
||||||
name = 'ssh-rsa1'
|
|
||||||
fp = Fingerprint(algs.ssh1kex.host_key_fingerprint_data)
|
|
||||||
# bits = algs.ssh1kex.host_key_bits
|
|
||||||
fps[name] = fp
|
|
||||||
if algs.ssh2kex is not None:
|
if algs.ssh2kex is not None:
|
||||||
host_keys = algs.ssh2kex.host_keys()
|
host_keys = algs.ssh2kex.host_keys()
|
||||||
for host_key_type in algs.ssh2kex.host_keys():
|
for host_key_type in algs.ssh2kex.host_keys():
|
||||||
@@ -371,7 +311,7 @@ def output_recommendations(out: OutputBuffer, algs: Algorithms, algorithm_recomm
|
|||||||
notes = " (%s)" % notes
|
notes = " (%s)" % notes
|
||||||
|
|
||||||
fm = '(rec) {0}{1}{2}-- {3} algorithm to {4}{5} '
|
fm = '(rec) {0}{1}{2}-- {3} algorithm to {4}{5} '
|
||||||
fn(fm.format(sg, name, p, alg_type, an, notes))
|
fn(fm.format(sg, name, p, alg_type, an, notes)) # type: ignore[operator]
|
||||||
|
|
||||||
if not out.is_section_empty() and not is_json_output:
|
if not out.is_section_empty() and not is_json_output:
|
||||||
if software is not None:
|
if software is not None:
|
||||||
@@ -393,7 +333,7 @@ def output_info(out: OutputBuffer, software: Optional['Software'], client_audit:
|
|||||||
|
|
||||||
# If any warnings or failures were given, print a link to the hardening guides.
|
# If any warnings or failures were given, print a link to the hardening guides.
|
||||||
if any_problems:
|
if any_problems:
|
||||||
out.warn('(nfo) For hardening guides on common OSes, please see: <https://www.ssh-audit.com/hardening_guides.html>')
|
out.warn('(nfo) For hardening guides on common OSes, a built-in list can be viewed with --list-hardening-guides, or an online list can be found at: <https://www.ssh-audit.com/hardening_guides.html>')
|
||||||
|
|
||||||
# Add any additional notes.
|
# Add any additional notes.
|
||||||
for additional_note in additional_notes:
|
for additional_note in additional_notes:
|
||||||
@@ -563,12 +503,11 @@ def post_process_findings(banner: Optional[Banner], algs: Algorithms, client_aud
|
|||||||
|
|
||||||
|
|
||||||
# Returns a exitcodes.* flag to denote if any failures or warnings were encountered.
|
# Returns a exitcodes.* flag to denote if any failures or warnings were encountered.
|
||||||
def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header: List[str], client_host: Optional[str] = None, kex: Optional[SSH2_Kex] = None, pkm: Optional[SSH1_PublicKeyMessage] = None, print_target: bool = False, dh_rate_test_notes: str = "") -> int:
|
def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header: List[str], client_host: Optional[str] = None, kex: Optional[SSH2_Kex] = None, print_target: bool = False, dh_rate_test_notes: str = "") -> int:
|
||||||
|
|
||||||
program_retval = exitcodes.GOOD
|
program_retval = exitcodes.GOOD
|
||||||
client_audit = client_host is not None # If set, this is a client audit.
|
client_audit = client_host is not None # If set, this is a client audit.
|
||||||
sshv = 1 if pkm is not None else 2
|
algs = Algorithms(kex)
|
||||||
algs = Algorithms(pkm, kex)
|
|
||||||
|
|
||||||
# Perform post-processing on the findings to make final adjustments before outputting the results.
|
# Perform post-processing on the findings to make final adjustments before outputting the results.
|
||||||
algorithm_recommendation_suppress_list, additional_notes = post_process_findings(banner, algs, client_audit, dh_rate_test_notes)
|
algorithm_recommendation_suppress_list, additional_notes = post_process_findings(banner, algs, client_audit, dh_rate_test_notes)
|
||||||
@@ -586,14 +525,14 @@ def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header
|
|||||||
else:
|
else:
|
||||||
host = '%s:%d' % (aconf.host, aconf.port)
|
host = '%s:%d' % (aconf.host, aconf.port)
|
||||||
|
|
||||||
out.good('(gen) target: {}'. format(host))
|
out.good('(gen) target: {}'. format(host), always_print=True)
|
||||||
if client_audit:
|
if client_audit:
|
||||||
out.good('(gen) client IP: {}'.format(client_host))
|
out.good('(gen) client IP: {}'.format(client_host), always_print=True)
|
||||||
if len(header) > 0:
|
if len(header) > 0:
|
||||||
out.info('(gen) header: ' + '\n'.join(header))
|
out.info('(gen) header: ' + '\n'.join(header))
|
||||||
if banner is not None:
|
if banner is not None:
|
||||||
banner_line = '(gen) banner: {}'.format(banner)
|
banner_line = '(gen) banner: {}'.format(banner)
|
||||||
if sshv == 1 or banner.protocol[0] == 1:
|
if banner.protocol[0] == 1:
|
||||||
out.fail(banner_line)
|
out.fail(banner_line)
|
||||||
out.fail('(gen) protocol SSH1 enabled')
|
out.fail('(gen) protocol SSH1 enabled')
|
||||||
else:
|
else:
|
||||||
@@ -625,18 +564,6 @@ def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header
|
|||||||
# Filled in by output_algorithms() with unidentified algs.
|
# Filled in by output_algorithms() with unidentified algs.
|
||||||
unknown_algorithms: List[str] = []
|
unknown_algorithms: List[str] = []
|
||||||
|
|
||||||
# SSHv1
|
|
||||||
if pkm is not None:
|
|
||||||
adb = SSH1_KexDB.get_db()
|
|
||||||
ciphers = pkm.supported_ciphers
|
|
||||||
auths = pkm.supported_authentications
|
|
||||||
title, atype = 'SSH1 host-key algorithms', 'key'
|
|
||||||
program_retval = output_algorithms(out, title, adb, atype, ['ssh-rsa1'], unknown_algorithms, aconf.json, program_retval, maxlen)
|
|
||||||
title, atype = 'SSH1 encryption algorithms (ciphers)', 'enc'
|
|
||||||
program_retval = output_algorithms(out, title, adb, atype, ciphers, unknown_algorithms, aconf.json, program_retval, maxlen)
|
|
||||||
title, atype = 'SSH1 authentication types', 'aut'
|
|
||||||
program_retval = output_algorithms(out, title, adb, atype, auths, unknown_algorithms, aconf.json, program_retval, maxlen)
|
|
||||||
|
|
||||||
# SSHv2
|
# SSHv2
|
||||||
if kex is not None:
|
if kex is not None:
|
||||||
adb = SSH2_KexDB.get_db()
|
adb = SSH2_KexDB.get_db()
|
||||||
@@ -823,7 +750,7 @@ def make_policy(aconf: AuditConf, banner: Optional['Banner'], kex: Optional['SSH
|
|||||||
print(err)
|
print(err)
|
||||||
|
|
||||||
|
|
||||||
def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[..., None]) -> 'AuditConf': # pylint: disable=too-many-statements
|
def process_commandline(out: OutputBuffer, args: List[str]) -> 'AuditConf': # pylint: disable=too-many-statements
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
aconf = AuditConf()
|
aconf = AuditConf()
|
||||||
|
|
||||||
@@ -836,82 +763,90 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
|
|||||||
aconf.colors = enable_colors
|
aconf.colors = enable_colors
|
||||||
out.use_colors = enable_colors
|
out.use_colors = enable_colors
|
||||||
|
|
||||||
try:
|
|
||||||
sopts = 'h1246M:p:P:jbcnvl:t:T:Lmdg:'
|
|
||||||
lopts = ['help', 'ssh1', 'ssh2', 'ipv4', 'ipv6', 'make-policy=', 'port=', 'policy=', 'json', 'batch', 'client-audit', 'no-colors', 'verbose', 'level=', 'timeout=', 'targets=', 'list-policies', 'lookup=', 'threads=', 'manual', 'debug', 'gex-test=', 'dheat=', 'skip-rate-test', 'conn-rate-test=']
|
|
||||||
opts, args = getopt.gnu_getopt(args, sopts, lopts)
|
|
||||||
except getopt.GetoptError as err:
|
|
||||||
usage_cb(out, str(err))
|
|
||||||
aconf.ssh1, aconf.ssh2 = False, False
|
|
||||||
host: str = ''
|
host: str = ''
|
||||||
oport: Optional[str] = None
|
port: int = 22
|
||||||
port: int = 0
|
|
||||||
for o, a in opts:
|
|
||||||
if o in ('-h', '--help'):
|
|
||||||
usage_cb(out)
|
|
||||||
elif o in ('-1', '--ssh1'):
|
|
||||||
aconf.ssh1 = True
|
|
||||||
elif o in ('-2', '--ssh2'):
|
|
||||||
aconf.ssh2 = True
|
|
||||||
elif o in ('-4', '--ipv4'):
|
|
||||||
aconf.ipv4 = True
|
|
||||||
elif o in ('-6', '--ipv6'):
|
|
||||||
aconf.ipv6 = True
|
|
||||||
elif o in ('-p', '--port'):
|
|
||||||
oport = a
|
|
||||||
elif o in ('-b', '--batch'):
|
|
||||||
aconf.batch = True
|
|
||||||
aconf.verbose = True
|
|
||||||
elif o in ('-c', '--client-audit'):
|
|
||||||
aconf.client_audit = True
|
|
||||||
elif o in ('-j', '--json'):
|
|
||||||
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
|
|
||||||
elif o in ('-l', '--level'):
|
|
||||||
if a not in ('info', 'warn', 'fail'):
|
|
||||||
usage_cb(out, 'level {} is not valid'.format(a))
|
|
||||||
aconf.level = a
|
|
||||||
elif o in ('-t', '--timeout'):
|
|
||||||
aconf.timeout = float(a)
|
|
||||||
aconf.timeout_set = True
|
|
||||||
elif o in ('-M', '--make-policy'):
|
|
||||||
aconf.make_policy = True
|
|
||||||
aconf.policy_file = a
|
|
||||||
elif o in ('-P', '--policy'):
|
|
||||||
aconf.policy_file = a
|
|
||||||
elif o in ('-T', '--targets'):
|
|
||||||
aconf.target_file = a
|
|
||||||
|
|
||||||
# If we're on Windows, and we can't use the idna workaround, force only one thread to be used (otherwise a crash would occur).
|
parser = argparse.ArgumentParser(description="# {} {}, https://github.com/jtesta/ssh-audit".format(os.path.basename(sys.argv[0]), VERSION), allow_abbrev=False)
|
||||||
# if no_idna_workaround:
|
|
||||||
# print("\nWARNING: the idna module was not found on this system, thus only single-threaded scanning will be done (this is a workaround for this Windows-specific crash: https://github.com/python/cpython/issues/73474). Multi-threaded scanning can be enabled by installing the idna module (pip install idna).\n")
|
# Add short options to the parser
|
||||||
# aconf.threads = 1
|
parser.add_argument("-4", "--ipv4", action="store_true", dest="ipv4", default=False, help="enable IPv4 (order of precedence)")
|
||||||
elif o == '--threads':
|
parser.add_argument("-6", "--ipv6", action="store_true", dest="ipv6", default=False, help="enable IPv6 (order of precedence)")
|
||||||
aconf.threads = int(a)
|
parser.add_argument("-b", "--batch", action="store_true", dest="batch", default=False, help="batch output")
|
||||||
# if no_idna_workaround:
|
parser.add_argument("-c", "--client-audit", action="store_true", dest="client_audit", default=False, help="starts a server on port 2222 to audit client software config (use -p to change port; use -t to change timeout)")
|
||||||
# aconf.threads = 1
|
parser.add_argument("-d", "--debug", action="store_true", dest="debug", default=False, help="enable debugging output")
|
||||||
elif o in ('-L', '--list-policies'):
|
parser.add_argument("-g", "--gex-test", action="store", dest="gex_test", metavar="<min1:pref1:max1[,min2:pref2:max2,...]> / <x-y[:step]>", type=str, default=None, help="conducts a very customized Diffie-Hellman GEX modulus size test. Tests an array of minimum, preferred, and maximum values, or a range of values with an optional incremental step amount")
|
||||||
aconf.list_policies = True
|
parser.add_argument("-j", "--json", action="count", dest="json", default=0, help="enable JSON output (use -jj to enable indentation for better readability)")
|
||||||
elif o == '--lookup':
|
parser.add_argument("-l", "--level", action="store", dest="level", type=str, choices=["info", "warn", "fail"], default="info", help="minimum output level (default: %(default)s)")
|
||||||
aconf.lookup = a
|
parser.add_argument("-L", "--list-policies", action="store_true", dest="list_policies", default=False, help="list all the official, built-in policies. Combine with -v to view policy change logs")
|
||||||
elif o in ('-m', '--manual'):
|
parser.add_argument("-M", "--make-policy", action="store", dest="make_policy", metavar="custom_policy.txt", type=str, default=None, help="creates a policy based on the target server (i.e.: the target server has the ideal configuration that other servers should adhere to), and stores it in the file path specified")
|
||||||
aconf.manual = True
|
parser.add_argument("-m", "--manual", action="store_true", dest="manual", default=False, help="print the man page (Docker, PyPI, Snap, and Windows builds only)")
|
||||||
elif o in ('-d', '--debug'):
|
parser.add_argument("-n", "--no-colors", action="store_true", dest="no_colors", default=False, help="disable colors (automatic when the NO_COLOR environment variable is set)")
|
||||||
|
parser.add_argument("-P", "--policy", action="store", dest="policy", metavar="\"Built-In Policy Name\" / custom_policy.txt", type=str, default=None, help="run a policy test using the specified policy (use -L to see built-in policies, or specify filesystem path to custom policy created by -M)")
|
||||||
|
parser.add_argument("-p", "--port", action="store", dest="oport", metavar="N", type=int, default=None, help="the TCP port to connect to (or to listen on when -c is used)")
|
||||||
|
parser.add_argument("-T", "--targets", action="store", dest="targets", metavar="targets.txt", type=str, default=None, help="a file containing a list of target hosts (one per line, format HOST[:PORT]). Use -p/--port to set the default port for all hosts. Use --threads to control concurrent scans")
|
||||||
|
parser.add_argument("-t", "--timeout", action="store", dest="timeout", metavar="N", type=int, default=5, help="timeout (in seconds) for connection and reading (default: %(default)s)")
|
||||||
|
parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False, help="enable verbose output")
|
||||||
|
|
||||||
|
# Add long options to the parser
|
||||||
|
parser.add_argument("--conn-rate-test", action="store", dest="conn_rate_test", metavar="N[:max_rate]", type=str, default=None, help="perform a connection rate test (useful for collecting metrics related to susceptibility of the DHEat vuln). Testing is conducted with N concurrent sockets with an optional maximum rate of connections per second")
|
||||||
|
parser.add_argument("--dheat", action="store", dest="dheat", metavar="N[:kex[:e_len]]", type=str, default=None, help="continuously perform the DHEat DoS attack (CVE-2002-20001) against the target using N concurrent sockets. Optionally, a specific key exchange algorithm can be specified instead of allowing it to be automatically chosen. Additionally, a small length of the fake e value sent to the server can be chosen for a more efficient attack (such as 4).")
|
||||||
|
parser.add_argument("--get-hardening-guide", action="store", metavar="platform", dest="get_hardening_guide", type=str, default=None, help="retrieves the hardening guide for the specified platform name (use --list-hardening-guides to see list of available guides).")
|
||||||
|
parser.add_argument("--list-hardening-guides", action="store_true", dest="list_hardening_guides", default=False, help="list all official, built-in hardening guides for common systems. Their full names can then be passed to --get-hardening-guide. Add -v to this option to view hardening guide change logs and prior versions.")
|
||||||
|
parser.add_argument("--lookup", action="store", dest="lookup", metavar="alg1[,alg2,...]", type=str, default=None, help="looks up an algorithm(s) without connecting to a server.")
|
||||||
|
parser.add_argument("--skip-rate-test", action="store_true", dest="skip_rate_test", default=False, help="skip the connection rate test during standard audits (used to safely infer whether the DHEat attack is viable)")
|
||||||
|
parser.add_argument("--threads", action="store", dest="threads", metavar="N", type=int, default=32, help="number of threads to use when scanning multiple targets (-T/--targets) (default: %(default)s)")
|
||||||
|
|
||||||
|
|
||||||
|
# The mandatory target option. Or rather, mandatory when -L, -T, --lookup or --print-config are not used.
|
||||||
|
parser.add_argument("host", nargs="?", action="store", type=str, default="", help="target hostname or IPv4/IPv6 address")
|
||||||
|
|
||||||
|
# If no arguments were given, print the help and exit.
|
||||||
|
if len(args) < 1:
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
|
||||||
|
oport: Optional[int] = None
|
||||||
|
try:
|
||||||
|
argument = parser.parse_args(args=args)
|
||||||
|
|
||||||
|
# Set simple flags.
|
||||||
|
aconf.client_audit = argument.client_audit
|
||||||
|
aconf.ipv4 = argument.ipv4
|
||||||
|
aconf.ipv6 = argument.ipv6
|
||||||
|
aconf.level = argument.level
|
||||||
|
aconf.list_policies = argument.list_policies
|
||||||
|
aconf.manual = argument.manual
|
||||||
|
aconf.skip_rate_test = argument.skip_rate_test
|
||||||
|
oport = argument.oport
|
||||||
|
|
||||||
|
if argument.batch is True:
|
||||||
|
aconf.batch = True
|
||||||
|
|
||||||
|
# If one -j was given, turn on JSON output. If -jj was given, enable indentation.
|
||||||
|
aconf.json = argument.json > 0
|
||||||
|
if argument.json > 1:
|
||||||
|
aconf.json_print_indent = True
|
||||||
|
|
||||||
|
if argument.conn_rate_test is not None:
|
||||||
|
aconf.conn_rate_test = argument.conn_rate_test
|
||||||
|
|
||||||
|
if argument.debug is True:
|
||||||
aconf.debug = True
|
aconf.debug = True
|
||||||
out.debug = True
|
out.debug = True
|
||||||
elif o in ('-g', '--gex-test'):
|
|
||||||
|
if argument.dheat is not None:
|
||||||
|
aconf.dheat = argument.dheat
|
||||||
|
|
||||||
|
if argument.gex_test is not None:
|
||||||
|
dh_gex = argument.gex_test
|
||||||
permitted_syntax = get_permitted_syntax_for_gex_test()
|
permitted_syntax = get_permitted_syntax_for_gex_test()
|
||||||
|
|
||||||
if not any(re.search(regex_str, a) for regex_str in permitted_syntax.values()):
|
if not any(re.search(regex_str, dh_gex) for regex_str in permitted_syntax.values()):
|
||||||
usage_cb(out, '{} {} is not valid'.format(o, a))
|
out.fail('{} is not valid'.format(dh_gex), write_now=True)
|
||||||
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
|
||||||
if re.search(permitted_syntax['RANGE'], a):
|
if re.search(permitted_syntax['RANGE'], dh_gex):
|
||||||
extracted_digits = re.findall(r'\d+', a)
|
extracted_digits = re.findall(r'\d+', dh_gex)
|
||||||
bits_left_bound = int(extracted_digits[0])
|
bits_left_bound = int(extracted_digits[0])
|
||||||
bits_right_bound = int(extracted_digits[1])
|
bits_right_bound = int(extracted_digits[1])
|
||||||
|
|
||||||
@@ -920,56 +855,87 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
|
|||||||
bits_step = int(extracted_digits[2])
|
bits_step = int(extracted_digits[2])
|
||||||
|
|
||||||
if bits_step <= 0:
|
if bits_step <= 0:
|
||||||
usage_cb(out, '{} {} is not valid'.format(o, bits_step))
|
out.fail('the step field cannot be 0 or less: {}'.format(bits_step), write_now=True)
|
||||||
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
|
||||||
if all(x < 0 for x in (bits_left_bound, bits_right_bound)):
|
if all(x < 0 for x in (bits_left_bound, bits_right_bound)):
|
||||||
usage_cb(out, '{} {} {} is not valid'.format(o, bits_left_bound, bits_right_bound))
|
out.fail('{} {} {} is not valid'.format(dh_gex, bits_left_bound, bits_right_bound), write_now=True)
|
||||||
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
|
||||||
aconf.gex_test = a
|
aconf.gex_test = dh_gex
|
||||||
elif o == '--dheat':
|
|
||||||
aconf.dheat = a
|
|
||||||
elif o == '--skip-rate-test':
|
|
||||||
aconf.skip_rate_test = True
|
|
||||||
elif o == '--conn-rate-test':
|
|
||||||
aconf.conn_rate_test = a
|
|
||||||
|
|
||||||
|
if argument.lookup is not None:
|
||||||
|
aconf.lookup = argument.lookup
|
||||||
|
|
||||||
if len(args) == 0 and aconf.client_audit is False and aconf.target_file is None and aconf.list_policies is False and aconf.lookup == '' and aconf.manual is False:
|
if argument.make_policy is not None:
|
||||||
usage_cb(out)
|
aconf.make_policy = True
|
||||||
|
aconf.policy_file = argument.make_policy
|
||||||
|
|
||||||
|
if argument.policy is not None:
|
||||||
|
aconf.policy_file = argument.policy
|
||||||
|
|
||||||
|
if argument.targets is not None:
|
||||||
|
aconf.target_file = argument.targets
|
||||||
|
|
||||||
|
if argument.threads is not None:
|
||||||
|
aconf.threads = argument.threads
|
||||||
|
|
||||||
|
if argument.timeout is not None:
|
||||||
|
aconf.timeout = float(argument.timeout)
|
||||||
|
aconf.timeout_set = True
|
||||||
|
|
||||||
|
if argument.verbose is True:
|
||||||
|
aconf.verbose = True
|
||||||
|
out.verbose = True
|
||||||
|
|
||||||
|
except argparse.ArgumentError as err:
|
||||||
|
out.fail(str(err), write_now=True)
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
|
||||||
|
if argument.host == "" and argument.client_audit is False and argument.targets is None and argument.list_policies is False and argument.lookup is None and argument.manual is False and argument.list_hardening_guides is False and argument.get_hardening_guide is None:
|
||||||
|
out.fail("target host must be specified, unless -c, -m, -L, -T, --lookup or --list-hardening-guides are used", write_now=True)
|
||||||
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
|
||||||
if aconf.manual:
|
if aconf.manual:
|
||||||
return aconf
|
return aconf
|
||||||
|
|
||||||
if aconf.lookup != '':
|
if aconf.lookup != "":
|
||||||
return aconf
|
return aconf
|
||||||
|
|
||||||
if aconf.list_policies:
|
if aconf.list_policies:
|
||||||
list_policies(out, aconf.verbose)
|
list_policies(out, aconf.verbose)
|
||||||
sys.exit(exitcodes.GOOD)
|
sys.exit(exitcodes.GOOD)
|
||||||
|
|
||||||
|
# Print a list of the hardening guides, or the specific guide requested by the user.
|
||||||
|
if argument.list_hardening_guides is True:
|
||||||
|
Hardening_Guides.list_guides(out, aconf.verbose)
|
||||||
|
sys.exit(exitcodes.GOOD)
|
||||||
|
elif argument.get_hardening_guide is not None:
|
||||||
|
Hardening_Guides.print_hardening_guide(out, argument.get_hardening_guide)
|
||||||
|
sys.exit(exitcodes.GOOD)
|
||||||
|
|
||||||
if aconf.client_audit is False and aconf.target_file is None:
|
if aconf.client_audit is False and aconf.target_file is None:
|
||||||
if oport is not None:
|
if oport is not None:
|
||||||
host = args[0]
|
host = argument.host
|
||||||
else:
|
else:
|
||||||
host, port = Utils.parse_host_and_port(args[0])
|
host, port = Utils.parse_host_and_port(argument.host)
|
||||||
if not host and aconf.target_file is None:
|
|
||||||
usage_cb(out, 'host is empty')
|
|
||||||
|
|
||||||
if port == 0 and oport is None:
|
if not host and aconf.target_file is None:
|
||||||
if aconf.client_audit: # The default port to listen on during a client audit is 2222.
|
out.fail("target host is not specified", write_now=True)
|
||||||
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
|
||||||
|
if oport is None and aconf.client_audit: # The default port to listen on during a client audit is 2222.
|
||||||
port = 2222
|
port = 2222
|
||||||
else:
|
|
||||||
port = 22
|
|
||||||
|
|
||||||
if oport is not None:
|
if oport is not None:
|
||||||
port = Utils.parse_int(oport)
|
port = Utils.parse_int(oport)
|
||||||
if port <= 0 or port > 65535:
|
if port < 1 or port > 65535:
|
||||||
usage_cb(out, 'port {} is not valid'.format(oport))
|
out.fail("port must be greater than 0 and less than 65535: {}".format(oport), write_now=True)
|
||||||
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
|
||||||
aconf.host = host
|
aconf.host = host
|
||||||
aconf.port = port
|
aconf.port = port
|
||||||
if not (aconf.ssh1 or aconf.ssh2):
|
|
||||||
aconf.ssh1, aconf.ssh2 = True, True
|
|
||||||
|
|
||||||
# If a file containing a list of targets was given, read it.
|
# If a file containing a list of targets was given, read it.
|
||||||
if aconf.target_file is not None:
|
if aconf.target_file is not None:
|
||||||
@@ -996,26 +962,23 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
|
|||||||
try:
|
try:
|
||||||
aconf.policy = Policy(policy_file=aconf.policy_file, json_output=aconf.json)
|
aconf.policy = Policy(policy_file=aconf.policy_file, json_output=aconf.json)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
out.fail("Error while loading policy file: %s: %s" % (str(e), traceback.format_exc()))
|
out.fail("Error while loading policy file: %s: %s" % (str(e), traceback.format_exc()), write_now=True)
|
||||||
out.write()
|
|
||||||
sys.exit(exitcodes.UNKNOWN_ERROR)
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
|
||||||
# If the user wants to do a client audit, but provided a server policy, terminate.
|
# If the user wants to do a client audit, but provided a server policy, terminate.
|
||||||
if aconf.client_audit and aconf.policy.is_server_policy():
|
if aconf.client_audit and aconf.policy.is_server_policy():
|
||||||
out.fail("Error: client audit selected, but server policy provided.")
|
out.fail("Error: client audit selected, but server policy provided.", write_now=True)
|
||||||
out.write()
|
|
||||||
sys.exit(exitcodes.UNKNOWN_ERROR)
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
|
||||||
# If the user wants to do a server audit, but provided a client policy, terminate.
|
# If the user wants to do a server audit, but provided a client policy, terminate.
|
||||||
if aconf.client_audit is False and aconf.policy.is_server_policy() is False:
|
if aconf.client_audit is False and aconf.policy.is_server_policy() is False:
|
||||||
out.fail("Error: server audit selected, but client policy provided.")
|
out.fail("Error: server audit selected, but client policy provided.", write_now=True)
|
||||||
out.write()
|
|
||||||
sys.exit(exitcodes.UNKNOWN_ERROR)
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
|
||||||
return aconf
|
return aconf
|
||||||
|
|
||||||
|
|
||||||
def build_struct(target_host: str, banner: Optional['Banner'], kex: Optional['SSH2_Kex'] = None, pkm: Optional['SSH1_PublicKeyMessage'] = None, client_host: Optional[str] = None, software: Optional[Software] = None, algorithms: Optional[Algorithms] = None, algorithm_recommendation_suppress_list: Optional[List[str]] = None, additional_notes: List[str] = []) -> Any: # pylint: disable=dangerous-default-value
|
def build_struct(target_host: str, banner: Optional['Banner'], kex: Optional['SSH2_Kex'] = None, client_host: Optional[str] = None, software: Optional[Software] = None, algorithms: Optional[Algorithms] = None, algorithm_recommendation_suppress_list: Optional[List[str]] = None, additional_notes: List[str] = []) -> Any: # pylint: disable=dangerous-default-value
|
||||||
|
|
||||||
def fetch_notes(algorithm: str, alg_type: str) -> Dict[str, List[Optional[str]]]:
|
def fetch_notes(algorithm: str, alg_type: str) -> Dict[str, List[Optional[str]]]:
|
||||||
'''Returns a dictionary containing the messages in the "fail", "warn", and "info" levels for this algorithm.'''
|
'''Returns a dictionary containing the messages in the "fail", "warn", and "info" levels for this algorithm.'''
|
||||||
@@ -1160,22 +1123,6 @@ def build_struct(target_host: str, banner: Optional['Banner'], kex: Optional['SS
|
|||||||
'hash_alg': 'MD5',
|
'hash_alg': 'MD5',
|
||||||
'hash': fp.md5[4:]
|
'hash': fp.md5[4:]
|
||||||
})
|
})
|
||||||
else:
|
|
||||||
pkm_supported_ciphers = None
|
|
||||||
pkm_supported_authentications = None
|
|
||||||
pkm_fp = None
|
|
||||||
if pkm is not None:
|
|
||||||
pkm_supported_ciphers = pkm.supported_ciphers
|
|
||||||
pkm_supported_authentications = pkm.supported_authentications
|
|
||||||
pkm_fp = Fingerprint(pkm.host_key_fingerprint_data).sha256
|
|
||||||
|
|
||||||
res['key'] = ['ssh-rsa1']
|
|
||||||
res['enc'] = pkm_supported_ciphers
|
|
||||||
res['aut'] = pkm_supported_authentications
|
|
||||||
res['fingerprints'] = [{
|
|
||||||
'type': 'ssh-rsa1',
|
|
||||||
'fp': pkm_fp,
|
|
||||||
}]
|
|
||||||
|
|
||||||
# Historically, CVE information was returned. Now we'll just return an empty dictionary so as to not break any legacy clients.
|
# Historically, CVE information was returned. Now we'll just return an empty dictionary so as to not break any legacy clients.
|
||||||
res['cves'] = []
|
res['cves'] = []
|
||||||
@@ -1190,7 +1137,7 @@ def build_struct(target_host: str, banner: Optional['Banner'], kex: Optional['SS
|
|||||||
|
|
||||||
|
|
||||||
# Returns one of the exitcodes.* flags.
|
# Returns one of the exitcodes.* flags.
|
||||||
def audit(out: OutputBuffer, aconf: AuditConf, sshv: Optional[int] = None, print_target: bool = False) -> int:
|
def audit(out: OutputBuffer, aconf: AuditConf, print_target: bool = False) -> int:
|
||||||
program_retval = exitcodes.GOOD
|
program_retval = exitcodes.GOOD
|
||||||
out.batch = aconf.batch
|
out.batch = aconf.batch
|
||||||
out.verbose = aconf.verbose
|
out.verbose = aconf.verbose
|
||||||
@@ -1216,10 +1163,8 @@ def audit(out: OutputBuffer, aconf: AuditConf, sshv: Optional[int] = None, print
|
|||||||
out.write()
|
out.write()
|
||||||
sys.exit(exitcodes.CONNECTION_ERROR)
|
sys.exit(exitcodes.CONNECTION_ERROR)
|
||||||
|
|
||||||
if sshv is None:
|
|
||||||
sshv = 2 if aconf.ssh2 else 1
|
|
||||||
err = None
|
err = None
|
||||||
banner, header, err = s.get_banner(sshv)
|
banner, header, err = s.get_banner()
|
||||||
if banner is None:
|
if banner is None:
|
||||||
if err is None:
|
if err is None:
|
||||||
err = '[exception] did not receive banner.'
|
err = '[exception] did not receive banner.'
|
||||||
@@ -1228,7 +1173,7 @@ def audit(out: OutputBuffer, aconf: AuditConf, sshv: Optional[int] = None, print
|
|||||||
if err is None:
|
if err is None:
|
||||||
s.send_kexinit() # Send the algorithms we support (except we don't since this isn't a real SSH connection).
|
s.send_kexinit() # Send the algorithms we support (except we don't since this isn't a real SSH connection).
|
||||||
|
|
||||||
packet_type, payload = s.read_packet(sshv)
|
packet_type, payload = s.read_packet()
|
||||||
if packet_type < 0:
|
if packet_type < 0:
|
||||||
try:
|
try:
|
||||||
if len(payload) > 0:
|
if len(payload) > 0:
|
||||||
@@ -1237,17 +1182,10 @@ def audit(out: OutputBuffer, aconf: AuditConf, sshv: Optional[int] = None, print
|
|||||||
payload_txt = 'empty'
|
payload_txt = 'empty'
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
payload_txt = '"{}"'.format(repr(payload).lstrip('b')[1:-1])
|
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()
|
|
||||||
return ret
|
|
||||||
err = '[exception] error reading packet ({})'.format(payload_txt)
|
err = '[exception] error reading packet ({})'.format(payload_txt)
|
||||||
else:
|
else:
|
||||||
err_pair = None
|
err_pair = None
|
||||||
if sshv == 1 and packet_type != Protocol.SMSG_PUBLIC_KEY:
|
if packet_type != Protocol.MSG_KEXINIT:
|
||||||
err_pair = ('SMSG_PUBLIC_KEY', Protocol.SMSG_PUBLIC_KEY)
|
|
||||||
elif sshv == 2 and packet_type != Protocol.MSG_KEXINIT:
|
|
||||||
err_pair = ('MSG_KEXINIT', Protocol.MSG_KEXINIT)
|
err_pair = ('MSG_KEXINIT', Protocol.MSG_KEXINIT)
|
||||||
if err_pair is not None:
|
if err_pair is not None:
|
||||||
fmt = '[exception] did not receive {0} ({1}), ' + \
|
fmt = '[exception] did not receive {0} ({1}), ' + \
|
||||||
@@ -1257,9 +1195,7 @@ def audit(out: OutputBuffer, aconf: AuditConf, sshv: Optional[int] = None, print
|
|||||||
output(out, aconf, banner, header)
|
output(out, aconf, banner, header)
|
||||||
out.fail(err)
|
out.fail(err)
|
||||||
return exitcodes.CONNECTION_ERROR
|
return exitcodes.CONNECTION_ERROR
|
||||||
if sshv == 1:
|
|
||||||
program_retval = output(out, aconf, banner, header, pkm=SSH1_PublicKeyMessage.parse(payload))
|
|
||||||
elif sshv == 2:
|
|
||||||
try:
|
try:
|
||||||
kex = SSH2_Kex.parse(out, payload)
|
kex = SSH2_Kex.parse(out, payload)
|
||||||
out.d(str(kex))
|
out.d(str(kex))
|
||||||
@@ -1499,7 +1435,7 @@ def run_gex_granular_modulus_size_test(out: OutputBuffer, s: 'SSH_Socket', kex:
|
|||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
out = OutputBuffer()
|
out = OutputBuffer()
|
||||||
aconf = process_commandline(out, sys.argv[1:], usage)
|
aconf = process_commandline(out, sys.argv[1:])
|
||||||
|
|
||||||
# If we're on Windows, but the colorama module could not be imported, print a warning if we're in verbose mode.
|
# If we're on Windows, but the colorama module could not be imported, print a warning if we're in verbose mode.
|
||||||
if (sys.platform == 'win32') and ('colorama' not in sys.modules):
|
if (sys.platform == 'win32') and ('colorama' not in sys.modules):
|
||||||
@@ -1569,7 +1505,6 @@ def main() -> int:
|
|||||||
print(']')
|
print(']')
|
||||||
|
|
||||||
# Send notification that this thread is exiting. This deletes the thread's local copy of the algorithm databases.
|
# Send notification that this thread is exiting. This deletes the thread's local copy of the algorithm databases.
|
||||||
SSH1_KexDB.thread_exit()
|
|
||||||
SSH2_KexDB.thread_exit()
|
SSH2_KexDB.thread_exit()
|
||||||
|
|
||||||
else: # Just a scan against a single target.
|
else: # Just a scan against a single target.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (C) 2017-2021 Joe Testa (jtesta@positronsecurity.com)
|
Copyright (C) 2017-2025 Joe Testa (jtesta@positronsecurity.com)
|
||||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@@ -39,7 +39,6 @@ from ssh_audit.globals import SSH_HEADER
|
|||||||
from ssh_audit.outputbuffer import OutputBuffer
|
from ssh_audit.outputbuffer import OutputBuffer
|
||||||
from ssh_audit.protocol import Protocol
|
from ssh_audit.protocol import Protocol
|
||||||
from ssh_audit.readbuf import ReadBuf
|
from ssh_audit.readbuf import ReadBuf
|
||||||
from ssh_audit.ssh1 import SSH1
|
|
||||||
from ssh_audit.ssh2_kex import SSH2_Kex
|
from ssh_audit.ssh2_kex import SSH2_Kex
|
||||||
from ssh_audit.ssh2_kexparty import SSH2_KexParty
|
from ssh_audit.ssh2_kexparty import SSH2_KexParty
|
||||||
from ssh_audit.utils import Utils
|
from ssh_audit.utils import Utils
|
||||||
@@ -173,7 +172,7 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
|||||||
errm = 'cannot connect to {} port {}: {}'.format(*errt)
|
errm = 'cannot connect to {} port {}: {}'.format(*errt)
|
||||||
return '[exception] {}'.format(errm)
|
return '[exception] {}'.format(errm)
|
||||||
|
|
||||||
def get_banner(self, sshv: int = 2) -> Tuple[Optional['Banner'], List[str], Optional[str]]:
|
def get_banner(self) -> Tuple[Optional['Banner'], List[str], Optional[str]]:
|
||||||
self.__outputbuffer.d('Getting banner...', write_now=True)
|
self.__outputbuffer.d('Getting banner...', write_now=True)
|
||||||
|
|
||||||
if self.__sock is None:
|
if self.__sock is None:
|
||||||
@@ -181,7 +180,7 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
|||||||
if self.__banner is not None:
|
if self.__banner is not None:
|
||||||
return self.__banner, self.__header, None
|
return self.__banner, self.__header, None
|
||||||
|
|
||||||
banner = SSH_HEADER.format('1.5' if sshv == 1 else '2.0')
|
banner = SSH_HEADER.format('2.0')
|
||||||
if self.__state < self.SM_BANNER_SENT:
|
if self.__state < self.SM_BANNER_SENT:
|
||||||
self.send_banner(banner)
|
self.send_banner(banner)
|
||||||
|
|
||||||
@@ -254,21 +253,13 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
|||||||
if s < 0:
|
if s < 0:
|
||||||
raise SSH_Socket.InsufficientReadException(e)
|
raise SSH_Socket.InsufficientReadException(e)
|
||||||
|
|
||||||
def read_packet(self, sshv: int = 2) -> Tuple[int, bytes]:
|
def read_packet(self) -> Tuple[int, bytes]:
|
||||||
try:
|
try:
|
||||||
header = WriteBuf()
|
header = WriteBuf()
|
||||||
self.ensure_read(4)
|
self.ensure_read(4)
|
||||||
packet_length = self.read_int()
|
packet_length = self.read_int()
|
||||||
header.write_int(packet_length)
|
header.write_int(packet_length)
|
||||||
# XXX: validate length
|
# XXX: validate length
|
||||||
if sshv == 1:
|
|
||||||
padding_length = 8 - packet_length % 8
|
|
||||||
self.ensure_read(padding_length)
|
|
||||||
padding = self.read(padding_length)
|
|
||||||
header.write(padding)
|
|
||||||
payload_length = packet_length
|
|
||||||
check_size = padding_length + payload_length
|
|
||||||
else:
|
|
||||||
self.ensure_read(1)
|
self.ensure_read(1)
|
||||||
padding_length = self.read_byte()
|
padding_length = self.read_byte()
|
||||||
header.write_byte(padding_length)
|
header.write_byte(padding_length)
|
||||||
@@ -278,23 +269,11 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
|||||||
self.__outputbuffer.fail('[exception] invalid ssh packet (block size)').write()
|
self.__outputbuffer.fail('[exception] invalid ssh packet (block size)').write()
|
||||||
sys.exit(exitcodes.CONNECTION_ERROR)
|
sys.exit(exitcodes.CONNECTION_ERROR)
|
||||||
self.ensure_read(payload_length)
|
self.ensure_read(payload_length)
|
||||||
if sshv == 1:
|
|
||||||
payload = self.read(payload_length - 4)
|
|
||||||
header.write(payload)
|
|
||||||
crc = self.read_int()
|
|
||||||
header.write_int(crc)
|
|
||||||
else:
|
|
||||||
payload = self.read(payload_length)
|
payload = self.read(payload_length)
|
||||||
header.write(payload)
|
header.write(payload)
|
||||||
packet_type = ord(payload[0:1])
|
packet_type = ord(payload[0:1])
|
||||||
if sshv == 1:
|
|
||||||
rcrc = SSH1.crc32(padding + payload)
|
|
||||||
if crc != rcrc:
|
|
||||||
self.__outputbuffer.fail('[exception] packet checksum CRC32 mismatch.').write()
|
|
||||||
sys.exit(exitcodes.CONNECTION_ERROR)
|
|
||||||
else:
|
|
||||||
self.ensure_read(padding_length)
|
self.ensure_read(padding_length)
|
||||||
padding = self.read(padding_length)
|
_ = self.read(padding_length)
|
||||||
payload = payload[1:]
|
payload = payload[1:]
|
||||||
return packet_type, payload
|
return packet_type, payload
|
||||||
except SSH_Socket.InsufficientReadException as ex:
|
except SSH_Socket.InsufficientReadException as ex:
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ class Utils:
|
|||||||
return -1.0
|
return -1.0
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_host_and_port(host_and_port: str, default_port: int = 0) -> Tuple[str, int]:
|
def parse_host_and_port(host_and_port: str, default_port: int = 22) -> Tuple[str, int]:
|
||||||
'''Parses a string into a tuple of its host and port. The port is 0 if not specified.'''
|
'''Parses a string into a tuple of its host and port. The port is 0 if not specified.'''
|
||||||
host = host_and_port
|
host = host_and_port
|
||||||
port = default_port
|
port = default_port
|
||||||
|
|||||||
24
ssh-audit.1
24
ssh-audit.1
@@ -1,4 +1,4 @@
|
|||||||
.TH SSH-AUDIT 1 "September 24, 2024"
|
.TH SSH-AUDIT 1 "August 17, 2025"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
\fBssh-audit\fP \- SSH server & client configuration auditor
|
\fBssh-audit\fP \- SSH server & client configuration auditor
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@@ -16,16 +16,6 @@ See <https://www.ssh\-audit.com/> for official hardening guides for common platf
|
|||||||
.br
|
.br
|
||||||
Print short summary of options.
|
Print short summary of options.
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -1, \-\-ssh1
|
|
||||||
.br
|
|
||||||
Only perform an audit using SSH protocol version 1.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -2, \-\-ssh2
|
|
||||||
.br
|
|
||||||
Only perform an audit using SSH protocol version 2.
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B -4, \-\-ipv4
|
.B -4, \-\-ipv4
|
||||||
.br
|
.br
|
||||||
@@ -61,6 +51,11 @@ Enable debug output.
|
|||||||
.br
|
.br
|
||||||
Run the DHEat DoS attack (CVE-2002-20001) against the target server (which will consume all available CPU resources). The number of concurrent sockets, N, needed to achieve this effect will be highly dependent on the CPU resources available on the target, as well as the latency between the source and target machines. The key exchange is automatically chosen based on which would cause maximum effect, unless explicitly chosen in the second field. Lastly, an (experimental) option allows the length in bytes of the fake e value sent to the server to be specified in the third field. Normally, the length of e is roughly the length of the modulus of the Diffie-Hellman exchange (hence, an 8192-bit / 1024-byte value of e is sent in each connection when targeting the diffie-hellman-group18-sha512 algorithm). Instead, it was observed that many SSH implementations accept small values, such as 4 bytes; this results in a much more network-efficient attack.
|
Run the DHEat DoS attack (CVE-2002-20001) against the target server (which will consume all available CPU resources). The number of concurrent sockets, N, needed to achieve this effect will be highly dependent on the CPU resources available on the target, as well as the latency between the source and target machines. The key exchange is automatically chosen based on which would cause maximum effect, unless explicitly chosen in the second field. Lastly, an (experimental) option allows the length in bytes of the fake e value sent to the server to be specified in the third field. Normally, the length of e is roughly the length of the modulus of the Diffie-Hellman exchange (hence, an 8192-bit / 1024-byte value of e is sent in each connection when targeting the diffie-hellman-group18-sha512 algorithm). Instead, it was observed that many SSH implementations accept small values, such as 4 bytes; this results in a much more network-efficient attack.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B \-\-get\-hardening\-guide=<platform_name>
|
||||||
|
.br
|
||||||
|
Retrieves the hardening guide for the specified platform name (use \-\-list\-hardening\-guides to see list of available guides).
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B -g, \-\-gex-test=<x[,y,...] | min1:pref1:max1[,min2:pref2:max2,...] | x-y[:step]>
|
.B -g, \-\-gex-test=<x[,y,...] | min1:pref1:max1[,min2:pref2:max2,...] | x-y[:step]>
|
||||||
.br
|
.br
|
||||||
@@ -101,10 +96,15 @@ Output results in JSON format. Specify twice (-jj) to enable indent printing (u
|
|||||||
.br
|
.br
|
||||||
Specify the minimum output level. Default is info.
|
Specify the minimum output level. Default is info.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B \-\-list-hardening-guides
|
||||||
|
.br
|
||||||
|
List all official, built-in hardening guides for common systems. Their full names can then be passed to \-\-get\-hardening\-guide. Add \-v to this option to view hardening guide change logs and prior versions.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B -L, \-\-list-policies
|
.B -L, \-\-list-policies
|
||||||
.br
|
.br
|
||||||
List all official, built-in policies for common systems. Their full names can then be passed to -P/--policy. Add \-v to \-L to view policy change logs.
|
List all official, built-in policies for common systems. Their full names can then be passed to \-P/\-\-policy. Add \-v to \-L to view policy change logs.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B \-\-lookup=<alg1,alg2,...>
|
.B \-\-lookup=<alg1,alg2,...>
|
||||||
|
|||||||
@@ -116,6 +116,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"default key exchange from OpenSSH 7.4 to 8.9",
|
"default key exchange from OpenSSH 7.4 to 8.9",
|
||||||
"available since OpenSSH 7.4, Dropbear SSH 2018.76"
|
"available since OpenSSH 7.4, Dropbear SSH 2018.76"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -125,6 +128,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"default key exchange from OpenSSH 6.5 to 7.3",
|
"default key exchange from OpenSSH 6.5 to 7.3",
|
||||||
"available since OpenSSH 6.4, Dropbear SSH 2013.62"
|
"available since OpenSSH 6.4, Dropbear SSH 2013.62"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -136,6 +142,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -147,6 +156,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -158,6 +170,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -168,7 +183,8 @@
|
|||||||
"available since OpenSSH 7.3, Dropbear SSH 2016.73"
|
"available since OpenSSH 7.3, Dropbear SSH 2016.73"
|
||||||
],
|
],
|
||||||
"warn": [
|
"warn": [
|
||||||
"2048-bit modulus only provides 112-bits of symmetric strength"
|
"2048-bit modulus only provides 112-bits of symmetric strength",
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -182,7 +198,8 @@
|
|||||||
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
||||||
],
|
],
|
||||||
"warn": [
|
"warn": [
|
||||||
"2048-bit modulus only provides 112-bits of symmetric strength"
|
"2048-bit modulus only provides 112-bits of symmetric strength",
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -191,6 +208,9 @@
|
|||||||
"notes": {
|
"notes": {
|
||||||
"info": [
|
"info": [
|
||||||
"available since Dropbear SSH 2013.57"
|
"available since Dropbear SSH 2013.57"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -349,12 +369,6 @@
|
|||||||
"name": "twofish256-ctr",
|
"name": "twofish256-ctr",
|
||||||
"notes": ""
|
"notes": ""
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"kex": [
|
|
||||||
{
|
|
||||||
"name": "diffie-hellman-group16-sha512",
|
|
||||||
"notes": ""
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -371,9 +385,21 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"kex": [
|
"kex": [
|
||||||
|
{
|
||||||
|
"name": "curve25519-sha256",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "curve25519-sha256@libssh.org",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "diffie-hellman-group14-sha256",
|
"name": "diffie-hellman-group14-sha256",
|
||||||
"notes": ""
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "kexguess2@matt.ucc.asn.au",
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"mac": [
|
"mac": [
|
||||||
|
|||||||
@@ -5,22 +5,30 @@
|
|||||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||||
|
|
||||||
[0;36m# key exchange algorithms[0m
|
[0;36m# key exchange algorithms[0m
|
||||||
[0;32m(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76[0m
|
[0;33m(kex) curve25519-sha256 -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
[0;32m `- [info] default key exchange from OpenSSH 7.4 to 8.9[0m
|
`- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
|
||||||
[0;32m(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62[0m
|
`- [info] default key exchange from OpenSSH 7.4 to 8.9
|
||||||
[0;32m `- [info] default key exchange from OpenSSH 6.5 to 7.3[0m
|
[0;33m(kex) curve25519-sha256@libssh.org -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
|
`- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
|
||||||
|
`- [info] default key exchange from OpenSSH 6.5 to 7.3
|
||||||
[0;31m(kex) ecdh-sha2-nistp521 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
[0;31m(kex) ecdh-sha2-nistp521 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||||
[0;31m(kex) ecdh-sha2-nistp384 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
[0;31m(kex) ecdh-sha2-nistp384 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||||
[0;31m(kex) ecdh-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
[0;31m(kex) ecdh-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||||
[0;33m(kex) diffie-hellman-group14-sha256 -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
[0;33m(kex) diffie-hellman-group14-sha256 -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
|
`- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
|
||||||
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||||
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
||||||
[0;32m(kex) kexguess2@matt.ucc.asn.au -- [info] available since Dropbear SSH 2013.57[0m
|
[0;33m(kex) kexguess2@matt.ucc.asn.au -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
|
`- [info] available since Dropbear SSH 2013.57
|
||||||
|
|
||||||
[0;36m# host-key algorithms[0m
|
[0;36m# host-key algorithms[0m
|
||||||
[0;31m(key) ecdsa-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
[0;31m(key) ecdsa-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
||||||
@@ -74,14 +82,16 @@
|
|||||||
[0;31m(rec) -hmac-sha1-96 -- mac algorithm to remove [0m
|
[0;31m(rec) -hmac-sha1-96 -- mac algorithm to remove [0m
|
||||||
[0;31m(rec) -ssh-dss -- key algorithm to remove [0m
|
[0;31m(rec) -ssh-dss -- key algorithm to remove [0m
|
||||||
[0;31m(rec) -ssh-rsa -- key algorithm to remove [0m
|
[0;31m(rec) -ssh-rsa -- key algorithm to remove [0m
|
||||||
[0;32m(rec) +diffie-hellman-group16-sha512 -- kex algorithm to append [0m
|
|
||||||
[0;32m(rec) +twofish128-ctr -- enc algorithm to append [0m
|
[0;32m(rec) +twofish128-ctr -- enc algorithm to append [0m
|
||||||
[0;32m(rec) +twofish256-ctr -- enc algorithm to append [0m
|
[0;32m(rec) +twofish256-ctr -- enc algorithm to append [0m
|
||||||
[0;33m(rec) -aes128-cbc -- enc algorithm to remove [0m
|
[0;33m(rec) -aes128-cbc -- enc algorithm to remove [0m
|
||||||
[0;33m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
[0;33m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
||||||
|
[0;33m(rec) -curve25519-sha256 -- kex algorithm to remove [0m
|
||||||
|
[0;33m(rec) -curve25519-sha256@libssh.org -- kex algorithm to remove [0m
|
||||||
[0;33m(rec) -diffie-hellman-group14-sha256 -- kex algorithm to remove [0m
|
[0;33m(rec) -diffie-hellman-group14-sha256 -- kex algorithm to remove [0m
|
||||||
[0;33m(rec) -hmac-sha2-256 -- mac algorithm to remove [0m
|
[0;33m(rec) -hmac-sha2-256 -- mac algorithm to remove [0m
|
||||||
|
[0;33m(rec) -kexguess2@matt.ucc.asn.au -- kex algorithm to remove [0m
|
||||||
|
|
||||||
[0;36m# additional info[0m
|
[0;36m# additional info[0m
|
||||||
[0;33m(nfo) For hardening guides on common OSes, please see: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
[0;33m(nfo) For hardening guides on common OSes, a built-in list can be viewed with --list-hardening-guides, or an online list can be found at: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
||||||
|
|
||||||
|
|||||||
@@ -173,6 +173,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 2.3.0"
|
"available since OpenSSH 2.3.0"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -186,7 +189,8 @@
|
|||||||
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
||||||
],
|
],
|
||||||
"warn": [
|
"warn": [
|
||||||
"2048-bit modulus only provides 112-bits of symmetric strength"
|
"2048-bit modulus only provides 112-bits of symmetric strength",
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -201,6 +205,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
|
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
|
||||||
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
|
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,16 @@
|
|||||||
|
|
||||||
[0;36m# key exchange algorithms[0m
|
[0;36m# key exchange algorithms[0m
|
||||||
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 2.3.0
|
`- [info] available since OpenSSH 2.3.0
|
||||||
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||||
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
||||||
[0;31m(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus[0m
|
||||||
[0;31m `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)[0m
|
[0;31m `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)[0m
|
||||||
[0;31m `- [fail] using broken SHA-1 hash algorithm[0m
|
[0;31m `- [fail] using broken SHA-1 hash algorithm[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
||||||
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
|
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
|
||||||
|
|
||||||
@@ -104,5 +107,5 @@
|
|||||||
[0;33m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
[0;33m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
||||||
|
|
||||||
[0;36m# additional info[0m
|
[0;36m# additional info[0m
|
||||||
[0;33m(nfo) For hardening guides on common OSes, please see: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
[0;33m(nfo) For hardening guides on common OSes, a built-in list can be viewed with --list-hardening-guides, or an online list can be found at: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
||||||
|
|
||||||
|
|||||||
@@ -195,6 +195,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 4.4"
|
"available since OpenSSH 4.4"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -207,6 +210,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 2.3.0"
|
"available since OpenSSH 2.3.0"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -220,7 +226,8 @@
|
|||||||
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
||||||
],
|
],
|
||||||
"warn": [
|
"warn": [
|
||||||
"2048-bit modulus only provides 112-bits of symmetric strength"
|
"2048-bit modulus only provides 112-bits of symmetric strength",
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -235,6 +242,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
|
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
|
||||||
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
|
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,19 @@
|
|||||||
|
|
||||||
[0;36m# key exchange algorithms[0m
|
[0;36m# key exchange algorithms[0m
|
||||||
[0;31m(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 4.4
|
`- [info] available since OpenSSH 4.4
|
||||||
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 2.3.0
|
`- [info] available since OpenSSH 2.3.0
|
||||||
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||||
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
||||||
[0;31m(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus[0m
|
||||||
[0;31m `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)[0m
|
[0;31m `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)[0m
|
||||||
[0;31m `- [fail] using broken SHA-1 hash algorithm[0m
|
[0;31m `- [fail] using broken SHA-1 hash algorithm[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
||||||
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
|
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
|
||||||
|
|
||||||
@@ -113,5 +117,5 @@
|
|||||||
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
||||||
|
|
||||||
[0;36m# additional info[0m
|
[0;36m# additional info[0m
|
||||||
[0;33m(nfo) For hardening guides on common OSes, please see: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
[0;33m(nfo) For hardening guides on common OSes, a built-in list can be viewed with --list-hardening-guides, or an online list can be found at: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
||||||
|
|
||||||
|
|||||||
@@ -185,6 +185,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 4.4"
|
"available since OpenSSH 4.4"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -197,6 +200,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 2.3.0"
|
"available since OpenSSH 2.3.0"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -210,7 +216,8 @@
|
|||||||
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
||||||
],
|
],
|
||||||
"warn": [
|
"warn": [
|
||||||
"2048-bit modulus only provides 112-bits of symmetric strength"
|
"2048-bit modulus only provides 112-bits of symmetric strength",
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -225,6 +232,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
|
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
|
||||||
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
|
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,19 @@
|
|||||||
|
|
||||||
[0;36m# key exchange algorithms[0m
|
[0;36m# key exchange algorithms[0m
|
||||||
[0;31m(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 4.4
|
`- [info] available since OpenSSH 4.4
|
||||||
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 2.3.0
|
`- [info] available since OpenSSH 2.3.0
|
||||||
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||||
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
||||||
[0;31m(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus[0m
|
||||||
[0;31m `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)[0m
|
[0;31m `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)[0m
|
||||||
[0;31m `- [fail] using broken SHA-1 hash algorithm[0m
|
[0;31m `- [fail] using broken SHA-1 hash algorithm[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
||||||
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
|
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
|
||||||
|
|
||||||
@@ -114,5 +118,5 @@
|
|||||||
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
||||||
|
|
||||||
[0;36m# additional info[0m
|
[0;36m# additional info[0m
|
||||||
[0;33m(nfo) For hardening guides on common OSes, please see: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
[0;33m(nfo) For hardening guides on common OSes, a built-in list can be viewed with --list-hardening-guides, or an online list can be found at: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
||||||
|
|
||||||
|
|||||||
@@ -185,6 +185,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 4.4"
|
"available since OpenSSH 4.4"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -197,6 +200,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 2.3.0"
|
"available since OpenSSH 2.3.0"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -210,7 +216,8 @@
|
|||||||
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
||||||
],
|
],
|
||||||
"warn": [
|
"warn": [
|
||||||
"2048-bit modulus only provides 112-bits of symmetric strength"
|
"2048-bit modulus only provides 112-bits of symmetric strength",
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -225,6 +232,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
|
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
|
||||||
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
|
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,19 @@
|
|||||||
|
|
||||||
[0;36m# key exchange algorithms[0m
|
[0;36m# key exchange algorithms[0m
|
||||||
[0;31m(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 4.4
|
`- [info] available since OpenSSH 4.4
|
||||||
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 2.3.0
|
`- [info] available since OpenSSH 2.3.0
|
||||||
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||||
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
||||||
[0;31m(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus[0m
|
||||||
[0;31m `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)[0m
|
[0;31m `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)[0m
|
||||||
[0;31m `- [fail] using broken SHA-1 hash algorithm[0m
|
[0;31m `- [fail] using broken SHA-1 hash algorithm[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
||||||
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
|
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
|
||||||
|
|
||||||
@@ -113,5 +117,5 @@
|
|||||||
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
||||||
|
|
||||||
[0;36m# additional info[0m
|
[0;36m# additional info[0m
|
||||||
[0;33m(nfo) For hardening guides on common OSes, please see: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
[0;33m(nfo) For hardening guides on common OSes, a built-in list can be viewed with --list-hardening-guides, or an online list can be found at: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
||||||
|
|
||||||
|
|||||||
@@ -185,6 +185,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 4.4"
|
"available since OpenSSH 4.4"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -197,6 +200,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 2.3.0"
|
"available since OpenSSH 2.3.0"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -210,7 +216,8 @@
|
|||||||
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
||||||
],
|
],
|
||||||
"warn": [
|
"warn": [
|
||||||
"2048-bit modulus only provides 112-bits of symmetric strength"
|
"2048-bit modulus only provides 112-bits of symmetric strength",
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -225,6 +232,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
|
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
|
||||||
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
|
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,19 @@
|
|||||||
|
|
||||||
[0;36m# key exchange algorithms[0m
|
[0;36m# key exchange algorithms[0m
|
||||||
[0;31m(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 4.4
|
`- [info] available since OpenSSH 4.4
|
||||||
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 2.3.0
|
`- [info] available since OpenSSH 2.3.0
|
||||||
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||||
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
||||||
[0;31m(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus[0m
|
||||||
[0;31m `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)[0m
|
[0;31m `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)[0m
|
||||||
[0;31m `- [fail] using broken SHA-1 hash algorithm[0m
|
[0;31m `- [fail] using broken SHA-1 hash algorithm[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
||||||
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
|
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
|
||||||
|
|
||||||
@@ -112,5 +116,5 @@
|
|||||||
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
||||||
|
|
||||||
[0;36m# additional info[0m
|
[0;36m# additional info[0m
|
||||||
[0;33m(nfo) For hardening guides on common OSes, please see: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
[0;33m(nfo) For hardening guides on common OSes, a built-in list can be viewed with --list-hardening-guides, or an online list can be found at: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
||||||
|
|
||||||
|
|||||||
@@ -185,6 +185,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 4.4"
|
"available since OpenSSH 4.4"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -197,6 +200,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 2.3.0"
|
"available since OpenSSH 2.3.0"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -210,7 +216,8 @@
|
|||||||
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
||||||
],
|
],
|
||||||
"warn": [
|
"warn": [
|
||||||
"2048-bit modulus only provides 112-bits of symmetric strength"
|
"2048-bit modulus only provides 112-bits of symmetric strength",
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -225,6 +232,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
|
"removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9",
|
||||||
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
|
"available since OpenSSH 2.3.0, Dropbear SSH 0.28"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,19 @@
|
|||||||
|
|
||||||
[0;36m# key exchange algorithms[0m
|
[0;36m# key exchange algorithms[0m
|
||||||
[0;31m(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 4.4
|
`- [info] available since OpenSSH 4.4
|
||||||
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 2.3.0
|
`- [info] available since OpenSSH 2.3.0
|
||||||
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||||
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
||||||
[0;31m(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus[0m
|
[0;31m(kex) diffie-hellman-group1-sha1 -- [fail] using small 1024-bit modulus[0m
|
||||||
[0;31m `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)[0m
|
[0;31m `- [fail] vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)[0m
|
||||||
[0;31m `- [fail] using broken SHA-1 hash algorithm[0m
|
[0;31m `- [fail] using broken SHA-1 hash algorithm[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
||||||
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
|
`- [info] removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9
|
||||||
|
|
||||||
@@ -111,5 +115,5 @@
|
|||||||
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
||||||
|
|
||||||
[0;36m# additional info[0m
|
[0;36m# additional info[0m
|
||||||
[0;33m(nfo) For hardening guides on common OSes, please see: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
[0;33m(nfo) For hardening guides on common OSes, a built-in list can be viewed with --list-hardening-guides, or an online list can be found at: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"errors": [],
|
||||||
|
"host": "localhost",
|
||||||
|
"passed": true,
|
||||||
|
"policy": "Docker policy: test18 (version 1)",
|
||||||
|
"port": 2222,
|
||||||
|
"warnings": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Host: localhost:2222
|
||||||
|
Policy: Docker policy: test18 (version 1)
|
||||||
|
Result: [0;32m✔ Passed[0m
|
||||||
@@ -104,6 +104,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"default key exchange from OpenSSH 7.4 to 8.9",
|
"default key exchange from OpenSSH 7.4 to 8.9",
|
||||||
"available since OpenSSH 7.4, Dropbear SSH 2018.76"
|
"available since OpenSSH 7.4, Dropbear SSH 2018.76"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -113,6 +116,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"default key exchange from OpenSSH 6.5 to 7.3",
|
"default key exchange from OpenSSH 6.5 to 7.3",
|
||||||
"available since OpenSSH 6.4, Dropbear SSH 2013.62"
|
"available since OpenSSH 6.4, Dropbear SSH 2013.62"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -124,6 +130,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -135,6 +144,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -146,6 +158,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -156,6 +171,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).",
|
"OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).",
|
||||||
"available since OpenSSH 4.4"
|
"available since OpenSSH 4.4"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -164,6 +182,9 @@
|
|||||||
"notes": {
|
"notes": {
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 7.3, Dropbear SSH 2016.73"
|
"available since OpenSSH 7.3, Dropbear SSH 2016.73"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -172,6 +193,9 @@
|
|||||||
"notes": {
|
"notes": {
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 7.3"
|
"available since OpenSSH 7.3"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -182,7 +206,8 @@
|
|||||||
"available since OpenSSH 7.3, Dropbear SSH 2016.73"
|
"available since OpenSSH 7.3, Dropbear SSH 2016.73"
|
||||||
],
|
],
|
||||||
"warn": [
|
"warn": [
|
||||||
"2048-bit modulus only provides 112-bits of symmetric strength"
|
"2048-bit modulus only provides 112-bits of symmetric strength",
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -196,7 +221,8 @@
|
|||||||
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
||||||
],
|
],
|
||||||
"warn": [
|
"warn": [
|
||||||
"2048-bit modulus only provides 112-bits of symmetric strength"
|
"2048-bit modulus only provides 112-bits of symmetric strength",
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -407,6 +433,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"warning": {
|
"warning": {
|
||||||
|
"chg": {
|
||||||
|
"kex": [
|
||||||
|
{
|
||||||
|
"name": "diffie-hellman-group-exchange-sha256",
|
||||||
|
"notes": "increase modulus size to 3072 bits or larger"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"del": {
|
"del": {
|
||||||
"enc": [
|
"enc": [
|
||||||
{
|
{
|
||||||
@@ -415,9 +449,25 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"kex": [
|
"kex": [
|
||||||
|
{
|
||||||
|
"name": "curve25519-sha256",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "curve25519-sha256@libssh.org",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "diffie-hellman-group14-sha256",
|
"name": "diffie-hellman-group14-sha256",
|
||||||
"notes": ""
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "diffie-hellman-group16-sha512",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "diffie-hellman-group18-sha512",
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"mac": [
|
"mac": [
|
||||||
|
|||||||
@@ -5,24 +5,34 @@
|
|||||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||||
|
|
||||||
[0;36m# key exchange algorithms[0m
|
[0;36m# key exchange algorithms[0m
|
||||||
[0;32m(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76[0m
|
[0;33m(kex) curve25519-sha256 -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
[0;32m `- [info] default key exchange from OpenSSH 7.4 to 8.9[0m
|
`- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
|
||||||
[0;32m(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62[0m
|
`- [info] default key exchange from OpenSSH 7.4 to 8.9
|
||||||
[0;32m `- [info] default key exchange from OpenSSH 6.5 to 7.3[0m
|
[0;33m(kex) curve25519-sha256@libssh.org -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
|
`- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
|
||||||
|
`- [info] default key exchange from OpenSSH 6.5 to 7.3
|
||||||
[0;31m(kex) ecdh-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
[0;31m(kex) ecdh-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||||
[0;31m(kex) ecdh-sha2-nistp384 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
[0;31m(kex) ecdh-sha2-nistp384 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||||
[0;31m(kex) ecdh-sha2-nistp521 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
[0;31m(kex) ecdh-sha2-nistp521 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||||
[0;32m(kex) diffie-hellman-group-exchange-sha256 (4096-bit) -- [info] available since OpenSSH 4.4[0m
|
[0;33m(kex) diffie-hellman-group-exchange-sha256 (4096-bit) -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
[0;32m `- [info] OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).[0m
|
`- [info] available since OpenSSH 4.4
|
||||||
[0;32m(kex) diffie-hellman-group16-sha512 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73[0m
|
`- [info] OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).
|
||||||
[0;32m(kex) diffie-hellman-group18-sha512 -- [info] available since OpenSSH 7.3[0m
|
[0;33m(kex) diffie-hellman-group16-sha512 -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
|
`- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
|
||||||
|
[0;33m(kex) diffie-hellman-group18-sha512 -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
|
`- [info] available since OpenSSH 7.3
|
||||||
[0;33m(kex) diffie-hellman-group14-sha256 -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
[0;33m(kex) diffie-hellman-group14-sha256 -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
|
`- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
|
||||||
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||||
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
||||||
|
|
||||||
[0;36m# host-key algorithms[0m
|
[0;36m# host-key algorithms[0m
|
||||||
@@ -80,8 +90,13 @@
|
|||||||
[0;31m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
[0;31m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
||||||
[0;31m(rec) -hmac-sha1-etm@openssh.com -- mac algorithm to remove [0m
|
[0;31m(rec) -hmac-sha1-etm@openssh.com -- mac algorithm to remove [0m
|
||||||
[0;31m(rec) -ssh-rsa -- key algorithm to remove [0m
|
[0;31m(rec) -ssh-rsa -- key algorithm to remove [0m
|
||||||
|
[0;33m(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 3072 bits or larger) [0m
|
||||||
[0;33m(rec) -chacha20-poly1305@openssh.com -- enc algorithm to remove [0m
|
[0;33m(rec) -chacha20-poly1305@openssh.com -- enc algorithm to remove [0m
|
||||||
|
[0;33m(rec) -curve25519-sha256 -- kex algorithm to remove [0m
|
||||||
|
[0;33m(rec) -curve25519-sha256@libssh.org -- kex algorithm to remove [0m
|
||||||
[0;33m(rec) -diffie-hellman-group14-sha256 -- kex algorithm to remove [0m
|
[0;33m(rec) -diffie-hellman-group14-sha256 -- kex algorithm to remove [0m
|
||||||
|
[0;33m(rec) -diffie-hellman-group16-sha512 -- kex algorithm to remove [0m
|
||||||
|
[0;33m(rec) -diffie-hellman-group18-sha512 -- kex algorithm to remove [0m
|
||||||
[0;33m(rec) -hmac-sha2-256 -- mac algorithm to remove [0m
|
[0;33m(rec) -hmac-sha2-256 -- mac algorithm to remove [0m
|
||||||
[0;33m(rec) -hmac-sha2-512 -- mac algorithm to remove [0m
|
[0;33m(rec) -hmac-sha2-512 -- mac algorithm to remove [0m
|
||||||
[0;33m(rec) -umac-128@openssh.com -- mac algorithm to remove [0m
|
[0;33m(rec) -umac-128@openssh.com -- mac algorithm to remove [0m
|
||||||
@@ -89,5 +104,5 @@
|
|||||||
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
||||||
|
|
||||||
[0;36m# additional info[0m
|
[0;36m# additional info[0m
|
||||||
[0;33m(nfo) For hardening guides on common OSes, please see: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
[0;33m(nfo) For hardening guides on common OSes, a built-in list can be viewed with --list-hardening-guides, or an online list can be found at: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"default key exchange from OpenSSH 7.4 to 8.9",
|
"default key exchange from OpenSSH 7.4 to 8.9",
|
||||||
"available since OpenSSH 7.4, Dropbear SSH 2018.76"
|
"available since OpenSSH 7.4, Dropbear SSH 2018.76"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -93,6 +96,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"default key exchange from OpenSSH 6.5 to 7.3",
|
"default key exchange from OpenSSH 6.5 to 7.3",
|
||||||
"available since OpenSSH 6.4, Dropbear SSH 2013.62"
|
"available since OpenSSH 6.4, Dropbear SSH 2013.62"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -104,6 +110,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -115,6 +124,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -126,6 +138,9 @@
|
|||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
"available since OpenSSH 5.7, Dropbear SSH 2013.62"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -136,6 +151,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).",
|
"OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).",
|
||||||
"available since OpenSSH 4.4"
|
"available since OpenSSH 4.4"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -144,6 +162,9 @@
|
|||||||
"notes": {
|
"notes": {
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 7.3, Dropbear SSH 2016.73"
|
"available since OpenSSH 7.3, Dropbear SSH 2016.73"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -152,6 +173,9 @@
|
|||||||
"notes": {
|
"notes": {
|
||||||
"info": [
|
"info": [
|
||||||
"available since OpenSSH 7.3"
|
"available since OpenSSH 7.3"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -162,7 +186,8 @@
|
|||||||
"available since OpenSSH 7.3, Dropbear SSH 2016.73"
|
"available since OpenSSH 7.3, Dropbear SSH 2016.73"
|
||||||
],
|
],
|
||||||
"warn": [
|
"warn": [
|
||||||
"2048-bit modulus only provides 112-bits of symmetric strength"
|
"2048-bit modulus only provides 112-bits of symmetric strength",
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -176,7 +201,8 @@
|
|||||||
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
"available since OpenSSH 3.9, Dropbear SSH 0.53"
|
||||||
],
|
],
|
||||||
"warn": [
|
"warn": [
|
||||||
"2048-bit modulus only provides 112-bits of symmetric strength"
|
"2048-bit modulus only provides 112-bits of symmetric strength",
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,6 +382,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"warning": {
|
"warning": {
|
||||||
|
"chg": {
|
||||||
|
"kex": [
|
||||||
|
{
|
||||||
|
"name": "diffie-hellman-group-exchange-sha256",
|
||||||
|
"notes": "increase modulus size to 3072 bits or larger"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"del": {
|
"del": {
|
||||||
"enc": [
|
"enc": [
|
||||||
{
|
{
|
||||||
@@ -364,9 +398,25 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"kex": [
|
"kex": [
|
||||||
|
{
|
||||||
|
"name": "curve25519-sha256",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "curve25519-sha256@libssh.org",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "diffie-hellman-group14-sha256",
|
"name": "diffie-hellman-group14-sha256",
|
||||||
"notes": ""
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "diffie-hellman-group16-sha512",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "diffie-hellman-group18-sha512",
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"mac": [
|
"mac": [
|
||||||
|
|||||||
@@ -5,24 +5,34 @@
|
|||||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||||
|
|
||||||
[0;36m# key exchange algorithms[0m
|
[0;36m# key exchange algorithms[0m
|
||||||
[0;32m(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76[0m
|
[0;33m(kex) curve25519-sha256 -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
[0;32m `- [info] default key exchange from OpenSSH 7.4 to 8.9[0m
|
`- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
|
||||||
[0;32m(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62[0m
|
`- [info] default key exchange from OpenSSH 7.4 to 8.9
|
||||||
[0;32m `- [info] default key exchange from OpenSSH 6.5 to 7.3[0m
|
[0;33m(kex) curve25519-sha256@libssh.org -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
|
`- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
|
||||||
|
`- [info] default key exchange from OpenSSH 6.5 to 7.3
|
||||||
[0;31m(kex) ecdh-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
[0;31m(kex) ecdh-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||||
[0;31m(kex) ecdh-sha2-nistp384 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
[0;31m(kex) ecdh-sha2-nistp384 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||||
[0;31m(kex) ecdh-sha2-nistp521 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
[0;31m(kex) ecdh-sha2-nistp521 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||||
[0;32m(kex) diffie-hellman-group-exchange-sha256 (4096-bit) -- [info] available since OpenSSH 4.4[0m
|
[0;33m(kex) diffie-hellman-group-exchange-sha256 (4096-bit) -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
[0;32m `- [info] OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).[0m
|
`- [info] available since OpenSSH 4.4
|
||||||
[0;32m(kex) diffie-hellman-group16-sha512 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73[0m
|
`- [info] OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).
|
||||||
[0;32m(kex) diffie-hellman-group18-sha512 -- [info] available since OpenSSH 7.3[0m
|
[0;33m(kex) diffie-hellman-group16-sha512 -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
|
`- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
|
||||||
|
[0;33m(kex) diffie-hellman-group18-sha512 -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
|
`- [info] available since OpenSSH 7.3
|
||||||
[0;33m(kex) diffie-hellman-group14-sha256 -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
[0;33m(kex) diffie-hellman-group14-sha256 -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
|
`- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
|
||||||
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
[0;31m(kex) diffie-hellman-group14-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||||
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
[0;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||||
|
[0;33m `- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
||||||
|
|
||||||
[0;36m# host-key algorithms[0m
|
[0;36m# host-key algorithms[0m
|
||||||
@@ -72,8 +82,13 @@
|
|||||||
[0;31m(rec) -hmac-sha1-etm@openssh.com -- mac algorithm to remove [0m
|
[0;31m(rec) -hmac-sha1-etm@openssh.com -- mac algorithm to remove [0m
|
||||||
[0;32m(rec) +rsa-sha2-256 -- key algorithm to append [0m
|
[0;32m(rec) +rsa-sha2-256 -- key algorithm to append [0m
|
||||||
[0;32m(rec) +rsa-sha2-512 -- key algorithm to append [0m
|
[0;32m(rec) +rsa-sha2-512 -- key algorithm to append [0m
|
||||||
|
[0;33m(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 3072 bits or larger) [0m
|
||||||
[0;33m(rec) -chacha20-poly1305@openssh.com -- enc algorithm to remove [0m
|
[0;33m(rec) -chacha20-poly1305@openssh.com -- enc algorithm to remove [0m
|
||||||
|
[0;33m(rec) -curve25519-sha256 -- kex algorithm to remove [0m
|
||||||
|
[0;33m(rec) -curve25519-sha256@libssh.org -- kex algorithm to remove [0m
|
||||||
[0;33m(rec) -diffie-hellman-group14-sha256 -- kex algorithm to remove [0m
|
[0;33m(rec) -diffie-hellman-group14-sha256 -- kex algorithm to remove [0m
|
||||||
|
[0;33m(rec) -diffie-hellman-group16-sha512 -- kex algorithm to remove [0m
|
||||||
|
[0;33m(rec) -diffie-hellman-group18-sha512 -- kex algorithm to remove [0m
|
||||||
[0;33m(rec) -hmac-sha2-256 -- mac algorithm to remove [0m
|
[0;33m(rec) -hmac-sha2-256 -- mac algorithm to remove [0m
|
||||||
[0;33m(rec) -hmac-sha2-512 -- mac algorithm to remove [0m
|
[0;33m(rec) -hmac-sha2-512 -- mac algorithm to remove [0m
|
||||||
[0;33m(rec) -umac-128@openssh.com -- mac algorithm to remove [0m
|
[0;33m(rec) -umac-128@openssh.com -- mac algorithm to remove [0m
|
||||||
@@ -81,5 +96,5 @@
|
|||||||
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
||||||
|
|
||||||
[0;36m# additional info[0m
|
[0;36m# additional info[0m
|
||||||
[0;33m(nfo) For hardening guides on common OSes, please see: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
[0;33m(nfo) For hardening guides on common OSes, a built-in list can be viewed with --list-hardening-guides, or an online list can be found at: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"default key exchange from OpenSSH 7.4 to 8.9",
|
"default key exchange from OpenSSH 7.4 to 8.9",
|
||||||
"available since OpenSSH 7.4, Dropbear SSH 2018.76"
|
"available since OpenSSH 7.4, Dropbear SSH 2018.76"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -93,6 +96,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"default key exchange from OpenSSH 6.5 to 7.3",
|
"default key exchange from OpenSSH 6.5 to 7.3",
|
||||||
"available since OpenSSH 6.4, Dropbear SSH 2013.62"
|
"available since OpenSSH 6.4, Dropbear SSH 2013.62"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -103,6 +109,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).",
|
"OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).",
|
||||||
"available since OpenSSH 4.4"
|
"available since OpenSSH 4.4"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,16 +155,6 @@
|
|||||||
"recommendations": {
|
"recommendations": {
|
||||||
"informational": {
|
"informational": {
|
||||||
"add": {
|
"add": {
|
||||||
"kex": [
|
|
||||||
{
|
|
||||||
"name": "diffie-hellman-group16-sha512",
|
|
||||||
"notes": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "diffie-hellman-group18-sha512",
|
|
||||||
"notes": ""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"key": [
|
"key": [
|
||||||
{
|
{
|
||||||
"name": "rsa-sha2-256",
|
"name": "rsa-sha2-256",
|
||||||
@@ -169,12 +168,30 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"warning": {
|
"warning": {
|
||||||
|
"chg": {
|
||||||
|
"kex": [
|
||||||
|
{
|
||||||
|
"name": "diffie-hellman-group-exchange-sha256",
|
||||||
|
"notes": "increase modulus size to 3072 bits or larger"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"del": {
|
"del": {
|
||||||
"enc": [
|
"enc": [
|
||||||
{
|
{
|
||||||
"name": "chacha20-poly1305@openssh.com",
|
"name": "chacha20-poly1305@openssh.com",
|
||||||
"notes": ""
|
"notes": ""
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"kex": [
|
||||||
|
{
|
||||||
|
"name": "curve25519-sha256",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "curve25519-sha256@libssh.org",
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,15 @@
|
|||||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||||
|
|
||||||
[0;36m# key exchange algorithms[0m
|
[0;36m# key exchange algorithms[0m
|
||||||
[0;32m(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76[0m
|
[0;33m(kex) curve25519-sha256 -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
[0;32m `- [info] default key exchange from OpenSSH 7.4 to 8.9[0m
|
`- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
|
||||||
[0;32m(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62[0m
|
`- [info] default key exchange from OpenSSH 7.4 to 8.9
|
||||||
[0;32m `- [info] default key exchange from OpenSSH 6.5 to 7.3[0m
|
[0;33m(kex) curve25519-sha256@libssh.org -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
[0;32m(kex) diffie-hellman-group-exchange-sha256 (4096-bit) -- [info] available since OpenSSH 4.4[0m
|
`- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
|
||||||
[0;32m `- [info] OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).[0m
|
`- [info] default key exchange from OpenSSH 6.5 to 7.3
|
||||||
|
[0;33m(kex) diffie-hellman-group-exchange-sha256 (4096-bit) -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
|
`- [info] available since OpenSSH 4.4
|
||||||
|
`- [info] OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).
|
||||||
|
|
||||||
[0;36m# host-key algorithms[0m
|
[0;36m# host-key algorithms[0m
|
||||||
[0;32m(key) ssh-ed25519 -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79[0m
|
[0;32m(key) ssh-ed25519 -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79[0m
|
||||||
@@ -34,12 +37,13 @@
|
|||||||
[0;32m(fin) ssh-ed25519: SHA256:UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU[0m
|
[0;32m(fin) ssh-ed25519: SHA256:UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU[0m
|
||||||
|
|
||||||
[0;36m# algorithm recommendations (for OpenSSH 8.0)[0m
|
[0;36m# algorithm recommendations (for OpenSSH 8.0)[0m
|
||||||
[0;32m(rec) +diffie-hellman-group16-sha512 -- kex algorithm to append [0m
|
|
||||||
[0;32m(rec) +diffie-hellman-group18-sha512 -- kex algorithm to append [0m
|
|
||||||
[0;32m(rec) +rsa-sha2-256 -- key algorithm to append [0m
|
[0;32m(rec) +rsa-sha2-256 -- key algorithm to append [0m
|
||||||
[0;32m(rec) +rsa-sha2-512 -- key algorithm to append [0m
|
[0;32m(rec) +rsa-sha2-512 -- key algorithm to append [0m
|
||||||
|
[0;33m(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 3072 bits or larger) [0m
|
||||||
[0;33m(rec) -chacha20-poly1305@openssh.com -- enc algorithm to remove [0m
|
[0;33m(rec) -chacha20-poly1305@openssh.com -- enc algorithm to remove [0m
|
||||||
|
[0;33m(rec) -curve25519-sha256 -- kex algorithm to remove [0m
|
||||||
|
[0;33m(rec) -curve25519-sha256@libssh.org -- kex algorithm to remove [0m
|
||||||
|
|
||||||
[0;36m# additional info[0m
|
[0;36m# additional info[0m
|
||||||
[0;33m(nfo) For hardening guides on common OSes, please see: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
[0;33m(nfo) For hardening guides on common OSes, a built-in list can be viewed with --list-hardening-guides, or an online list can be found at: <https://www.ssh-audit.com/hardening_guides.html>[0m
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"default key exchange from OpenSSH 7.4 to 8.9",
|
"default key exchange from OpenSSH 7.4 to 8.9",
|
||||||
"available since OpenSSH 7.4, Dropbear SSH 2018.76"
|
"available since OpenSSH 7.4, Dropbear SSH 2018.76"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -52,6 +55,9 @@
|
|||||||
"info": [
|
"info": [
|
||||||
"default key exchange from OpenSSH 6.5 to 7.3",
|
"default key exchange from OpenSSH 6.5 to 7.3",
|
||||||
"available since OpenSSH 6.4, Dropbear SSH 2013.62"
|
"available since OpenSSH 6.4, Dropbear SSH 2013.62"
|
||||||
|
],
|
||||||
|
"warn": [
|
||||||
|
"does not provide protection against post-quantum attacks"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,10 +4,12 @@
|
|||||||
[0;32m(gen) compression: disabled[0m
|
[0;32m(gen) compression: disabled[0m
|
||||||
|
|
||||||
[0;36m# key exchange algorithms[0m
|
[0;36m# key exchange algorithms[0m
|
||||||
[0;32m(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76[0m
|
[0;33m(kex) curve25519-sha256 -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
[0;32m `- [info] default key exchange from OpenSSH 7.4 to 8.9[0m
|
`- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
|
||||||
[0;32m(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62[0m
|
`- [info] default key exchange from OpenSSH 7.4 to 8.9
|
||||||
[0;32m `- [info] default key exchange from OpenSSH 6.5 to 7.3[0m
|
[0;33m(kex) curve25519-sha256@libssh.org -- [warn] does not provide protection against post-quantum attacks[0m
|
||||||
|
`- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
|
||||||
|
`- [info] default key exchange from OpenSSH 6.5 to 7.3
|
||||||
[0;33m(kex) sntrup4591761x25519-sha512@tinyssh.org -- [warn] using experimental algorithm[0m
|
[0;33m(kex) sntrup4591761x25519-sha512@tinyssh.org -- [warn] using experimental algorithm[0m
|
||||||
`- [info] available since OpenSSH 8.0
|
`- [info] available since OpenSSH 8.0
|
||||||
`- [info] the sntrup4591761 algorithm was withdrawn, as it may not provide strong post-quantum security
|
`- [info] the sntrup4591761 algorithm was withdrawn, as it may not provide strong post-quantum security
|
||||||
|
|||||||
17
test/docker/policies/policy_test18.txt
Normal file
17
test/docker/policies/policy_test18.txt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#
|
||||||
|
# Docker policy: test18
|
||||||
|
#
|
||||||
|
|
||||||
|
name = "Docker policy: test18"
|
||||||
|
version = 1
|
||||||
|
allow_algorithm_subset_and_reordering = false
|
||||||
|
allow_hostkey_subset_and_reordering = true
|
||||||
|
allow_larger_keys = false
|
||||||
|
banner = "SSH-2.0-OpenSSH_8.0"
|
||||||
|
compressions = none, zlib@openssh.com
|
||||||
|
host keys = ssh-rsa, rsa-sha2-256, rsa-sha2-512, ecdsa-sha2-nistp256, ssh-ed25519, x
|
||||||
|
key exchanges = curve25519-sha256, curve25519-sha256@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, diffie-hellman-group14-sha1
|
||||||
|
ciphers = chacha20-poly1305@openssh.com, aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, aes256-gcm@openssh.com
|
||||||
|
macs = umac-64-etm@openssh.com, umac-128-etm@openssh.com, hmac-sha2-256-etm@openssh.com, hmac-sha2-512-etm@openssh.com, hmac-sha1-etm@openssh.com, umac-64@openssh.com, umac-128@openssh.com, hmac-sha2-256, hmac-sha2-512, hmac-sha1
|
||||||
|
host_key_sizes = {"ssh-rsa": {"hostkey_size": 3072}, "rsa-sha2-256": {"hostkey_size": 3072}, "rsa-sha2-512": {"hostkey_size": 3072}, "ssh-ed25519": {"hostkey_size": 256}}
|
||||||
|
dh_modulus_sizes = {"diffie-hellman-group-exchange-sha256": 4096}
|
||||||
@@ -8,7 +8,6 @@ class TestAuditConf:
|
|||||||
def init(self, ssh_audit):
|
def init(self, ssh_audit):
|
||||||
self.AuditConf = ssh_audit.AuditConf
|
self.AuditConf = ssh_audit.AuditConf
|
||||||
self.OutputBuffer = ssh_audit.OutputBuffer()
|
self.OutputBuffer = ssh_audit.OutputBuffer()
|
||||||
self.usage = ssh_audit.usage
|
|
||||||
self.process_commandline = process_commandline
|
self.process_commandline = process_commandline
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -16,8 +15,6 @@ class TestAuditConf:
|
|||||||
options = {
|
options = {
|
||||||
'host': '',
|
'host': '',
|
||||||
'port': 22,
|
'port': 22,
|
||||||
'ssh1': True,
|
|
||||||
'ssh2': True,
|
|
||||||
'batch': False,
|
'batch': False,
|
||||||
'colors': True,
|
'colors': True,
|
||||||
'verbose': False,
|
'verbose': False,
|
||||||
@@ -29,8 +26,6 @@ class TestAuditConf:
|
|||||||
options[k] = v
|
options[k] = v
|
||||||
assert conf.host == options['host']
|
assert conf.host == options['host']
|
||||||
assert conf.port == options['port']
|
assert conf.port == options['port']
|
||||||
assert conf.ssh1 is options['ssh1']
|
|
||||||
assert conf.ssh2 is options['ssh2']
|
|
||||||
assert conf.batch is options['batch']
|
assert conf.batch is options['batch']
|
||||||
assert conf.colors is options['colors']
|
assert conf.colors is options['colors']
|
||||||
assert conf.verbose is options['verbose']
|
assert conf.verbose is options['verbose']
|
||||||
@@ -44,7 +39,7 @@ class TestAuditConf:
|
|||||||
|
|
||||||
def test_audit_conf_booleans(self):
|
def test_audit_conf_booleans(self):
|
||||||
conf = self.AuditConf()
|
conf = self.AuditConf()
|
||||||
for p in ['ssh1', 'ssh2', 'batch', 'colors', 'verbose']:
|
for p in ['batch', 'colors', 'verbose']:
|
||||||
for v in [True, 1]:
|
for v in [True, 1]:
|
||||||
setattr(conf, p, v)
|
setattr(conf, p, v)
|
||||||
assert getattr(conf, p) is True
|
assert getattr(conf, p) is True
|
||||||
@@ -107,7 +102,7 @@ class TestAuditConf:
|
|||||||
|
|
||||||
def test_audit_conf_process_commandline(self):
|
def test_audit_conf_process_commandline(self):
|
||||||
# pylint: disable=too-many-statements
|
# pylint: disable=too-many-statements
|
||||||
c = lambda x: self.process_commandline(self.OutputBuffer, x.split(), self.usage) # noqa
|
c = lambda x: self.process_commandline(self.OutputBuffer, x.split()) # noqa
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
conf = c('')
|
conf = c('')
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
@@ -148,12 +143,6 @@ class TestAuditConf:
|
|||||||
conf = c('localhost:99999')
|
conf = c('localhost:99999')
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
conf = c('-p 99999 localhost')
|
conf = c('-p 99999 localhost')
|
||||||
conf = c('-1 localhost')
|
|
||||||
self._test_conf(conf, host='localhost', ssh1=True, ssh2=False)
|
|
||||||
conf = c('-2 localhost')
|
|
||||||
self._test_conf(conf, host='localhost', ssh1=False, ssh2=True)
|
|
||||||
conf = c('-12 localhost')
|
|
||||||
self._test_conf(conf, host='localhost', ssh1=True, ssh2=True)
|
|
||||||
conf = c('-4 localhost')
|
conf = c('-4 localhost')
|
||||||
self._test_conf(conf, host='localhost', ipv4=True, ipv6=False, ipvo=(4,))
|
self._test_conf(conf, host='localhost', ipv4=True, ipv6=False, ipvo=(4,))
|
||||||
conf = c('-6 localhost')
|
conf = c('-6 localhost')
|
||||||
@@ -163,7 +152,7 @@ class TestAuditConf:
|
|||||||
conf = c('-64 localhost')
|
conf = c('-64 localhost')
|
||||||
self._test_conf(conf, host='localhost', ipv4=True, ipv6=True, ipvo=(6, 4))
|
self._test_conf(conf, host='localhost', ipv4=True, ipv6=True, ipvo=(6, 4))
|
||||||
conf = c('-b localhost')
|
conf = c('-b localhost')
|
||||||
self._test_conf(conf, host='localhost', batch=True, verbose=True)
|
self._test_conf(conf, host='localhost', batch=True)
|
||||||
conf = c('-n localhost')
|
conf = c('-n localhost')
|
||||||
self._test_conf(conf, host='localhost', colors=False)
|
self._test_conf(conf, host='localhost', colors=False)
|
||||||
conf = c('-v localhost')
|
conf = c('-v localhost')
|
||||||
|
|||||||
@@ -166,7 +166,6 @@ class TestErrors:
|
|||||||
vsocket.rdata.append(b'SSH-1.3-ssh-audit-test\r\n')
|
vsocket.rdata.append(b'SSH-1.3-ssh-audit-test\r\n')
|
||||||
vsocket.rdata.append(b'Protocol major versions differ.\n')
|
vsocket.rdata.append(b'Protocol major versions differ.\n')
|
||||||
conf = self._conf()
|
conf = self._conf()
|
||||||
conf.ssh1, conf.ssh2 = True, False
|
|
||||||
lines = self._audit(output_spy, conf)
|
lines = self._audit(output_spy, conf)
|
||||||
assert len(lines) == 4
|
assert len(lines) == 4
|
||||||
assert 'error reading packet' in lines[-1]
|
assert 'error reading packet' in lines[-1]
|
||||||
|
|||||||
81
test/test_hardeningguides.py
Normal file
81
test/test_hardeningguides.py
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from ssh_audit.hardening_guides import Hardening_Guides
|
||||||
|
|
||||||
|
|
||||||
|
class TestHardeningGuides:
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def init(self, ssh_audit):
|
||||||
|
self.OutputBuffer = ssh_audit.OutputBuffer()
|
||||||
|
|
||||||
|
|
||||||
|
def test_hardening_guides_consistency(self):
|
||||||
|
'''Ensure that the HARDENING_GUIDES struct is consistent.'''
|
||||||
|
|
||||||
|
# Required keys in each guide dict.
|
||||||
|
required_guide_fields = ["server_guide", "version", "version_date", "change_log", "notes", "commands"]
|
||||||
|
|
||||||
|
# Required keys in the commands dict.
|
||||||
|
required_command_fields = ["heading", "comment", "command"]
|
||||||
|
|
||||||
|
for name, guides in Hardening_Guides.HARDENING_GUIDES.items():
|
||||||
|
|
||||||
|
# Ensure the key (guide name) is a string.
|
||||||
|
assert type(name) is str
|
||||||
|
|
||||||
|
# Ensure the value (guides) is a list.
|
||||||
|
assert type(guides) is list
|
||||||
|
|
||||||
|
for guide in guides:
|
||||||
|
|
||||||
|
# Ensure each guide is a dict.
|
||||||
|
assert type(guide) is dict
|
||||||
|
|
||||||
|
# Ensure each required key is in this guide.
|
||||||
|
for required_guide_field in required_guide_fields:
|
||||||
|
assert required_guide_field in guide
|
||||||
|
|
||||||
|
# Check the guide values are the correct type.
|
||||||
|
assert type(guide["server_guide"]) is bool
|
||||||
|
assert type(guide["version"]) is int
|
||||||
|
assert type(guide["version_date"]) is str
|
||||||
|
assert type(guide["change_log"]) is str
|
||||||
|
assert type(guide["notes"]) is str
|
||||||
|
assert type(guide["commands"]) is list
|
||||||
|
|
||||||
|
# The version must be creater than zero.
|
||||||
|
assert guide["version"] > 0
|
||||||
|
|
||||||
|
# Ensure the format is "YYYY-MM-DD".
|
||||||
|
version_date = guide["version_date"]
|
||||||
|
date_fields = version_date.split("-")
|
||||||
|
assert len(date_fields) == 3
|
||||||
|
|
||||||
|
# Check that the year is 4 digits and greater than 0.
|
||||||
|
year = date_fields[0]
|
||||||
|
assert len(year) == 4
|
||||||
|
assert int(year) > 0
|
||||||
|
|
||||||
|
# Check that the month is 2 digits and between 1 and 12.
|
||||||
|
month = date_fields[1]
|
||||||
|
assert len(month) == 2
|
||||||
|
assert 1 <= int(month) <= 12
|
||||||
|
|
||||||
|
# Check that the day is 2 digits and between 1 and 31.
|
||||||
|
day = date_fields[2]
|
||||||
|
assert len(day) == 2
|
||||||
|
assert 1 <= int(day) <= 31
|
||||||
|
|
||||||
|
# Check that the change log is filled in.
|
||||||
|
assert len(guide["change_log"]) > 0
|
||||||
|
|
||||||
|
commands = guide["commands"]
|
||||||
|
for command in commands:
|
||||||
|
|
||||||
|
# Ensure each required key is in this command list.
|
||||||
|
for required_command_field in required_command_fields:
|
||||||
|
assert required_command_field in command
|
||||||
|
|
||||||
|
# Check that these fields are not empty.
|
||||||
|
assert len(command["heading"]) > 0
|
||||||
|
assert len(command["command"]) > 0
|
||||||
@@ -60,9 +60,6 @@ class TestPolicy:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
assert False, "version field of %s policy is not parseable as an integer." % policy_name
|
assert False, "version field of %s policy is not parseable as an integer." % policy_name
|
||||||
|
|
||||||
# Ensure no extra fields are present.
|
|
||||||
assert len(required_fields) == len(BUILTIN_POLICIES[policy_name])
|
|
||||||
|
|
||||||
# Ensure that the changelog field is a string and non-empty.
|
# Ensure that the changelog field is a string and non-empty.
|
||||||
assert type(BUILTIN_POLICIES[policy_name]['changelog']) is str
|
assert type(BUILTIN_POLICIES[policy_name]['changelog']) is str
|
||||||
assert len(BUILTIN_POLICIES[policy_name]['changelog']) > 0
|
assert len(BUILTIN_POLICIES[policy_name]['changelog']) > 0
|
||||||
@@ -158,7 +155,7 @@ ciphers = cipher_alg1, cipher_alg2, cipher_alg3
|
|||||||
macs = mac_alg1, mac_alg2, mac_alg3'''
|
macs = mac_alg1, mac_alg2, mac_alg3'''
|
||||||
|
|
||||||
policy = self.Policy(policy_data=policy_data)
|
policy = self.Policy(policy_data=policy_data)
|
||||||
assert str(policy) == "Name: [Test Policy]\nVersion: [1]\nAllow Algorithm Subset and/or Reordering: False\nBanner: {undefined}\nCompressions: comp_alg1\nHost Keys: key_alg1\nOptional Host Keys: {undefined}\nKey Exchanges: kex_alg1, kex_alg2\nCiphers: cipher_alg1, cipher_alg2, cipher_alg3\nMACs: mac_alg1, mac_alg2, mac_alg3\nHost Key Sizes: {undefined}\nDH Modulus Sizes: {undefined}\nServer Policy: True"
|
assert str(policy) == "Name: [Test Policy]\nVersion: [1]\nAllow Algorithm Subset and/or Reordering: False\nAllow Host Key Subset and/or Reordering: False\nBanner: {undefined}\nCompressions: comp_alg1\nHost Keys: key_alg1\nOptional Host Keys: {undefined}\nKey Exchanges: kex_alg1, kex_alg2\nCiphers: cipher_alg1, cipher_alg2, cipher_alg3\nMACs: mac_alg1, mac_alg2, mac_alg3\nHost Key Sizes: {undefined}\nDH Modulus Sizes: {undefined}\nServer Policy: True"
|
||||||
|
|
||||||
|
|
||||||
def test_policy_invalid_1(self):
|
def test_policy_invalid_1(self):
|
||||||
@@ -305,7 +302,7 @@ macs = mac_alg1, mac_alg2, mac_alg3'''
|
|||||||
pol_data = pol_data.replace(date.today().strftime('%Y/%m/%d'), '[todays date]')
|
pol_data = pol_data.replace(date.today().strftime('%Y/%m/%d'), '[todays date]')
|
||||||
|
|
||||||
# Instead of writing out the entire expected policy--line by line--just check that it has the expected hash.
|
# Instead of writing out the entire expected policy--line by line--just check that it has the expected hash.
|
||||||
assert hashlib.sha256(pol_data.encode('ascii')).hexdigest() == 'fb84bce442cff2bce9bf653d6373a8a938e3bfcfbd1e876f51a08c1842df3cff'
|
assert hashlib.sha256(pol_data.encode('ascii')).hexdigest() == '3862e56ea60c1ecba6dffbf724216c4391b6fe00a790b0075617477d4addf761'
|
||||||
|
|
||||||
|
|
||||||
def test_policy_evaluate_passing_1(self):
|
def test_policy_evaluate_passing_1(self):
|
||||||
|
|||||||
@@ -1,174 +0,0 @@
|
|||||||
import struct
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from ssh_audit.auditconf import AuditConf
|
|
||||||
from ssh_audit.fingerprint import Fingerprint
|
|
||||||
from ssh_audit.outputbuffer import OutputBuffer
|
|
||||||
from ssh_audit.protocol import Protocol
|
|
||||||
from ssh_audit.readbuf import ReadBuf
|
|
||||||
from ssh_audit.ssh1 import SSH1
|
|
||||||
from ssh_audit.ssh1_publickeymessage import SSH1_PublicKeyMessage
|
|
||||||
from ssh_audit.ssh_audit import audit
|
|
||||||
from ssh_audit.writebuf import WriteBuf
|
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=line-too-long,attribute-defined-outside-init
|
|
||||||
class TestSSH1:
|
|
||||||
@pytest.fixture(autouse=True)
|
|
||||||
def init(self, ssh_audit):
|
|
||||||
self.OutputBuffer = OutputBuffer
|
|
||||||
self.protocol = Protocol
|
|
||||||
self.ssh1 = SSH1
|
|
||||||
self.PublicKeyMessage = SSH1_PublicKeyMessage
|
|
||||||
self.rbuf = ReadBuf
|
|
||||||
self.wbuf = WriteBuf
|
|
||||||
self.audit = audit
|
|
||||||
self.AuditConf = AuditConf
|
|
||||||
self.fingerprint = Fingerprint
|
|
||||||
|
|
||||||
def _conf(self):
|
|
||||||
conf = self.AuditConf('localhost', 22)
|
|
||||||
conf.colors = False
|
|
||||||
conf.batch = True
|
|
||||||
conf.verbose = True
|
|
||||||
conf.ssh1 = True
|
|
||||||
conf.ssh2 = False
|
|
||||||
conf.skip_rate_test = True
|
|
||||||
return conf
|
|
||||||
|
|
||||||
def _create_ssh1_packet(self, payload, valid_crc=True):
|
|
||||||
padding = -(len(payload) + 4) % 8
|
|
||||||
plen = len(payload) + 4
|
|
||||||
pad_bytes = b'\x00' * padding
|
|
||||||
cksum = self.ssh1.crc32(pad_bytes + payload) if valid_crc else 0
|
|
||||||
data = struct.pack('>I', plen) + pad_bytes + payload + struct.pack('>I', cksum)
|
|
||||||
return data
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _server_key(cls):
|
|
||||||
return (1024, 0x10001, 0xee6552da432e0ac2c422df1a51287507748bfe3b5e3e4fa989a8f49fdc163a17754939ef18ef8a667ea3b71036a151fcd7f5e01ceef1e4439864baf3ac569047582c69d6c128212e0980dcb3168f00d371004039983f6033cd785b8b8f85096c7d9405cbfdc664e27c966356a6b4eb6ee20ad43414b50de18b22829c1880b551)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _host_key(cls):
|
|
||||||
return (2048, 0x10001, 0xdfa20cd2a530ccc8c870aa60d9feb3b35deeab81c3215a96557abbd683d21f4600f38e475d87100da9a4404220eeb3bb5584e5a2b5b48ffda58530ea19104a32577d7459d91e76aa711b241050f4cc6d5327ccce254f371acad3be56d46eb5919b73f20dbdb1177b700f00891c5bf4ed128bb90ed541b778288285bcfa28432ab5cbcb8321b6e24760e998e0daa519f093a631e44276d7dd252ce0c08c75e2ab28a7349ead779f97d0f20a6d413bf3623cd216dc35375f6366690bcc41e3b2d5465840ec7ee0dc7e3f1c101d674a0c7dbccbc3942788b111396add2f8153b46a0e4b50d66e57ee92958f1c860dd97cc0e40e32febff915343ed53573142bdf4b)
|
|
||||||
|
|
||||||
def _pkm_payload(self):
|
|
||||||
w = self.wbuf()
|
|
||||||
w.write(b'\x88\x99\xaa\xbb\xcc\xdd\xee\xff')
|
|
||||||
b, e, m = self._server_key()
|
|
||||||
w.write_int(b).write_mpint1(e).write_mpint1(m)
|
|
||||||
b, e, m = self._host_key()
|
|
||||||
w.write_int(b).write_mpint1(e).write_mpint1(m)
|
|
||||||
w.write_int(2)
|
|
||||||
w.write_int(72)
|
|
||||||
w.write_int(36)
|
|
||||||
return w.write_flush()
|
|
||||||
|
|
||||||
def test_crc32(self):
|
|
||||||
assert self.ssh1.crc32(b'') == 0x00
|
|
||||||
assert self.ssh1.crc32(b'The quick brown fox jumps over the lazy dog') == 0xb9c60808
|
|
||||||
|
|
||||||
def test_fingerprint(self):
|
|
||||||
# pylint: disable=protected-access
|
|
||||||
b, e, m = self._host_key()
|
|
||||||
fpd = self.wbuf._create_mpint(m, False)
|
|
||||||
fpd += self.wbuf._create_mpint(e, False)
|
|
||||||
fp = self.fingerprint(fpd)
|
|
||||||
assert b == 2048
|
|
||||||
assert fp.md5 == 'MD5:9d:26:f8:39:fc:20:9d:9b:ca:cc:4a:0f:e1:93:f5:96'
|
|
||||||
assert fp.sha256 == 'SHA256:vZdx3mhzbvVJmn08t/ruv8WDhJ9jfKYsCTuSzot+QIs'
|
|
||||||
|
|
||||||
def _assert_pkm_keys(self, pkm, skey, hkey):
|
|
||||||
b, e, m = skey
|
|
||||||
assert pkm.server_key_bits == b
|
|
||||||
assert pkm.server_key_public_exponent == e
|
|
||||||
assert pkm.server_key_public_modulus == m
|
|
||||||
b, e, m = hkey
|
|
||||||
assert pkm.host_key_bits == b
|
|
||||||
assert pkm.host_key_public_exponent == e
|
|
||||||
assert pkm.host_key_public_modulus == m
|
|
||||||
|
|
||||||
def _assert_pkm_fields(self, pkm, skey, hkey):
|
|
||||||
assert pkm is not None
|
|
||||||
assert pkm.cookie == b'\x88\x99\xaa\xbb\xcc\xdd\xee\xff'
|
|
||||||
self._assert_pkm_keys(pkm, skey, hkey)
|
|
||||||
assert pkm.protocol_flags == 2
|
|
||||||
assert pkm.supported_ciphers_mask == 72
|
|
||||||
assert pkm.supported_ciphers == ['3des', 'blowfish']
|
|
||||||
assert pkm.supported_authentications_mask == 36
|
|
||||||
assert pkm.supported_authentications == ['rsa', 'tis']
|
|
||||||
fp = self.fingerprint(pkm.host_key_fingerprint_data)
|
|
||||||
assert fp.md5 == 'MD5:9d:26:f8:39:fc:20:9d:9b:ca:cc:4a:0f:e1:93:f5:96'
|
|
||||||
assert fp.sha256 == 'SHA256:vZdx3mhzbvVJmn08t/ruv8WDhJ9jfKYsCTuSzot+QIs'
|
|
||||||
|
|
||||||
def test_pkm_init(self):
|
|
||||||
cookie = b'\x88\x99\xaa\xbb\xcc\xdd\xee\xff'
|
|
||||||
pflags, cmask, amask = 2, 72, 36
|
|
||||||
skey, hkey = self._server_key(), self._host_key()
|
|
||||||
pkm = self.PublicKeyMessage(cookie, skey, hkey, pflags, cmask, amask)
|
|
||||||
self._assert_pkm_fields(pkm, skey, hkey)
|
|
||||||
for skey2 in ([], [0], [0, 1], [0, 1, 2, 3]):
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
pkm = self.PublicKeyMessage(cookie, skey2, hkey, pflags, cmask, amask)
|
|
||||||
for hkey2 in ([], [0], [0, 1], [0, 1, 2, 3]):
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
print(hkey2)
|
|
||||||
pkm = self.PublicKeyMessage(cookie, skey, hkey2, pflags, cmask, amask)
|
|
||||||
|
|
||||||
def test_pkm_read(self):
|
|
||||||
pkm = self.PublicKeyMessage.parse(self._pkm_payload())
|
|
||||||
self._assert_pkm_fields(pkm, self._server_key(), self._host_key())
|
|
||||||
|
|
||||||
def test_pkm_payload(self):
|
|
||||||
cookie = b'\x88\x99\xaa\xbb\xcc\xdd\xee\xff'
|
|
||||||
skey, hkey = self._server_key(), self._host_key()
|
|
||||||
pflags, cmask, amask = 2, 72, 36
|
|
||||||
pkm1 = self.PublicKeyMessage(cookie, skey, hkey, pflags, cmask, amask)
|
|
||||||
pkm2 = self.PublicKeyMessage.parse(self._pkm_payload())
|
|
||||||
assert pkm1.payload == pkm2.payload
|
|
||||||
|
|
||||||
def test_ssh1_server_simple(self, output_spy, virtual_socket):
|
|
||||||
vsocket = virtual_socket
|
|
||||||
w = self.wbuf()
|
|
||||||
w.write_byte(self.protocol.SMSG_PUBLIC_KEY)
|
|
||||||
w.write(self._pkm_payload())
|
|
||||||
vsocket.rdata.append(b'SSH-1.5-OpenSSH_7.2 ssh-audit-test\r\n')
|
|
||||||
vsocket.rdata.append(self._create_ssh1_packet(w.write_flush()))
|
|
||||||
output_spy.begin()
|
|
||||||
out = self.OutputBuffer()
|
|
||||||
self.audit(out, self._conf())
|
|
||||||
out.write()
|
|
||||||
lines = output_spy.flush()
|
|
||||||
assert len(lines) == 13
|
|
||||||
|
|
||||||
def test_ssh1_server_invalid_first_packet(self, output_spy, virtual_socket):
|
|
||||||
vsocket = virtual_socket
|
|
||||||
w = self.wbuf()
|
|
||||||
w.write_byte(self.protocol.SMSG_PUBLIC_KEY + 1)
|
|
||||||
w.write(self._pkm_payload())
|
|
||||||
vsocket.rdata.append(b'SSH-1.5-OpenSSH_7.2 ssh-audit-test\r\n')
|
|
||||||
vsocket.rdata.append(self._create_ssh1_packet(w.write_flush()))
|
|
||||||
output_spy.begin()
|
|
||||||
out = self.OutputBuffer()
|
|
||||||
ret = self.audit(out, self._conf())
|
|
||||||
out.write()
|
|
||||||
assert ret != 0
|
|
||||||
lines = output_spy.flush()
|
|
||||||
assert len(lines) == 6
|
|
||||||
assert 'unknown message' in lines[-1]
|
|
||||||
|
|
||||||
def test_ssh1_server_invalid_checksum(self, output_spy, virtual_socket):
|
|
||||||
vsocket = virtual_socket
|
|
||||||
w = self.wbuf()
|
|
||||||
w.write_byte(self.protocol.SMSG_PUBLIC_KEY + 1)
|
|
||||||
w.write(self._pkm_payload())
|
|
||||||
vsocket.rdata.append(b'SSH-1.5-OpenSSH_7.2 ssh-audit-test\r\n')
|
|
||||||
vsocket.rdata.append(self._create_ssh1_packet(w.write_flush(), False))
|
|
||||||
output_spy.begin()
|
|
||||||
out = self.OutputBuffer()
|
|
||||||
with pytest.raises(SystemExit):
|
|
||||||
self.audit(out, self._conf())
|
|
||||||
out.write()
|
|
||||||
lines = output_spy.flush()
|
|
||||||
assert len(lines) == 3
|
|
||||||
assert ('checksum' in lines[0]) or ('checksum' in lines[1]) or ('checksum' in lines[2])
|
|
||||||
@@ -165,7 +165,7 @@ class TestSSH2:
|
|||||||
self.audit(out, self._conf())
|
self.audit(out, self._conf())
|
||||||
out.write()
|
out.write()
|
||||||
lines = output_spy.flush()
|
lines = output_spy.flush()
|
||||||
assert len(lines) == 78
|
assert len(lines) == 74
|
||||||
|
|
||||||
def test_ssh2_server_invalid_first_packet(self, output_spy, virtual_socket):
|
def test_ssh2_server_invalid_first_packet(self, output_spy, virtual_socket):
|
||||||
vsocket = virtual_socket
|
vsocket = virtual_socket
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ class Test_SSH2_KexDB:
|
|||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def init(self):
|
def init(self):
|
||||||
self.db = SSH2_KexDB.get_db()
|
self.db = SSH2_KexDB.get_db()
|
||||||
|
self.pq_warning = SSH2_KexDB.WARN_NOT_PQ_SAFE
|
||||||
|
|
||||||
def test_ssh2_kexdb(self):
|
def test_ssh2_kexdb(self):
|
||||||
'''Ensures that the SSH2_KexDB.ALGORITHMS dictionary is in the right format.'''
|
'''Ensures that the SSH2_KexDB.ALGORITHMS dictionary is in the right format.'''
|
||||||
@@ -33,3 +34,40 @@ class Test_SSH2_KexDB:
|
|||||||
# The first entry denotes the versions when this algorithm was added to OpenSSH, Dropbear, and/or libssh, followed by when it was deprecated, and finally when it was removed. Hence it must have between 0 and 3 entries.
|
# The first entry denotes the versions when this algorithm was added to OpenSSH, Dropbear, and/or libssh, followed by when it was deprecated, and finally when it was removed. Hence it must have between 0 and 3 entries.
|
||||||
added_entry = alg_data[0]
|
added_entry = alg_data[0]
|
||||||
assert 0 <= len(added_entry) <= 3
|
assert 0 <= len(added_entry) <= 3
|
||||||
|
|
||||||
|
|
||||||
|
def test_kex_pq_unsafe(self):
|
||||||
|
'''Ensures that all key exchange algorithms are marked as post-quantum unsafe, unless they appear in a whitelist.'''
|
||||||
|
|
||||||
|
# These algorithms include protections against quantum attacks.
|
||||||
|
kex_pq_safe = [
|
||||||
|
"ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org",
|
||||||
|
"ecdh-nistp384-kyber-768r3-sha384-d00@openquantumsafe.org",
|
||||||
|
"ecdh-nistp521-kyber-1024r3-sha512-d00@openquantumsafe.org",
|
||||||
|
"ext-info-c",
|
||||||
|
"ext-info-s",
|
||||||
|
"kex-strict-c-v00@openssh.com",
|
||||||
|
"kex-strict-s-v00@openssh.com",
|
||||||
|
"mlkem768x25519-sha256",
|
||||||
|
"sntrup4591761x25519-sha512@tinyssh.org",
|
||||||
|
"sntrup761x25519-sha512@openssh.com",
|
||||||
|
"sntrup761x25519-sha512",
|
||||||
|
"x25519-kyber-512r3-sha256-d00@amazon.com",
|
||||||
|
"x25519-kyber512-sha512@aws.amazon.com",
|
||||||
|
"mlkem768nistp256-sha256", # PQ safe, but has a conventional back-door.
|
||||||
|
"mlkem1024nistp384-sha384" # PQ safe, but has a conventional back-door.
|
||||||
|
]
|
||||||
|
|
||||||
|
failures = []
|
||||||
|
for kex_name in self.db['kex']:
|
||||||
|
|
||||||
|
# Skip key exchanges that are PQ safe.
|
||||||
|
if kex_name in kex_pq_safe:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Ensure all other kex exchanges have the proper PQ unsafe flag set in their warnings list.
|
||||||
|
alg_data = self.db['kex'][kex_name]
|
||||||
|
if len(alg_data) < 3 or self.pq_warning not in alg_data[2]:
|
||||||
|
failures.append(kex_name)
|
||||||
|
|
||||||
|
assert failures == []
|
||||||
|
|||||||
Reference in New Issue
Block a user