mirror of
https://github.com/jtesta/ssh-audit.git
synced 2025-07-06 05:57:50 -05:00
Compare commits
98 Commits
Author | SHA1 | Date | |
---|---|---|---|
3ba28b01e9 | |||
3c1451cfdc | |||
929652c9b7 | |||
e172932977 | |||
c33e7d9b72 | |||
0074fcc1af | |||
1eab4ab0e6 | |||
7f8d6b4d5b | |||
4c098b7d12 | |||
0bfb5d6979 | |||
a5f5e0dab2 | |||
05f159a152 | |||
263267c5ad | |||
4f31304b66 | |||
6f05a2c6b5 | |||
784d412148 | |||
dc083de87e | |||
7d5eb37a0f | |||
5c1c447755 | |||
cbb7d43006 | |||
cc9e4fbc4a | |||
992aa1b961 | |||
413dea60ae | |||
e2a9896397 | |||
71feaa191e | |||
c02ab8f170 | |||
cdaee69642 | |||
7bbf4cdff0 | |||
e4d864c6c1 | |||
1663e5bdcf | |||
5ecad8fac9 | |||
38ff225ed8 | |||
c9dc9a9c10 | |||
f9e00b6f2d | |||
433c7e779d | |||
984ea1eee3 | |||
0b905a7fdd | |||
6e9283e643 | |||
32ff04c2cc | |||
e50ac5c84d | |||
29496b43d5 | |||
3300c60aaa | |||
78a9475a32 | |||
8d861dcdc6 | |||
c50cc040c2 | |||
93f0692444 | |||
6e9945337e | |||
d429b543d0 | |||
b9520cbc25 | |||
0b8ecf2fb5 | |||
eb4ae65b0a | |||
113d1de443 | |||
4d89f9b30b | |||
11905ed44a | |||
19f192d21f | |||
5ac0ffa8f1 | |||
0a6ac5de54 | |||
c6b8dc97e1 | |||
1bdf7029b4 | |||
5fbcb1b90f | |||
b04acc3737 | |||
4ace52a190 | |||
22a9559a82 | |||
57e6c0246d | |||
80a718a5af | |||
1f0b3acff2 | |||
cdc379d6df | |||
9f87acfc74 | |||
597b500eba | |||
96efb3efb4 | |||
ce5939856c | |||
7f74731351 | |||
8c4855ffa2 | |||
4f2f995b62 | |||
134236fa7f | |||
a6b658d194 | |||
297a807f88 | |||
20d94df400 | |||
b76060cf49 | |||
1cf1c874db | |||
992d8233c9 | |||
f377b7cea3 | |||
70d9ab2e6b | |||
e7d320f602 | |||
682cb66f85 | |||
076681a671 | |||
98a1fb0315 | |||
45da9f20ae | |||
aa21df29e7 | |||
32ed9242af | |||
07862489c4 | |||
e508a963e7 | |||
2f1a2a60b1 | |||
5eb669e01c | |||
8e9fe20fac | |||
83bd049486 | |||
c483fe1861 | |||
741bd631e2 |
@ -1,33 +0,0 @@
|
||||
version: 'v2.2.1-dev.{build}'
|
||||
|
||||
build: off
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- develop
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- PYTHON: "C:\\Python35"
|
||||
- PYTHON: "C:\\Python35-x64"
|
||||
- PYTHON: "C:\\Python36"
|
||||
- PYTHON: "C:\\Python36-x64"
|
||||
- PYTHON: "C:\\Python37"
|
||||
- PYTHON: "C:\\Python37-x64"
|
||||
- PYTHON: "C:\\Python38"
|
||||
- PYTHON: "C:\\Python38-x64"
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
cache:
|
||||
- '%LOCALAPPDATA%\pip\Cache'
|
||||
- .downloads -> .appveyor.yml
|
||||
|
||||
install:
|
||||
- "cmd /c .\\test\\tools\\ci-win.cmd install"
|
||||
|
||||
test_script:
|
||||
- "cmd /c .\\test\\tools\\ci-win.cmd test"
|
||||
|
||||
on_failure:
|
||||
- ps: get-content .tox\*\log\*
|
24
.github/workflows/tox.yaml
vendored
Normal file
24
.github/workflows/tox.yaml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
name: ssh-audit
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.7, 3.8, 3.9, "3.10", 3.11]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U codecov coveralls flake8 mypy pylint pytest tox vulture
|
||||
- name: Run Tox
|
||||
run: |
|
||||
tox
|
24
.travis.yml
24
.travis.yml
@ -1,24 +0,0 @@
|
||||
language: python
|
||||
|
||||
arch:
|
||||
- arm64
|
||||
- amd64
|
||||
- ppc64le
|
||||
|
||||
python:
|
||||
- "3.6"
|
||||
- "3.7"
|
||||
- "3.8"
|
||||
- "3.9"
|
||||
|
||||
cache:
|
||||
- pip
|
||||
|
||||
install:
|
||||
- pip install -U pip tox tox-travis coveralls codecov
|
||||
|
||||
script:
|
||||
- tox
|
||||
|
||||
after_success:
|
||||
- codecov
|
@ -1,6 +1,6 @@
|
||||
# Contributing to ssh-audit
|
||||
|
||||
We are very much open to receiving patches from the community! To encourage participation, passing Travis tests, unit tests, etc., *is OPTIONAL*. As long as the patch works properly, it can be merged.
|
||||
We are very much open to receiving patches from the community! To encourage participation, passing CI tests, unit tests, etc., *is OPTIONAL*. As long as the patch works properly, it can be merged.
|
||||
|
||||
However, if you can submit patches that pass all of our automated tests, then you'll lighten the load for the project maintainer (who already has enough to do!). This document describes what tests are done and what documentation is maintained.
|
||||
|
||||
@ -9,34 +9,16 @@ However, if you can submit patches that pass all of our automated tests, then yo
|
||||
|
||||
## Tox Tests
|
||||
|
||||
Tox is used to do unit testing, linting with [pylint](http://pylint.pycqa.org/en/latest/) & [flake8](https://flake8.pycqa.org/en/latest/), and static type-checking with [mypy](https://mypy.readthedocs.io/en/stable/).
|
||||
[Tox](https://tox.wiki/) is used to automate testing. Linting is done with [pylint](http://pylint.pycqa.org/en/latest/) & [flake8](https://flake8.pycqa.org/en/latest/), and static type-checking is done with [mypy](https://mypy.readthedocs.io/en/stable/).
|
||||
|
||||
### Running tests on Ubuntu 18.04 and later
|
||||
|
||||
For Ubuntu 18.04 or later, install tox with `apt install tox`, then simply run `tox` in the top-level directory. Look for any error messages in the (verbose) output.
|
||||
|
||||
### Running tests on Ubuntu 16.04
|
||||
|
||||
For Ubuntu 16.04 (which is still supported until April 2021), a newer version of tox is needed. The easiest way is to use virtualenv:
|
||||
```
|
||||
$ sudo apt install python3-virtualenv
|
||||
$ virtualenv -p /usr/bin/python3 ~/venv_ssh-audit
|
||||
$ source ~/venv_ssh-audit/bin/activate
|
||||
$ pip install tox
|
||||
```
|
||||
Then, to run the tox tests:
|
||||
```
|
||||
$ source ~/venv_ssh-audit/bin/activate
|
||||
$ cd path/to/ssh-audit
|
||||
$ tox
|
||||
```
|
||||
For Ubuntu systems, install tox with `apt install tox`, then simply run `tox` in the top-level directory. Look for any error messages in the (verbose) output.
|
||||
|
||||
|
||||
## Docker Tests
|
||||
|
||||
Docker is used to run ssh-audit against various real SSH servers (OpenSSH, Dropbear, and TinySSH). The output is then diff'ed against the expected result. Any differences result in failure.
|
||||
|
||||
The docker tests are run with `./docker_test.sh`. The first time it is run, it will download and compile the SSH servers; this may take awhile. Subsequent runs, however, will take only a minute to complete, as the docker image will already be up-to-date.
|
||||
The docker tests are run with `./docker_test.sh`.
|
||||
|
||||
|
||||
## Man Page
|
||||
|
14
Dockerfile
14
Dockerfile
@ -1,10 +1,18 @@
|
||||
FROM python:3.9-slim
|
||||
FROM python:3-slim
|
||||
|
||||
WORKDIR /
|
||||
|
||||
# Remove suid & sgid bits from all files.
|
||||
RUN find / -xdev -perm /6000 -exec chmod ug-s {} \; 2> /dev/null || true
|
||||
|
||||
# Copy the ssh-audit code.
|
||||
COPY ssh-audit.py .
|
||||
COPY src/ .
|
||||
|
||||
ENTRYPOINT ["python3", "/ssh-audit.py"]
|
||||
|
||||
# Allow listening on 2222/tcp for client auditing.
|
||||
EXPOSE 2222
|
||||
|
||||
# Drop root privileges.
|
||||
USER nobody:nogroup
|
||||
|
||||
ENTRYPOINT ["python3", "/ssh-audit.py"]
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2017-2020 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
||||
|
||||
|
||||
|
@ -1,6 +0,0 @@
|
||||
all:
|
||||
echo -e "\n\nDid you remember to bump the version number in snapcraft.yaml?\n\n"
|
||||
snapcraft --use-lxd
|
||||
|
||||
clean:
|
||||
rm -rf parts/ prime/ snap/ stage/ build/ dist/ src/*.egg-info/ ssh-audit*.snap
|
40
PACKAGING.md
40
PACKAGING.md
@ -2,23 +2,16 @@
|
||||
|
||||
An executable can only be made on a Windows host because the PyInstaller tool (https://www.pyinstaller.org/) does not support cross-compilation.
|
||||
|
||||
On a Windows machine, do the following:
|
||||
1.) Install Python v3.11.x from https://www.python.org/. To make life easier, check the option to add Python to the PATH environment variable.
|
||||
|
||||
1.) Install Python v3.9.x from https://www.python.org/. To make life easier, check the option to add Python to the PATH environment variable.
|
||||
2.) Install Cygwin (https://www.cygwin.com/).
|
||||
|
||||
2.) Using pip, install pyinstaller and colorama:
|
||||
3.) Install/update package dependencies and create the executable with:
|
||||
|
||||
```
|
||||
pip install pyinstaller colorama
|
||||
$ ./build_windows_executable.sh
|
||||
```
|
||||
|
||||
3.) Create the executable with:
|
||||
|
||||
```
|
||||
cd src\ssh_audit
|
||||
rename ssh_audit.py ssh-audit.py
|
||||
pyinstaller -F --icon ..\..\windows_icon.ico ssh-audit.py
|
||||
```
|
||||
|
||||
# PyPI
|
||||
|
||||
@ -38,7 +31,7 @@ To download from test server and verify:
|
||||
$ pip3 install --index-url https://test.pypi.org/simple ssh-audit
|
||||
```
|
||||
|
||||
To upload to production server (hint: use username '__token__' and API token):
|
||||
To upload to production server (hint: use username '\_\_token\_\_' and API token):
|
||||
|
||||
```
|
||||
$ make -f Makefile.pypi uploadprod
|
||||
@ -52,27 +45,14 @@ To download from production server and verify:
|
||||
$ pip3 install ssh-audit
|
||||
```
|
||||
|
||||
|
||||
# Snap
|
||||
|
||||
To create the snap package, run a fully-updated Ubuntu Server 20.04 VM.
|
||||
|
||||
Install pre-requisites with:
|
||||
To create the snap package, run a fully-updated Ubuntu Server 22.04 VM.
|
||||
|
||||
Create the snap package with:
|
||||
```
|
||||
$ sudo apt install make snapcraft
|
||||
$ sudo snap install review-tools
|
||||
```
|
||||
|
||||
Initialize LXD (leave all options default):
|
||||
|
||||
```
|
||||
$ sudo lxd init
|
||||
```
|
||||
|
||||
Bump the version number in snapcraft.yaml. Then run:
|
||||
|
||||
```
|
||||
$ make -f Makefile.snap
|
||||
$ ./build_snap.sh
|
||||
```
|
||||
|
||||
Upload the snap with:
|
||||
@ -91,7 +71,7 @@ Build image with:
|
||||
$ make -f Makefile.docker
|
||||
```
|
||||
|
||||
Then upload them to Dockerhub with:
|
||||
Then upload it to Dockerhub with:
|
||||
|
||||
```
|
||||
$ make -f Makefile.docker upload
|
||||
|
84
README.md
84
README.md
@ -1,14 +1,25 @@
|
||||
# ssh-audit
|
||||
[](https://travis-ci.org/jtesta/ssh-audit)
|
||||
<!--
|
||||
[](https://ci.appveyor.com/project/arthepsy/ssh-audit)
|
||||
[](https://codecov.io/gh/arthepsy/ssh-audit)
|
||||
[](https://sq.evolutiongaming.com/dashboard?id=arthepsy-github%3Assh-audit%3Adevelop)
|
||||
-->
|
||||
[](https://github.com/jtesta/ssh-audit/blob/master/LICENSE)
|
||||
[](https://pypi.org/project/ssh-audit/)
|
||||
[](https://hub.docker.com/r/positronsecurity/ssh-audit)
|
||||
[](https://github.com/jtesta/ssh-audit/actions)
|
||||
[](https://github.com/jtesta/ssh-audit/blob/master/CONTRIBUTING.md)
|
||||
|
||||
**ssh-audit** is a tool for ssh server & client configuration auditing.
|
||||
|
||||
[jtesta/ssh-audit](https://github.com/jtesta/ssh-audit/) (v2.0+) is the updated and maintained version of ssh-audit forked from [arthepsy/ssh-audit](https://github.com/arthepsy/ssh-audit) (v1.x) due to inactivity.
|
||||
|
||||
- [Features](#features)
|
||||
- [Usage](#usage)
|
||||
- [Screenshots](#screenshots)
|
||||
- [Server Standard Audit Example](#server-standard-audit-example)
|
||||
- [Server Policy Audit Example](#server-policy-audit-example)
|
||||
- [Client Standard Audit Example](#client-standard-audit-example)
|
||||
- [Hardening Guides](#hardening-guides)
|
||||
- [Pre-Built Packages](#pre-built-packages)
|
||||
- [Web Front-End](#web-front-end)
|
||||
- [ChangeLog](#changelog)
|
||||
|
||||
## Features
|
||||
- SSH1 and SSH2 protocol server support;
|
||||
- analyze SSH client configuration;
|
||||
@ -21,7 +32,7 @@
|
||||
- historical information from OpenSSH, Dropbear SSH and libssh;
|
||||
- policy scans to ensure adherence to a hardened/standard configuration;
|
||||
- runs on Linux and Windows;
|
||||
- supports Python 3.6 - 3.9;
|
||||
- supports Python 3.7 - 3.11;
|
||||
- no dependencies
|
||||
|
||||
## Usage
|
||||
@ -37,7 +48,11 @@ usage: ssh-audit.py [options] <host>
|
||||
-c, --client-audit starts a server on port 2222 to audit client
|
||||
software config (use -p to change port;
|
||||
use -t to change timeout)
|
||||
-j, --json JSON output
|
||||
-d, --debug Enable debug output.
|
||||
-g, --gex-test=<x[,y,...]> dh gex modulus size test
|
||||
<min1:pref1:max1[,min2:pref2:max2,...]>
|
||||
<x-y[:step]>
|
||||
-j, --json JSON output (use -jj to enable indents)
|
||||
-l, --level=<level> minimum output level (info|warn|fail)
|
||||
-L, --list-policies list all the official, built-in policies
|
||||
--lookup=<alg1,alg2,...> looks up an algorithm(s) without
|
||||
@ -115,6 +130,8 @@ To create a policy based on a target server (which can be manually edited):
|
||||
ssh-audit -M new_policy.txt targetserver
|
||||
```
|
||||
|
||||
## Screenshots
|
||||
|
||||
### Server Standard Audit Example
|
||||
Below is a screen shot of the standard server-auditing output when connecting to an unhardened OpenSSH v5.3 service:
|
||||

|
||||
@ -130,11 +147,11 @@ After applying the steps in the hardening guide (see below), the output changes
|
||||
Below is a screen shot of the client-auditing output when an unhardened OpenSSH v7.2 client connects:
|
||||

|
||||
|
||||
### Hardening Guides
|
||||
## Hardening Guides
|
||||
Guides to harden server & client configuration can be found here: [https://www.ssh-audit.com/hardening_guides.html](https://www.ssh-audit.com/hardening_guides.html)
|
||||
|
||||
### Pre-Built Packages
|
||||
Pre-built packages are available for Windows (see the releases page), on PyPI, Snap, and Homebrew.
|
||||
## Pre-Built Packages
|
||||
Pre-built packages are available for Windows (see the releases page), PyPI, Snap, and Docker:
|
||||
|
||||
To install from PyPI:
|
||||
```
|
||||
@ -146,21 +163,54 @@ To install the Snap package:
|
||||
$ snap install ssh-audit
|
||||
```
|
||||
|
||||
To install on Homebrew:
|
||||
```
|
||||
$ brew install ssh-audit
|
||||
```
|
||||
|
||||
To install from Dockerhub:
|
||||
```
|
||||
$ docker pull positronsecurity/ssh-audit
|
||||
```
|
||||
(Then run with: `docker run -it -p 2222:2222 positronsecurity/ssh-audit 10.1.1.1`)
|
||||
|
||||
### Web Front-End
|
||||
The status of various other platform packages can be found below (via Repology):
|
||||
|
||||
<a href="https://repology.org/project/ssh-audit/versions"><img src="https://repology.org/badge/vertical-allrepos/ssh-audit.svg?columns=4" alt="Packaging status" align="center"></a>
|
||||
|
||||
## Web Front-End
|
||||
For convenience, a web front-end on top of the command-line tool is available at [https://www.ssh-audit.com/](https://www.ssh-audit.com/).
|
||||
|
||||
## ChangeLog
|
||||
|
||||
### v2.9.0 (2023-04-29)
|
||||
- Dropped support for Python 3.6, as it reached EOL at the end of 2021.
|
||||
- Added Ubuntu Server & Client 22.04 hardening policies.
|
||||
- Removed experimental warning tag from `sntrup761x25519-sha512@openssh.com`.
|
||||
- Updated CVE database; credit [Alexandre Zanni](https://github.com/noraj).
|
||||
- Added `-g` and `--gex-test` for granular GEX modulus size tests; credit [Adam Russell](https://github.com/thecliguy).
|
||||
- Snap packages now print more user-friendly error messages when permission errors are encountered.
|
||||
- JSON 'target' field now always includes port number; credit [tomatohater1337](https://github.com/tomatohater1337).
|
||||
- JSON output now includes recommendations and CVE data.
|
||||
- Mixed host key/CA key types (i.e.: RSA host keys signed with ED25519 CAs, etc.) are now properly handled.
|
||||
- Warnings are now printed for 2048-bit moduli; partial credit [Adam Russell](https://github.com/thecliguy).
|
||||
- SHA-1 algorithms now cause failures.
|
||||
- CBC mode ciphers are now warnings instead of failures.
|
||||
- Generic failure/warning messages replaced with more specific reasons (i.e.: 'using weak cipher' => 'using broken RC4 cipher').
|
||||
- Updated built-in policies to include missing host key size information.
|
||||
- Added built-in policies for OpenSSH 8.8, 8.9, 9.0, 9.1, 9.2, and 9.3.
|
||||
- Added 33 new host keys: `dsa2048-sha224@libassh.org`, `dsa2048-sha256@libassh.org`, `dsa3072-sha256@libassh.org`, `ecdsa-sha2-1.3.132.0.10-cert-v01@openssh.com`, `eddsa-e382-shake256@libassh.org`, `eddsa-e521-shake256@libassh.org`, `null`, `pgp-sign-dss`, `pgp-sign-rsa`, `spki-sign-dss`, `spki-sign-rsa`, `ssh-dss-sha224@ssh.com`, `ssh-dss-sha384@ssh.com`, `ssh-dss-sha512@ssh.com`, `ssh-ed448-cert-v01@openssh.com`, `ssh-rsa-sha224@ssh.com`, `ssh-rsa-sha2-256`, `ssh-rsa-sha2-512`, `ssh-rsa-sha384@ssh.com`, `ssh-rsa-sha512@ssh.com`, `ssh-xmss-cert-v01@openssh.com`, `ssh-xmss@openssh.com`, `webauthn-sk-ecdsa-sha2-nistp256@openssh.com`, `x509v3-ecdsa-sha2-1.3.132.0.10`, `x509v3-sign-dss-sha1`, `x509v3-sign-dss-sha224@ssh.com`, `x509v3-sign-dss-sha256@ssh.com`, `x509v3-sign-dss-sha384@ssh.com`, `x509v3-sign-dss-sha512@ssh.com`, `x509v3-sign-rsa-sha1`, `x509v3-sign-rsa-sha224@ssh.com`, `x509v3-sign-rsa-sha384@ssh.com`, `x509v3-sign-rsa-sha512@ssh.com`.
|
||||
- Added 46 new key exchanges: `diffie-hellman-group14-sha224@ssh.com`, `diffie-hellman_group17-sha512`, `diffie-hellman-group-exchange-sha224@ssh.com`, `diffie-hellman-group-exchange-sha384@ssh.com`, `ecdh-sha2-1.2.840.10045.3.1.1`, `ecdh-sha2-1.2.840.10045.3.1.7`, `ecdh-sha2-1.3.132.0.1`, `ecdh-sha2-1.3.132.0.16`, `ecdh-sha2-1.3.132.0.26`, `ecdh-sha2-1.3.132.0.27`, `ecdh-sha2-1.3.132.0.33`, `ecdh-sha2-1.3.132.0.34`, `ecdh-sha2-1.3.132.0.35`, `ecdh-sha2-1.3.132.0.36`, `ecdh-sha2-1.3.132.0.37`, `ecdh-sha2-1.3.132.0.38`, `ecdh-sha2-4MHB+NBt3AlaSRQ7MnB4cg==`, `ecdh-sha2-5pPrSUQtIaTjUSt5VZNBjg==`, `ecdh-sha2-9UzNcgwTlEnSCECZa7V1mw==`, `ecdh-sha2-D3FefCjYoJ/kfXgAyLddYA==`, `ecdh-sha2-h/SsxnLCtRBh7I9ATyeB3A==`, `ecdh-sha2-m/FtSAmrV4j/Wy6RVUaK7A==`, `ecdh-sha2-mNVwCXAoS1HGmHpLvBC94w==`, `ecdh-sha2-qCbG5Cn/jjsZ7nBeR7EnOA==`, `ecdh-sha2-qcFQaMAMGhTziMT0z+Tuzw==`, `ecdh-sha2-VqBg4QRPjxx1EXZdV0GdWQ==`, `ecdh-sha2-wiRIU8TKjMZ418sMqlqtvQ==`, `ecdh-sha2-zD/b3hu/71952ArpUG4OjQ==`, `ecmqv-sha2`, `gss-13.3.132.0.10-sha256-*`, `gss-curve25519-sha256-*`, `gss-curve448-sha512-*`, `gss-gex-sha1-*`, `gss-gex-sha256-*`, `gss-group14-sha1-*`, `gss-group14-sha256-*`, `gss-group15-sha512-*`, `gss-group16-sha512-*`, `gss-group17-sha512-*`, `gss-group18-sha512-*`, `gss-group1-sha1-*`, `gss-nistp256-sha256-*`, `gss-nistp384-sha256-*`, `gss-nistp521-sha512-*`, `m383-sha384@libassh.org`, `m511-sha512@libassh.org`.
|
||||
- Added 28 new ciphers: `3des-cfb`, `3des-ecb`, `3des-ofb`, `blowfish-cfb`, `blowfish-ecb`, `blowfish-ofb`, `camellia128-cbc@openssh.org`, `camellia128-ctr@openssh.org`, `camellia192-cbc@openssh.org`, `camellia192-ctr@openssh.org`, `camellia256-cbc@openssh.org`, `camellia256-ctr@openssh.org`, `cast128-cfb`, `cast128-ecb`, `cast128-ofb`, `cast128-12-cbc@ssh.com`, `idea-cfb`, `idea-ecb`, `idea-ofb`, `rijndael-cbc@ssh.com`, `seed-ctr@ssh.com`, `serpent128-gcm@libassh.org`, `serpent256-gcm@libassh.org`, `twofish128-gcm@libassh.org`, `twofish256-gcm@libassh.org`, `twofish-cfb`, `twofish-ecb`, `twofish-ofb`
|
||||
- Added 5 new MACs: `hmac-sha1-96@openssh.com`, `hmac-sha224@ssh.com`, `hmac-sha256-2@ssh.com`, `hmac-sha384@ssh.com`, `hmac-whirlpool`.
|
||||
|
||||
### v2.5.0 (2021-08-26)
|
||||
- Fixed crash when running host key tests.
|
||||
- Handles server connection failures more gracefully.
|
||||
- Now prints JSON with indents when `-jj` is used (useful for debugging).
|
||||
- Added MD5 fingerprints to verbose output.
|
||||
- Added `-d`/`--debug` option for getting debugging output; credit [Adam Russell](https://github.com/thecliguy).
|
||||
- Updated JSON output to include MD5 fingerprints. Note that this results in a breaking change in the 'fingerprints' dictionary format.
|
||||
- Updated OpenSSH 8.1 (and earlier) policies to include `rsa-sha2-512` and `rsa-sha2-256`.
|
||||
- Added OpenSSH v8.6 & v8.7 policies.
|
||||
- Added 3 new key exchanges: `gss-gex-sha1-eipGX3TCiQSrx573bT1o1Q==`, `gss-group1-sha1-eipGX3TCiQSrx573bT1o1Q==`, and `gss-group14-sha1-eipGX3TCiQSrx573bT1o1Q==`.
|
||||
- Added 3 new MACs: `hmac-ripemd160-96`, `AEAD_AES_128_GCM`, and `AEAD_AES_256_GCM`.
|
||||
|
||||
### v2.4.0 (2021-02-23)
|
||||
- Added multi-threaded scanning support.
|
||||
- Added built-in Windows manual page (see `-m`/`--manual`); credit [Adam Russell](https://github.com/thecliguy).
|
||||
|
73
build_snap.sh
Executable file
73
build_snap.sh
Executable file
@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (C) 2021 Joe Testa (jtesta@positronsecurity.com)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
|
||||
################################################################################
|
||||
# build_snap.sh
|
||||
#
|
||||
# Builds a Snap package.
|
||||
################################################################################
|
||||
|
||||
|
||||
# Pre-requisites
|
||||
sudo apt install -y make
|
||||
sudo snap install snapcraft --classic
|
||||
sudo snap install review-tools lxd
|
||||
|
||||
# Initialize LXD.
|
||||
sudo lxd init --auto
|
||||
|
||||
# Reset the filesystem from any previous runs.
|
||||
rm -rf parts/ prime/ snap/ stage/ build/ dist/ src/*.egg-info/ ssh-audit*.snap
|
||||
git checkout snapcraft.yaml 2> /dev/null
|
||||
git checkout src/ssh_audit/globals.py 2> /dev/null
|
||||
|
||||
# Get the version from the globals.py file.
|
||||
version=$(grep VERSION src/ssh_audit/globals.py | awk 'BEGIN {FS="="} ; {print $2}' | tr -d '[:space:]')
|
||||
|
||||
# Strip the quotes around the version (along with the initial 'v' character) and append "-1" to make the default Snap version (i.e.: 'v2.5.0' => '2.5.0-1')
|
||||
default_snap_version="${version:2:-1}-1"
|
||||
echo -e -n "\nEnter Snap package version [default: ${default_snap_version}]: "
|
||||
read -r snap_version
|
||||
|
||||
# If no version was specified, use the default version.
|
||||
if [[ $snap_version == '' ]]; then
|
||||
snap_version=$default_snap_version
|
||||
echo -e "Using default snap version: ${snap_version}\n"
|
||||
fi
|
||||
|
||||
# Ensure that the snap version fits the format of X.X.X-X.
|
||||
if [[ ! $snap_version =~ ^[0-9]\.[0-9]\.[0-9]\-[0-9]$ ]]; then
|
||||
echo "Error: version string does not match format X.X.X-X!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Append the version field to the end of the file. Not pretty, but it works.
|
||||
echo -e "\nversion: '${snap_version}'" >> snapcraft.yaml
|
||||
|
||||
# Set the SNAP_PACKAGE variable to True so that file permission errors give more user-friendly
|
||||
sed -i 's/SNAP_PACKAGE = False/SNAP_PACKAGE = True/' src/ssh_audit/globals.py
|
||||
|
||||
snapcraft --use-lxd && echo -e "\nDone.\n"
|
@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
@ -37,9 +37,9 @@ PLATFORM="$(uname -s)"
|
||||
case "$PLATFORM" in
|
||||
CYGWIN*) ;;
|
||||
*)
|
||||
echo "Platform not supported ($PLATFORM). This must be run in Cygwin only."
|
||||
exit 1
|
||||
;;
|
||||
echo "Platform not supported ($PLATFORM). This must be run in Cygwin only."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Ensure that Python 3.x is installed.
|
||||
@ -48,16 +48,34 @@ if [[ "$(python -V)" != "Python 3."* ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ensure that pyinstaller is installed.
|
||||
command -v pyinstaller >/dev/null 2>&1 || { echo >&2 "pyinstaller not found. Install with: 'pip install pyinstaller'"; exit 1; }
|
||||
# Install/update package dependencies.
|
||||
echo "Installing/updating pyinstaller and colorama packages..."
|
||||
pip install -U pyinstaller colorama
|
||||
echo
|
||||
|
||||
# Ensure that the colorama module is installed.
|
||||
X=`pip show colorama` 2> /dev/null
|
||||
if [[ $? != 0 ]]; then
|
||||
echo "Colorama module not found. Install with: 'pip install colorama'"
|
||||
exit 1
|
||||
# Prompt for the version to release.
|
||||
echo -n "Enter the version to release, using format 'vX.X.X': "
|
||||
read -r version
|
||||
|
||||
# Ensure that entered version fits required format.
|
||||
if [[ ! $version =~ ^v[0-9]\.[0-9]\.[0-9]$ ]]; then
|
||||
echo "Error: version string does not match format vX.X.X!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify that version is correct.
|
||||
echo -n "Version will be set to '${version}'. Is this correct? (y/n): "
|
||||
read -r yn
|
||||
echo
|
||||
|
||||
if [[ $yn != "y" ]]; then
|
||||
echo "Build cancelled."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Reset any local changes made to globals.py from a previous run.
|
||||
git checkout src/ssh_audit/globals.py 2> /dev/null
|
||||
|
||||
# Update the man page.
|
||||
./update_windows_man_page.sh
|
||||
if [[ $? != 0 ]]; then
|
||||
@ -68,12 +86,14 @@ fi
|
||||
# Do all operations from this point from the main source directory.
|
||||
pushd src/ssh_audit > /dev/null
|
||||
|
||||
# Delete the executable if it exists from a prior run.
|
||||
if [[ -f dist/ssh-audit.exe ]]; then
|
||||
rm dist/ssh-audit.exe
|
||||
fi
|
||||
# Delete the existing VERSION variable and add the value that the user entered, above.
|
||||
sed -i '/^VERSION/d' globals.py
|
||||
echo "VERSION = '$version'" >> globals.py
|
||||
|
||||
# Create a link from ssh_audit.py to ssh-audit.py.
|
||||
# Delete cached files if they exist from a prior run.
|
||||
rm -rf dist/ build/ ssh-audit.spec
|
||||
|
||||
# Create a hard link from ssh_audit.py to ssh-audit.py.
|
||||
if [[ ! -f ssh-audit.py ]]; then
|
||||
ln ssh_audit.py ssh-audit.py
|
||||
fi
|
||||
@ -83,10 +103,23 @@ pyinstaller -F --icon ../../windows_icon.ico ssh-audit.py
|
||||
|
||||
if [[ -f dist/ssh-audit.exe ]]; then
|
||||
echo -e "\nExecutable created in $(pwd)/dist/ssh-audit.exe\n"
|
||||
else
|
||||
echo -e "\nFAILED to create $(pwd)/dist/ssh-audit.exe!\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Remove the link we created, above.
|
||||
rm ssh-audit.py
|
||||
# Ensure that the version string doesn't have '-dev' in it.
|
||||
X=`dist/ssh-audit.exe | grep -E 'ssh-audit.exe v.+\-dev'` > /dev/null
|
||||
if [[ $? == 0 ]]; then
|
||||
echo -e "\nError: executable's version number includes '-dev'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Remove the cache files created during the build process, along with the link we created, above.
|
||||
rm -rf build/ ssh-audit.spec ssh-audit.py
|
||||
|
||||
# Reset the changes we made to globals.py.
|
||||
git checkout globals.py 2> /dev/null
|
||||
|
||||
popd > /dev/null
|
||||
exit 0
|
||||
|
404
docker_test.sh
404
docker_test.sh
@ -4,6 +4,11 @@
|
||||
# This script will set up a docker image with multiple versions of OpenSSH, then
|
||||
# use it to run tests.
|
||||
#
|
||||
# Optional arguments:
|
||||
# --accept: accepts test failures and overwrites expected results with actual results (useful for updating the tests themselves).
|
||||
# --create: attempts to create a new docker image.
|
||||
#
|
||||
#
|
||||
# For debugging purposes, here is a cheat sheet for manually running the docker image:
|
||||
#
|
||||
# docker run -p 2222:22 -it ssh-audit-test:X /bin/bash
|
||||
@ -26,8 +31,9 @@ CLR="\033[0m"
|
||||
RED="\033[0;31m"
|
||||
YELLOW="\033[0;33m"
|
||||
GREEN="\033[0;32m"
|
||||
REDB="\033[1;31m" # Red + bold
|
||||
GREENB="\033[1;32m" # Green + bold
|
||||
REDB="\033[1;31m" # Red + bold
|
||||
YELLOWB="\033[1;33m" # Yellow + bold
|
||||
GREENB="\033[1;32m" # Green + bold
|
||||
|
||||
# Program return values.
|
||||
PROGRAM_RETVAL_FAILURE=3
|
||||
@ -39,35 +45,38 @@ PROGRAM_RETVAL_GOOD=0
|
||||
# Counts the number of test failures.
|
||||
num_failures=0
|
||||
|
||||
# When set, if a failure is encountered, overwrite the expected output with the actual value (i.e.: the user validated the failures already and wants to update the tests themselves).
|
||||
accept=0
|
||||
|
||||
|
||||
# Returns 0 if current docker image exists.
|
||||
function check_if_docker_image_exists {
|
||||
images=`docker image ls | egrep "$IMAGE_NAME[[:space:]]+$IMAGE_VERSION"`
|
||||
check_if_docker_image_exists() {
|
||||
images=$(docker image ls | grep -E "$IMAGE_NAME[[:space:]]+$IMAGE_VERSION")
|
||||
}
|
||||
|
||||
|
||||
# Uncompresses and compiles the specified version of Dropbear.
|
||||
function compile_dropbear {
|
||||
compile_dropbear() {
|
||||
version=$1
|
||||
compile 'Dropbear' $version
|
||||
compile 'Dropbear' "$version"
|
||||
}
|
||||
|
||||
|
||||
# Uncompresses and compiles the specified version of OpenSSH.
|
||||
function compile_openssh {
|
||||
compile_openssh() {
|
||||
version=$1
|
||||
compile 'OpenSSH' $version
|
||||
compile 'OpenSSH' "$version"
|
||||
}
|
||||
|
||||
|
||||
# Uncompresses and compiles the specified version of TinySSH.
|
||||
function compile_tinyssh {
|
||||
compile_tinyssh() {
|
||||
version=$1
|
||||
compile 'TinySSH' $version
|
||||
compile 'TinySSH' "$version"
|
||||
}
|
||||
|
||||
|
||||
function compile {
|
||||
compile() {
|
||||
project=$1
|
||||
version=$2
|
||||
|
||||
@ -76,38 +85,38 @@ function compile {
|
||||
source_dir=
|
||||
server_executable=
|
||||
if [[ $project == 'OpenSSH' ]]; then
|
||||
tarball="openssh-${version}.tar.gz"
|
||||
uncompress_options="xzf"
|
||||
source_dir="openssh-${version}"
|
||||
server_executable=sshd
|
||||
tarball="openssh-${version}.tar.gz"
|
||||
uncompress_options="xzf"
|
||||
source_dir="openssh-${version}"
|
||||
server_executable=sshd
|
||||
elif [[ $project == 'Dropbear' ]]; then
|
||||
tarball="dropbear-${version}.tar.bz2"
|
||||
uncompress_options="xjf"
|
||||
source_dir="dropbear-${version}"
|
||||
server_executable=dropbear
|
||||
tarball="dropbear-${version}.tar.bz2"
|
||||
uncompress_options="xjf"
|
||||
source_dir="dropbear-${version}"
|
||||
server_executable=dropbear
|
||||
elif [[ $project == 'TinySSH' ]]; then
|
||||
tarball="${version}.tar.gz"
|
||||
uncompress_options="xzf"
|
||||
source_dir="tinyssh-${version}"
|
||||
server_executable='build/bin/tinysshd'
|
||||
tarball="${version}.tar.gz"
|
||||
uncompress_options="xzf"
|
||||
source_dir="tinyssh-${version}"
|
||||
server_executable='build/bin/tinysshd'
|
||||
fi
|
||||
|
||||
echo "Uncompressing ${project} ${version}..."
|
||||
tar $uncompress_options $tarball
|
||||
tar $uncompress_options "$tarball"
|
||||
|
||||
echo "Compiling ${project} ${version}..."
|
||||
pushd $source_dir > /dev/null
|
||||
pushd "$source_dir" > /dev/null
|
||||
|
||||
# TinySSH has no configure script... only a Makefile.
|
||||
if [[ $project == 'TinySSH' ]]; then
|
||||
make -j 10
|
||||
make -j 10
|
||||
else
|
||||
./configure && make -j 10
|
||||
./configure && make -j 10
|
||||
fi
|
||||
|
||||
if [[ ! -f $server_executable ]]; then
|
||||
echo -e "${REDB}Error: ${server_executable} not built!${CLR}"
|
||||
exit 1
|
||||
echo -e "${REDB}Error: ${server_executable} not built!${CLR}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\n${GREEN}Successfully built ${project} ${version}${CLR}\n"
|
||||
@ -116,16 +125,16 @@ function compile {
|
||||
|
||||
|
||||
# Creates a new docker image.
|
||||
function create_docker_image {
|
||||
create_docker_image() {
|
||||
# Create a new temporary directory.
|
||||
TMP_DIR=`mktemp -d /tmp/sshaudit-docker-XXXXXXXXXX`
|
||||
TMP_DIR=$(mktemp -d /tmp/sshaudit-docker-XXXXXXXXXX)
|
||||
|
||||
# Copy the Dockerfile and all files in the test/docker/ dir to our new temp directory.
|
||||
find test/docker/ -maxdepth 1 -type f | xargs cp -t $TMP_DIR
|
||||
find test/docker/ -maxdepth 1 -type f -exec cp -t "$TMP_DIR" '{}' +
|
||||
|
||||
# Make the temp directory our working directory for the duration of the build
|
||||
# process.
|
||||
pushd $TMP_DIR > /dev/null
|
||||
pushd "$TMP_DIR" > /dev/null
|
||||
|
||||
# Get the release keys.
|
||||
get_dropbear_release_key
|
||||
@ -204,43 +213,43 @@ function create_docker_image {
|
||||
|
||||
|
||||
# Now build the docker image!
|
||||
docker build --tag $IMAGE_NAME:$IMAGE_VERSION .
|
||||
docker build --tag "$IMAGE_NAME:$IMAGE_VERSION" .
|
||||
|
||||
popd > /dev/null
|
||||
rm -rf $TMP_DIR
|
||||
rm -rf -- "$TMP_DIR"
|
||||
}
|
||||
|
||||
|
||||
# Creates an OpenSSH configuration file for a specific test.
|
||||
function create_openssh_config {
|
||||
create_openssh_config() {
|
||||
openssh_version=$1
|
||||
test_number=$2
|
||||
config_text=$3
|
||||
|
||||
cp sshd_config-${openssh_version}_orig sshd_config-${openssh_version}_${test_number}
|
||||
echo -e "${config_text}" >> sshd_config-${openssh_version}_${test_number}
|
||||
cp "sshd_config-${openssh_version}_orig" "sshd_config-${openssh_version}_${test_number}"
|
||||
echo -e "${config_text}" >> "sshd_config-${openssh_version}_${test_number}"
|
||||
}
|
||||
|
||||
|
||||
# Downloads the Dropbear release key and adds it to the local keyring.
|
||||
function get_dropbear_release_key {
|
||||
get_dropbear_release_key() {
|
||||
get_release_key 'Dropbear' 'https://matt.ucc.asn.au/dropbear/releases/dropbear-key-2015.asc' 'F29C6773' 'F734 7EF2 EE2E 07A2 6762 8CA9 4493 1494 F29C 6773'
|
||||
}
|
||||
|
||||
|
||||
# Downloads the OpenSSH release key and adds it to the local keyring.
|
||||
function get_openssh_release_key {
|
||||
get_openssh_release_key() {
|
||||
get_release_key 'OpenSSH' 'https://ftp.openbsd.org/pub/OpenBSD/OpenSSH/RELEASE_KEY.asc' '6D920D30' '59C2 118E D206 D927 E667 EBE3 D3E5 F56B 6D92 0D30'
|
||||
}
|
||||
|
||||
|
||||
# Downloads the TinySSH release key and adds it to the local keyring.
|
||||
function get_tinyssh_release_key {
|
||||
get_tinyssh_release_key() {
|
||||
get_release_key 'TinySSH' '' '96939FF9' 'AADF 2EDF 5529 F170 2772 C8A2 DEC4 D246 931E F49B'
|
||||
}
|
||||
|
||||
|
||||
function get_release_key {
|
||||
get_release_key() {
|
||||
project=$1
|
||||
key_url=$2
|
||||
key_id=$3
|
||||
@ -248,51 +257,51 @@ function get_release_key {
|
||||
|
||||
# The TinySSH release key isn't on any website, apparently.
|
||||
if [[ $project == 'TinySSH' ]]; then
|
||||
gpg --keyserver keys.gnupg.net --recv-key $key_id
|
||||
gpg --keyserver keys.gnupg.net --recv-key "$key_id"
|
||||
else
|
||||
echo -e "\nGetting ${project} release key...\n"
|
||||
wget -O key.asc $2
|
||||
echo -e "\nGetting ${project} release key...\n"
|
||||
wget -O key.asc "$2"
|
||||
|
||||
echo -e "\nImporting ${project} release key...\n"
|
||||
gpg --import key.asc
|
||||
echo -e "\nImporting ${project} release key...\n"
|
||||
gpg --import key.asc
|
||||
|
||||
rm key.asc
|
||||
rm key.asc
|
||||
fi
|
||||
|
||||
local release_key_fingerprint_actual=`gpg --fingerprint ${key_id}`
|
||||
local release_key_fingerprint_actual=$(gpg --fingerprint "$key_id")
|
||||
if [[ $release_key_fingerprint_actual != *"$release_key_fingerprint_expected"* ]]; then
|
||||
echo -e "\n${REDB}Error: ${project} release key fingerprint does not match expected value!\n\tExpected: $release_key_fingerprint_expected\n\tActual: $release_key_fingerprint_actual\n\nTerminating.${CLR}"
|
||||
exit -1
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\n\n${GREEN}${project} release key matches expected value.${CLR}\n"
|
||||
}
|
||||
|
||||
|
||||
# Downloads the specified version of Dropbear.
|
||||
function get_dropbear {
|
||||
get_dropbear() {
|
||||
version=$1
|
||||
tarball_checksum_expected=$2
|
||||
get_source 'Dropbear' $version $tarball_checksum_expected
|
||||
get_source 'Dropbear' "$version" "$tarball_checksum_expected"
|
||||
}
|
||||
|
||||
|
||||
# Downloads the specified version of OpenSSH.
|
||||
function get_openssh {
|
||||
get_openssh() {
|
||||
version=$1
|
||||
tarball_checksum_expected=$2
|
||||
get_source 'OpenSSH' $version $tarball_checksum_expected
|
||||
get_source 'OpenSSH' "$version" "$tarball_checksum_expected"
|
||||
}
|
||||
|
||||
|
||||
# Downloads the specified version of TinySSH.
|
||||
function get_tinyssh {
|
||||
get_tinyssh() {
|
||||
version=$1
|
||||
tarball_checksum_expected=$2
|
||||
get_source 'TinySSH' $version $tarball_checksum_expected
|
||||
get_source 'TinySSH' "$version" "$tarball_checksum_expected"
|
||||
}
|
||||
|
||||
|
||||
function get_source {
|
||||
get_source() {
|
||||
project=$1
|
||||
version=$2
|
||||
tarball_checksum_expected=$3
|
||||
@ -303,23 +312,23 @@ function get_source {
|
||||
sig=
|
||||
signer=
|
||||
if [[ $project == 'OpenSSH' ]]; then
|
||||
base_url_source='https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/'
|
||||
base_url_sig=$base_url_source
|
||||
tarball="openssh-${version}.tar.gz"
|
||||
sig="${tarball}.asc"
|
||||
signer="Damien Miller "
|
||||
base_url_source='https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/'
|
||||
base_url_sig=$base_url_source
|
||||
tarball="openssh-${version}.tar.gz"
|
||||
sig="${tarball}.asc"
|
||||
signer="Damien Miller "
|
||||
elif [[ $project == 'Dropbear' ]]; then
|
||||
base_url_source='https://matt.ucc.asn.au/dropbear/releases/'
|
||||
base_url_sig=$base_url_source
|
||||
tarball="dropbear-${version}.tar.bz2"
|
||||
sig="${tarball}.asc"
|
||||
signer="Dropbear SSH Release Signing <matt@ucc.asn.au>"
|
||||
base_url_source='https://matt.ucc.asn.au/dropbear/releases/'
|
||||
base_url_sig=$base_url_source
|
||||
tarball="dropbear-${version}.tar.bz2"
|
||||
sig="${tarball}.asc"
|
||||
signer="Dropbear SSH Release Signing <matt@ucc.asn.au>"
|
||||
elif [[ $project == 'TinySSH' ]]; then
|
||||
base_url_source='https://github.com/janmojzis/tinyssh/archive/'
|
||||
base_url_sig="https://github.com/janmojzis/tinyssh/releases/download/${version}/"
|
||||
tarball="${version}.tar.gz"
|
||||
sig="${tarball}.asc"
|
||||
signer="Jan Mojžíš <jan.mojzis@gmail.com>"
|
||||
base_url_source='https://github.com/janmojzis/tinyssh/archive/'
|
||||
base_url_sig="https://github.com/janmojzis/tinyssh/releases/download/${version}/"
|
||||
tarball="${version}.tar.gz"
|
||||
sig="${tarball}.asc"
|
||||
signer="Jan Mojžíš <jan.mojzis@gmail.com>"
|
||||
fi
|
||||
|
||||
echo -e "\nGetting ${project} ${version} sources...\n"
|
||||
@ -331,48 +340,48 @@ function get_source {
|
||||
|
||||
# Older OpenSSH releases were .sigs.
|
||||
if [[ ($project == 'OpenSSH') && (! -f $sig) ]]; then
|
||||
wget ${base_url_sig}openssh-${version}.tar.gz.sig
|
||||
sig=openssh-${version}.tar.gz.sig
|
||||
wget "${base_url_sig}openssh-${version}.tar.gz.sig"
|
||||
sig=openssh-${version}.tar.gz.sig
|
||||
fi
|
||||
|
||||
local gpg_verify=`gpg --verify ${sig} ${tarball} 2>&1`
|
||||
local gpg_verify=$(gpg --verify "${sig}" "${tarball}" 2>&1)
|
||||
if [[ $gpg_verify != *"Good signature from \"${signer}"* ]]; then
|
||||
echo -e "\n\n${REDB}Error: ${project} signature invalid!\n$gpg_verify\n\nTerminating.${CLR}"
|
||||
exit -1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check GPG's return value. 0 denotes a valid signature, and 1 is returned
|
||||
# on invalid signatures.
|
||||
if [[ $? != 0 ]]; then
|
||||
echo -e "\n\n${REDB}Error: ${project} signature invalid! Verification returned code: $?\n\nTerminating.${CLR}"
|
||||
exit -1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Signature on ${project} sources verified.${CLR}\n"
|
||||
|
||||
local checksum_actual=`sha256sum ${tarball} | cut -f1 -d" "`
|
||||
if [[ $checksum_actual != $tarball_checksum_expected ]]; then
|
||||
local checksum_actual=$(sha256sum "${tarball}" | cut -f1 -d" ")
|
||||
if [[ $checksum_actual != "$tarball_checksum_expected" ]]; then
|
||||
echo -e "${REDB}Error: ${project} checksum is invalid!\n Expected: ${tarball_checksum_expected}\n Actual: ${checksum_actual}\n\n Terminating.${CLR}"
|
||||
exit -1
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Pulls the defined image from Dockerhub.
|
||||
function pull_docker_image {
|
||||
docker pull $IMAGE_NAME:$IMAGE_VERSION
|
||||
pull_docker_image() {
|
||||
docker pull "$IMAGE_NAME:$IMAGE_VERSION"
|
||||
if [[ $? == 0 ]]; then
|
||||
echo -e "${GREEN}Successfully downloaded image ${IMAGE_NAME}:${IMAGE_VERSION} from Dockerhub.${CLR}\n"
|
||||
echo -e "${GREEN}Successfully downloaded image $IMAGE_NAME:$IMAGE_VERSION from Dockerhub.${CLR}\n"
|
||||
else
|
||||
echo -e "${REDB}Failed to pull image ${IMAGE_NAME}:${IMAGE_VERSION} from Dockerhub! Error code: $?${CLR}\n"
|
||||
exit -1
|
||||
echo -e "${REDB}Failed to pull image $IMAGE_NAME:$IMAGE_VERSION from Dockerhub! Error code: $?${CLR}\n"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Runs a Dropbear test. Upon failure, a diff between the expected and actual results
|
||||
# is shown, then the script immediately terminates.
|
||||
function run_dropbear_test {
|
||||
run_dropbear_test() {
|
||||
dropbear_version=$1
|
||||
test_number=$2
|
||||
options=$3
|
||||
@ -384,7 +393,7 @@ function run_dropbear_test {
|
||||
|
||||
# Runs an OpenSSH test. Upon failure, a diff between the expected and actual results
|
||||
# is shown, then the script immediately terminates.
|
||||
function run_openssh_test {
|
||||
run_openssh_test() {
|
||||
openssh_version=$1
|
||||
test_number=$2
|
||||
expected_retval=$3
|
||||
@ -395,7 +404,7 @@ function run_openssh_test {
|
||||
|
||||
# Runs a TinySSH test. Upon failure, a diff between the expected and actual results
|
||||
# is shown, then the script immediately terminates.
|
||||
function run_tinyssh_test {
|
||||
run_tinyssh_test() {
|
||||
tinyssh_version=$1
|
||||
test_number=$2
|
||||
expected_retval=$3
|
||||
@ -404,7 +413,7 @@ function run_tinyssh_test {
|
||||
}
|
||||
|
||||
|
||||
function run_test {
|
||||
run_test() {
|
||||
server_type=$1
|
||||
version=$2
|
||||
test_number=$3
|
||||
@ -419,50 +428,62 @@ function run_test {
|
||||
expected_result_json=
|
||||
test_name=
|
||||
if [[ $server_type == 'OpenSSH' ]]; then
|
||||
server_exec="/openssh/sshd-${version} -D -f /etc/ssh/sshd_config-${version}_${test_number}"
|
||||
test_result_stdout="${TEST_RESULT_DIR}/openssh_${version}_${test_number}.txt"
|
||||
test_result_json="${TEST_RESULT_DIR}/openssh_${version}_${test_number}.json"
|
||||
expected_result_stdout="test/docker/expected_results/openssh_${version}_${test_number}.txt"
|
||||
expected_result_json="test/docker/expected_results/openssh_${version}_${test_number}.json"
|
||||
test_name="OpenSSH ${version} ${test_number}"
|
||||
options=
|
||||
server_exec="/openssh/sshd-${version} -D -f /etc/ssh/sshd_config-${version}_${test_number}"
|
||||
test_result_stdout="${TEST_RESULT_DIR}/openssh_${version}_${test_number}.txt"
|
||||
test_result_json="${TEST_RESULT_DIR}/openssh_${version}_${test_number}.json"
|
||||
expected_result_stdout="test/docker/expected_results/openssh_${version}_${test_number}.txt"
|
||||
expected_result_json="test/docker/expected_results/openssh_${version}_${test_number}.json"
|
||||
test_name="OpenSSH ${version} ${test_number}"
|
||||
options=
|
||||
elif [[ $server_type == 'Dropbear' ]]; then
|
||||
server_exec="/dropbear/dropbear-${version} -F ${options}"
|
||||
test_result_stdout="${TEST_RESULT_DIR}/dropbear_${version}_${test_number}.txt"
|
||||
test_result_json="${TEST_RESULT_DIR}/dropbear_${version}_${test_number}.json"
|
||||
expected_result_stdout="test/docker/expected_results/dropbear_${version}_${test_number}.txt"
|
||||
expected_result_json="test/docker/expected_results/dropbear_${version}_${test_number}.json"
|
||||
test_name="Dropbear ${version} ${test_number}"
|
||||
server_exec="/dropbear/dropbear-${version} -F ${options}"
|
||||
test_result_stdout="${TEST_RESULT_DIR}/dropbear_${version}_${test_number}.txt"
|
||||
test_result_json="${TEST_RESULT_DIR}/dropbear_${version}_${test_number}.json"
|
||||
expected_result_stdout="test/docker/expected_results/dropbear_${version}_${test_number}.txt"
|
||||
expected_result_json="test/docker/expected_results/dropbear_${version}_${test_number}.json"
|
||||
test_name="Dropbear ${version} ${test_number}"
|
||||
elif [[ $server_type == 'TinySSH' ]]; then
|
||||
server_exec="/usr/bin/tcpserver -HRDl0 0.0.0.0 22 /tinysshd/tinyssh-20190101 -v /etc/tinyssh/"
|
||||
test_result_stdout="${TEST_RESULT_DIR}/tinyssh_${version}_${test_number}.txt"
|
||||
test_result_json="${TEST_RESULT_DIR}/tinyssh_${version}_${test_number}.json"
|
||||
expected_result_stdout="test/docker/expected_results/tinyssh_${version}_${test_number}.txt"
|
||||
expected_result_json="test/docker/expected_results/tinyssh_${version}_${test_number}.json"
|
||||
test_name="TinySSH ${version} ${test_number}"
|
||||
server_exec="/usr/bin/tcpserver -HRDl0 0.0.0.0 22 /tinysshd/tinyssh-20190101 -v /etc/tinyssh/"
|
||||
test_result_stdout="${TEST_RESULT_DIR}/tinyssh_${version}_${test_number}.txt"
|
||||
test_result_json="${TEST_RESULT_DIR}/tinyssh_${version}_${test_number}.json"
|
||||
expected_result_stdout="test/docker/expected_results/tinyssh_${version}_${test_number}.txt"
|
||||
expected_result_json="test/docker/expected_results/tinyssh_${version}_${test_number}.json"
|
||||
test_name="TinySSH ${version} ${test_number}"
|
||||
fi
|
||||
|
||||
cid=`docker run -d -p 2222:22 ${IMAGE_NAME}:${IMAGE_VERSION} ${server_exec}`
|
||||
#echo "Running: docker run -d -p 2222:22 ${IMAGE_NAME}:${IMAGE_VERSION} ${server_exec}"
|
||||
cid=$(docker run -d -p 2222:22 "$IMAGE_NAME:$IMAGE_VERSION" ${server_exec})
|
||||
#echo "Running: docker run -d -p 2222:22 $IMAGE_NAME:$IMAGE_VERSION ${server_exec}"
|
||||
if [[ $? != 0 ]]; then
|
||||
echo -e "${REDB}Failed to run docker image! (exit code: $?)${CLR}"
|
||||
exit 1
|
||||
echo -e "${REDB}Failed to run docker image! (exit code: $?)${CLR}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
./ssh-audit.py localhost:2222 > $test_result_stdout
|
||||
./ssh-audit.py localhost:2222 > "$test_result_stdout"
|
||||
actual_retval=$?
|
||||
if [[ $actual_retval != $expected_retval ]]; then
|
||||
echo -e "${REDB}Unexpected return value. Expected: ${expected_retval}; Actual: ${actual_retval}${CLR}"
|
||||
docker container stop -t 0 $cid > /dev/null
|
||||
exit 1
|
||||
if [[ $actual_retval != "$expected_retval" ]]; then
|
||||
echo -e "${REDB}Unexpected return value. Expected: ${expected_retval}; Actual: ${actual_retval}${CLR}"
|
||||
|
||||
if [[ $accept == 1 ]]; then
|
||||
echo -e "\n${REDB}This failure cannot be automatically fixed; this script must be manually updated with the new expected return value.${CLR}"
|
||||
fi
|
||||
|
||||
cat ${test_result_stdout}
|
||||
docker container stop -t 0 $cid > /dev/null
|
||||
exit 1
|
||||
fi
|
||||
|
||||
./ssh-audit.py -j localhost:2222 > $test_result_json
|
||||
./ssh-audit.py -jj localhost:2222 > "$test_result_json"
|
||||
actual_retval=$?
|
||||
if [[ $actual_retval != $expected_retval ]]; then
|
||||
echo -e "${REDB}Unexpected return value. Expected: ${expected_retval}; Actual: ${actual_retval}${CLR}"
|
||||
docker container stop -t 0 $cid > /dev/null
|
||||
exit 1
|
||||
if [[ $actual_retval != "$expected_retval" ]]; then
|
||||
echo -e "${REDB}Unexpected return value. Expected: ${expected_retval}; Actual: ${actual_retval}${CLR}"
|
||||
|
||||
if [[ $accept == 1 ]]; then
|
||||
echo -e "\n${REDB}This failure cannot be automatically fixed; this script must be manually updated with the new expected return value.${CLR}"
|
||||
fi
|
||||
|
||||
cat ${test_result_json}
|
||||
docker container stop -t 0 $cid > /dev/null
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docker container stop -t 0 $cid > /dev/null
|
||||
@ -475,32 +496,48 @@ function run_test {
|
||||
# we need to filter out the banner part of the output so we get stable, repeatable
|
||||
# results.
|
||||
if [[ $server_type == 'TinySSH' ]]; then
|
||||
grep -v "(gen) banner: " ${test_result_stdout} > "${test_result_stdout}.tmp"
|
||||
mv "${test_result_stdout}.tmp" ${test_result_stdout}
|
||||
cat "${test_result_json}" | perl -pe 's/"comments": ".*?"/"comments": ""/' | perl -pe 's/"raw": ".+?"/"raw": ""/' > "${test_result_json}.tmp"
|
||||
mv "${test_result_json}.tmp" ${test_result_json}
|
||||
grep -v "(gen) banner: " "${test_result_stdout}" > "${test_result_stdout}.tmp"
|
||||
mv "${test_result_stdout}.tmp" "${test_result_stdout}"
|
||||
cat "${test_result_json}" | perl -pe 's/"comments": ".*?"/"comments": ""/' | perl -pe 's/"raw": ".+?"/"raw": ""/' > "${test_result_json}.tmp"
|
||||
mv "${test_result_json}.tmp" "${test_result_json}"
|
||||
fi
|
||||
|
||||
diff=`diff -u ${expected_result_stdout} ${test_result_stdout}`
|
||||
diff=$(diff -u "${expected_result_stdout}" "${test_result_stdout}")
|
||||
if [[ $? != 0 ]]; then
|
||||
echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n"
|
||||
failed=1
|
||||
num_failures=$((num_failures+1))
|
||||
|
||||
# If the user wants to update the tests, then overwrite the expected results with the actual results.
|
||||
if [[ $accept == 1 ]]; then
|
||||
cp "${test_result_stdout}" "${expected_result_stdout}"
|
||||
echo -e "${test_name} ${YELLOWB}UPDATED${CLR}\n"
|
||||
else
|
||||
echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n"
|
||||
failed=1
|
||||
num_failures=$((num_failures+1))
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
diff=`diff -u ${expected_result_json} ${test_result_json}`
|
||||
diff=$(diff -u "${expected_result_json}" "${test_result_json}")
|
||||
if [[ $? != 0 ]]; then
|
||||
echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n"
|
||||
failed=1
|
||||
num_failures=$((num_failures+1))
|
||||
|
||||
# If the user wants to update the tests, then overwrite the expected results with the actual results.
|
||||
if [[ $accept == 1 ]]; then
|
||||
cp "${test_result_json}" "${expected_result_json}"
|
||||
echo -e "${test_name} ${YELLOWB}UPDATED${CLR}\n"
|
||||
else
|
||||
echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n"
|
||||
failed=1
|
||||
num_failures=$((num_failures+1))
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if [[ $failed == 0 ]]; then
|
||||
echo -e "${test_name} ${GREEN}passed${CLR}."
|
||||
echo -e "${test_name} ${GREEN}passed${CLR}."
|
||||
fi
|
||||
}
|
||||
|
||||
function run_builtin_policy_test {
|
||||
run_builtin_policy_test() {
|
||||
policy_name=$1 # The built-in policy name to use.
|
||||
version=$2 # Version of OpenSSH to test with.
|
||||
test_number=$3 # The test number to run.
|
||||
@ -518,7 +555,7 @@ function run_builtin_policy_test {
|
||||
}
|
||||
|
||||
|
||||
function run_custom_policy_test {
|
||||
run_custom_policy_test() {
|
||||
config_number=$1 # The configuration number to use.
|
||||
test_number=$2 # The policy test number to run.
|
||||
expected_exit_code=$3 # The expected exit code of ssh-audit.py.
|
||||
@ -548,7 +585,7 @@ function run_custom_policy_test {
|
||||
}
|
||||
|
||||
|
||||
function run_policy_test {
|
||||
run_policy_test() {
|
||||
test_name=$1
|
||||
server_exec=$2
|
||||
policy_path=$3
|
||||
@ -557,31 +594,41 @@ function run_policy_test {
|
||||
expected_exit_code=$6
|
||||
|
||||
|
||||
#echo "Running: docker run -d -p 2222:22 ${IMAGE_NAME}:${IMAGE_VERSION} ${server_exec}"
|
||||
cid=`docker run -d -p 2222:22 ${IMAGE_NAME}:${IMAGE_VERSION} ${server_exec}`
|
||||
#echo "Running: docker run -d -p 2222:22 $IMAGE_NAME:$IMAGE_VERSION ${server_exec}"
|
||||
cid=$(docker run -d -p 2222:22 "$IMAGE_NAME:$IMAGE_VERSION" ${server_exec})
|
||||
if [[ $? != 0 ]]; then
|
||||
echo -e "${REDB}Failed to run docker image! (exit code: $?)${CLR}"
|
||||
exit 1
|
||||
echo -e "${REDB}Failed to run docker image! (exit code: $?)${CLR}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#echo "Running: ./ssh-audit.py -P \"${policy_path}\" localhost:2222 > ${test_result_stdout}"
|
||||
./ssh-audit.py -P "${policy_path}" localhost:2222 > ${test_result_stdout}
|
||||
./ssh-audit.py -P "${policy_path}" localhost:2222 > "${test_result_stdout}"
|
||||
actual_exit_code=$?
|
||||
if [[ ${actual_exit_code} != ${expected_exit_code} ]]; then
|
||||
echo -e "${test_name} ${REDB}FAILED${CLR} (expected exit code: ${expected_exit_code}; actual exit code: ${actual_exit_code}\n"
|
||||
cat ${test_result_stdout}
|
||||
docker container stop -t 0 $cid > /dev/null
|
||||
exit 1
|
||||
if [[ ${actual_exit_code} != "${expected_exit_code}" ]]; then
|
||||
echo -e "${test_name} ${REDB}FAILED${CLR} (expected exit code: ${expected_exit_code}; actual exit code: ${actual_exit_code}\n"
|
||||
|
||||
if [[ $accept == 1 ]]; then
|
||||
echo -e "\n${REDB}This failure cannot be automatically fixed; this script must be manually updated with the new expected return value.${CLR}"
|
||||
fi
|
||||
|
||||
cat "${test_result_stdout}"
|
||||
docker container stop -t 0 $cid > /dev/null
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#echo "Running: ./ssh-audit.py -P \"${policy_path}\" -j localhost:2222 > ${test_result_json}"
|
||||
./ssh-audit.py -P "${policy_path}" -j localhost:2222 > ${test_result_json}
|
||||
#echo "Running: ./ssh-audit.py -P \"${policy_path}\" -jj localhost:2222 > ${test_result_json} 2> /dev/null"
|
||||
./ssh-audit.py -P "${policy_path}" -jj localhost:2222 > "${test_result_json}" 2> /dev/null
|
||||
actual_exit_code=$?
|
||||
if [[ ${actual_exit_code} != ${expected_exit_code} ]]; then
|
||||
echo -e "${test_name} ${REDB}FAILED${CLR} (expected exit code: ${expected_exit_code}; actual exit code: ${actual_exit_code}\n"
|
||||
cat ${test_result_json}
|
||||
docker container stop -t 0 $cid > /dev/null
|
||||
exit 1
|
||||
if [[ ${actual_exit_code} != "${expected_exit_code}" ]]; then
|
||||
echo -e "${test_name} ${REDB}FAILED${CLR} (expected exit code: ${expected_exit_code}; actual exit code: ${actual_exit_code}\n"
|
||||
|
||||
if [[ $accept == 1 ]]; then
|
||||
echo -e "\n${REDB}This failure cannot be automatically fixed; this script must be manually updated with the new expected return value.${CLR}"
|
||||
fi
|
||||
|
||||
cat "${test_result_json}"
|
||||
docker container stop -t 0 $cid > /dev/null
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docker container stop -t 0 $cid > /dev/null
|
||||
@ -590,16 +637,32 @@ function run_policy_test {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
diff=`diff -u ${expected_result_stdout} ${test_result_stdout}`
|
||||
diff=$(diff -u "${expected_result_stdout}" "${test_result_stdout}")
|
||||
if [[ $? != 0 ]]; then
|
||||
echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n"
|
||||
exit 1
|
||||
|
||||
# If the user wants to update the tests, then overwrite the expected results with the actual results.
|
||||
if [[ $accept == 1 ]]; then
|
||||
cp "${test_result_stdout}" "${expected_result_stdout}"
|
||||
echo -e "${test_name} ${YELLOWB}UPDATED${CLR}\n"
|
||||
else
|
||||
echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
diff=`diff -u ${expected_result_json} ${test_result_json}`
|
||||
diff=$(diff -u "${expected_result_json}" "${test_result_json}")
|
||||
if [[ $? != 0 ]]; then
|
||||
echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n"
|
||||
exit 1
|
||||
|
||||
# If the user wants to update the tests, then overwrite the expected results with the actual results.
|
||||
if [[ $accept == 1 ]]; then
|
||||
cp "${test_result_json}" "${expected_result_json}"
|
||||
echo -e "${test_name} ${YELLOWB}UPDATED${CLR}\n"
|
||||
else
|
||||
echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
echo -e "${test_name} ${GREEN}passed${CLR}."
|
||||
@ -637,6 +700,13 @@ if [[ ($# == 1) && ($1 == "--create") ]]; then
|
||||
fi
|
||||
|
||||
|
||||
# If the user passes --accept, then the actual results will replace the expected results (meaning the user wants to update the tests themselves due to new functionality).
|
||||
if [[ ($# == 1) && ($1 == "--accept") ]]; then
|
||||
accept=1
|
||||
echo -e "\n${YELLOWB}Expected test results will be replaced with actual results.${CLR}"
|
||||
fi
|
||||
|
||||
|
||||
# If we weren't explicitly told to create a new image, and it doesn't exist, then pull it from Dockerhub.
|
||||
if [[ $docker_image_exists == 0 ]]; then
|
||||
echo -e "\nPulling docker image $IMAGE_NAME:$IMAGE_VERSION..."
|
||||
@ -647,7 +717,7 @@ fi
|
||||
echo -e "\n${GREEN}Starting tests...${CLR}"
|
||||
|
||||
# Create a temporary directory to write test results to.
|
||||
TEST_RESULT_DIR=`mktemp -d /tmp/ssh-audit_test-results_XXXXXXXXXX`
|
||||
TEST_RESULT_DIR=$(mktemp -d /tmp/ssh-audit_test-results_XXXXXXXXXX)
|
||||
|
||||
# Now run all the tests.
|
||||
echo -e "\nRunning tests..."
|
||||
@ -661,7 +731,7 @@ run_openssh_test '5.6p1' 'test5' $PROGRAM_RETVAL_FAILURE
|
||||
echo
|
||||
run_openssh_test '8.0p1' 'test1' $PROGRAM_RETVAL_FAILURE
|
||||
run_openssh_test '8.0p1' 'test2' $PROGRAM_RETVAL_FAILURE
|
||||
run_openssh_test '8.0p1' 'test3' $PROGRAM_RETVAL_GOOD
|
||||
run_openssh_test '8.0p1' 'test3' $PROGRAM_RETVAL_WARNING
|
||||
echo
|
||||
run_dropbear_test '2019.78' 'test1' '-r /etc/dropbear/dropbear_rsa_host_key_1024 -r /etc/dropbear/dropbear_dss_host_key -r /etc/dropbear/dropbear_ecdsa_host_key' 3
|
||||
echo
|
||||
@ -699,16 +769,16 @@ run_custom_policy_test 'config2' 'test13' $PROGRAM_RETVAL_GOOD
|
||||
# Failing test with DH modulus test.
|
||||
run_custom_policy_test 'config2' 'test14' $PROGRAM_RETVAL_FAILURE
|
||||
|
||||
# Passing test for built-in OpenSSH 8.0p1 server policy.
|
||||
run_builtin_policy_test "Hardened OpenSSH Server v8.0 (version 1)" "8.0p1" "test1" "-o HostKeyAlgorithms=ssh-ed25519 -o KexAlgorithms=curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr -o MACs=hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com" $PROGRAM_RETVAL_GOOD
|
||||
# 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 2)" "8.0p1" "test1" "-o HostKeyAlgorithms=rsa-sha2-512,rsa-sha2-256,ssh-ed25519 -o KexAlgorithms=curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr -o MACs=hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com" $PROGRAM_RETVAL_FAILURE
|
||||
|
||||
# Failing test for built-in OpenSSH 8.0p1 server policy (MACs not hardened).
|
||||
run_builtin_policy_test "Hardened OpenSSH Server v8.0 (version 1)" "8.0p1" "test2" "-o HostKeyAlgorithms=ssh-ed25519 -o KexAlgorithms=curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr" $PROGRAM_RETVAL_FAILURE
|
||||
run_builtin_policy_test "Hardened OpenSSH Server v8.0 (version 2)" "8.0p1" "test2" "-o HostKeyAlgorithms=rsa-sha2-512,rsa-sha2-256,ssh-ed25519 -o KexAlgorithms=curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr" $PROGRAM_RETVAL_FAILURE
|
||||
|
||||
|
||||
if [[ $num_failures == 0 ]]; then
|
||||
echo -e "\n${GREENB}ALL TESTS PASS!${CLR}\n"
|
||||
rm -rf $TEST_RESULT_DIR
|
||||
rm -rf -- "$TEST_RESULT_DIR"
|
||||
else
|
||||
echo -e "\n${REDB}${num_failures} TESTS FAILED!${CLR}\n"
|
||||
fi
|
||||
|
@ -6,7 +6,8 @@ author_email = jtesta@positronsecurity.com
|
||||
description = An SSH server & client configuration security auditing tool
|
||||
long_description = file: README.md
|
||||
long_description_content_type = text/markdown
|
||||
license_file = LICENSE
|
||||
license = MIT
|
||||
license_files = LICENSE
|
||||
url = https://github.com/jtesta/ssh-audit
|
||||
project_urls =
|
||||
Source Code = https://github.com/jtesta/ssh-audit
|
||||
@ -18,10 +19,11 @@ classifiers =
|
||||
License :: OSI Approved :: MIT License
|
||||
Operating System :: OS Independent
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.6
|
||||
Programming Language :: Python :: 3.7
|
||||
Programming Language :: Python :: 3.8
|
||||
Programming Language :: Python :: 3.9
|
||||
Programming Language :: Python :: 3.10
|
||||
Programming Language :: Python :: 3.11
|
||||
Programming Language :: Python :: Implementation :: CPython
|
||||
Programming Language :: Python :: Implementation :: PyPy
|
||||
Topic :: Security
|
||||
@ -31,7 +33,7 @@ classifiers =
|
||||
packages = find:
|
||||
package_dir =
|
||||
= src
|
||||
python_requires = >=3.6,<4
|
||||
python_requires = >=3.7,<4
|
||||
|
||||
[options.packages.find]
|
||||
where = src
|
||||
|
@ -1,21 +1,20 @@
|
||||
name: ssh-audit
|
||||
version: '2.4.0-1'
|
||||
# 'version' field will be automatically added by build_snap.sh.
|
||||
license: 'MIT'
|
||||
summary: ssh-audit
|
||||
description: |
|
||||
SSH server and client security configuration auditor. Official repository: <https://github.com/jtesta/ssh-audit>
|
||||
|
||||
base: core20
|
||||
base: core22
|
||||
grade: stable
|
||||
confinement: strict
|
||||
|
||||
apps:
|
||||
ssh-audit:
|
||||
command: bin/ssh-audit
|
||||
plugs: [network,network-bind]
|
||||
plugs: [network,network-bind,home]
|
||||
|
||||
parts:
|
||||
ssh-audit:
|
||||
plugin: python
|
||||
# python-version: python3
|
||||
source: .
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2017-2020 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017-2021 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -55,7 +55,7 @@ class Algorithms:
|
||||
if self.ssh1kex is None:
|
||||
return None
|
||||
item = Algorithms.Item(1, SSH1_KexDB.ALGORITHMS)
|
||||
item.add('key', [u'ssh-rsa1'])
|
||||
item.add('key', ['ssh-rsa1'])
|
||||
item.add('enc', self.ssh1kex.supported_ciphers)
|
||||
item.add('aut', self.ssh1kex.supported_authentications)
|
||||
return item
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2017-2020 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017-2021 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -41,6 +41,7 @@ class AuditConf:
|
||||
self.client_audit = False
|
||||
self.colors = True
|
||||
self.json = False
|
||||
self.json_print_indent = False
|
||||
self.verbose = False
|
||||
self.level = 'info'
|
||||
self.ip_version_preference: List[int] = [] # Holds only 5 possible values: [] (no preference), [4] (use IPv4 only), [6] (use IPv6 only), [46] (use both IPv4 and IPv6, but prioritize v4), and [64] (use both IPv4 and IPv6, but prioritize v6).
|
||||
@ -57,10 +58,12 @@ class AuditConf:
|
||||
self.list_policies = False
|
||||
self.lookup = ''
|
||||
self.manual = False
|
||||
self.debug = False
|
||||
self.gex_test = ''
|
||||
|
||||
def __setattr__(self, name: str, value: Union[str, int, float, bool, Sequence[int]]) -> None:
|
||||
valid = False
|
||||
if name in ['batch', 'client_audit', 'colors', 'json', 'list_policies', 'manual', 'make_policy', 'ssh1', 'ssh2', 'timeout_set', 'verbose']:
|
||||
if name in ['batch', 'client_audit', 'colors', 'json', 'json_print_indent', 'list_policies', 'manual', 'make_policy', 'ssh1', 'ssh2', 'timeout_set', 'verbose', 'debug']:
|
||||
valid, value = True, bool(value)
|
||||
elif name in ['ipv4', 'ipv6']:
|
||||
valid, value = True, bool(value)
|
||||
@ -84,7 +87,7 @@ class AuditConf:
|
||||
if value == -1.0:
|
||||
raise ValueError('invalid timeout: {}'.format(value))
|
||||
valid = True
|
||||
elif name in ['ip_version_preference', 'lookup', 'policy_file', 'policy', 'target_file', 'target_list']:
|
||||
elif name in ['ip_version_preference', 'lookup', 'policy_file', 'policy', 'target_file', 'target_list', 'gex_test']:
|
||||
valid = True
|
||||
elif name == "threads":
|
||||
valid, num_threads = True, Utils.parse_int(value)
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2017-2020 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017-2021 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -33,11 +33,11 @@ class Fingerprint:
|
||||
@property
|
||||
def md5(self) -> str:
|
||||
h = hashlib.md5(self.__fpd).hexdigest()
|
||||
r = u':'.join(h[i:i + 2] for i in range(0, len(h), 2))
|
||||
return u'MD5:{}'.format(r)
|
||||
r = ':'.join(h[i:i + 2] for i in range(0, len(h), 2))
|
||||
return 'MD5:{}'.format(r)
|
||||
|
||||
@property
|
||||
def sha256(self) -> str:
|
||||
h = base64.b64encode(hashlib.sha256(self.__fpd).digest())
|
||||
r = h.decode('ascii').rstrip('=')
|
||||
return u'SHA256:{}'.format(r)
|
||||
return 'SHA256:{}'.format(r)
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2017-2021 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@ -21,15 +21,18 @@
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
import traceback
|
||||
|
||||
# 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.kexdh import KexGroupExchange_SHA1, KexGroupExchange_SHA256
|
||||
from ssh_audit.kexdh import KexDHException, KexGroupExchange_SHA1, KexGroupExchange_SHA256
|
||||
from ssh_audit.ssh2_kexdb import SSH2_KexDB
|
||||
from ssh_audit.ssh2_kex import SSH2_Kex
|
||||
from ssh_audit.ssh_socket import SSH_Socket
|
||||
from ssh_audit.outputbuffer import OutputBuffer
|
||||
from ssh_audit import exitcodes
|
||||
|
||||
|
||||
# Performs DH group exchanges to find what moduli are supported, and checks
|
||||
@ -38,16 +41,18 @@ class GEXTest:
|
||||
|
||||
# Creates a new connection to the server. Returns True on success, or False.
|
||||
@staticmethod
|
||||
def reconnect(s: 'SSH_Socket', kex: 'SSH2_Kex', gex_alg: str) -> bool:
|
||||
def reconnect(out: 'OutputBuffer', s: 'SSH_Socket', kex: 'SSH2_Kex', gex_alg: str) -> bool:
|
||||
if s.is_connected():
|
||||
return True
|
||||
|
||||
err = s.connect()
|
||||
if err is not None:
|
||||
out.v(err, write_now=True)
|
||||
return False
|
||||
|
||||
_, _, err = s.get_banner()
|
||||
if err is not None:
|
||||
out.v(err, write_now=True)
|
||||
s.close()
|
||||
return False
|
||||
|
||||
@ -55,15 +60,81 @@ class GEXTest:
|
||||
# server's own values.
|
||||
s.send_kexinit(key_exchanges=[gex_alg], hostkeys=kex.key_algorithms, ciphers=kex.server.encryption, macs=kex.server.mac, compressions=kex.server.compression, languages=kex.server.languages)
|
||||
|
||||
# Parse the server's KEX.
|
||||
_, payload = s.read_packet(2)
|
||||
SSH2_Kex.parse(payload)
|
||||
try:
|
||||
# Parse the server's KEX.
|
||||
_, payload = s.read_packet(2)
|
||||
SSH2_Kex.parse(out, payload)
|
||||
except KexDHException:
|
||||
out.v("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc()), write_now=True)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def granular_modulus_size_test(out: 'OutputBuffer', s: 'SSH_Socket', kex: 'SSH2_Kex', bits_min: int, bits_pref: int, bits_max: int, modulus_dict: Dict[str, List[int]]) -> int:
|
||||
'''
|
||||
Tests for granular modulus sizes.
|
||||
Builds a dictionary, where a key represents a DH algorithm name and the
|
||||
values are the modulus sizes (in bits) that have been returned by the
|
||||
target server.
|
||||
Returns an exitcodes.* flag.
|
||||
'''
|
||||
|
||||
retval = exitcodes.GOOD
|
||||
|
||||
out.d("Starting modulus_size_test...")
|
||||
out.d("Bits Min: " + str(bits_min))
|
||||
out.d("Bits Pref: " + str(bits_pref))
|
||||
out.d("Bits Max: " + str(bits_max))
|
||||
|
||||
GEX_ALGS = {
|
||||
'diffie-hellman-group-exchange-sha1': KexGroupExchange_SHA1,
|
||||
'diffie-hellman-group-exchange-sha256': KexGroupExchange_SHA256,
|
||||
}
|
||||
|
||||
# Check if the server supports any of the group-exchange
|
||||
# algorithms. If so, test each one.
|
||||
for gex_alg, kex_group_class in GEX_ALGS.items():
|
||||
if gex_alg not in kex.kex_algorithms:
|
||||
out.d('Server does not support the algorithm "' + gex_alg + '".', write_now=True)
|
||||
else:
|
||||
kex_group = kex_group_class(out)
|
||||
out.d('Preparing to perform DH group exchange using ' + gex_alg + ' with min, pref and max modulus sizes of ' + str(bits_min) + ' bits, ' + str(bits_pref) + ' bits and ' + str(bits_max) + ' bits...', write_now=True)
|
||||
|
||||
# It has been observed that reconnecting to some SSH servers
|
||||
# multiple times in quick succession can eventually result
|
||||
# in a "connection reset by peer" error. It may be possible
|
||||
# to recover from such an error by sleeping for some time
|
||||
# before continuing to issue reconnects.
|
||||
if GEXTest.reconnect(out, s, kex, gex_alg) is False:
|
||||
out.fail('Reconnect failed.')
|
||||
return exitcodes.FAILURE
|
||||
try:
|
||||
modulus_size_returned = None
|
||||
kex_group.send_init_gex(s, bits_min, bits_pref, bits_max)
|
||||
kex_group.recv_reply(s, False)
|
||||
modulus_size_returned = kex_group.get_dh_modulus_size()
|
||||
out.d('Modulus size returned by server: ' + str(modulus_size_returned) + ' bits', write_now=True)
|
||||
except KexDHException:
|
||||
out.d('[exception] ' + str(traceback.format_exc()), write_now=True)
|
||||
finally:
|
||||
# The server is in a state that is not re-testable,
|
||||
# so there's nothing else to do with this open
|
||||
# connection.
|
||||
s.close()
|
||||
|
||||
if modulus_size_returned is not None:
|
||||
if gex_alg in modulus_dict:
|
||||
if modulus_size_returned not in modulus_dict[gex_alg]:
|
||||
modulus_dict[gex_alg].append(modulus_size_returned)
|
||||
else:
|
||||
modulus_dict[gex_alg] = [modulus_size_returned]
|
||||
|
||||
return retval
|
||||
|
||||
# Runs the DH moduli test against the specified target.
|
||||
@staticmethod
|
||||
def run(s: 'SSH_Socket', kex: 'SSH2_Kex') -> None:
|
||||
def run(out: 'OutputBuffer', s: 'SSH_Socket', kex: 'SSH2_Kex') -> None:
|
||||
GEX_ALGS = {
|
||||
'diffie-hellman-group-exchange-sha1': KexGroupExchange_SHA1,
|
||||
'diffie-hellman-group-exchange-sha256': KexGroupExchange_SHA256,
|
||||
@ -77,13 +148,14 @@ class GEXTest:
|
||||
|
||||
# Check if the server supports any of the group-exchange
|
||||
# algorithms. If so, test each one.
|
||||
for gex_alg in GEX_ALGS:
|
||||
for gex_alg, kex_group_class in GEX_ALGS.items():
|
||||
if gex_alg in kex.kex_algorithms:
|
||||
out.d('Preparing to perform DH group exchange using ' + gex_alg + ' with min, pref and max modulus sizes of 512 bits, 1024 bits and 1536 bits...', write_now=True)
|
||||
|
||||
if GEXTest.reconnect(s, kex, gex_alg) is False:
|
||||
if GEXTest.reconnect(out, s, kex, gex_alg) is False:
|
||||
break
|
||||
|
||||
kex_group = GEX_ALGS[gex_alg]()
|
||||
kex_group = kex_group_class(out)
|
||||
smallest_modulus = -1
|
||||
|
||||
# First try a range of weak sizes.
|
||||
@ -95,9 +167,10 @@ class GEXTest:
|
||||
# larger than the requested max. So just because we
|
||||
# got here, doesn't mean the server is vulnerable...
|
||||
smallest_modulus = kex_group.get_dh_modulus_size()
|
||||
out.d('Modulus size returned by server: ' + str(smallest_modulus) + ' bits', write_now=True)
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
except KexDHException:
|
||||
out.d('[exception] ' + str(traceback.format_exc()), write_now=True)
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
@ -110,7 +183,9 @@ class GEXTest:
|
||||
if bits >= smallest_modulus > 0:
|
||||
break
|
||||
|
||||
if GEXTest.reconnect(s, kex, gex_alg) is False:
|
||||
out.d('Preparing to perform DH group exchange using ' + gex_alg + ' with min, pref and max modulus sizes of ' + str(bits) + ' bits...', write_now=True)
|
||||
|
||||
if GEXTest.reconnect(out, s, kex, gex_alg) is False:
|
||||
reconnect_failed = True
|
||||
break
|
||||
|
||||
@ -118,10 +193,9 @@ class GEXTest:
|
||||
kex_group.send_init_gex(s, bits, bits, bits)
|
||||
kex_group.recv_reply(s, False)
|
||||
smallest_modulus = kex_group.get_dh_modulus_size()
|
||||
except Exception:
|
||||
# import traceback
|
||||
# print(traceback.format_exc())
|
||||
pass
|
||||
out.d('Modulus size returned by server: ' + str(smallest_modulus) + ' bits', write_now=True)
|
||||
except KexDHException as e:
|
||||
out.d('Exception when testing DH group exchange ' + gex_alg + ' with modulus size ' + str(bits) + '. (Hint: this is probably normal since the server does not support this modulus size.): ' + str(e), write_now=True)
|
||||
finally:
|
||||
# The server is in a state that is not re-testable,
|
||||
# so there's nothing else to do with this open
|
||||
@ -146,5 +220,18 @@ class GEXTest:
|
||||
del lst[1]
|
||||
lst.insert(1, [text])
|
||||
|
||||
# Moduli smaller than 3072 get flagged as a warning.
|
||||
elif smallest_modulus < 3072:
|
||||
lst = SSH2_KexDB.ALGORITHMS['kex'][gex_alg]
|
||||
|
||||
# Ensure that a warning list exists for us to append to, below.
|
||||
while len(lst) < 3:
|
||||
lst.append([])
|
||||
|
||||
# Ensure this is only added once.
|
||||
text = '2048-bit modulus only provides 112-bits of symmetric strength'
|
||||
if text not in lst[2]:
|
||||
lst[2].append(text)
|
||||
|
||||
if reconnect_failed:
|
||||
break
|
||||
|
@ -21,7 +21,20 @@
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
VERSION = 'v2.4.0'
|
||||
SSH_HEADER = 'SSH-{0}-OpenSSH_8.2' # SSH software to impersonate
|
||||
GITHUB_ISSUES_URL = 'https://github.com/jtesta/ssh-audit/issues' # The URL to the Github issues tracker.
|
||||
# The version to display.
|
||||
VERSION = 'v2.9.0'
|
||||
|
||||
# SSH software to impersonate
|
||||
SSH_HEADER = 'SSH-{0}-OpenSSH_8.2'
|
||||
|
||||
# The URL to the Github issues tracker.
|
||||
GITHUB_ISSUES_URL = 'https://github.com/jtesta/ssh-audit/issues'
|
||||
|
||||
# The man page. Only filled in on Windows systems.
|
||||
WINDOWS_MAN_PAGE = ''
|
||||
|
||||
# True when installed from a Snap package, otherwise False.
|
||||
SNAP_PACKAGE = False
|
||||
|
||||
# Error message when installed as a Snap package and a file access fails.
|
||||
SNAP_PERMISSIONS_ERROR = 'Error while accessing file. It appears that ssh-audit was installed as a Snap package. In that case, there are two options: 1.) only try to read & write files in the $HOME/snap/ssh-audit/common/ directory, or 2.) grant permissions to read & write files in $HOME using the following command: "sudo snap connect ssh-audit:home :home"'
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2017-2021 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@ -26,10 +26,13 @@
|
||||
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
|
||||
from typing import Callable, Optional, Union, Any # noqa: F401
|
||||
|
||||
from ssh_audit.kexdh import KexDH, KexGroup1, KexGroup14_SHA1, KexGroup14_SHA256, KexCurve25519_SHA256, KexGroup16_SHA512, KexGroup18_SHA512, KexGroupExchange_SHA1, KexGroupExchange_SHA256, KexNISTP256, KexNISTP384, KexNISTP521
|
||||
import traceback
|
||||
|
||||
from ssh_audit.kexdh import KexDH, KexDHException, KexGroup1, KexGroup14_SHA1, KexGroup14_SHA256, KexCurve25519_SHA256, KexGroup16_SHA512, KexGroup18_SHA512, KexGroupExchange_SHA1, KexGroupExchange_SHA256, KexNISTP256, KexNISTP384, KexNISTP521
|
||||
from ssh_audit.ssh2_kex import SSH2_Kex
|
||||
from ssh_audit.ssh2_kexdb import SSH2_KexDB
|
||||
from ssh_audit.ssh_socket import SSH_Socket
|
||||
from ssh_audit.outputbuffer import OutputBuffer
|
||||
|
||||
|
||||
# Obtains host keys, checks their size, and derives their fingerprints.
|
||||
@ -51,8 +54,12 @@ class HostKeyTest:
|
||||
'ssh-ed25519-cert-v01@openssh.com': {'cert': True, 'variable_key_len': False},
|
||||
}
|
||||
|
||||
TWO2K_MODULUS_WARNING = '2048-bit modulus only provides 112-bits of symmetric strength'
|
||||
SMALL_ECC_MODULUS_WARNING = '224-bit ECC modulus only provides 112-bits of symmetric strength'
|
||||
|
||||
|
||||
@staticmethod
|
||||
def run(s: 'SSH_Socket', server_kex: 'SSH2_Kex') -> None:
|
||||
def run(out: 'OutputBuffer', s: 'SSH_Socket', server_kex: 'SSH2_Kex') -> None:
|
||||
KEX_TO_DHGROUP = {
|
||||
'diffie-hellman-group1-sha1': KexGroup1,
|
||||
'diffie-hellman-group14-sha1': KexGroup14_SHA1,
|
||||
@ -76,14 +83,14 @@ class HostKeyTest:
|
||||
for server_kex_alg in server_kex.kex_algorithms:
|
||||
if server_kex_alg in KEX_TO_DHGROUP:
|
||||
kex_str = server_kex_alg
|
||||
kex_group = KEX_TO_DHGROUP[kex_str]()
|
||||
kex_group = KEX_TO_DHGROUP[kex_str](out)
|
||||
break
|
||||
|
||||
if kex_str is not None and kex_group is not None:
|
||||
HostKeyTest.perform_test(s, server_kex, kex_str, kex_group, HostKeyTest.HOST_KEY_TYPES)
|
||||
HostKeyTest.perform_test(out, s, server_kex, kex_str, kex_group, HostKeyTest.HOST_KEY_TYPES)
|
||||
|
||||
@staticmethod
|
||||
def perform_test(s: 'SSH_Socket', server_kex: 'SSH2_Kex', kex_str: str, kex_group: 'KexDH', host_key_types: Dict[str, Dict[str, bool]]) -> None:
|
||||
def perform_test(out: 'OutputBuffer', s: 'SSH_Socket', server_kex: 'SSH2_Kex', kex_str: str, kex_group: 'KexDH', host_key_types: Dict[str, Dict[str, bool]]) -> None:
|
||||
hostkey_modulus_size = 0
|
||||
ca_modulus_size = 0
|
||||
|
||||
@ -95,46 +102,69 @@ class HostKeyTest:
|
||||
|
||||
# For each host key type...
|
||||
for host_key_type in host_key_types:
|
||||
key_fail_comments = []
|
||||
key_warn_comments = []
|
||||
|
||||
# Skip those already handled (i.e.: those in the RSA family, as testing one tests them all).
|
||||
if 'parsed' in host_key_types[host_key_type] and host_key_types[host_key_type]['parsed']:
|
||||
continue
|
||||
|
||||
# If this host key type is supported by the server, we test it.
|
||||
if host_key_type in server_kex.key_algorithms:
|
||||
out.d('Preparing to obtain ' + host_key_type + ' host key...', write_now=True)
|
||||
|
||||
cert = host_key_types[host_key_type]['cert']
|
||||
variable_key_len = host_key_types[host_key_type]['variable_key_len']
|
||||
|
||||
# If the connection is closed, re-open it and get the kex again.
|
||||
if not s.is_connected():
|
||||
err = s.connect()
|
||||
if err is not None:
|
||||
out.v(err, write_now=True)
|
||||
return
|
||||
|
||||
_, _, err = s.get_banner()
|
||||
if err is not None:
|
||||
out.v(err, write_now=True)
|
||||
s.close()
|
||||
return
|
||||
|
||||
# Send our KEX using the specified group-exchange and most of the server's own values.
|
||||
s.send_kexinit(key_exchanges=[kex_str], hostkeys=[host_key_type], ciphers=server_kex.server.encryption, macs=server_kex.server.mac, compressions=server_kex.server.compression, languages=server_kex.server.languages)
|
||||
|
||||
# Parse the server's KEX.
|
||||
_, payload = s.read_packet()
|
||||
SSH2_Kex.parse(payload)
|
||||
|
||||
try:
|
||||
# Parse the server's KEX.
|
||||
_, payload = s.read_packet()
|
||||
SSH2_Kex.parse(out, payload)
|
||||
except Exception:
|
||||
out.v("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc()), write_now=True)
|
||||
return
|
||||
|
||||
# Do the initial DH exchange. The server responds back
|
||||
# with the host key and its length. Bingo. We also get back the host key fingerprint.
|
||||
kex_group.send_init(s)
|
||||
raw_hostkey_bytes = b''
|
||||
try:
|
||||
host_key = kex_group.recv_reply(s, variable_key_len)
|
||||
if host_key is not None:
|
||||
server_kex.set_host_key(host_key_type, host_key)
|
||||
except Exception:
|
||||
pass
|
||||
kex_reply = kex_group.recv_reply(s)
|
||||
raw_hostkey_bytes = kex_reply if kex_reply is not None else b''
|
||||
except KexDHException:
|
||||
out.v("Failed to parse server's host key. Stack trace:\n%s" % str(traceback.format_exc()), write_now=True)
|
||||
|
||||
# Since parsing this host key failed, there's nothing more to do but close the socket and move on to the next host key type.
|
||||
s.close()
|
||||
continue
|
||||
|
||||
hostkey_modulus_size = kex_group.get_hostkey_size()
|
||||
ca_key_type = kex_group.get_ca_type()
|
||||
ca_modulus_size = kex_group.get_ca_size()
|
||||
out.d("Hostkey type: [%s]; hostkey size: %u; CA type: [%s]; CA modulus size: %u" % (host_key_type, hostkey_modulus_size, ca_key_type, ca_modulus_size), write_now=True)
|
||||
|
||||
# Record all the host key info.
|
||||
server_kex.set_host_key(host_key_type, raw_hostkey_bytes, hostkey_modulus_size, ca_key_type, ca_modulus_size)
|
||||
|
||||
# Set the hostkey size for all RSA key types since 'ssh-rsa', 'rsa-sha2-256', etc. are all using the same host key. Note, however, that this may change in the future.
|
||||
if cert is False and host_key_type in HostKeyTest.RSA_FAMILY:
|
||||
for rsa_type in HostKeyTest.RSA_FAMILY:
|
||||
server_kex.set_host_key(rsa_type, raw_hostkey_bytes, hostkey_modulus_size, ca_key_type, ca_modulus_size)
|
||||
|
||||
# Close the socket, as the connection has
|
||||
# been put in a state that later tests can't use.
|
||||
@ -142,37 +172,60 @@ class HostKeyTest:
|
||||
|
||||
# If the host key modulus or CA modulus was successfully parsed, check to see that its a safe size.
|
||||
if hostkey_modulus_size > 0 or ca_modulus_size > 0:
|
||||
# Set the hostkey size for all RSA key types since 'ssh-rsa',
|
||||
# 'rsa-sha2-256', etc. are all using the same host key.
|
||||
# Note, however, that this may change in the future.
|
||||
if cert is False and host_key_type in HostKeyTest.RSA_FAMILY:
|
||||
for rsa_type in HostKeyTest.RSA_FAMILY:
|
||||
server_kex.set_rsa_key_size(rsa_type, hostkey_modulus_size)
|
||||
elif cert is True:
|
||||
server_kex.set_rsa_key_size(host_key_type, hostkey_modulus_size, ca_modulus_size)
|
||||
# The minimum good modulus size for RSA host keys is 3072. However, since ECC cryptosystems are fundamentally different, the minimum good is 256.
|
||||
hostkey_min_good = cakey_min_good = 3072
|
||||
hostkey_min_warn = cakey_min_warn = 2048
|
||||
hostkey_warn_str = cakey_warn_str = HostKeyTest.TWO2K_MODULUS_WARNING
|
||||
if host_key_type.startswith('ssh-ed25519') or host_key_type.startswith('ecdsa-sha2-nistp'):
|
||||
hostkey_min_good = 256
|
||||
hostkey_min_warn = 224
|
||||
hostkey_warn_str = HostKeyTest.SMALL_ECC_MODULUS_WARNING
|
||||
if ca_key_type.startswith('ssh-ed25519') or host_key_type.startswith('ecdsa-sha2-nistp'):
|
||||
cakey_min_good = 256
|
||||
cakey_min_warn = 224
|
||||
cakey_warn_str = HostKeyTest.SMALL_ECC_MODULUS_WARNING
|
||||
|
||||
# Keys smaller than 2048 result in a failure. Update the database accordingly.
|
||||
if (cert is False) and (hostkey_modulus_size < 2048):
|
||||
for rsa_type in HostKeyTest.RSA_FAMILY:
|
||||
alg_list = SSH2_KexDB.ALGORITHMS['key'][rsa_type]
|
||||
# Keys smaller than 2048 result in a failure. Keys smaller 3072 result in a warning. Update the database accordingly.
|
||||
if (cert is False) and (hostkey_modulus_size < hostkey_min_good):
|
||||
|
||||
# If no failure list exists, add an empty failure list.
|
||||
if len(alg_list) < 2:
|
||||
alg_list.append([])
|
||||
alg_list[1].append('using small %d-bit modulus' % hostkey_modulus_size)
|
||||
elif (cert is True) and ((hostkey_modulus_size < 2048) or (ca_modulus_size > 0 and ca_modulus_size < 2048)): # pylint: disable=chained-comparison
|
||||
alg_list = SSH2_KexDB.ALGORITHMS['key'][host_key_type]
|
||||
min_modulus = min(hostkey_modulus_size, ca_modulus_size)
|
||||
min_modulus = min_modulus if min_modulus > 0 else max(hostkey_modulus_size, ca_modulus_size)
|
||||
# If the key is under 2048, add to the failure list.
|
||||
if hostkey_modulus_size < hostkey_min_warn:
|
||||
key_fail_comments.append('using small %d-bit modulus' % hostkey_modulus_size)
|
||||
elif hostkey_warn_str not in key_warn_comments: # Issue a warning about 2048-bit moduli.
|
||||
key_warn_comments.append(hostkey_warn_str)
|
||||
|
||||
# If no failure list exists, add an empty failure list.
|
||||
if len(alg_list) < 2:
|
||||
alg_list.append([])
|
||||
alg_list[1].append('using small %d-bit modulus' % min_modulus)
|
||||
elif (cert is True) and ((hostkey_modulus_size < hostkey_min_good) or (0 < ca_modulus_size < cakey_min_good)):
|
||||
# If the host key is smaller than 2048-bit/224-bit, flag this as a failure.
|
||||
if hostkey_modulus_size < hostkey_min_warn:
|
||||
key_fail_comments.append('using small %d-bit hostkey modulus' % hostkey_modulus_size)
|
||||
# Otherwise, this is just a warning.
|
||||
elif (hostkey_modulus_size < hostkey_min_good) and (hostkey_warn_str not in key_warn_comments):
|
||||
key_warn_comments.append(hostkey_warn_str)
|
||||
|
||||
# If the CA key is smaller than 2048-bit/224-bit, flag this as a failure.
|
||||
if 0 < ca_modulus_size < cakey_min_warn:
|
||||
key_fail_comments.append('using small %d-bit CA key modulus' % ca_modulus_size)
|
||||
# Otherwise, this is just a warning.
|
||||
elif (0 < ca_modulus_size < cakey_min_good) and (cakey_warn_str not in key_warn_comments):
|
||||
key_warn_comments.append(cakey_warn_str)
|
||||
|
||||
# If this host key type is in the RSA family, then mark them all as parsed (since results in one are valid for them all).
|
||||
if host_key_type in HostKeyTest.RSA_FAMILY:
|
||||
for rsa_type in HostKeyTest.RSA_FAMILY:
|
||||
host_key_types[rsa_type]['parsed'] = True
|
||||
|
||||
# If the current key is a member of the RSA family, then populate all RSA family members with the same
|
||||
# failure and/or warning comments.
|
||||
while len(SSH2_KexDB.ALGORITHMS['key'][rsa_type]) < 3:
|
||||
SSH2_KexDB.ALGORITHMS['key'][rsa_type].append([])
|
||||
|
||||
SSH2_KexDB.ALGORITHMS['key'][rsa_type][1].extend(key_fail_comments)
|
||||
SSH2_KexDB.ALGORITHMS['key'][rsa_type][2].extend(key_warn_comments)
|
||||
|
||||
else:
|
||||
host_key_types[host_key_type]['parsed'] = True
|
||||
while len(SSH2_KexDB.ALGORITHMS['key'][host_key_type]) < 3:
|
||||
SSH2_KexDB.ALGORITHMS['key'][host_key_type].append([])
|
||||
|
||||
SSH2_KexDB.ALGORITHMS['key'][host_key_type][1].extend(key_fail_comments)
|
||||
SSH2_KexDB.ALGORITHMS['key'][host_key_type][2].extend(key_warn_comments)
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2017-2020 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -31,14 +31,20 @@ import struct
|
||||
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
|
||||
from typing import Callable, Optional, Union, Any # noqa: F401
|
||||
|
||||
from ssh_audit.outputbuffer import OutputBuffer
|
||||
from ssh_audit.protocol import Protocol
|
||||
from ssh_audit.ssh_socket import SSH_Socket
|
||||
|
||||
|
||||
class KexDHException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class KexDH: # pragma: nocover
|
||||
def __init__(self, kex_name: str, hash_alg: str, g: int, p: int) -> None:
|
||||
self.__kex_name = kex_name
|
||||
self.__hash_alg = hash_alg
|
||||
def __init__(self, out: 'OutputBuffer', kex_name: str, hash_alg: str, g: int, p: int) -> None:
|
||||
self.out = out
|
||||
self.__kex_name = kex_name # pylint: disable=unused-private-member
|
||||
self.__hash_alg = hash_alg # pylint: disable=unused-private-member
|
||||
self.__g = 0
|
||||
self.__p = 0
|
||||
self.__q = 0
|
||||
@ -46,11 +52,12 @@ class KexDH: # pragma: nocover
|
||||
self.__e = 0
|
||||
self.set_params(g, p)
|
||||
|
||||
self.__ed25519_pubkey: Optional[bytes] = None
|
||||
self.__hostkey_type: Optional[bytes] = None
|
||||
self.__hostkey_e = 0
|
||||
self.__hostkey_n = 0
|
||||
self.__ed25519_pubkey: Optional[bytes] = None # pylint: disable=unused-private-member
|
||||
self.__hostkey_type = ''
|
||||
self.__hostkey_e = 0 # pylint: disable=unused-private-member
|
||||
self.__hostkey_n = 0 # pylint: disable=unused-private-member
|
||||
self.__hostkey_n_len = 0 # Length of the host key modulus.
|
||||
self.__ca_key_type = '' # Type of CA key ('ssh-rsa', etc).
|
||||
self.__ca_n_len = 0 # Length of the CA key modulus (if hostkey is a cert).
|
||||
|
||||
def set_params(self, g: int, p: int) -> None:
|
||||
@ -72,6 +79,14 @@ class KexDH: # pragma: nocover
|
||||
# contains the host key, among other things. Function returns the host
|
||||
# key blob (from which the fingerprint can be calculated).
|
||||
def recv_reply(self, s: 'SSH_Socket', parse_host_key_size: bool = True) -> Optional[bytes]:
|
||||
# Reset the CA info, in case it was set from a prior invokation.
|
||||
self.__hostkey_type = ''
|
||||
self.__hostkey_e = 0 # pylint: disable=unused-private-member
|
||||
self.__hostkey_n = 0 # pylint: disable=unused-private-member
|
||||
self.__hostkey_n_len = 0
|
||||
self.__ca_key_type = ''
|
||||
self.__ca_n_len = 0
|
||||
|
||||
packet_type, payload = s.read_packet(2)
|
||||
|
||||
# Skip any & all MSG_DEBUG messages.
|
||||
@ -79,29 +94,17 @@ class KexDH: # pragma: nocover
|
||||
packet_type, payload = s.read_packet(2)
|
||||
|
||||
if packet_type != -1 and packet_type not in [Protocol.MSG_KEXDH_REPLY, Protocol.MSG_KEXDH_GEX_REPLY]: # pylint: disable=no-else-raise
|
||||
# TODO: change Exception to something more specific.
|
||||
raise Exception('Expected MSG_KEXDH_REPLY (%d) or MSG_KEXDH_GEX_REPLY (%d), but got %d instead.' % (Protocol.MSG_KEXDH_REPLY, Protocol.MSG_KEXDH_GEX_REPLY, packet_type))
|
||||
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))
|
||||
elif packet_type == -1:
|
||||
# A connection error occurred. We can't parse anything, so just
|
||||
# return. The host key modulus (and perhaps certificate modulus)
|
||||
# will remain at length 0.
|
||||
self.out.d("KexDH.recv_reply(): received packge_type == -1.")
|
||||
return None
|
||||
|
||||
hostkey_len = 0 # pylint: disable=unused-variable
|
||||
hostkey_type_len = hostkey_e_len = 0 # pylint: disable=unused-variable
|
||||
key_id_len = principles_len = 0 # pylint: disable=unused-variable
|
||||
critical_options_len = extensions_len = 0 # pylint: disable=unused-variable
|
||||
nonce_len = ca_key_len = ca_key_type_len = 0 # pylint: disable=unused-variable
|
||||
ca_key_len = ca_key_type_len = ca_key_e_len = 0 # pylint: disable=unused-variable
|
||||
|
||||
key_id = principles = None # pylint: disable=unused-variable
|
||||
critical_options = extensions = None # pylint: disable=unused-variable
|
||||
nonce = ca_key = ca_key_type = None # pylint: disable=unused-variable
|
||||
ca_key_e = ca_key_n = None # pylint: disable=unused-variable
|
||||
|
||||
# Get the host key blob, F, and signature.
|
||||
ptr = 0
|
||||
hostkey, hostkey_len, ptr = KexDH.__get_bytes(payload, ptr)
|
||||
hostkey, _, ptr = KexDH.__get_bytes(payload, ptr)
|
||||
|
||||
# If we are not supposed to parse the host key size (i.e.: it is a type that is of fixed size such as ed25519), then stop here.
|
||||
if not parse_host_key_size:
|
||||
@ -113,76 +116,106 @@ class KexDH: # pragma: nocover
|
||||
# Now pick apart the host key blob.
|
||||
# Get the host key type (i.e.: 'ssh-rsa', 'ssh-ed25519', etc).
|
||||
ptr = 0
|
||||
self.__hostkey_type, hostkey_type_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
hostkey_type, _, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
self.__hostkey_type = hostkey_type.decode('ascii')
|
||||
self.out.d("Parsing host key type: %s" % self.__hostkey_type)
|
||||
|
||||
# If this is an RSA certificate, skip over the nonce.
|
||||
if self.__hostkey_type.startswith(b'ssh-rsa-cert-v0'):
|
||||
nonce, nonce_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
if self.__hostkey_type.startswith('ssh-rsa-cert-v0'):
|
||||
self.out.d("RSA certificate found, so skipping nonce.")
|
||||
_, _, ptr = KexDH.__get_bytes(hostkey, ptr) # Read & skip over the nonce.
|
||||
|
||||
# The public key exponent.
|
||||
hostkey_e, hostkey_e_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
self.__hostkey_e = int(binascii.hexlify(hostkey_e), 16)
|
||||
hostkey_e, _, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
self.__hostkey_e = int(binascii.hexlify(hostkey_e), 16) # pylint: disable=unused-private-member
|
||||
|
||||
# Here is the modulus size & actual modulus of the host key public key.
|
||||
hostkey_n, self.__hostkey_n_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
self.__hostkey_n = int(binascii.hexlify(hostkey_n), 16)
|
||||
# ED25519 moduli are fixed at 32 bytes.
|
||||
if self.__hostkey_type == 'ssh-ed25519':
|
||||
self.out.d("%s has a fixed host key modulus of 32." % self.__hostkey_type)
|
||||
self.__hostkey_n_len = 32
|
||||
else:
|
||||
# Here is the modulus size & actual modulus of the host key public key.
|
||||
hostkey_n, self.__hostkey_n_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
self.__hostkey_n = int(binascii.hexlify(hostkey_n), 16) # pylint: disable=unused-private-member
|
||||
|
||||
# If this is an RSA certificate, continue parsing to extract the CA
|
||||
# key.
|
||||
if self.__hostkey_type.startswith(b'ssh-rsa-cert-v0'):
|
||||
# Skip over the serial number.
|
||||
ptr += 8
|
||||
|
||||
# Get the certificate type.
|
||||
cert_type = int(binascii.hexlify(hostkey[ptr:ptr + 4]), 16)
|
||||
ptr += 4
|
||||
|
||||
# Only SSH2_CERT_TYPE_HOST (2) makes sense in this context.
|
||||
if cert_type == 2:
|
||||
|
||||
# Skip the key ID (this is the serial number of the
|
||||
# certificate).
|
||||
key_id, key_id_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
|
||||
# The principles, which are... I don't know what.
|
||||
principles, principles_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
|
||||
# Skip over the timestamp that this certificate is valid after.
|
||||
ptr += 8
|
||||
|
||||
# Skip over the timestamp that this certificate is valid before.
|
||||
ptr += 8
|
||||
|
||||
# TODO: validate the principles, and time range.
|
||||
|
||||
# The critical options.
|
||||
critical_options, critical_options_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
|
||||
# Certificate extensions.
|
||||
extensions, extensions_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
|
||||
# Another nonce.
|
||||
nonce, nonce_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
|
||||
# Finally, we get to the CA key.
|
||||
ca_key, ca_key_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
|
||||
# Last in the host key blob is the CA signature. It isn't
|
||||
# interesting to us, so we won't bother parsing any further.
|
||||
# The CA key has the modulus, however...
|
||||
ptr = 0
|
||||
|
||||
# 'ssh-rsa', 'rsa-sha2-256', etc.
|
||||
ca_key_type, ca_key_type_len, ptr = KexDH.__get_bytes(ca_key, ptr)
|
||||
|
||||
# CA's public key exponent.
|
||||
ca_key_e, ca_key_e_len, ptr = KexDH.__get_bytes(ca_key, ptr)
|
||||
|
||||
# CA's modulus. Bingo.
|
||||
ca_key_n, self.__ca_n_len, ptr = KexDH.__get_bytes(ca_key, ptr)
|
||||
# If this is a certificate, continue parsing to extract the CA type and key length. Even though a hostkey type might be 'ssh-ed25519-cert-v01@openssh.com', its CA may still be RSA.
|
||||
if self.__hostkey_type.startswith('ssh-rsa-cert-v0') or self.__hostkey_type.startswith('ssh-ed25519-cert-v0'):
|
||||
# Get the CA key type and key length.
|
||||
self.__ca_key_type, self.__ca_n_len = self.__parse_ca_key(hostkey, self.__hostkey_type, ptr)
|
||||
self.out.d("KexDH.__parse_ca_key(): CA key type: [%s]; CA key length: %u" % (self.__ca_key_type, self.__ca_n_len))
|
||||
|
||||
return hostkey
|
||||
|
||||
def __parse_ca_key(self, hostkey: bytes, hostkey_type: str, ptr: int) -> Tuple[str, int]:
|
||||
ca_key_type = ''
|
||||
ca_key_n_len = 0
|
||||
|
||||
# If this is a certificate, continue parsing to extract the CA type and key length. Even though a hostkey type might be 'ssh-ed25519-cert-v01@openssh.com', its CA may still be RSA.
|
||||
# if hostkey_type.startswith('ssh-rsa-cert-v0') or hostkey_type.startswith('ssh-ed25519-cert-v0'):
|
||||
self.out.d("Parsing CA for hostkey type [%s]..." % hostkey_type)
|
||||
|
||||
# Skip over the serial number.
|
||||
ptr += 8
|
||||
|
||||
# Get the certificate type.
|
||||
cert_type = int(binascii.hexlify(hostkey[ptr:ptr + 4]), 16)
|
||||
ptr += 4
|
||||
|
||||
# Only SSH2_CERT_TYPE_HOST (2) makes sense in this context.
|
||||
if cert_type == 2:
|
||||
|
||||
# Skip the key ID (this is the serial number of the
|
||||
# certificate).
|
||||
key_id, key_id_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
|
||||
|
||||
# The principles, which are... I don't know what.
|
||||
principles, principles_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
|
||||
|
||||
# Skip over the timestamp that this certificate is valid after.
|
||||
ptr += 8
|
||||
|
||||
# Skip over the timestamp that this certificate is valid before.
|
||||
ptr += 8
|
||||
|
||||
# TODO: validate the principles, and time range.
|
||||
|
||||
# The critical options.
|
||||
critical_options, critical_options_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
|
||||
|
||||
# Certificate extensions.
|
||||
extensions, extensions_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
|
||||
|
||||
# Another nonce.
|
||||
nonce, nonce_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
|
||||
|
||||
# Finally, we get to the CA key.
|
||||
ca_key, ca_key_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
|
||||
|
||||
# Last in the host key blob is the CA signature. It isn't
|
||||
# interesting to us, so we won't bother parsing any further.
|
||||
# The CA key has the modulus, however...
|
||||
ptr = 0
|
||||
|
||||
# 'ssh-rsa', 'rsa-sha2-256', etc.
|
||||
ca_key_type_bytes, ca_key_type_len, ptr = KexDH.__get_bytes(ca_key, ptr) # pylint: disable=unused-variable
|
||||
ca_key_type = ca_key_type_bytes.decode('ascii')
|
||||
self.out.d("Found CA type: [%s]" % ca_key_type)
|
||||
|
||||
# ED25519 CA's don't explicitly include the modulus size in the public key, since its fixed at 32 in all cases.
|
||||
if ca_key_type == 'ssh-ed25519':
|
||||
ca_key_n_len = 32
|
||||
else:
|
||||
# CA's public key exponent.
|
||||
ca_key_e, ca_key_e_len, ptr = KexDH.__get_bytes(ca_key, ptr) # pylint: disable=unused-variable
|
||||
|
||||
# CA's modulus. Bingo.
|
||||
ca_key_n, ca_key_n_len, ptr = KexDH.__get_bytes(ca_key, ptr) # pylint: disable=unused-variable
|
||||
|
||||
else:
|
||||
self.out.d("Certificate type %u found; this is not usually valid in the context of a host key! Skipping it..." % cert_type)
|
||||
|
||||
return ca_key_type, ca_key_n_len
|
||||
|
||||
@staticmethod
|
||||
def __get_bytes(buf: bytes, ptr: int) -> Tuple[bytes, int, int]:
|
||||
num_bytes = struct.unpack('>I', buf[ptr:ptr + 4])[0]
|
||||
@ -202,10 +235,18 @@ class KexDH: # pragma: nocover
|
||||
size = size - 8
|
||||
return size
|
||||
|
||||
# Returns the hostkey type.
|
||||
def get_hostkey_type(self) -> str:
|
||||
return self.__hostkey_type
|
||||
|
||||
# Returns the size of the hostkey, in bits.
|
||||
def get_hostkey_size(self) -> int:
|
||||
return KexDH.__adjust_key_size(self.__hostkey_n_len)
|
||||
|
||||
# Returns the CA type ('ssh-rsa', 'ssh-ed25519', etc).
|
||||
def get_ca_type(self) -> str:
|
||||
return self.__ca_key_type
|
||||
|
||||
# Returns the size of the CA key, in bits.
|
||||
def get_ca_size(self) -> int:
|
||||
return KexDH.__adjust_key_size(self.__ca_n_len)
|
||||
@ -217,46 +258,46 @@ class KexDH: # pragma: nocover
|
||||
|
||||
|
||||
class KexGroup1(KexDH): # pragma: nocover
|
||||
def __init__(self) -> None:
|
||||
def __init__(self, out: 'OutputBuffer') -> None:
|
||||
# rfc2409: second oakley group
|
||||
p = int('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff', 16)
|
||||
super(KexGroup1, self).__init__('KexGroup1', 'sha1', 2, p)
|
||||
super(KexGroup1, self).__init__(out, 'KexGroup1', 'sha1', 2, p)
|
||||
|
||||
|
||||
class KexGroup14(KexDH): # pragma: nocover
|
||||
def __init__(self, hash_alg: str) -> None:
|
||||
def __init__(self, out: 'OutputBuffer', hash_alg: str) -> None:
|
||||
# rfc3526: 2048-bit modp group
|
||||
p = int('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff', 16)
|
||||
super(KexGroup14, self).__init__('KexGroup14', hash_alg, 2, p)
|
||||
super(KexGroup14, self).__init__(out, 'KexGroup14', hash_alg, 2, p)
|
||||
|
||||
|
||||
class KexGroup14_SHA1(KexGroup14):
|
||||
def __init__(self) -> None:
|
||||
super(KexGroup14_SHA1, self).__init__('sha1')
|
||||
def __init__(self, out: 'OutputBuffer') -> None:
|
||||
super(KexGroup14_SHA1, self).__init__(out, 'sha1')
|
||||
|
||||
|
||||
class KexGroup14_SHA256(KexGroup14):
|
||||
def __init__(self) -> None:
|
||||
super(KexGroup14_SHA256, self).__init__('sha256')
|
||||
def __init__(self, out: 'OutputBuffer') -> None:
|
||||
super(KexGroup14_SHA256, self).__init__(out, 'sha256')
|
||||
|
||||
|
||||
class KexGroup16_SHA512(KexDH):
|
||||
def __init__(self) -> None:
|
||||
def __init__(self, out: 'OutputBuffer') -> None:
|
||||
# rfc3526: 4096-bit modp group
|
||||
p = int('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c934063199ffffffffffffffff', 16)
|
||||
super(KexGroup16_SHA512, self).__init__('KexGroup16_SHA512', 'sha512', 2, p)
|
||||
super(KexGroup16_SHA512, self).__init__(out, 'KexGroup16_SHA512', 'sha512', 2, p)
|
||||
|
||||
|
||||
class KexGroup18_SHA512(KexDH):
|
||||
def __init__(self) -> None:
|
||||
def __init__(self, out: 'OutputBuffer') -> None:
|
||||
# rfc3526: 8192-bit modp group
|
||||
p = int('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dbe115974a3926f12fee5e438777cb6a932df8cd8bec4d073b931ba3bc832b68d9dd300741fa7bf8afc47ed2576f6936ba424663aab639c5ae4f5683423b4742bf1c978238f16cbe39d652de3fdb8befc848ad922222e04a4037c0713eb57a81a23f0c73473fc646cea306b4bcbc8862f8385ddfa9d4b7fa2c087e879683303ed5bdd3a062b3cf5b3a278a66d2a13f83f44f82ddf310ee074ab6a364597e899a0255dc164f31cc50846851df9ab48195ded7ea1b1d510bd7ee74d73faf36bc31ecfa268359046f4eb879f924009438b481c6cd7889a002ed5ee382bc9190da6fc026e479558e4475677e9aa9e3050e2765694dfc81f56e880b96e7160c980dd98edd3dfffffffffffffffff', 16)
|
||||
super(KexGroup18_SHA512, self).__init__('KexGroup18_SHA512', 'sha512', 2, p)
|
||||
super(KexGroup18_SHA512, self).__init__(out, 'KexGroup18_SHA512', 'sha512', 2, p)
|
||||
|
||||
|
||||
class KexCurve25519_SHA256(KexDH):
|
||||
def __init__(self) -> None:
|
||||
super(KexCurve25519_SHA256, self).__init__('KexCurve25519_SHA256', 'sha256', 0, 0)
|
||||
def __init__(self, out: 'OutputBuffer') -> None:
|
||||
super(KexCurve25519_SHA256, self).__init__(out, 'KexCurve25519_SHA256', 'sha256', 0, 0)
|
||||
|
||||
# To start an ED25519 kex, we simply send a random 256-bit number as the
|
||||
# public key.
|
||||
@ -268,8 +309,8 @@ class KexCurve25519_SHA256(KexDH):
|
||||
|
||||
|
||||
class KexNISTP256(KexDH):
|
||||
def __init__(self) -> None:
|
||||
super(KexNISTP256, self).__init__('KexNISTP256', 'sha256', 0, 0)
|
||||
def __init__(self, out: 'OutputBuffer') -> None:
|
||||
super(KexNISTP256, self).__init__(out, 'KexNISTP256', 'sha256', 0, 0)
|
||||
|
||||
# Because the server checks that the value sent here is valid (i.e.: it lies
|
||||
# on the curve, among other things), we would have to write a lot of code
|
||||
@ -283,8 +324,8 @@ class KexNISTP256(KexDH):
|
||||
|
||||
|
||||
class KexNISTP384(KexDH):
|
||||
def __init__(self) -> None:
|
||||
super(KexNISTP384, self).__init__('KexNISTP384', 'sha256', 0, 0)
|
||||
def __init__(self, out: 'OutputBuffer') -> None:
|
||||
super(KexNISTP384, self).__init__(out, 'KexNISTP384', 'sha256', 0, 0)
|
||||
|
||||
# See comment for KexNISTP256.send_init().
|
||||
def send_init(self, s: 'SSH_Socket', init_msg: int = Protocol.MSG_KEXDH_INIT) -> None:
|
||||
@ -294,8 +335,8 @@ class KexNISTP384(KexDH):
|
||||
|
||||
|
||||
class KexNISTP521(KexDH):
|
||||
def __init__(self) -> None:
|
||||
super(KexNISTP521, self).__init__('KexNISTP521', 'sha256', 0, 0)
|
||||
def __init__(self, out: 'OutputBuffer') -> None:
|
||||
super(KexNISTP521, self).__init__(out, 'KexNISTP521', 'sha256', 0, 0)
|
||||
|
||||
# See comment for KexNISTP256.send_init().
|
||||
def send_init(self, s: 'SSH_Socket', init_msg: int = Protocol.MSG_KEXDH_INIT) -> None:
|
||||
@ -305,8 +346,8 @@ class KexNISTP521(KexDH):
|
||||
|
||||
|
||||
class KexGroupExchange(KexDH):
|
||||
def __init__(self, classname: str, hash_alg: str) -> None:
|
||||
super(KexGroupExchange, self).__init__(classname, hash_alg, 0, 0)
|
||||
def __init__(self, out: 'OutputBuffer', classname: str, hash_alg: str) -> None:
|
||||
super(KexGroupExchange, self).__init__(out, classname, hash_alg, 0, 0)
|
||||
|
||||
def send_init(self, s: 'SSH_Socket', init_msg: int = Protocol.MSG_KEXDH_GEX_REQUEST) -> None:
|
||||
self.send_init_gex(s)
|
||||
@ -327,9 +368,8 @@ class KexGroupExchange(KexDH):
|
||||
s.send_packet()
|
||||
|
||||
packet_type, payload = s.read_packet(2)
|
||||
if (packet_type != Protocol.MSG_KEXDH_GEX_GROUP) and (packet_type != Protocol.MSG_DEBUG): # pylint: disable=consider-using-in
|
||||
# TODO: replace with a better exception type.
|
||||
raise Exception('Expected MSG_KEXDH_GEX_REPLY (%d), but got %d instead.' % (Protocol.MSG_KEXDH_GEX_REPLY, packet_type))
|
||||
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))
|
||||
|
||||
# Skip any & all MSG_DEBUG messages.
|
||||
while packet_type == Protocol.MSG_DEBUG:
|
||||
@ -356,10 +396,10 @@ class KexGroupExchange(KexDH):
|
||||
|
||||
|
||||
class KexGroupExchange_SHA1(KexGroupExchange):
|
||||
def __init__(self) -> None:
|
||||
super(KexGroupExchange_SHA1, self).__init__('KexGroupExchange_SHA1', 'sha1')
|
||||
def __init__(self, out: 'OutputBuffer') -> None:
|
||||
super(KexGroupExchange_SHA1, self).__init__(out, 'KexGroupExchange_SHA1', 'sha1')
|
||||
|
||||
|
||||
class KexGroupExchange_SHA256(KexGroupExchange):
|
||||
def __init__(self) -> None:
|
||||
super(KexGroupExchange_SHA256, self).__init__('KexGroupExchange_SHA256', 'sha256')
|
||||
def __init__(self, out: 'OutputBuffer') -> None:
|
||||
super(KexGroupExchange_SHA256, self).__init__(out, 'KexGroupExchange_SHA256', 'sha256')
|
||||
|
@ -47,6 +47,7 @@ class OutputBuffer:
|
||||
self.section: List[str] = []
|
||||
self.batch = False
|
||||
self.verbose = False
|
||||
self.debug = False
|
||||
self.use_colors = True
|
||||
self.json = False
|
||||
self.__level = 0
|
||||
@ -167,7 +168,16 @@ class OutputBuffer:
|
||||
|
||||
def v(self, s: str, write_now: bool = False) -> 'OutputBuffer':
|
||||
'''Prints a message if verbose output is enabled.'''
|
||||
if self.verbose:
|
||||
if self.verbose or self.debug:
|
||||
self.info(s)
|
||||
if write_now:
|
||||
self.write()
|
||||
|
||||
return self
|
||||
|
||||
def d(self, s: str, write_now: bool = False) -> 'OutputBuffer':
|
||||
'''Prints a message if verbose output is enabled.'''
|
||||
if self.debug:
|
||||
self.info(s)
|
||||
if write_now:
|
||||
self.write()
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2020 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2020-2023 Joe Testa (jtesta@positronsecurity.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@ -21,6 +21,8 @@
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
import copy
|
||||
import json
|
||||
import sys
|
||||
|
||||
from typing import Dict, List, Tuple
|
||||
@ -28,58 +30,80 @@ from typing import Optional, Any, Union, cast
|
||||
from datetime import date
|
||||
|
||||
from ssh_audit import exitcodes
|
||||
from ssh_audit.ssh2_kex import SSH2_Kex # pylint: disable=unused-import
|
||||
from ssh_audit.banner import Banner # pylint: disable=unused-import
|
||||
from ssh_audit.banner import Banner
|
||||
from ssh_audit.globals import SNAP_PACKAGE, SNAP_PERMISSIONS_ERROR
|
||||
from ssh_audit.ssh2_kex import SSH2_Kex
|
||||
|
||||
|
||||
# Validates policy files and performs policy testing
|
||||
class Policy:
|
||||
|
||||
# Each field maps directly to a private member variable of the Policy class.
|
||||
BUILTIN_POLICIES: Dict[str, Dict[str, Union[Optional[str], Optional[List[str]], bool, Dict[str, int]]]] = {
|
||||
BUILTIN_POLICIES: Dict[str, Dict[str, Union[Optional[str], Optional[List[str]], bool, Dict[str, Any]]]] = {
|
||||
|
||||
# Ubuntu Server policies
|
||||
|
||||
'Hardened Ubuntu Server 16.04 LTS (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256@libssh.org', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
'Hardened Ubuntu Server 16.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256@libssh.org', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened Ubuntu Server 18.04 LTS (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
'Hardened Ubuntu Server 18.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened Ubuntu Server 20.04 LTS (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-v01@openssh.com': 4096, 'rsa-sha2-512-cert-v01@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
'Hardened Ubuntu Server 20.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened Ubuntu Server 22.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
|
||||
# Generic OpenSSH Server policies
|
||||
|
||||
'Hardened OpenSSH Server v7.7 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
'Hardened OpenSSH Server v7.7 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v7.8 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
'Hardened OpenSSH Server v7.8 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v7.9 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
'Hardened OpenSSH Server v7.9 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v8.0 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
'Hardened OpenSSH Server v8.0 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v8.1 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
'Hardened OpenSSH Server v8.1 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v8.2 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-v01@openssh.com': 4096, 'rsa-sha2-512-cert-v01@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
'Hardened OpenSSH Server v8.2 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v8.3 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-v01@openssh.com': 4096, 'rsa-sha2-512-cert-v01@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
'Hardened OpenSSH Server v8.3 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v8.4 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-v01@openssh.com': 4096, 'rsa-sha2-512-cert-v01@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
'Hardened OpenSSH Server v8.4 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v8.5 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {'rsa-sha2-256': 4096, 'rsa-sha2-512': 4096}, 'cakey_sizes': {'rsa-sha2-256-cert-v01@openssh.com': 4096, 'rsa-sha2-512-cert-v01@openssh.com': 4096}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
'Hardened OpenSSH Server v8.5 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v8.6 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v8.7 (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v8.8 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v8.9 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v9.0 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v9.1 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v9.2 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v9.3 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 2048}, 'server_policy': True},
|
||||
|
||||
|
||||
# Ubuntu Client policies
|
||||
|
||||
'Hardened Ubuntu Client 16.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256', 'rsa-sha2-512'], 'optional_host_keys': None, 'kex': ['curve25519-sha256@libssh.org', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
|
||||
'Hardened Ubuntu Client 16.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256', 'rsa-sha2-512'], 'optional_host_keys': None, 'kex': ['curve25519-sha256@libssh.org', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
|
||||
|
||||
'Hardened Ubuntu Client 18.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256', 'rsa-sha2-512'], 'optional_host_keys': None, 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
|
||||
'Hardened Ubuntu Client 18.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256', 'rsa-sha2-512'], 'optional_host_keys': None, 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
|
||||
|
||||
'Hardened Ubuntu Client 20.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512', 'rsa-sha2-512-cert-v01@openssh.com'], 'optional_host_keys': None, 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
|
||||
'Hardened Ubuntu Client 20.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512', 'rsa-sha2-512-cert-v01@openssh.com'], 'optional_host_keys': None, 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
|
||||
|
||||
'Hardened Ubuntu Client 22.04 LTS (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512', 'rsa-sha2-512-cert-v01@openssh.com'], 'optional_host_keys': None, 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
|
||||
|
||||
}
|
||||
|
||||
WARNING_DEPRECATED_DIRECTIVES = "\nWARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.\n"
|
||||
|
||||
def __init__(self, policy_file: Optional[str] = None, policy_data: Optional[str] = None, manual_load: bool = False) -> None:
|
||||
def __init__(self, policy_file: Optional[str] = None, policy_data: Optional[str] = None, manual_load: bool = False, json_output: bool = False) -> None:
|
||||
self._name: Optional[str] = None
|
||||
self._version: Optional[str] = None
|
||||
self._banner: Optional[str] = None
|
||||
@ -89,13 +113,18 @@ class Policy:
|
||||
self._kex: Optional[List[str]] = None
|
||||
self._ciphers: Optional[List[str]] = None
|
||||
self._macs: Optional[List[str]] = None
|
||||
self._hostkey_sizes: Optional[Dict[str, int]] = None
|
||||
self._cakey_sizes: Optional[Dict[str, int]] = None
|
||||
self._hostkey_sizes: Optional[Dict[str, Dict[str, Union[int, str, bytes]]]] = None
|
||||
self._dh_modulus_sizes: Optional[Dict[str, int]] = None
|
||||
self._server_policy = True
|
||||
|
||||
self._name_and_version: str = ''
|
||||
|
||||
# If invoked while JSON output is expected, send warnings to stderr instead of stdout (which would corrupt the JSON output).
|
||||
if json_output:
|
||||
self._warning_target = sys.stderr
|
||||
else:
|
||||
self._warning_target = sys.stdout
|
||||
|
||||
# Ensure that only one mode was specified.
|
||||
num_modes = 0
|
||||
if policy_file is not None:
|
||||
@ -113,11 +142,18 @@ class Policy:
|
||||
|
||||
if policy_file is not None:
|
||||
try:
|
||||
with open(policy_file, "r") as f:
|
||||
with open(policy_file, "r", encoding='utf-8') as f:
|
||||
policy_data = f.read()
|
||||
except FileNotFoundError:
|
||||
print("Error: policy file not found: %s" % policy_file)
|
||||
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||
except PermissionError as e:
|
||||
# If installed as a Snap package, print a more useful message with potential work-arounds.
|
||||
if SNAP_PACKAGE:
|
||||
print(SNAP_PERMISSIONS_ERROR)
|
||||
else:
|
||||
print("Error: insufficient permissions: %s" % str(e))
|
||||
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||
|
||||
lines = []
|
||||
if policy_data is not None:
|
||||
@ -138,7 +174,7 @@ class Policy:
|
||||
key = key.strip()
|
||||
val = val.strip()
|
||||
|
||||
if key not in ['name', 'version', 'banner', 'compressions', 'host keys', 'optional host keys', 'key exchanges', 'ciphers', 'macs', 'client policy'] and not key.startswith('hostkey_size_') and not key.startswith('cakey_size_') and not key.startswith('dh_modulus_size_'):
|
||||
if key not in ['name', 'version', 'banner', 'compressions', 'host keys', 'optional host keys', 'key exchanges', 'ciphers', 'macs', 'client policy', 'host_key_sizes', 'dh_modulus_sizes'] and not key.startswith('hostkey_size_') and not key.startswith('cakey_size_') and not key.startswith('dh_modulus_size_'):
|
||||
raise ValueError("invalid field found in policy: %s" % line)
|
||||
|
||||
if key in ['name', 'banner']:
|
||||
@ -157,8 +193,10 @@ class Policy:
|
||||
self._name = val
|
||||
elif key == 'banner':
|
||||
self._banner = val
|
||||
|
||||
elif key == 'version':
|
||||
self._version = val
|
||||
|
||||
elif key in ['compressions', 'host keys', 'optional host keys', 'key exchanges', 'ciphers', 'macs']:
|
||||
try:
|
||||
algs = val.split(',')
|
||||
@ -181,21 +219,52 @@ class Policy:
|
||||
self._ciphers = algs
|
||||
elif key == 'macs':
|
||||
self._macs = algs
|
||||
elif key.startswith('hostkey_size_'):
|
||||
|
||||
elif key.startswith('hostkey_size_'): # Old host key size format.
|
||||
print(Policy.WARNING_DEPRECATED_DIRECTIVES, file=self._warning_target) # Warn the user that the policy file is using deprecated directives.
|
||||
|
||||
hostkey_type = key[13:]
|
||||
hostkey_size = int(val)
|
||||
|
||||
if self._hostkey_sizes is None:
|
||||
self._hostkey_sizes = {}
|
||||
self._hostkey_sizes[hostkey_type] = int(val)
|
||||
elif key.startswith('cakey_size_'):
|
||||
cakey_type = key[11:]
|
||||
if self._cakey_sizes is None:
|
||||
self._cakey_sizes = {}
|
||||
self._cakey_sizes[cakey_type] = int(val)
|
||||
elif key.startswith('dh_modulus_size_'):
|
||||
dh_modulus_type = key[16:]
|
||||
|
||||
self._hostkey_sizes[hostkey_type] = {'hostkey_size': hostkey_size, 'ca_key_type': '', 'ca_key_size': 0}
|
||||
|
||||
elif key.startswith('cakey_size_'): # Old host key size format.
|
||||
print(Policy.WARNING_DEPRECATED_DIRECTIVES, file=self._warning_target) # Warn the user that the policy file is using deprecated directives.
|
||||
|
||||
hostkey_type = key[11:]
|
||||
ca_key_size = int(val)
|
||||
|
||||
ca_key_type = 'ssh-ed25519'
|
||||
if hostkey_type in ['ssh-rsa-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com']:
|
||||
ca_key_type = 'ssh-rsa'
|
||||
|
||||
if self._hostkey_sizes is None:
|
||||
self._hostkey_sizes = {}
|
||||
self._hostkey_sizes[hostkey_type] = {'hostkey_size': hostkey_size, 'ca_key_type': ca_key_type, 'ca_key_size': ca_key_size}
|
||||
|
||||
elif key == 'host_key_sizes': # New host key size format.
|
||||
self._hostkey_sizes = json.loads(val)
|
||||
|
||||
# Fill in the trimmed fields that were omitted from the policy.
|
||||
self._normalize_hostkey_sizes()
|
||||
|
||||
elif key.startswith('dh_modulus_size_'): # Old DH modulus format.
|
||||
print(Policy.WARNING_DEPRECATED_DIRECTIVES, file=self._warning_target) # Warn the user that the policy file is using deprecated directives.
|
||||
|
||||
dh_type = key[16:]
|
||||
dh_size = int(val)
|
||||
|
||||
if self._dh_modulus_sizes is None:
|
||||
self._dh_modulus_sizes = {}
|
||||
self._dh_modulus_sizes[dh_modulus_type] = int(val)
|
||||
|
||||
self._dh_modulus_sizes[dh_type] = dh_size
|
||||
|
||||
elif key == 'dh_modulus_sizes': # New DH modulus format.
|
||||
self._dh_modulus_sizes = json.loads(val)
|
||||
|
||||
elif key.startswith('client policy') and val.lower() == 'true':
|
||||
self._server_policy = False
|
||||
|
||||
@ -217,6 +286,19 @@ class Policy:
|
||||
errors.append({'mismatched_field': mismatched_field, 'expected_required': expected_required, 'expected_optional': expected_optional, 'actual': actual})
|
||||
|
||||
|
||||
def _normalize_hostkey_sizes(self) -> None:
|
||||
'''Normalizes the self._hostkey_sizes structure to ensure all required fields are present.'''
|
||||
|
||||
if self._hostkey_sizes is not None:
|
||||
for host_key_type in self._hostkey_sizes:
|
||||
if 'ca_key_type' not in self._hostkey_sizes[host_key_type]:
|
||||
self._hostkey_sizes[host_key_type]['ca_key_type'] = ''
|
||||
if 'ca_key_size' not in self._hostkey_sizes[host_key_type]:
|
||||
self._hostkey_sizes[host_key_type]['ca_key_size'] = 0
|
||||
if 'raw_hostkey_bytes' not in self._hostkey_sizes[host_key_type]:
|
||||
self._hostkey_sizes[host_key_type]['raw_hostkey_bytes'] = b''
|
||||
|
||||
|
||||
@staticmethod
|
||||
def create(source: Optional[str], banner: Optional['Banner'], kex: Optional['SSH2_Kex'], client_audit: bool) -> str:
|
||||
'''Creates a policy based on a server configuration. Returns a string.'''
|
||||
@ -227,10 +309,9 @@ class Policy:
|
||||
kex_algs = None
|
||||
ciphers = None
|
||||
macs = None
|
||||
rsa_hostkey_sizes_str = ''
|
||||
rsa_cakey_sizes_str = ''
|
||||
dh_modulus_sizes_str = ''
|
||||
client_policy_str = ''
|
||||
host_keys_json = ''
|
||||
|
||||
if client_audit:
|
||||
client_policy_str = "\n# Set to true to signify this is a policy for clients, not servers.\nclient policy = true\n"
|
||||
@ -246,26 +327,23 @@ class Policy:
|
||||
ciphers = ', '.join(kex.server.encryption)
|
||||
if kex.server.mac is not None:
|
||||
macs = ', '.join(kex.server.mac)
|
||||
if kex.rsa_key_sizes():
|
||||
rsa_key_sizes_dict = kex.rsa_key_sizes()
|
||||
for host_key_type in sorted(rsa_key_sizes_dict):
|
||||
hostkey_size, cakey_size = rsa_key_sizes_dict[host_key_type]
|
||||
|
||||
rsa_hostkey_sizes_str = "%shostkey_size_%s = %d\n" % (rsa_hostkey_sizes_str, host_key_type, hostkey_size)
|
||||
if cakey_size != -1:
|
||||
rsa_cakey_sizes_str = "%scakey_size_%s = %d\n" % (rsa_cakey_sizes_str, host_key_type, cakey_size)
|
||||
if kex.host_keys():
|
||||
|
||||
# Make a deep copy of the host keys dict, then delete all the raw hostkey bytes from the copy.
|
||||
host_keys_trimmed = copy.deepcopy(kex.host_keys())
|
||||
for hostkey_alg in host_keys_trimmed:
|
||||
del host_keys_trimmed[hostkey_alg]['raw_hostkey_bytes']
|
||||
|
||||
# Delete the CA signature if any of its fields are empty.
|
||||
if host_keys_trimmed[hostkey_alg]['ca_key_type'] == '' or host_keys_trimmed[hostkey_alg]['ca_key_size'] == 0:
|
||||
del host_keys_trimmed[hostkey_alg]['ca_key_type']
|
||||
del host_keys_trimmed[hostkey_alg]['ca_key_size']
|
||||
|
||||
host_keys_json = "\n# Dictionary containing all host key and size information. Optionally contains the certificate authority's signature algorithm ('ca_key_type') and signature length ('ca_key_size'), if any.\nhost_key_sizes = %s\n" % json.dumps(host_keys_trimmed)
|
||||
|
||||
if len(rsa_hostkey_sizes_str) > 0:
|
||||
rsa_hostkey_sizes_str = "\n# RSA host key sizes.\n%s" % rsa_hostkey_sizes_str
|
||||
if len(rsa_cakey_sizes_str) > 0:
|
||||
rsa_cakey_sizes_str = "\n# RSA CA key sizes.\n%s" % rsa_cakey_sizes_str
|
||||
if kex.dh_modulus_sizes():
|
||||
dh_modulus_sizes_dict = kex.dh_modulus_sizes()
|
||||
for gex_type in sorted(dh_modulus_sizes_dict):
|
||||
modulus_size, _ = dh_modulus_sizes_dict[gex_type]
|
||||
dh_modulus_sizes_str = "%sdh_modulus_size_%s = %d\n" % (dh_modulus_sizes_str, gex_type, modulus_size)
|
||||
if len(dh_modulus_sizes_str) > 0:
|
||||
dh_modulus_sizes_str = "\n# Group exchange DH modulus sizes.\n%s" % dh_modulus_sizes_str
|
||||
dh_modulus_sizes_str = "\n# Group exchange DH modulus sizes.\ndh_modulus_sizes = %s\n" % json.dumps(kex.dh_modulus_sizes())
|
||||
|
||||
|
||||
policy_data = '''#
|
||||
@ -283,7 +361,7 @@ version = 1
|
||||
|
||||
# The compression options that must match exactly (order matters). Commented out to ignore by default.
|
||||
# compressions = %s
|
||||
%s%s%s
|
||||
%s%s
|
||||
# The host key types that must match exactly (order matters).
|
||||
host keys = %s
|
||||
|
||||
@ -298,7 +376,7 @@ ciphers = %s
|
||||
|
||||
# The MACs that must match exactly (order matters).
|
||||
macs = %s
|
||||
''' % (source, today, client_policy_str, source, today, banner, compressions, rsa_hostkey_sizes_str, rsa_cakey_sizes_str, dh_modulus_sizes_str, host_keys, kex_algs, ciphers, macs)
|
||||
''' % (source, today, client_policy_str, source, today, banner, compressions, host_keys_json, dh_modulus_sizes_str, host_keys, kex_algs, ciphers, macs)
|
||||
|
||||
return policy_data
|
||||
|
||||
@ -335,23 +413,29 @@ macs = %s
|
||||
hostkey_types = list(self._hostkey_sizes.keys())
|
||||
hostkey_types.sort() # Sorted to make testing output repeatable.
|
||||
for hostkey_type in hostkey_types:
|
||||
expected_hostkey_size = self._hostkey_sizes[hostkey_type]
|
||||
if hostkey_type in kex.rsa_key_sizes():
|
||||
actual_hostkey_size, actual_cakey_size = kex.rsa_key_sizes()[hostkey_type]
|
||||
expected_hostkey_size = self._hostkey_sizes[hostkey_type]['hostkey_size']
|
||||
server_host_keys = kex.host_keys()
|
||||
if hostkey_type in server_host_keys:
|
||||
actual_hostkey_size = server_host_keys[hostkey_type]['hostkey_size']
|
||||
if actual_hostkey_size != expected_hostkey_size:
|
||||
ret = False
|
||||
self._append_error(errors, 'RSA host key (%s) sizes' % hostkey_type, [str(expected_hostkey_size)], None, [str(actual_hostkey_size)])
|
||||
self._append_error(errors, 'Host key (%s) sizes' % hostkey_type, [str(expected_hostkey_size)], None, [str(actual_hostkey_size)])
|
||||
|
||||
if self._cakey_sizes is not None:
|
||||
hostkey_types = list(self._cakey_sizes.keys())
|
||||
hostkey_types.sort() # Sorted to make testing output repeatable.
|
||||
for hostkey_type in hostkey_types:
|
||||
expected_cakey_size = self._cakey_sizes[hostkey_type]
|
||||
if hostkey_type in kex.rsa_key_sizes():
|
||||
actual_hostkey_size, actual_cakey_size = kex.rsa_key_sizes()[hostkey_type]
|
||||
if actual_cakey_size != expected_cakey_size:
|
||||
ret = False
|
||||
self._append_error(errors, 'RSA CA key (%s) sizes' % hostkey_type, [str(expected_cakey_size)], None, [str(actual_cakey_size)])
|
||||
# If we have expected CA signatures set, check them against what the server returned.
|
||||
if self._hostkey_sizes is not None and len(cast(str, self._hostkey_sizes[hostkey_type]['ca_key_type'])) > 0 and cast(int, self._hostkey_sizes[hostkey_type]['ca_key_size']) > 0:
|
||||
expected_ca_key_type = cast(str, self._hostkey_sizes[hostkey_type]['ca_key_type'])
|
||||
expected_ca_key_size = cast(int, self._hostkey_sizes[hostkey_type]['ca_key_size'])
|
||||
actual_ca_key_type = cast(str, server_host_keys[hostkey_type]['ca_key_type'])
|
||||
actual_ca_key_size = cast(int, server_host_keys[hostkey_type]['ca_key_size'])
|
||||
|
||||
# Ensure that the CA signature type is what's expected (i.e.: the server doesn't have an RSA sig when we're expecting an ED25519 sig).
|
||||
if actual_ca_key_type != expected_ca_key_type:
|
||||
ret = False
|
||||
self._append_error(errors, 'CA signature type', [expected_ca_key_type], None, [actual_ca_key_type])
|
||||
# Ensure that the actual and expected signature sizes match.
|
||||
elif actual_ca_key_size != expected_ca_key_size:
|
||||
ret = False
|
||||
self._append_error(errors, 'CA signature size (%s)' % actual_ca_key_type, [str(expected_ca_key_size)], None, [str(actual_ca_key_size)])
|
||||
|
||||
if kex.kex_algorithms != self._kex:
|
||||
ret = False
|
||||
@ -371,7 +455,7 @@ macs = %s
|
||||
for dh_modulus_type in dh_modulus_types:
|
||||
expected_dh_modulus_size = self._dh_modulus_sizes[dh_modulus_type]
|
||||
if dh_modulus_type in kex.dh_modulus_sizes():
|
||||
actual_dh_modulus_size, _ = kex.dh_modulus_sizes()[dh_modulus_type]
|
||||
actual_dh_modulus_size = kex.dh_modulus_sizes()[dh_modulus_type]
|
||||
if expected_dh_modulus_size != actual_dh_modulus_size:
|
||||
ret = False
|
||||
self._append_error(errors, 'Group exchange (%s) modulus sizes' % dh_modulus_type, [str(expected_dh_modulus_size)], None, [str(actual_dh_modulus_size)])
|
||||
@ -421,8 +505,8 @@ macs = %s
|
||||
server_policy_names = []
|
||||
client_policy_names = []
|
||||
|
||||
for policy_name in Policy.BUILTIN_POLICIES:
|
||||
if Policy.BUILTIN_POLICIES[policy_name]['server_policy']:
|
||||
for policy_name, policy in Policy.BUILTIN_POLICIES.items():
|
||||
if policy['server_policy']:
|
||||
server_policy_names.append(policy_name)
|
||||
else:
|
||||
client_policy_names.append(policy_name)
|
||||
@ -433,12 +517,12 @@ macs = %s
|
||||
|
||||
|
||||
@staticmethod
|
||||
def load_builtin_policy(policy_name: str) -> Optional['Policy']:
|
||||
def load_builtin_policy(policy_name: str, json_output: bool = False) -> Optional['Policy']:
|
||||
'''Returns a Policy with the specified built-in policy name loaded, or None if no policy of that name exists.'''
|
||||
p = None
|
||||
if policy_name in Policy.BUILTIN_POLICIES:
|
||||
policy_struct = Policy.BUILTIN_POLICIES[policy_name]
|
||||
p = Policy(manual_load=True)
|
||||
p = Policy(manual_load=True, json_output=json_output)
|
||||
policy_name_without_version = policy_name[0:policy_name.rfind(' (')]
|
||||
p._name = policy_name_without_version # pylint: disable=protected-access
|
||||
p._version = cast(str, policy_struct['version']) # pylint: disable=protected-access
|
||||
@ -449,13 +533,14 @@ macs = %s
|
||||
p._kex = cast(Optional[List[str]], policy_struct['kex']) # pylint: disable=protected-access
|
||||
p._ciphers = cast(Optional[List[str]], policy_struct['ciphers']) # pylint: disable=protected-access
|
||||
p._macs = cast(Optional[List[str]], policy_struct['macs']) # pylint: disable=protected-access
|
||||
p._hostkey_sizes = cast(Optional[Dict[str, int]], policy_struct['hostkey_sizes']) # pylint: disable=protected-access
|
||||
p._cakey_sizes = cast(Optional[Dict[str, int]], policy_struct['cakey_sizes']) # pylint: disable=protected-access
|
||||
p._hostkey_sizes = cast(Optional[Dict[str, Dict[str, Union[int, str, bytes]]]], policy_struct['hostkey_sizes']) # pylint: disable=protected-access
|
||||
p._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._name_and_version = "%s (version %s)" % (p._name, p._version) # pylint: disable=protected-access
|
||||
|
||||
# Ensure this struct has all the necessary fields.
|
||||
p._normalize_hostkey_sizes() # pylint: disable=protected-access
|
||||
|
||||
return p
|
||||
|
||||
|
||||
@ -484,7 +569,6 @@ macs = %s
|
||||
ciphers_str = undefined
|
||||
macs_str = undefined
|
||||
hostkey_sizes_str = undefined
|
||||
cakey_sizes_str = undefined
|
||||
dh_modulus_sizes_str = undefined
|
||||
|
||||
|
||||
@ -509,9 +593,7 @@ macs = %s
|
||||
macs_str = ', '.join(self._macs)
|
||||
if self._hostkey_sizes is not None:
|
||||
hostkey_sizes_str = str(self._hostkey_sizes)
|
||||
if self._cakey_sizes is not None:
|
||||
cakey_sizes_str = str(self._cakey_sizes)
|
||||
if self._dh_modulus_sizes is not None:
|
||||
dh_modulus_sizes_str = str(self._dh_modulus_sizes)
|
||||
|
||||
return "Name: %s\nVersion: %s\nBanner: %s\nCompressions: %s\nHost Keys: %s\nOptional Host Keys: %s\nKey Exchanges: %s\nCiphers: %s\nMACs: %s\nHost Key Sizes: %s\nCA Key Sizes: %s\nDH Modulus Sizes: %s\nServer Policy: %r" % (name, version, banner, compressions_str, host_keys_str, optional_host_keys_str, kex_str, ciphers_str, macs_str, hostkey_sizes_str, cakey_sizes_str, dh_modulus_sizes_str, self._server_policy)
|
||||
return "Name: %s\nVersion: %s\nBanner: %s\nCompressions: %s\nHost Keys: %s\nOptional Host Keys: %s\nKey Exchanges: %s\nCiphers: %s\nMACs: %s\nHost Key Sizes: %s\nDH Modulus Sizes: %s\nServer Policy: %r" % (name, version, banner, compressions_str, host_keys_str, optional_host_keys_str, kex_str, ciphers_str, macs_str, hostkey_sizes_str, dh_modulus_sizes_str, self._server_policy)
|
||||
|
@ -90,7 +90,7 @@ class SSH1_PublicKeyMessage:
|
||||
@property
|
||||
def supported_ciphers(self) -> List[str]:
|
||||
ciphers = []
|
||||
for i in range(len(SSH1.CIPHERS)):
|
||||
for i in range(len(SSH1.CIPHERS)): # pylint: disable=consider-using-enumerate
|
||||
if self.__supported_ciphers_mask & (1 << i) != 0:
|
||||
ciphers.append(Utils.to_text(SSH1.CIPHERS[i]))
|
||||
return ciphers
|
||||
|
@ -22,17 +22,18 @@
|
||||
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 typing import Dict, List
|
||||
from typing import Union
|
||||
|
||||
from ssh_audit.ssh2_kexparty import SSH2_KexParty
|
||||
from ssh_audit.outputbuffer import OutputBuffer
|
||||
from ssh_audit.readbuf import ReadBuf
|
||||
from ssh_audit.ssh2_kexparty import SSH2_KexParty
|
||||
from ssh_audit.writebuf import WriteBuf
|
||||
|
||||
|
||||
class SSH2_Kex:
|
||||
def __init__(self, cookie: bytes, kex_algs: List[str], key_algs: List[str], cli: 'SSH2_KexParty', srv: 'SSH2_KexParty', follows: bool, unused: int = 0) -> None:
|
||||
def __init__(self, outputbuffer: 'OutputBuffer', cookie: bytes, kex_algs: List[str], key_algs: List[str], cli: 'SSH2_KexParty', srv: 'SSH2_KexParty', follows: bool, unused: int = 0) -> None: # pylint: disable=too-many-arguments
|
||||
self.__outputbuffer = outputbuffer
|
||||
self.__cookie = cookie
|
||||
self.__kex_algs = kex_algs
|
||||
self.__key_algs = key_algs
|
||||
@ -41,9 +42,8 @@ class SSH2_Kex:
|
||||
self.__follows = follows
|
||||
self.__unused = unused
|
||||
|
||||
self.__rsa_key_sizes: Dict[str, Tuple[int, int]] = {}
|
||||
self.__dh_modulus_sizes: Dict[str, Tuple[int, int]] = {}
|
||||
self.__host_keys: Dict[str, bytes] = {}
|
||||
self.__dh_modulus_sizes: Dict[str, int] = {}
|
||||
self.__host_keys: Dict[str, Dict[str, Union[bytes, str, int]]] = {}
|
||||
|
||||
@property
|
||||
def cookie(self) -> bytes:
|
||||
@ -75,22 +75,20 @@ class SSH2_Kex:
|
||||
def unused(self) -> int:
|
||||
return self.__unused
|
||||
|
||||
def set_rsa_key_size(self, rsa_type: str, hostkey_size: int, ca_size: int = -1) -> None:
|
||||
self.__rsa_key_sizes[rsa_type] = (hostkey_size, ca_size)
|
||||
|
||||
def rsa_key_sizes(self) -> Dict[str, Tuple[int, int]]:
|
||||
return self.__rsa_key_sizes
|
||||
|
||||
def set_dh_modulus_size(self, gex_alg: str, modulus_size: int) -> None:
|
||||
self.__dh_modulus_sizes[gex_alg] = (modulus_size, -1)
|
||||
self.__dh_modulus_sizes[gex_alg] = modulus_size
|
||||
|
||||
def dh_modulus_sizes(self) -> Dict[str, Tuple[int, int]]:
|
||||
def dh_modulus_sizes(self) -> Dict[str, int]:
|
||||
return self.__dh_modulus_sizes
|
||||
|
||||
def set_host_key(self, key_type: str, hostkey: bytes) -> None:
|
||||
self.__host_keys[key_type] = hostkey
|
||||
def set_host_key(self, key_type: str, raw_hostkey_bytes: bytes, hostkey_size: int, ca_key_type: str, ca_key_size: int) -> None:
|
||||
|
||||
def host_keys(self) -> Dict[str, bytes]:
|
||||
if key_type not in self.__host_keys:
|
||||
self.__host_keys[key_type] = {'raw_hostkey_bytes': raw_hostkey_bytes, 'hostkey_size': hostkey_size, 'ca_key_type': ca_key_type, 'ca_key_size': ca_key_size}
|
||||
else: # A host key may only have one CA signature...
|
||||
self.__outputbuffer.d("WARNING: called SSH2_Kex.set_host_key() multiple times with the same host key type (%s)! Existing info: %r, %r, %r; Duplicate (ignored) info: %r, %r, %r" % (key_type, self.__host_keys[key_type]['hostkey_size'], self.__host_keys[key_type]['ca_key_type'], self.__host_keys[key_type]['ca_key_size'], hostkey_size, ca_key_type, ca_key_size))
|
||||
|
||||
def host_keys(self) -> Dict[str, Dict[str, Union[bytes, str, int]]]:
|
||||
return self.__host_keys
|
||||
|
||||
def write(self, wbuf: 'WriteBuf') -> None:
|
||||
@ -115,7 +113,7 @@ class SSH2_Kex:
|
||||
return wbuf.write_flush()
|
||||
|
||||
@classmethod
|
||||
def parse(cls, payload: bytes) -> 'SSH2_Kex':
|
||||
def parse(cls, outputbuffer: 'OutputBuffer', payload: bytes) -> 'SSH2_Kex':
|
||||
buf = ReadBuf(payload)
|
||||
cookie = buf.read(16)
|
||||
kex_algs = buf.read_list()
|
||||
@ -132,5 +130,5 @@ class SSH2_Kex:
|
||||
unused = buf.read_int()
|
||||
cli = SSH2_KexParty(cli_enc, cli_mac, cli_compression, cli_languages)
|
||||
srv = SSH2_KexParty(srv_enc, srv_mac, srv_compression, srv_languages)
|
||||
kex = cls(cookie, kex_algs, key_algs, cli, srv, follows, unused)
|
||||
kex = cls(outputbuffer, cookie, kex_algs, key_algs, cli, srv, follows, unused)
|
||||
return kex
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2017-2020 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -28,60 +28,59 @@ from typing import Callable, Optional, Union, Any # noqa: F401
|
||||
|
||||
|
||||
class SSH2_KexDB: # pylint: disable=too-few-public-methods
|
||||
WARN_OPENSSH74_UNSAFE = 'disabled (in client) since OpenSSH 7.4, unsafe algorithm'
|
||||
WARN_OPENSSH72_LEGACY = 'disabled (in client) since OpenSSH 7.2, legacy algorithm'
|
||||
FAIL_OPENSSH70_LEGACY = 'removed since OpenSSH 7.0, legacy algorithm'
|
||||
FAIL_OPENSSH70_WEAK = 'removed (in server) and disabled (in client) since OpenSSH 7.0, weak algorithm'
|
||||
FAIL_OPENSSH70_LOGJAM = 'disabled (in client) since OpenSSH 7.0, logjam attack'
|
||||
INFO_OPENSSH69_CHACHA = 'default cipher since OpenSSH 6.9.'
|
||||
FAIL_OPENSSH67_UNSAFE = 'removed (in server) since OpenSSH 6.7, unsafe algorithm'
|
||||
FAIL_OPENSSH61_REMOVE = 'removed since OpenSSH 6.1, removed from specification'
|
||||
FAIL_OPENSSH31_REMOVE = 'removed since OpenSSH 3.1'
|
||||
INFO_OPENSSH82_FUTURE_DEPRECATION = 'a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2'
|
||||
FAIL_DBEAR67_DISABLED = 'disabled since Dropbear SSH 2015.67'
|
||||
FAIL_DBEAR53_DISABLED = 'disabled since Dropbear SSH 0.53'
|
||||
FAIL_DEPRECATED_CIPHER = 'deprecated cipher'
|
||||
FAIL_WEAK_CIPHER = 'using weak cipher'
|
||||
FAIL_WEAK_ALGORITHM = 'using weak/obsolete algorithm'
|
||||
FAIL_PLAINTEXT = 'no encryption/integrity'
|
||||
FAIL_DEPRECATED_MAC = 'deprecated MAC'
|
||||
FAIL_1024BIT_MODULUS = 'using small 1024-bit modulus'
|
||||
FAIL_3DES = 'using broken & deprecated 3DES cipher'
|
||||
FAIL_BLOWFISH = 'using weak & deprecated Blowfish cipher'
|
||||
FAIL_CAST = 'using weak & deprecated CAST cipher'
|
||||
FAIL_DES = 'using broken DES cipher'
|
||||
FAIL_IDEA = 'using deprecated IDEA cipher'
|
||||
FAIL_LOGJAM_ATTACK = 'vulnerable to the Logjam attack: https://en.wikipedia.org/wiki/Logjam_(computer_security)'
|
||||
FAIL_MD5 = 'using broken MD5 hash algorithm'
|
||||
FAIL_NSA_BACKDOORED_CURVE = 'using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency'
|
||||
FAIL_PLAINTEXT = 'no encryption/integrity'
|
||||
FAIL_RC4 = 'using broken RC4 cipher'
|
||||
FAIL_RIJNDAEL = 'using deprecated & non-standardized Rijndael cipher'
|
||||
FAIL_RIPEMD = 'using deprecated RIPEMD hash algorithm'
|
||||
FAIL_SEED = 'using deprecated SEED cipher'
|
||||
FAIL_SERPENT = 'using deprecated Serpent cipher'
|
||||
FAIL_SHA1 = 'using broken SHA-1 hash algorithm'
|
||||
FAIL_SMALL_ECC_MODULUS = 'using small ECC modulus'
|
||||
FAIL_UNKNOWN = 'using unknown algorithm'
|
||||
FAIL_UNPROVEN = 'using unproven algorithm'
|
||||
FAIL_HASH_WEAK = 'using weak hashing algorithm'
|
||||
WARN_CURVES_WEAK = 'using weak elliptic curves'
|
||||
WARN_RNDSIG_KEY = 'using weak random number generator could reveal the key'
|
||||
WARN_HASH_WEAK = 'using weak hashing algorithm'
|
||||
WARN_CIPHER_MODE = 'using weak cipher mode'
|
||||
FAIL_UNTRUSTED = 'using untrusted algorithm developed in secret by a government entity'
|
||||
|
||||
WARN_2048BIT_MODULUS = '2048-bit modulus only provides 112-bits of symmetric strength'
|
||||
WARN_BLOCK_SIZE = 'using small 64-bit block size'
|
||||
WARN_CIPHER_WEAK = 'using weak cipher'
|
||||
WARN_CIPHER_MODE = 'using weak cipher mode'
|
||||
WARN_ENCRYPT_AND_MAC = 'using encrypt-and-MAC mode'
|
||||
WARN_EXPERIMENTAL = 'using experimental algorithm'
|
||||
WARN_RNDSIG_KEY = 'using weak random number generator could reveal the key'
|
||||
WARN_TAG_SIZE = 'using small 64-bit tag size'
|
||||
WARN_TAG_SIZE_96 = 'using small 96-bit tag size'
|
||||
WARN_EXPERIMENTAL = 'using experimental algorithm'
|
||||
WARN_OBSOLETE = 'using obsolete algorithm'
|
||||
WARN_UNTRUSTED = 'using untrusted algorithm'
|
||||
|
||||
INFO_DEFAULT_OPENSSH_CIPHER = 'default cipher since OpenSSH 6.9'
|
||||
INFO_DEFAULT_OPENSSH_KEX = 'default key exchange since OpenSSH 6.4'
|
||||
INFO_DEPRECATED_IN_OPENSSH88 = 'deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8'
|
||||
INFO_DISABLED_IN_DBEAR67 = 'disabled in Dropbear SSH 2015.67'
|
||||
INFO_DISABLED_IN_OPENSSH70 = 'disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0'
|
||||
INFO_NEVER_IMPLEMENTED_IN_OPENSSH = 'despite the @openssh.com tag, this was never implemented in OpenSSH'
|
||||
INFO_REMOVED_IN_OPENSSH61 = 'removed since OpenSSH 6.1, removed from specification'
|
||||
INFO_REMOVED_IN_OPENSSH69 = 'removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9'
|
||||
INFO_REMOVED_IN_OPENSSH70 = 'removed in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0'
|
||||
INFO_WITHDRAWN_PQ_ALG = 'the sntrup4591761 algorithm was withdrawn, as it may not provide strong post-quantum security'
|
||||
|
||||
|
||||
ALGORITHMS: Dict[str, Dict[str, List[List[Optional[str]]]]] = {
|
||||
# Format: 'algorithm_name': [['version_first_appeared_in'], [reason_for_failure1, reason_for_failure2, ...], [warning1, warning2, ...]]
|
||||
# Format: 'algorithm_name': [['version_first_appeared_in'], [reason_for_failure1, reason_for_failure2, ...], [warning1, warning2, ...], [info1, info2, ...]]
|
||||
'kex': {
|
||||
'diffie-hellman-group1-sha1': [['2.3.0,d0.28,l10.2', '6.6', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH67_UNSAFE, FAIL_OPENSSH70_LOGJAM], [WARN_HASH_WEAK]],
|
||||
'gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g==': [[], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH67_UNSAFE, FAIL_OPENSSH70_LOGJAM], [WARN_HASH_WEAK]],
|
||||
'gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==': [[], [], [WARN_HASH_WEAK]],
|
||||
'gss-gex-sha1-': [[], [], [WARN_HASH_WEAK]],
|
||||
'gss-group1-sha1-': [[], [FAIL_1024BIT_MODULUS], [WARN_HASH_WEAK]],
|
||||
'gss-group14-sha1-': [[], [], [WARN_HASH_WEAK]],
|
||||
'gss-group14-sha1-toWM5Slw5Ew8Mqkay+al2g==': [[], [], [WARN_HASH_WEAK]],
|
||||
'gss-group14-sha256-': [[]],
|
||||
'gss-group14-sha256-toWM5Slw5Ew8Mqkay+al2g==': [[]],
|
||||
'gss-group15-sha512-': [[]],
|
||||
'gss-group15-sha512-toWM5Slw5Ew8Mqkay+al2g==': [[]],
|
||||
'gss-group16-sha512-': [[]],
|
||||
'gss-nistp256-sha256-': [[], [WARN_CURVES_WEAK]],
|
||||
'gss-curve25519-sha256-': [[]],
|
||||
'diffie-hellman-group1-sha256': [[], [FAIL_1024BIT_MODULUS]],
|
||||
'diffie-hellman-group14-sha1': [['3.9,d0.53,l10.6.0'], [], [WARN_HASH_WEAK]],
|
||||
'diffie-hellman-group14-sha256': [['7.3,d2016.73']],
|
||||
'diffie-hellman-group14-sha256@ssh.com': [[]],
|
||||
'Curve25519SHA256': [[]],
|
||||
'curve25519-sha256': [['7.4,d2018.76'], [], [], [INFO_DEFAULT_OPENSSH_KEX]],
|
||||
'curve25519-sha256@libssh.org': [['6.4,d2013.62,l10.6.0'], [], [], [INFO_DEFAULT_OPENSSH_KEX]],
|
||||
'curve448-sha512': [[]],
|
||||
'diffie-hellman-group14-sha1': [['3.9,d0.53,l10.6.0'], [FAIL_SHA1], [WARN_2048BIT_MODULUS]],
|
||||
'diffie-hellman-group14-sha224@ssh.com': [[]],
|
||||
'diffie-hellman-group14-sha256': [['7.3,d2016.73'], [], [WARN_2048BIT_MODULUS]],
|
||||
'diffie-hellman-group14-sha256@ssh.com': [[], [], [WARN_2048BIT_MODULUS]],
|
||||
'diffie-hellman-group15-sha256': [[]],
|
||||
'diffie-hellman-group15-sha256@ssh.com': [[]],
|
||||
'diffie-hellman-group15-sha384@ssh.com': [[]],
|
||||
@ -91,184 +90,302 @@ class SSH2_KexDB: # pylint: disable=too-few-public-methods
|
||||
'diffie-hellman-group16-sha512': [['7.3,d2016.73']],
|
||||
'diffie-hellman-group16-sha512@ssh.com': [[]],
|
||||
'diffie-hellman-group17-sha512': [[]],
|
||||
'diffie-hellman_group17-sha512': [[]],
|
||||
'diffie-hellman-group18-sha512': [['7.3']],
|
||||
'diffie-hellman-group18-sha512@ssh.com': [[]],
|
||||
'diffie-hellman-group-exchange-sha1': [['2.3.0', '6.6', None], [FAIL_OPENSSH67_UNSAFE], [WARN_HASH_WEAK]],
|
||||
'diffie-hellman-group1-sha1': [['2.3.0,d0.28,l10.2', '6.6', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1], [], [INFO_REMOVED_IN_OPENSSH69]],
|
||||
'diffie-hellman-group1-sha256': [[], [FAIL_1024BIT_MODULUS]],
|
||||
'diffie-hellman-group-exchange-sha1': [['2.3.0', '6.6', None], [FAIL_SHA1]],
|
||||
'diffie-hellman-group-exchange-sha224@ssh.com': [[]],
|
||||
'diffie-hellman-group-exchange-sha256': [['4.4']],
|
||||
'diffie-hellman-group-exchange-sha256@ssh.com': [[]],
|
||||
'diffie-hellman-group-exchange-sha384@ssh.com': [[]],
|
||||
'diffie-hellman-group-exchange-sha512@ssh.com': [[]],
|
||||
'ecdh-sha2-curve25519': [[], []],
|
||||
'ecdh-sha2-nistb233': [[], [WARN_CURVES_WEAK]],
|
||||
'ecdh-sha2-nistb409': [[], [WARN_CURVES_WEAK]],
|
||||
'ecdh-sha2-nistk163': [[], [WARN_CURVES_WEAK]],
|
||||
'ecdh-sha2-nistk233': [[], [WARN_CURVES_WEAK]],
|
||||
'ecdh-sha2-nistk283': [[], [WARN_CURVES_WEAK]],
|
||||
'ecdh-sha2-nistk409': [[], [WARN_CURVES_WEAK]],
|
||||
'ecdh-sha2-nistp192': [[], [WARN_CURVES_WEAK]],
|
||||
'ecdh-sha2-nistp224': [[], [WARN_CURVES_WEAK]],
|
||||
'ecdh-sha2-nistp256': [['5.7,d2013.62,l10.6.0'], [WARN_CURVES_WEAK]],
|
||||
'ecdh-sha2-nistp384': [['5.7,d2013.62'], [WARN_CURVES_WEAK]],
|
||||
'ecdh-sha2-nistp521': [['5.7,d2013.62'], [WARN_CURVES_WEAK]],
|
||||
'ecdh-sha2-nistt571': [[], [WARN_CURVES_WEAK]],
|
||||
'ecdh-sha2-1.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.7': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-256 / secp256r1
|
||||
'ecdh-sha2-1.3.132.0.10': [[]], # ECDH over secp256k1 (i.e.: the Bitcoin curve)
|
||||
'curve25519-sha256@libssh.org': [['6.5,d2013.62,l10.6.0']],
|
||||
'curve25519-sha256': [['7.4,d2018.76']],
|
||||
'curve448-sha512': [[]],
|
||||
'kexguess2@matt.ucc.asn.au': [['d2013.57']],
|
||||
'rsa1024-sha1': [[], [FAIL_1024BIT_MODULUS], [WARN_HASH_WEAK]],
|
||||
'rsa2048-sha256': [[]],
|
||||
'sntrup4591761x25519-sha512@tinyssh.org': [['8.0', '8.4'], [], [WARN_EXPERIMENTAL]],
|
||||
'sntrup761x25519-sha512@openssh.com': [['8.5'], [], [WARN_EXPERIMENTAL]],
|
||||
'kexAlgoCurve25519SHA256': [[]],
|
||||
'Curve25519SHA256': [[]],
|
||||
'ecdh-sha2-1.3.132.0.16': [[]], # sect283k1
|
||||
'ecdh-sha2-1.3.132.0.1': [[], [FAIL_SMALL_ECC_MODULUS]], # sect163k1
|
||||
'ecdh-sha2-1.3.132.0.26': [[], [FAIL_SMALL_ECC_MODULUS]], # sect233k1
|
||||
'ecdh-sha2-1.3.132.0.27': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # 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.34': [[], [FAIL_NSA_BACKDOORED_CURVE]], # 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.36': [[]], # sect409k1
|
||||
'ecdh-sha2-1.3.132.0.37': [[], [FAIL_NSA_BACKDOORED_CURVE]], # sect409r1
|
||||
'ecdh-sha2-1.3.132.0.38': [[]], # sect571k1
|
||||
|
||||
# Note: the base64 strings, according to draft 6 of RFC5656, is Base64(MD5(DER(OID))). The final RFC5656 dropped the base64 strings in favor of plain OID concatenation, but apparently some SSH servers implement them anyway. See: https://datatracker.ietf.org/doc/html/draft-green-secsh-ecc-06#section-9.2
|
||||
'ecdh-sha2-4MHB+NBt3AlaSRQ7MnB4cg==': [[], [FAIL_SMALL_ECC_MODULUS]], # sect163k1
|
||||
'ecdh-sha2-5pPrSUQtIaTjUSt5VZNBjg==': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # NIST P-192 / secp192r1
|
||||
'ecdh-sha2-9UzNcgwTlEnSCECZa7V1mw==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-256 / secp256r1
|
||||
'ecdh-sha2-curve25519': [[], []],
|
||||
'ecdh-sha2-D3FefCjYoJ/kfXgAyLddYA==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # sect409r1
|
||||
'ecdh-sha2-h/SsxnLCtRBh7I9ATyeB3A==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-521 / secp521r1
|
||||
'ecdh-sha2-m/FtSAmrV4j/Wy6RVUaK7A==': [[]], # sect409k1
|
||||
'ecdh-sha2-mNVwCXAoS1HGmHpLvBC94w==': [[]], # sect571k1
|
||||
|
||||
'ecdh-sha2-nistb233': [[]], # The NIST P-curves are suspected as being backdoored; this isn't a P-curve.
|
||||
'ecdh-sha2-nistb409': [[]], # Not a NIST P-curve.
|
||||
'ecdh-sha2-nistk163': [[], [FAIL_SMALL_ECC_MODULUS]], # Not a NIST P-curve.
|
||||
'ecdh-sha2-nistk233': [[]], # Not a NIST P-curve.
|
||||
'ecdh-sha2-nistk283': [[]], # Not a NIST P-curve.
|
||||
'ecdh-sha2-nistk409': [[]], # Not a NIST P-curve.
|
||||
'ecdh-sha2-nistp192': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
||||
'ecdh-sha2-nistp224': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
||||
'ecdh-sha2-nistp256': [['5.7,d2013.62,l10.6.0'], [FAIL_NSA_BACKDOORED_CURVE]],
|
||||
'ecdh-sha2-nistp384': [['5.7,d2013.62'], [FAIL_NSA_BACKDOORED_CURVE]],
|
||||
'ecdh-sha2-nistp521': [['5.7,d2013.62'], [FAIL_NSA_BACKDOORED_CURVE]],
|
||||
'ecdh-sha2-nistt571': [[]], # Not a NIST P-curve.
|
||||
'ecdh-sha2-qCbG5Cn/jjsZ7nBeR7EnOA==': [[FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # sect233r1
|
||||
'ecdh-sha2-qcFQaMAMGhTziMT0z+Tuzw==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-384 / secp384r1
|
||||
'ecdh-sha2-VqBg4QRPjxx1EXZdV0GdWQ==': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # NIST P-224 / secp224r1
|
||||
'ecdh-sha2-wiRIU8TKjMZ418sMqlqtvQ==': [[]], # sect283k1
|
||||
'ecdh-sha2-zD/b3hu/71952ArpUG4OjQ==': [[], [FAIL_SMALL_ECC_MODULUS]], # sect233k1
|
||||
'ecmqv-sha2': [[], [FAIL_UNPROVEN]],
|
||||
'ext-info-c': [[]], # Extension negotiation (RFC 8308)
|
||||
'ext-info-s': [[]], # Extension negotiation (RFC 8308)
|
||||
|
||||
# The GSS kex algorithms get special wildcard handling, since they include variable base64 data after their standard prefixes.
|
||||
'gss-13.3.132.0.10-sha256-*': [[], [FAIL_UNKNOWN]],
|
||||
'gss-curve25519-sha256-*': [[]],
|
||||
'gss-curve448-sha512-*': [[]],
|
||||
'gss-gex-sha1-*': [[], [FAIL_SHA1]],
|
||||
'gss-gex-sha256-*': [[]],
|
||||
'gss-group14-sha1-*': [[], [FAIL_SHA1], [WARN_2048BIT_MODULUS]],
|
||||
'gss-group14-sha256-*': [[], [], [WARN_2048BIT_MODULUS]],
|
||||
'gss-group15-sha512-*': [[]],
|
||||
'gss-group16-sha512-*': [[]],
|
||||
'gss-group17-sha512-*': [[]],
|
||||
'gss-group18-sha512-*': [[]],
|
||||
'gss-group1-sha1-*': [[], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1]],
|
||||
'gss-nistp256-sha256-*': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
||||
'gss-nistp384-sha256-*': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
||||
'gss-nistp521-sha512-*': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
||||
|
||||
'kexAlgoCurve25519SHA256': [[]],
|
||||
'kexguess2@matt.ucc.asn.au': [['d2013.57']],
|
||||
'm383-sha384@libassh.org': [[], [FAIL_UNPROVEN]],
|
||||
'm511-sha512@libassh.org': [[], [FAIL_UNPROVEN]],
|
||||
'rsa1024-sha1': [[], [FAIL_1024BIT_MODULUS, FAIL_SHA1]],
|
||||
'rsa2048-sha256': [[], [], [WARN_2048BIT_MODULUS]],
|
||||
'sntrup4591761x25519-sha512@tinyssh.org': [['8.0', '8.4'], [], [WARN_EXPERIMENTAL], [INFO_WITHDRAWN_PQ_ALG]],
|
||||
'sntrup761x25519-sha512@openssh.com': [['8.5'], [], []],
|
||||
},
|
||||
'key': {
|
||||
'ssh-rsa1': [[], [FAIL_WEAK_ALGORITHM]],
|
||||
'rsa-sha2-256': [['7.2']],
|
||||
'rsa-sha2-512': [['7.2']],
|
||||
'ssh-ed25519': [['6.5,l10.7.0']],
|
||||
'ssh-ed25519-cert-v01@openssh.com': [['6.5']],
|
||||
'ssh-rsa': [['2.5.0,d0.28,l10.2'], [FAIL_HASH_WEAK], [], [INFO_OPENSSH82_FUTURE_DEPRECATION]],
|
||||
'ssh-dss': [['2.1.0,d0.28,l10.2', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH70_WEAK], [WARN_RNDSIG_KEY]],
|
||||
'ecdsa-sha2-nistp256': [['5.7,d2013.62,l10.6.4'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]],
|
||||
'ecdsa-sha2-nistp384': [['5.7,d2013.62,l10.6.4'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]],
|
||||
'ecdsa-sha2-nistp521': [['5.7,d2013.62,l10.6.4'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]],
|
||||
'dsa2048-sha224@libassh.org': [[], [FAIL_UNPROVEN], [WARN_2048BIT_MODULUS]],
|
||||
'dsa2048-sha256@libassh.org': [[], [FAIL_UNPROVEN], [WARN_2048BIT_MODULUS]],
|
||||
'dsa3072-sha256@libassh.org': [[], [FAIL_UNPROVEN]],
|
||||
'ecdsa-sha2-1.3.132.0.10-cert-v01@openssh.com': [[], [FAIL_UNKNOWN]],
|
||||
'ecdsa-sha2-1.3.132.0.10': [[], [], [WARN_RNDSIG_KEY]], # ECDSA over secp256k1 (i.e.: the Bitcoin curve)
|
||||
'x509v3-sign-dss': [[], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH70_WEAK], [WARN_RNDSIG_KEY]],
|
||||
'x509v3-sign-rsa': [[], [FAIL_HASH_WEAK], [], [INFO_OPENSSH82_FUTURE_DEPRECATION]],
|
||||
'x509v3-sign-rsa-sha256@ssh.com': [[]],
|
||||
'x509v3-ssh-dss': [[], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH70_WEAK], [WARN_RNDSIG_KEY]],
|
||||
'x509v3-ssh-rsa': [[], [FAIL_HASH_WEAK], [], [INFO_OPENSSH82_FUTURE_DEPRECATION]],
|
||||
'ssh-rsa-cert-v00@openssh.com': [['5.4', '6.9'], [FAIL_OPENSSH70_LEGACY, FAIL_HASH_WEAK], [], [INFO_OPENSSH82_FUTURE_DEPRECATION]],
|
||||
'ssh-dss-cert-v00@openssh.com': [['5.4', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH70_LEGACY], [WARN_RNDSIG_KEY]],
|
||||
'ssh-rsa-cert-v01@openssh.com': [['5.6'], [FAIL_HASH_WEAK], [], [INFO_OPENSSH82_FUTURE_DEPRECATION]],
|
||||
'ssh-dss-cert-v01@openssh.com': [['5.6', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH70_WEAK], [WARN_RNDSIG_KEY]],
|
||||
'ecdsa-sha2-nistp256-cert-v01@openssh.com': [['5.7'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]],
|
||||
'ecdsa-sha2-nistp384-cert-v01@openssh.com': [['5.7'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]],
|
||||
'ecdsa-sha2-nistp521-cert-v01@openssh.com': [['5.7'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]],
|
||||
'ecdsa-sha2-nistp256': [['5.7,d2013.62,l10.6.4'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
|
||||
'ecdsa-sha2-nistp256-cert-v01@openssh.com': [['5.7'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
|
||||
'ecdsa-sha2-nistp384': [['5.7,d2013.62,l10.6.4'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
|
||||
'ecdsa-sha2-nistp384-cert-v01@openssh.com': [['5.7'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
|
||||
'ecdsa-sha2-nistp521': [['5.7,d2013.62,l10.6.4'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
|
||||
'ecdsa-sha2-nistp521-cert-v01@openssh.com': [['5.7'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
|
||||
'eddsa-e382-shake256@libassh.org': [[], [FAIL_UNPROVEN]],
|
||||
'eddsa-e521-shake256@libassh.org': [[], [FAIL_UNPROVEN]],
|
||||
'null': [[], [FAIL_PLAINTEXT]],
|
||||
'pgp-sign-dss': [[], [FAIL_1024BIT_MODULUS]],
|
||||
'pgp-sign-rsa': [[], [FAIL_1024BIT_MODULUS]],
|
||||
'rsa-sha2-256': [['7.2']],
|
||||
'rsa-sha2-256-cert-v01@openssh.com': [['7.8']],
|
||||
'rsa-sha2-512': [['7.2']],
|
||||
'rsa-sha2-512-cert-v01@openssh.com': [['7.8']],
|
||||
'ssh-rsa-sha256@ssh.com': [[]],
|
||||
'ssh-dss-sha256@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
|
||||
'sk-ecdsa-sha2-nistp256-cert-v01@openssh.com': [['8.2'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]],
|
||||
'sk-ecdsa-sha2-nistp256@openssh.com': [['8.2'], [WARN_CURVES_WEAK], [WARN_RNDSIG_KEY]],
|
||||
'sk-ecdsa-sha2-nistp256-cert-v01@openssh.com': [['8.2'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
|
||||
'sk-ecdsa-sha2-nistp256@openssh.com': [['8.2'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
|
||||
'sk-ssh-ed25519-cert-v01@openssh.com': [['8.2']],
|
||||
'sk-ssh-ed25519@openssh.com': [['8.2']],
|
||||
'ssh-gost2001': [[], [], [WARN_UNTRUSTED]],
|
||||
'ssh-gost2012-256': [[], [], [WARN_UNTRUSTED]],
|
||||
'ssh-gost2012-512': [[], [], [WARN_UNTRUSTED]],
|
||||
'spi-sign-rsa': [[]],
|
||||
'spki-sign-dss': [[], [FAIL_1024BIT_MODULUS]],
|
||||
'spki-sign-rsa': [[], [FAIL_1024BIT_MODULUS]],
|
||||
'ssh-dss': [['2.1.0,d0.28,l10.2', '6.9'], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY], [INFO_DISABLED_IN_OPENSSH70]],
|
||||
'ssh-dss-cert-v00@openssh.com': [['5.4', '6.9'], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY], [INFO_DISABLED_IN_OPENSSH70]],
|
||||
'ssh-dss-cert-v01@openssh.com': [['5.6', '6.9'], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY]],
|
||||
'ssh-dss-sha224@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
|
||||
'ssh-dss-sha256@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
|
||||
'ssh-dss-sha384@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
|
||||
'ssh-dss-sha512@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
|
||||
'ssh-ed25519': [['6.5,l10.7.0']],
|
||||
'ssh-ed25519-cert-v01@openssh.com': [['6.5']],
|
||||
'ssh-ed448': [[]],
|
||||
'x509v3-ecdsa-sha2-nistp256': [[], [WARN_CURVES_WEAK]],
|
||||
'x509v3-ecdsa-sha2-nistp384': [[], [WARN_CURVES_WEAK]],
|
||||
'x509v3-ecdsa-sha2-nistp521': [[], [WARN_CURVES_WEAK]],
|
||||
'ssh-ed448-cert-v01@openssh.com': [[], [], [], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]],
|
||||
'ssh-gost2001': [[], [FAIL_UNTRUSTED]],
|
||||
'ssh-gost2012-256': [[], [FAIL_UNTRUSTED]],
|
||||
'ssh-gost2012-512': [[], [FAIL_UNTRUSTED]],
|
||||
'ssh-rsa1': [[], [FAIL_SHA1]],
|
||||
'ssh-rsa': [['2.5.0,d0.28,l10.2'], [FAIL_SHA1], [], [INFO_DEPRECATED_IN_OPENSSH88]],
|
||||
'ssh-rsa-cert-v00@openssh.com': [['5.4', '6.9'], [FAIL_SHA1], [], [INFO_REMOVED_IN_OPENSSH70]],
|
||||
'ssh-rsa-cert-v01@openssh.com': [['5.6'], [FAIL_SHA1], [], [INFO_DEPRECATED_IN_OPENSSH88]],
|
||||
'ssh-rsa-sha224@ssh.com': [[]],
|
||||
'ssh-rsa-sha2-256': [[]],
|
||||
'ssh-rsa-sha2-512': [[]],
|
||||
'ssh-rsa-sha256@ssh.com': [[]],
|
||||
'ssh-rsa-sha384@ssh.com': [[]],
|
||||
'ssh-rsa-sha512@ssh.com': [[]],
|
||||
'ssh-xmss-cert-v01@openssh.com': [['7.7'], [WARN_EXPERIMENTAL]],
|
||||
'ssh-xmss@openssh.com': [['7.7'], [WARN_EXPERIMENTAL]],
|
||||
'webauthn-sk-ecdsa-sha2-nistp256@openssh.com': [['8.3'], [FAIL_NSA_BACKDOORED_CURVE]],
|
||||
'x509v3-ecdsa-sha2-1.3.132.0.10': [[], [FAIL_UNKNOWN]],
|
||||
'x509v3-ecdsa-sha2-nistp256': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
||||
'x509v3-ecdsa-sha2-nistp384': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
||||
'x509v3-ecdsa-sha2-nistp521': [[], [FAIL_NSA_BACKDOORED_CURVE]],
|
||||
'x509v3-rsa2048-sha256': [[]],
|
||||
'x509v3-sign-dss': [[], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY]],
|
||||
'x509v3-sign-dss-sha1': [[], [FAIL_1024BIT_MODULUS, FAIL_SHA1]],
|
||||
'x509v3-sign-dss-sha224@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
|
||||
'x509v3-sign-dss-sha256@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
|
||||
'x509v3-sign-dss-sha384@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
|
||||
'x509v3-sign-dss-sha512@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
|
||||
'x509v3-sign-rsa': [[], [FAIL_SHA1]],
|
||||
'x509v3-sign-rsa-sha1': [[], [FAIL_SHA1]],
|
||||
'x509v3-sign-rsa-sha224@ssh.com': [[]],
|
||||
'x509v3-sign-rsa-sha256@ssh.com': [[]],
|
||||
'x509v3-sign-rsa-sha384@ssh.com': [[]],
|
||||
'x509v3-sign-rsa-sha512@ssh.com': [[]],
|
||||
'x509v3-ssh-dss': [[], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY]],
|
||||
'x509v3-ssh-rsa': [[], [FAIL_SHA1], [], [INFO_DEPRECATED_IN_OPENSSH88]],
|
||||
},
|
||||
'enc': {
|
||||
'none': [['1.2.2,d2013.56,l10.2'], [FAIL_PLAINTEXT]],
|
||||
'des': [[], [FAIL_WEAK_CIPHER], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'des-cbc': [[], [FAIL_WEAK_CIPHER], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'des-cbc@ssh.com': [[], [FAIL_WEAK_CIPHER], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'des-cbc-ssh1': [[], [FAIL_WEAK_CIPHER], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'3des': [[], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH74_UNSAFE, WARN_CIPHER_WEAK, WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'3des-cbc': [['1.2.2,d0.28,l10.2', '6.6', None], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH74_UNSAFE, WARN_CIPHER_WEAK, WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'3des-ctr': [['d0.52'], [FAIL_WEAK_CIPHER]],
|
||||
'blowfish': [[], [FAIL_WEAK_ALGORITHM], [WARN_BLOCK_SIZE]],
|
||||
'blowfish-cbc': [['1.2.2,d0.28,l10.2', '6.6,d0.52', '7.1,d0.52'], [FAIL_OPENSSH67_UNSAFE, FAIL_DBEAR53_DISABLED], [WARN_OPENSSH72_LEGACY, WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'blowfish-ctr': [[], [FAIL_OPENSSH67_UNSAFE, FAIL_DBEAR53_DISABLED], [WARN_OPENSSH72_LEGACY, WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'twofish-cbc': [['d0.28', 'd2014.66'], [FAIL_DBEAR67_DISABLED], [WARN_CIPHER_MODE]],
|
||||
'twofish128-cbc': [['d0.47', 'd2014.66'], [FAIL_DBEAR67_DISABLED], [WARN_CIPHER_MODE]],
|
||||
'twofish192-cbc': [[], [], [WARN_CIPHER_MODE]],
|
||||
'twofish256-cbc': [['d0.47', 'd2014.66'], [FAIL_DBEAR67_DISABLED], [WARN_CIPHER_MODE]],
|
||||
'twofish-ctr': [[]],
|
||||
'twofish128-ctr': [['d2015.68']],
|
||||
'twofish192-ctr': [[]],
|
||||
'twofish256-ctr': [['d2015.68']],
|
||||
'serpent128-cbc': [[], [FAIL_DEPRECATED_CIPHER], [WARN_CIPHER_MODE]],
|
||||
'serpent192-cbc': [[], [FAIL_DEPRECATED_CIPHER], [WARN_CIPHER_MODE]],
|
||||
'serpent256-cbc': [[], [FAIL_DEPRECATED_CIPHER], [WARN_CIPHER_MODE]],
|
||||
'serpent128-ctr': [[], [FAIL_DEPRECATED_CIPHER]],
|
||||
'serpent192-ctr': [[], [FAIL_DEPRECATED_CIPHER]],
|
||||
'serpent256-ctr': [[], [FAIL_DEPRECATED_CIPHER]],
|
||||
'idea-cbc': [[], [FAIL_DEPRECATED_CIPHER], [WARN_CIPHER_MODE]],
|
||||
'idea-ctr': [[], [FAIL_DEPRECATED_CIPHER]],
|
||||
'cast128-ctr': [[], [FAIL_DEPRECATED_CIPHER]],
|
||||
'cast128-cbc': [['2.1.0', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'arcfour': [['2.1.0', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_CIPHER_WEAK]],
|
||||
'arcfour128': [['4.2', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_CIPHER_WEAK]],
|
||||
'arcfour256': [['4.2', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_CIPHER_WEAK]],
|
||||
'aes128-cbc': [['2.3.0,d0.28,l10.2', '6.6', None], [FAIL_OPENSSH67_UNSAFE], [WARN_CIPHER_MODE]],
|
||||
'aes192-cbc': [['2.3.0,l10.2', '6.6', None], [FAIL_OPENSSH67_UNSAFE], [WARN_CIPHER_MODE]],
|
||||
'aes256-cbc': [['2.3.0,d0.47,l10.2', '6.6', None], [FAIL_OPENSSH67_UNSAFE], [WARN_CIPHER_MODE]],
|
||||
'rijndael128-cbc': [['2.3.0', '3.0.2'], [FAIL_OPENSSH31_REMOVE], [WARN_CIPHER_MODE]],
|
||||
'rijndael192-cbc': [['2.3.0', '3.0.2'], [FAIL_OPENSSH31_REMOVE], [WARN_CIPHER_MODE]],
|
||||
'rijndael256-cbc': [['2.3.0', '3.0.2'], [FAIL_OPENSSH31_REMOVE], [WARN_CIPHER_MODE]],
|
||||
'rijndael-cbc@lysator.liu.se': [['2.3.0', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_CIPHER_MODE]],
|
||||
'aes128-ctr': [['3.7,d0.52,l10.4.1']],
|
||||
'aes192-ctr': [['3.7,l10.4.1']],
|
||||
'aes256-ctr': [['3.7,d0.52,l10.4.1']],
|
||||
'aes128-gcm': [[]],
|
||||
'aes256-gcm': [[]],
|
||||
'3des-cbc': [['1.2.2,d0.28,l10.2', '6.6', None], [FAIL_3DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'3des-cfb': [[], [FAIL_3DES], [WARN_CIPHER_MODE]],
|
||||
'3des-ctr': [['d0.52'], [FAIL_3DES]],
|
||||
'3des-ecb': [[], [FAIL_3DES], [WARN_CIPHER_MODE]],
|
||||
'3des': [[], [FAIL_3DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'3des-ofb': [[], [FAIL_3DES], [WARN_CIPHER_MODE]],
|
||||
'AEAD_AES_128_GCM': [[]],
|
||||
'AEAD_AES_256_GCM': [[]],
|
||||
'aes128-cbc': [['2.3.0,d0.28,l10.2', '6.6', None], [], [WARN_CIPHER_MODE]],
|
||||
'aes128-ctr': [['3.7,d0.52,l10.4.1']],
|
||||
'aes128-gcm': [[]],
|
||||
'aes128-gcm@openssh.com': [['6.2']],
|
||||
'aes192-cbc': [['2.3.0,l10.2', '6.6', None], [], [WARN_CIPHER_MODE]],
|
||||
'aes192-ctr': [['3.7,l10.4.1']],
|
||||
'aes256-cbc': [['2.3.0,d0.47,l10.2', '6.6', None], [], [WARN_CIPHER_MODE]],
|
||||
'aes256-ctr': [['3.7,d0.52,l10.4.1']],
|
||||
'aes256-gcm': [[]],
|
||||
'aes256-gcm@openssh.com': [['6.2']],
|
||||
'chacha20-poly1305': [[], [], [], [INFO_OPENSSH69_CHACHA]],
|
||||
'chacha20-poly1305@openssh.com': [['6.5'], [], [], [INFO_OPENSSH69_CHACHA]],
|
||||
'arcfour128': [['4.2', '6.6', '7.1'], [FAIL_RC4]],
|
||||
'arcfour': [['2.1.0', '6.6', '7.1'], [FAIL_RC4]],
|
||||
'arcfour256': [['4.2', '6.6', '7.1'], [FAIL_RC4]],
|
||||
'blowfish-cbc': [['1.2.2,d0.28,l10.2', '6.6,d0.52', '7.1,d0.52'], [FAIL_BLOWFISH], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'blowfish-cfb': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE]],
|
||||
'blowfish-ctr': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'blowfish-ecb': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE]],
|
||||
'blowfish': [[], [FAIL_BLOWFISH], [WARN_BLOCK_SIZE]],
|
||||
'blowfish-ofb': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE]],
|
||||
'camellia128-cbc@openssh.org': [[], [], [WARN_CIPHER_MODE]],
|
||||
'camellia128-cbc': [[], [], [WARN_CIPHER_MODE]],
|
||||
'camellia128-ctr': [[]],
|
||||
'camellia128-ctr@openssh.org': [[]],
|
||||
'camellia192-cbc@openssh.org': [[], [], [WARN_CIPHER_MODE]],
|
||||
'camellia192-cbc': [[], [], [WARN_CIPHER_MODE]],
|
||||
'camellia192-ctr': [[]],
|
||||
'camellia192-ctr@openssh.org': [[]],
|
||||
'camellia256-cbc@openssh.org': [[], [], [WARN_CIPHER_MODE]],
|
||||
'camellia256-cbc': [[], [], [WARN_CIPHER_MODE]],
|
||||
'camellia256-ctr': [[]],
|
||||
'camellia256-ctr@openssh.org': [[]],
|
||||
'cast128-12-cbc@ssh.com': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
|
||||
'cast128-cbc': [['2.1.0', '6.6', '7.1'], [FAIL_CAST], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'cast128-cfb': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
|
||||
'cast128-ctr': [[], [FAIL_CAST]],
|
||||
'cast128-ecb': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
|
||||
'cast128-ofb': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
|
||||
'chacha20-poly1305': [[], [], [], [INFO_DEFAULT_OPENSSH_CIPHER]],
|
||||
'chacha20-poly1305@openssh.com': [['6.5'], [], [], [INFO_DEFAULT_OPENSSH_CIPHER]],
|
||||
'crypticore128@ssh.com': [[], [FAIL_UNPROVEN]],
|
||||
'seed-cbc@ssh.com': [[], [], [WARN_OBSOLETE, WARN_CIPHER_MODE]],
|
||||
'des-cbc': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'des-cbc-ssh1': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'des-cbc@ssh.com': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'des': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
|
||||
'idea-cbc': [[], [FAIL_IDEA], [WARN_CIPHER_MODE]],
|
||||
'idea-cfb': [[], [FAIL_IDEA], [WARN_CIPHER_MODE]],
|
||||
'idea-ctr': [[], [FAIL_IDEA]],
|
||||
'idea-ecb': [[], [FAIL_IDEA], [WARN_CIPHER_MODE]],
|
||||
'idea-ofb': [[], [FAIL_IDEA], [WARN_CIPHER_MODE]],
|
||||
'none': [['1.2.2,d2013.56,l10.2'], [FAIL_PLAINTEXT]],
|
||||
'rijndael128-cbc': [['2.3.0', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70]],
|
||||
'rijndael192-cbc': [['2.3.0', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70]],
|
||||
'rijndael256-cbc': [['2.3.0', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70]],
|
||||
'rijndael-cbc@lysator.liu.se': [['2.3.0', '6.6', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70]],
|
||||
'rijndael-cbc@ssh.com': [[], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE]],
|
||||
'seed-cbc@ssh.com': [[], [FAIL_SEED], [WARN_CIPHER_MODE]],
|
||||
'seed-ctr@ssh.com': [[], [FAIL_SEED]],
|
||||
'serpent128-cbc': [[], [FAIL_SERPENT], [WARN_CIPHER_MODE]],
|
||||
'serpent128-ctr': [[], [FAIL_SERPENT]],
|
||||
'serpent128-gcm@libassh.org': [[], [FAIL_SERPENT]],
|
||||
'serpent192-cbc': [[], [FAIL_SERPENT], [WARN_CIPHER_MODE]],
|
||||
'serpent192-ctr': [[], [FAIL_SERPENT]],
|
||||
'serpent256-cbc': [[], [FAIL_SERPENT], [WARN_CIPHER_MODE]],
|
||||
'serpent256-ctr': [[], [FAIL_SERPENT]],
|
||||
'serpent256-gcm@libassh.org': [[], [FAIL_SERPENT]],
|
||||
'twofish128-cbc': [['d0.47', 'd2014.66'], [], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_DBEAR67]],
|
||||
'twofish128-ctr': [['d2015.68']],
|
||||
'twofish128-gcm@libassh.org': [[]],
|
||||
'twofish192-cbc': [[], [], [WARN_CIPHER_MODE]],
|
||||
'twofish192-ctr': [[]],
|
||||
'twofish256-cbc': [['d0.47', 'd2014.66'], [], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_DBEAR67]],
|
||||
'twofish256-ctr': [['d2015.68']],
|
||||
'twofish256-gcm@libassh.org': [[]],
|
||||
'twofish-cbc': [['d0.28', 'd2014.66'], [], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_DBEAR67]],
|
||||
'twofish-cfb': [[], [], [WARN_CIPHER_MODE]],
|
||||
'twofish-ctr': [[]],
|
||||
'twofish-ecb': [[], [], [WARN_CIPHER_MODE]],
|
||||
'twofish-ofb': [[], [], [WARN_CIPHER_MODE]],
|
||||
},
|
||||
'mac': {
|
||||
'none': [['d2013.56'], [FAIL_PLAINTEXT]],
|
||||
'hmac-sha1': [['2.1.0,d0.28,l10.2'], [], [WARN_ENCRYPT_AND_MAC, WARN_HASH_WEAK]],
|
||||
'hmac-sha1-96': [['2.5.0,d0.47', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC, WARN_HASH_WEAK]],
|
||||
'hmac-sha2-56': [[], [], [WARN_TAG_SIZE, WARN_ENCRYPT_AND_MAC]],
|
||||
'AEAD_AES_128_GCM': [[]],
|
||||
'AEAD_AES_256_GCM': [[]],
|
||||
'aes128-gcm': [[]],
|
||||
'aes256-gcm': [[]],
|
||||
'chacha20-poly1305@openssh.com': [[], [], [], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]], # Despite the @openssh.com tag, this was never shipped as a MAC in OpenSSH (only as a cipher); it is only implemented as a MAC in Syncplify.
|
||||
'crypticore-mac@ssh.com': [[], [FAIL_UNPROVEN]],
|
||||
'hmac-md5': [['2.1.0,d0.28', '6.6', '7.1'], [FAIL_MD5], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-md5-96': [['2.5.0', '6.6', '7.1'], [FAIL_MD5], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-md5-96-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_MD5]],
|
||||
'hmac-md5-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_MD5]],
|
||||
'hmac-ripemd160': [['2.5.0', '6.6', '7.1'], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-ripemd160-96': [[], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]],
|
||||
'hmac-ripemd160-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_RIPEMD]],
|
||||
'hmac-ripemd160@openssh.com': [['2.1.0', '6.6', '7.1'], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-ripemd': [[], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha1': [['2.1.0,d0.28,l10.2'], [FAIL_SHA1], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha1-96': [['2.5.0,d0.47', '6.6', '7.1'], [FAIL_SHA1], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha1-96-etm@openssh.com': [['6.2', '6.6', None], [FAIL_SHA1]],
|
||||
'hmac-sha1-96@openssh.com': [[], [FAIL_SHA1], [WARN_TAG_SIZE, WARN_ENCRYPT_AND_MAC], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]],
|
||||
'hmac-sha1-etm@openssh.com': [['6.2'], [FAIL_SHA1]],
|
||||
'hmac-sha2-224': [[], [], [WARN_TAG_SIZE, WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha224@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha2-256': [['5.9,d2013.56,l10.7.0'], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha2-256-96': [['5.9', '6.0'], [FAIL_OPENSSH61_REMOVE], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha2-256-96': [['5.9', '6.0'], [], [WARN_ENCRYPT_AND_MAC], [INFO_REMOVED_IN_OPENSSH61]],
|
||||
'hmac-sha2-256-96-etm@openssh.com': [[], [], [WARN_TAG_SIZE_96], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]], # Only ever implemented in AsyncSSH (?).
|
||||
'hmac-sha2-256-etm@openssh.com': [['6.2']],
|
||||
'hmac-sha2-384': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha2-512': [['5.9,d2013.56,l10.7.0'], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha2-512-96': [['5.9', '6.0'], [FAIL_OPENSSH61_REMOVE], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha2-512-96': [['5.9', '6.0'], [], [WARN_ENCRYPT_AND_MAC], [INFO_REMOVED_IN_OPENSSH61]],
|
||||
'hmac-sha2-512-96-etm@openssh.com': [[], [], [WARN_TAG_SIZE_96], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]], # Only ever implemented in AsyncSSH (?).
|
||||
'hmac-sha2-512-etm@openssh.com': [['6.2']],
|
||||
'hmac-sha256-2@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha256-96@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]],
|
||||
'hmac-sha256@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha256': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha2-56': [[], [], [WARN_TAG_SIZE, WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha3-224': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha3-256': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha3-384': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha3-512': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha256': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha256-96@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]],
|
||||
'hmac-sha256@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha512': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha384@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha512@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-md5': [['2.1.0,d0.28', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC, WARN_HASH_WEAK]],
|
||||
'hmac-md5-96': [['2.5.0', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC, WARN_HASH_WEAK]],
|
||||
'hmac-ripemd': [[], [FAIL_DEPRECATED_MAC], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-ripemd160': [['2.5.0', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-ripemd160@openssh.com': [['2.1.0', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_ENCRYPT_AND_MAC]],
|
||||
'umac-64@openssh.com': [['4.7'], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]],
|
||||
'umac-128@openssh.com': [['6.2'], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-sha1-etm@openssh.com': [['6.2'], [], [WARN_HASH_WEAK]],
|
||||
'hmac-sha1-96-etm@openssh.com': [['6.2', '6.6', None], [FAIL_OPENSSH67_UNSAFE], [WARN_HASH_WEAK]],
|
||||
'hmac-sha2-256-96-etm@openssh.com': [[], [], [WARN_TAG_SIZE_96]], # Despite the @openssh.com tag, it doesn't appear that this was ever shipped with OpenSSH; it is only implemented in AsyncSSH (?).
|
||||
'hmac-sha2-512-96-etm@openssh.com': [[], [], [WARN_TAG_SIZE_96]], # Despite the @openssh.com tag, it doesn't appear that this was ever shipped with OpenSSH; it is only implemented in AsyncSSH (?).
|
||||
'hmac-sha2-256-etm@openssh.com': [['6.2']],
|
||||
'hmac-sha2-512-etm@openssh.com': [['6.2']],
|
||||
'hmac-md5-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_HASH_WEAK]],
|
||||
'hmac-md5-96-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY, WARN_HASH_WEAK]],
|
||||
'hmac-ripemd160-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_OPENSSH67_UNSAFE], [WARN_OPENSSH72_LEGACY]],
|
||||
'umac-32@openssh.com': [[], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]], # Despite having the @openssh.com suffix, this may never have shipped with OpenSSH (!).
|
||||
'umac-64-etm@openssh.com': [['6.2'], [], [WARN_TAG_SIZE]],
|
||||
'umac-96@openssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]], # Despite having the @openssh.com suffix, this may never have shipped with OpenSSH (!).
|
||||
'hmac-sha512': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'hmac-whirlpool': [[], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'none': [['d2013.56'], [FAIL_PLAINTEXT]],
|
||||
'umac-128-etm@openssh.com': [['6.2']],
|
||||
'aes128-gcm': [[]],
|
||||
'aes256-gcm': [[]],
|
||||
'chacha20-poly1305@openssh.com': [[]], # Despite the @openssh.com tag, this was never shipped as a MAC in OpenSSH (only as a cipher); it is only implemented as a MAC in Syncplify.
|
||||
'crypticore-mac@ssh.com': [[], [FAIL_UNPROVEN]],
|
||||
'umac-128@openssh.com': [['6.2'], [], [WARN_ENCRYPT_AND_MAC]],
|
||||
'umac-32@openssh.com': [[], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]],
|
||||
'umac-64-etm@openssh.com': [['6.2'], [], [WARN_TAG_SIZE]],
|
||||
'umac-64@openssh.com': [['4.7'], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]],
|
||||
'umac-96@openssh.com': [[], [], [WARN_ENCRYPT_AND_MAC], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]],
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2017-2021 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -34,8 +34,10 @@ import traceback
|
||||
|
||||
# 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 typing import cast, Callable, Optional, Union, Any # noqa: F401
|
||||
|
||||
from ssh_audit.globals import SNAP_PACKAGE
|
||||
from ssh_audit.globals import SNAP_PERMISSIONS_ERROR
|
||||
from ssh_audit.globals import VERSION
|
||||
from ssh_audit.globals import WINDOWS_MAN_PAGE
|
||||
from ssh_audit.algorithm import Algorithm
|
||||
@ -59,22 +61,32 @@ from ssh_audit.ssh_socket import SSH_Socket
|
||||
from ssh_audit.utils import Utils
|
||||
from ssh_audit.versionvulnerabilitydb import VersionVulnerabilityDB
|
||||
|
||||
|
||||
# no_idna_workaround = False
|
||||
|
||||
# Only import colorama under Windows. Other OSes can natively handle terminal colors.
|
||||
if sys.platform == 'win32':
|
||||
try:
|
||||
from colorama import init as colorama_init
|
||||
colorama_init()
|
||||
from colorama import just_fix_windows_console
|
||||
just_fix_windows_console()
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# This is a workaround for a Python bug that causes a crash on Windows when multiple threads are used (see https://github.com/python/cpython/issues/73474). Importing the idna module and using it in a no-op seems to fix the issue. Otherwise, if idna isn't available at run-time, force single threaded scans.
|
||||
# try:
|
||||
# import idna # noqa: F401
|
||||
#
|
||||
# ''.encode('idna')
|
||||
# except ImportError:
|
||||
# no_idna_workaround = True
|
||||
|
||||
def usage(err: Optional[str] = None) -> None:
|
||||
|
||||
def usage(uout: OutputBuffer, err: Optional[str] = None) -> None:
|
||||
retval = exitcodes.GOOD
|
||||
uout = OutputBuffer()
|
||||
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('\n' + err)
|
||||
uout.fail(err + '\n')
|
||||
retval = exitcodes.UNKNOWN_ERROR
|
||||
uout.info('usage: {0} [options] <host>\n'.format(p))
|
||||
uout.info(' -h, --help print this help')
|
||||
@ -84,7 +96,11 @@ def usage(err: Optional[str] = None) -> None:
|
||||
uout.info(' -6, --ipv6 enable IPv6 (order of precedence)')
|
||||
uout.info(' -b, --batch batch output')
|
||||
uout.info(' -c, --client-audit starts a server on port 2222 to audit client\n software config (use -p to change port;\n use -t to change timeout)')
|
||||
uout.info(' -j, --json JSON output')
|
||||
uout.info(' -d, --debug debug output')
|
||||
uout.info(' -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')
|
||||
uout.info(' --lookup=<alg1,alg2,...> looks up an algorithm(s) without\n connecting to a server')
|
||||
@ -102,10 +118,10 @@ def usage(err: Optional[str] = None) -> None:
|
||||
sys.exit(retval)
|
||||
|
||||
|
||||
def output_algorithms(out: OutputBuffer, title: str, alg_db: Dict[str, Dict[str, List[List[Optional[str]]]]], alg_type: str, algorithms: List[str], unknown_algs: List[str], is_json_output: bool, program_retval: int, maxlen: int = 0, alg_sizes: Optional[Dict[str, Tuple[int, int]]] = None) -> int: # pylint: disable=too-many-arguments
|
||||
def output_algorithms(out: OutputBuffer, title: str, alg_db: Dict[str, Dict[str, List[List[Optional[str]]]]], alg_type: str, algorithms: List[str], unknown_algs: List[str], is_json_output: bool, program_retval: int, maxlen: int = 0, host_keys: Optional[Dict[str, Dict[str, Union[bytes, str, int]]]] = None, dh_modulus_sizes: Optional[Dict[str, int]] = None) -> int: # pylint: disable=too-many-arguments
|
||||
with out:
|
||||
for algorithm in algorithms:
|
||||
program_retval = output_algorithm(out, alg_db, alg_type, algorithm, unknown_algs, program_retval, maxlen, alg_sizes)
|
||||
program_retval = output_algorithm(out, alg_db, alg_type, algorithm, unknown_algs, program_retval, maxlen, host_keys=host_keys, dh_modulus_sizes=dh_modulus_sizes)
|
||||
if not out.is_section_empty() and not is_json_output:
|
||||
out.head('# ' + title)
|
||||
out.flush_section()
|
||||
@ -114,7 +130,7 @@ def output_algorithms(out: OutputBuffer, title: str, alg_db: Dict[str, Dict[str,
|
||||
return program_retval
|
||||
|
||||
|
||||
def output_algorithm(out: OutputBuffer, alg_db: Dict[str, Dict[str, List[List[Optional[str]]]]], alg_type: str, alg_name: str, unknown_algs: List[str], program_retval: int, alg_max_len: int = 0, alg_sizes: Optional[Dict[str, Tuple[int, int]]] = None) -> int:
|
||||
def output_algorithm(out: OutputBuffer, alg_db: Dict[str, Dict[str, List[List[Optional[str]]]]], alg_type: str, alg_name: str, unknown_algs: List[str], program_retval: int, alg_max_len: int = 0, host_keys: Optional[Dict[str, Dict[str, Union[bytes, str, int]]]] = None, dh_modulus_sizes: Optional[Dict[str, int]] = None) -> int: # pylint: disable=too-many-arguments
|
||||
prefix = '(' + alg_type + ') '
|
||||
if alg_max_len == 0:
|
||||
alg_max_len = len(alg_name)
|
||||
@ -123,15 +139,31 @@ def output_algorithm(out: OutputBuffer, alg_db: Dict[str, Dict[str, List[List[Op
|
||||
# If this is an RSA host key or DH GEX, append the size to its name and fix
|
||||
# the padding.
|
||||
alg_name_with_size = None
|
||||
if (alg_sizes is not None) and (alg_name in alg_sizes):
|
||||
hostkey_size, ca_size = alg_sizes[alg_name]
|
||||
if ca_size > 0:
|
||||
alg_name_with_size = '%s (%d-bit cert/%d-bit CA)' % (alg_name, hostkey_size, ca_size)
|
||||
if (dh_modulus_sizes is not None) and (alg_name in dh_modulus_sizes):
|
||||
alg_name_with_size = '%s (%u-bit)' % (alg_name, dh_modulus_sizes[alg_name])
|
||||
padding = padding[0:-11]
|
||||
elif (host_keys is not None) and (alg_name in host_keys):
|
||||
hostkey_size = cast(int, host_keys[alg_name]['hostkey_size'])
|
||||
ca_key_type = cast(str, host_keys[alg_name]['ca_key_type'])
|
||||
ca_key_size = cast(int, host_keys[alg_name]['ca_key_size'])
|
||||
|
||||
# If this is an RSA variant, just print "RSA".
|
||||
if ca_key_type in HostKeyTest.RSA_FAMILY:
|
||||
ca_key_type = "RSA"
|
||||
|
||||
if len(ca_key_type) > 0 and ca_key_size > 0:
|
||||
alg_name_with_size = '%s (%u-bit cert/%u-bit %s CA)' % (alg_name, hostkey_size, ca_key_size, ca_key_type)
|
||||
padding = padding[0:-15]
|
||||
else:
|
||||
alg_name_with_size = '%s (%d-bit)' % (alg_name, hostkey_size)
|
||||
elif alg_name in HostKeyTest.RSA_FAMILY:
|
||||
alg_name_with_size = '%s (%u-bit)' % (alg_name, hostkey_size)
|
||||
padding = padding[0:-11]
|
||||
|
||||
# If this is a kex algorithm and starts with 'gss-', then normalize its name (i.e.: 'gss-gex-sha1-vz8J1E9PzLr8b1K+0remTg==' => 'gss-gex-sha1-*'). The base64 field can vary, so we'll convert it to the wildcard that our database uses and we'll just resume doing a straight match like all other algorithm names.
|
||||
alg_name_original = alg_name
|
||||
if alg_type == 'kex' and alg_name.startswith('gss-'):
|
||||
last_dash = alg_name.rindex('-')
|
||||
alg_name = "%s-*" % alg_name[0:last_dash]
|
||||
|
||||
texts = []
|
||||
if len(alg_name.strip()) == 0:
|
||||
return program_retval
|
||||
@ -157,6 +189,10 @@ def output_algorithm(out: OutputBuffer, alg_db: Dict[str, Dict[str, List[List[Op
|
||||
texts.append(('warn', 'unknown algorithm'))
|
||||
unknown_algs.append(alg_name)
|
||||
|
||||
# For kex GSS algorithms, now that we already did the database lookup (above), restore the original algorithm name so its reported properly in the output.
|
||||
if alg_name != alg_name_original:
|
||||
alg_name = alg_name_original
|
||||
|
||||
alg_name = alg_name_with_size if alg_name_with_size is not None else alg_name
|
||||
first = True
|
||||
for level, text in texts:
|
||||
@ -176,7 +212,7 @@ def output_algorithm(out: OutputBuffer, alg_db: Dict[str, Dict[str, List[List[Op
|
||||
if out.verbose:
|
||||
f(prefix + alg_name + comment)
|
||||
elif text != '':
|
||||
comment = (padding + ' `- [' + level + '] ' + text)
|
||||
comment = padding + ' `- [' + level + '] ' + text
|
||||
f(' ' * len(prefix + alg_name) + comment)
|
||||
|
||||
return program_retval
|
||||
@ -212,10 +248,12 @@ def output_compatibility(out: OutputBuffer, algs: Algorithms, client_audit: bool
|
||||
out.good('(gen) compatibility: ' + ', '.join(comp_text))
|
||||
|
||||
|
||||
def output_security_sub(out: OutputBuffer, sub: str, software: Optional[Software], client_audit: bool, padlen: int) -> None:
|
||||
def output_security_sub(out: OutputBuffer, sub: str, software: Optional[Software], client_audit: bool, padlen: int) -> List[Dict[str, Union[str, float]]]:
|
||||
ret: List[Dict[str, Union[str, float]]] = []
|
||||
|
||||
secdb = VersionVulnerabilityDB.CVE if sub == 'cve' else VersionVulnerabilityDB.TXT
|
||||
if software is None or software.product not in secdb:
|
||||
return
|
||||
return ret
|
||||
for line in secdb[software.product]:
|
||||
vfrom: str = ''
|
||||
vtill: str = ''
|
||||
@ -243,17 +281,22 @@ def output_security_sub(out: OutputBuffer, sub: str, software: Optional[Software
|
||||
if cvss >= 8.0:
|
||||
out_func = out.fail
|
||||
out_func('(cve) {}{} -- (CVSSv2: {}) {}'.format(name, p, cvss, descr))
|
||||
ret.append({'name': name, 'cvssv2': cvss, 'description': descr})
|
||||
else:
|
||||
descr = line[4]
|
||||
out.fail('(sec) {}{} -- {}'.format(name, p, descr))
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def output_security(out: OutputBuffer, banner: Optional[Banner], client_audit: bool, padlen: int, is_json_output: bool) -> List[Dict[str, Union[str, float]]]:
|
||||
cves = []
|
||||
|
||||
def output_security(out: OutputBuffer, banner: Optional[Banner], client_audit: bool, padlen: int, is_json_output: bool) -> None:
|
||||
with out:
|
||||
if banner is not None:
|
||||
software = Software.parse(banner)
|
||||
output_security_sub(out, 'cve', software, client_audit, padlen)
|
||||
output_security_sub(out, 'txt', software, client_audit, padlen)
|
||||
cves = output_security_sub(out, 'cve', software, client_audit, padlen)
|
||||
_ = output_security_sub(out, 'txt', software, client_audit, padlen)
|
||||
if banner.protocol[0] == 1:
|
||||
p = '' if out.batch else ' ' * (padlen - 14)
|
||||
out.fail('(sec) SSH v1 enabled{} -- SSH v1 can be exploited to recover plaintext passwords'.format(p))
|
||||
@ -262,38 +305,42 @@ def output_security(out: OutputBuffer, banner: Optional[Banner], client_audit: b
|
||||
out.flush_section()
|
||||
out.sep()
|
||||
|
||||
return cves
|
||||
|
||||
def output_fingerprints(out: OutputBuffer, algs: Algorithms, is_json_output: bool, sha256: bool = True) -> None:
|
||||
|
||||
def output_fingerprints(out: OutputBuffer, algs: Algorithms, is_json_output: bool) -> None:
|
||||
with out:
|
||||
fps = []
|
||||
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.append((name, fp))
|
||||
fps[name] = fp
|
||||
if algs.ssh2kex is not None:
|
||||
host_keys = algs.ssh2kex.host_keys()
|
||||
for host_key_type in algs.ssh2kex.host_keys():
|
||||
if host_keys[host_key_type] is None:
|
||||
continue
|
||||
|
||||
fp = Fingerprint(host_keys[host_key_type])
|
||||
fp = Fingerprint(cast(bytes, host_keys[host_key_type]['raw_hostkey_bytes']))
|
||||
|
||||
# Workaround for Python's order-indifference in dicts. We might get a random RSA type (ssh-rsa, rsa-sha2-256, or rsa-sha2-512), so running the tool against the same server three times may give three different host key types here. So if we have any RSA type, we will simply hard-code it to 'ssh-rsa'.
|
||||
if host_key_type in HostKeyTest.RSA_FAMILY:
|
||||
host_key_type = 'ssh-rsa'
|
||||
|
||||
# Skip over certificate host types (or we would return invalid fingerprints).
|
||||
# Skip over certificate host types (or we would return invalid fingerprints), and only add one fingerprint in the RSA family.
|
||||
if '-cert-' not in host_key_type:
|
||||
fps.append((host_key_type, fp))
|
||||
fps[host_key_type] = fp
|
||||
# Similarly, the host keys can be processed in random order due to Python's order-indifference in dicts. So we sort this list before printing; this makes automated testing possible.
|
||||
fps = sorted(fps)
|
||||
for fpp in fps:
|
||||
name, fp = fpp
|
||||
fpo = fp.sha256 if sha256 else fp.md5
|
||||
# p = '' if out.batch else ' ' * (padlen - len(name))
|
||||
# out.good('(fin) {0}{1} -- {2} {3}'.format(name, p, bits, fpo))
|
||||
out.good('(fin) {}: {}'.format(name, fpo))
|
||||
fp_types = sorted(fps.keys())
|
||||
for fp_type in fp_types:
|
||||
fp = fps[fp_type]
|
||||
out.good('(fin) {}: {}'.format(fp_type, fp.sha256))
|
||||
|
||||
# Output the MD5 hash too if verbose mode is enabled.
|
||||
if out.verbose:
|
||||
out.info('(fin) {}: {} -- [info] do not rely on MD5 fingerprints for server identification; it is insecure for this use case'.format(fp_type, fp.md5))
|
||||
|
||||
if not out.is_section_empty() and not is_json_output:
|
||||
out.head('# fingerprints')
|
||||
out.flush_section()
|
||||
@ -301,7 +348,7 @@ def output_fingerprints(out: OutputBuffer, algs: Algorithms, is_json_output: boo
|
||||
|
||||
|
||||
# Returns True if no warnings or failures encountered in configuration.
|
||||
def output_recommendations(out: OutputBuffer, algs: Algorithms, software: Optional[Software], is_json_output: bool, padlen: int = 0) -> bool:
|
||||
def output_recommendations(out: OutputBuffer, algs: Algorithms, algorithm_recommendation_suppress_list: List[str], software: Optional[Software], is_json_output: bool, padlen: int = 0) -> bool:
|
||||
|
||||
ret = True
|
||||
# PuTTY's algorithms cannot be modified, so there's no point in issuing recommendations.
|
||||
@ -332,35 +379,35 @@ def output_recommendations(out: OutputBuffer, algs: Algorithms, software: Option
|
||||
ret = False
|
||||
return ret
|
||||
|
||||
for_server = True
|
||||
with out:
|
||||
software, alg_rec = algs.get_recommendations(software, for_server)
|
||||
for sshv in range(2, 0, -1):
|
||||
if sshv not in alg_rec:
|
||||
continue
|
||||
for alg_type in ['kex', 'key', 'enc', 'mac']:
|
||||
if alg_type not in alg_rec[sshv]:
|
||||
continue
|
||||
for action in ['del', 'add', 'chg']:
|
||||
if action not in alg_rec[sshv][alg_type]:
|
||||
continue
|
||||
for name in alg_rec[sshv][alg_type][action]:
|
||||
recommendations = get_algorithm_recommendations(algs, algorithm_recommendation_suppress_list, software, for_server=True)
|
||||
|
||||
for level in recommendations: # pylint: disable=consider-using-dict-items
|
||||
for action in recommendations[level]:
|
||||
for alg_type in recommendations[level][action]:
|
||||
for alg_name_and_notes in recommendations[level][action][alg_type]:
|
||||
name = alg_name_and_notes['name']
|
||||
notes = alg_name_and_notes['notes']
|
||||
|
||||
p = '' if out.batch else ' ' * (padlen - len(name))
|
||||
chg_additional_info = ''
|
||||
|
||||
if action == 'del':
|
||||
an, sg, fn = 'remove', '-', out.warn
|
||||
ret = False
|
||||
if alg_rec[sshv][alg_type][action][name] >= 10:
|
||||
if level == 'critical':
|
||||
fn = out.fail
|
||||
elif action == 'add':
|
||||
an, sg, fn = 'append', '+', out.good
|
||||
elif action == 'chg':
|
||||
an, sg, fn = 'change', '!', out.fail
|
||||
ret = False
|
||||
chg_additional_info = ' (increase modulus size to 2048 bits or larger)'
|
||||
b = '(SSH{})'.format(sshv) if sshv == 1 else ''
|
||||
fm = '(rec) {0}{1}{2}-- {3} algorithm to {4}{5} {6}'
|
||||
fn(fm.format(sg, name, p, alg_type, an, chg_additional_info, b))
|
||||
|
||||
if notes != '':
|
||||
notes = " (%s)" % notes
|
||||
|
||||
fm = '(rec) {0}{1}{2}-- {3} algorithm to {4}{5} '
|
||||
fn(fm.format(sg, name, p, alg_type, an, notes))
|
||||
|
||||
if not out.is_section_empty() and not is_json_output:
|
||||
if software is not None:
|
||||
title = '(for {})'.format(software.display(False))
|
||||
@ -389,6 +436,27 @@ def output_info(out: OutputBuffer, software: Optional['Software'], client_audit:
|
||||
out.sep()
|
||||
|
||||
|
||||
def post_process_findings(banner: Optional[Banner], algs: Algorithms) -> List[str]:
|
||||
'''Perform post-processing on scan results before reporting them to the user. Returns a list of algorithms that should not be recommended'''
|
||||
|
||||
|
||||
algorithm_recommendation_suppress_list = []
|
||||
|
||||
# If the server is OpenSSH, and the diffie-hellman-group-exchange-sha256 key exchange was found with modulus size 2048, add a note regarding the bug that causes the server to support 2048-bit moduli no matter the configuration.
|
||||
if (algs.ssh2kex is not None and 'diffie-hellman-group-exchange-sha256' in algs.ssh2kex.kex_algorithms and 'diffie-hellman-group-exchange-sha256' in algs.ssh2kex.dh_modulus_sizes() and algs.ssh2kex.dh_modulus_sizes()['diffie-hellman-group-exchange-sha256'] == 2048) and (banner is not None and banner.software is not None and banner.software.find('OpenSSH') != -1):
|
||||
|
||||
# Ensure a list for notes exists.
|
||||
while len(SSH2_KexDB.ALGORITHMS['kex']['diffie-hellman-group-exchange-sha256']) < 4:
|
||||
SSH2_KexDB.ALGORITHMS['kex']['diffie-hellman-group-exchange-sha256'].append([])
|
||||
|
||||
SSH2_KexDB.ALGORITHMS['kex']['diffie-hellman-group-exchange-sha256'][3].append("A bug in OpenSSH causes it to fall back to a 2048-bit modulus regardless of server configuration (https://bugzilla.mindrot.org/show_bug.cgi?id=2793)")
|
||||
|
||||
# Ensure that this algorithm doesn't appear in the recommendations section since the user cannot control this OpenSSH bug.
|
||||
algorithm_recommendation_suppress_list.append('diffie-hellman-group-exchange-sha256')
|
||||
|
||||
return algorithm_recommendation_suppress_list
|
||||
|
||||
|
||||
# Returns a exitcodes.* flag to denote if any failures or warnings were encountered.
|
||||
def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header: List[str], client_host: Optional[str] = None, kex: Optional[SSH2_Kex] = None, pkm: Optional[SSH1_PublicKeyMessage] = None, print_target: bool = False) -> int:
|
||||
|
||||
@ -396,6 +464,10 @@ def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header
|
||||
client_audit = client_host is not None # If set, this is a client audit.
|
||||
sshv = 1 if pkm is not None else 2
|
||||
algs = Algorithms(pkm, kex)
|
||||
|
||||
# Perform post-processing on the findings to make final adjustments before outputting the results.
|
||||
algorithm_recommendation_suppress_list = post_process_findings(banner, algs)
|
||||
|
||||
with out:
|
||||
if print_target:
|
||||
host = aconf.host
|
||||
@ -444,9 +516,11 @@ def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header
|
||||
out.flush_section()
|
||||
out.sep()
|
||||
maxlen = algs.maxlen + 1
|
||||
output_security(out, banner, client_audit, maxlen, aconf.json)
|
||||
cves = output_security(out, banner, client_audit, maxlen, aconf.json)
|
||||
# Filled in by output_algorithms() with unidentified algs.
|
||||
unknown_algorithms: List[str] = []
|
||||
|
||||
# SSHv1
|
||||
if pkm is not None:
|
||||
adb = SSH1_KexDB.ALGORITHMS
|
||||
ciphers = pkm.supported_ciphers
|
||||
@ -457,24 +531,27 @@ def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header
|
||||
program_retval = output_algorithms(out, title, adb, atype, ciphers, unknown_algorithms, aconf.json, program_retval, maxlen)
|
||||
title, atype = 'SSH1 authentication types', 'aut'
|
||||
program_retval = output_algorithms(out, title, adb, atype, auths, unknown_algorithms, aconf.json, program_retval, maxlen)
|
||||
|
||||
# SSHv2
|
||||
if kex is not None:
|
||||
adb = SSH2_KexDB.ALGORITHMS
|
||||
title, atype = 'key exchange algorithms', 'kex'
|
||||
program_retval = output_algorithms(out, title, adb, atype, kex.kex_algorithms, unknown_algorithms, aconf.json, program_retval, maxlen, kex.dh_modulus_sizes())
|
||||
program_retval = output_algorithms(out, title, adb, atype, kex.kex_algorithms, unknown_algorithms, aconf.json, program_retval, maxlen, dh_modulus_sizes=kex.dh_modulus_sizes())
|
||||
title, atype = 'host-key algorithms', 'key'
|
||||
program_retval = output_algorithms(out, title, adb, atype, kex.key_algorithms, unknown_algorithms, aconf.json, program_retval, maxlen, kex.rsa_key_sizes())
|
||||
program_retval = output_algorithms(out, title, adb, atype, kex.key_algorithms, unknown_algorithms, aconf.json, program_retval, maxlen, host_keys=kex.host_keys())
|
||||
title, atype = 'encryption algorithms (ciphers)', 'enc'
|
||||
program_retval = output_algorithms(out, title, adb, atype, kex.server.encryption, unknown_algorithms, aconf.json, program_retval, maxlen)
|
||||
title, atype = 'message authentication code algorithms', 'mac'
|
||||
program_retval = output_algorithms(out, title, adb, atype, kex.server.mac, unknown_algorithms, aconf.json, program_retval, maxlen)
|
||||
output_fingerprints(out, algs, aconf.json, True)
|
||||
perfect_config = output_recommendations(out, algs, software, aconf.json, maxlen)
|
||||
|
||||
output_fingerprints(out, algs, aconf.json)
|
||||
perfect_config = output_recommendations(out, algs, algorithm_recommendation_suppress_list, software, aconf.json, maxlen)
|
||||
output_info(out, software, client_audit, not perfect_config, aconf.json)
|
||||
|
||||
if aconf.json:
|
||||
out.reset()
|
||||
# Build & write the JSON struct.
|
||||
out.info(json.dumps(build_struct(aconf.host, banner, kex=kex, client_host=client_host), sort_keys=True))
|
||||
out.info(json.dumps(build_struct(aconf.host + ":" + str(aconf.port), banner, cves, kex=kex, client_host=client_host, software=software, algorithms=algs, algorithm_recommendation_suppress_list=algorithm_recommendation_suppress_list), indent=4 if aconf.json_print_indent else None, sort_keys=True))
|
||||
elif len(unknown_algorithms) > 0: # If we encountered any unknown algorithms, ask the user to report them.
|
||||
out.warn("\n\n!!! WARNING: unknown algorithm(s) found!: %s. Please email the full output above to the maintainer (jtesta@positronsecurity.com), or create a Github issue at <https://github.com/jtesta/ssh-audit/issues>.\n" % ','.join(unknown_algorithms))
|
||||
|
||||
@ -489,7 +566,7 @@ def evaluate_policy(out: OutputBuffer, aconf: AuditConf, banner: Optional['Banne
|
||||
passed, error_struct, error_str = aconf.policy.evaluate(banner, kex)
|
||||
if aconf.json:
|
||||
json_struct = {'host': aconf.host, 'policy': aconf.policy.get_name_and_version(), 'passed': passed, 'errors': error_struct}
|
||||
out.info(json.dumps(json_struct, sort_keys=True))
|
||||
out.info(json.dumps(json_struct, indent=4 if aconf.json_print_indent else None, sort_keys=True))
|
||||
else:
|
||||
spacing = ''
|
||||
if aconf.client_audit:
|
||||
@ -524,6 +601,55 @@ def evaluate_policy(out: OutputBuffer, aconf: AuditConf, banner: Optional['Banne
|
||||
return passed
|
||||
|
||||
|
||||
def get_algorithm_recommendations(algs: Optional[Algorithms], algorithm_recommendation_suppress_list: Optional[List[str]], software: Optional[Software], for_server: bool = True) -> Dict[str, Any]:
|
||||
'''Returns the algorithm recommendations.'''
|
||||
ret: Dict[str, Any] = {}
|
||||
|
||||
if algs is None or software is None:
|
||||
return ret
|
||||
|
||||
software, alg_rec = algs.get_recommendations(software, for_server)
|
||||
for sshv in range(2, 0, -1):
|
||||
if sshv not in alg_rec:
|
||||
continue
|
||||
for alg_type in ['kex', 'key', 'enc', 'mac']:
|
||||
if alg_type not in alg_rec[sshv]:
|
||||
continue
|
||||
for action in ['del', 'add', 'chg']:
|
||||
if action not in alg_rec[sshv][alg_type]:
|
||||
continue
|
||||
|
||||
for name in alg_rec[sshv][alg_type][action]:
|
||||
|
||||
# If this algorithm should be suppressed, skip it.
|
||||
if algorithm_recommendation_suppress_list is not None and name in algorithm_recommendation_suppress_list:
|
||||
continue
|
||||
|
||||
level = 'informational'
|
||||
points = alg_rec[sshv][alg_type][action][name]
|
||||
if points >= 10:
|
||||
level = 'critical'
|
||||
elif points >= 1:
|
||||
level = 'warning'
|
||||
|
||||
if level not in ret:
|
||||
ret[level] = {}
|
||||
|
||||
if action not in ret[level]:
|
||||
ret[level][action] = {}
|
||||
|
||||
if alg_type not in ret[level][action]:
|
||||
ret[level][action][alg_type] = []
|
||||
|
||||
notes = ''
|
||||
if action == 'chg':
|
||||
notes = 'increase modulus size to 3072 bits or larger'
|
||||
|
||||
ret[level][action][alg_type].append({'name': name, 'notes': notes})
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def list_policies(out: OutputBuffer) -> None:
|
||||
'''Prints a list of server & client policies.'''
|
||||
|
||||
@ -557,36 +683,50 @@ def make_policy(aconf: AuditConf, banner: Optional['Banner'], kex: Optional['SSH
|
||||
if aconf.policy_file is None:
|
||||
raise RuntimeError('Internal error: cannot write policy file since filename is None!')
|
||||
|
||||
# Open with mode 'x' (creates the file, or fails if it already exist).
|
||||
succeeded = True
|
||||
succeeded = False
|
||||
err = ''
|
||||
try:
|
||||
with open(aconf.policy_file, 'x') as f:
|
||||
# Open with mode 'x' (creates the file, or fails if it already exist).
|
||||
with open(aconf.policy_file, 'x', encoding='utf-8') as f:
|
||||
f.write(policy_data)
|
||||
succeeded = True
|
||||
except FileExistsError:
|
||||
succeeded = False
|
||||
err = "Error: file already exists: %s" % aconf.policy_file
|
||||
except PermissionError as e:
|
||||
# If installed as a Snap package, print a more useful message with potential work-arounds.
|
||||
if SNAP_PACKAGE:
|
||||
print(SNAP_PERMISSIONS_ERROR)
|
||||
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||
else:
|
||||
err = "Error: insufficient permissions: %s" % str(e)
|
||||
|
||||
if succeeded:
|
||||
print("Wrote policy to %s. Customize as necessary, then run a policy scan with -P option." % aconf.policy_file)
|
||||
else:
|
||||
print("Error: file already exists: %s" % aconf.policy_file)
|
||||
print(err)
|
||||
|
||||
|
||||
def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[..., None]) -> 'AuditConf': # pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-branches
|
||||
aconf = AuditConf()
|
||||
|
||||
enable_colors = not any(i in args for i in ['--no-colors', '-n'])
|
||||
aconf.colors = enable_colors
|
||||
out.use_colors = enable_colors
|
||||
|
||||
try:
|
||||
sopts = 'h1246M:p:P:jbcnvl:t:T:Lm'
|
||||
lopts = ['help', 'ssh1', 'ssh2', 'ipv4', 'ipv6', 'make-policy=', 'port=', 'policy=', 'json', 'batch', 'client-audit', 'no-colors', 'verbose', 'level=', 'timeout=', 'targets=', 'list-policies', 'lookup=', 'threads=', 'manual']
|
||||
sopts = 'h1246M:p:P:jbcnvl:t:T: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=']
|
||||
opts, args = getopt.gnu_getopt(args, sopts, lopts)
|
||||
except getopt.GetoptError as err:
|
||||
usage_cb(str(err))
|
||||
usage_cb(out, str(err))
|
||||
aconf.ssh1, aconf.ssh2 = False, False
|
||||
host: str = ''
|
||||
oport: Optional[str] = None
|
||||
port: int = 0
|
||||
for o, a in opts:
|
||||
if o in ('-h', '--help'):
|
||||
usage_cb()
|
||||
usage_cb(out)
|
||||
elif o in ('-1', '--ssh1'):
|
||||
aconf.ssh1 = True
|
||||
elif o in ('-2', '--ssh2'):
|
||||
@ -602,17 +742,17 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
|
||||
aconf.verbose = True
|
||||
elif o in ('-c', '--client-audit'):
|
||||
aconf.client_audit = True
|
||||
elif o in ('-n', '--no-colors'):
|
||||
aconf.colors = False
|
||||
out.use_colors = False
|
||||
elif o in ('-j', '--json'):
|
||||
aconf.json = True
|
||||
if aconf.json: # If specified twice, enable indent printing.
|
||||
aconf.json_print_indent = True
|
||||
else:
|
||||
aconf.json = True
|
||||
elif o in ('-v', '--verbose'):
|
||||
aconf.verbose = True
|
||||
out.verbose = True
|
||||
elif o in ('-l', '--level'):
|
||||
if a not in ('info', 'warn', 'fail'):
|
||||
usage_cb('level {} is not valid'.format(a))
|
||||
usage_cb(out, 'level {} is not valid'.format(a))
|
||||
aconf.level = a
|
||||
elif o in ('-t', '--timeout'):
|
||||
aconf.timeout = float(a)
|
||||
@ -624,17 +764,50 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
|
||||
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).
|
||||
# if no_idna_workaround:
|
||||
# print("\nWARNING: the idna module was not found on this system, thus only single-threaded scanning will be done (this is a workaround for this Windows-specific crash: https://github.com/python/cpython/issues/73474). Multi-threaded scanning can be enabled by installing the idna module (pip install idna).\n")
|
||||
# aconf.threads = 1
|
||||
elif o == '--threads':
|
||||
aconf.threads = int(a)
|
||||
# if no_idna_workaround:
|
||||
# aconf.threads = 1
|
||||
elif o in ('-L', '--list-policies'):
|
||||
aconf.list_policies = True
|
||||
elif o == '--lookup':
|
||||
aconf.lookup = a
|
||||
elif o in ('-m', '--manual'):
|
||||
aconf.manual = True
|
||||
elif o in ('-d', '--debug'):
|
||||
aconf.debug = True
|
||||
out.debug = True
|
||||
elif o in ('-g', '--gex-test'):
|
||||
permitted_syntax = get_permitted_syntax_for_gex_test()
|
||||
|
||||
if not any(re.search(regex_str, a) for regex_str in permitted_syntax.values()):
|
||||
usage_cb(out, '{} {} is not valid'.format(o, a))
|
||||
|
||||
if re.search(permitted_syntax['RANGE'], a):
|
||||
extracted_digits = re.findall(r'\d+', a)
|
||||
bits_left_bound = int(extracted_digits[0])
|
||||
bits_right_bound = int(extracted_digits[1])
|
||||
|
||||
bits_step = 1
|
||||
if (len(extracted_digits)) == 3:
|
||||
bits_step = int(extracted_digits[2])
|
||||
|
||||
if bits_step <= 0:
|
||||
usage_cb(out, '{} {} is not valid'.format(o, bits_step))
|
||||
|
||||
if all(x < 0 for x in (bits_left_bound, bits_right_bound)):
|
||||
usage_cb(out, '{} {} {} is not valid'.format(o, bits_left_bound, bits_right_bound))
|
||||
|
||||
aconf.gex_test = a
|
||||
|
||||
|
||||
if len(args) == 0 and aconf.client_audit is False and aconf.target_file is None and aconf.list_policies is False and aconf.lookup == '' and aconf.manual is False:
|
||||
usage_cb()
|
||||
usage_cb(out)
|
||||
|
||||
if aconf.manual:
|
||||
return aconf
|
||||
@ -652,7 +825,7 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
|
||||
else:
|
||||
host, port = Utils.parse_host_and_port(args[0])
|
||||
if not host and aconf.target_file is None:
|
||||
usage_cb('host is empty')
|
||||
usage_cb(out, 'host is empty')
|
||||
|
||||
if port == 0 and oport is None:
|
||||
if aconf.client_audit: # The default port to listen on during a client audit is 2222.
|
||||
@ -663,7 +836,7 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
|
||||
if oport is not None:
|
||||
port = Utils.parse_int(oport)
|
||||
if port <= 0 or port > 65535:
|
||||
usage_cb('port {} is not valid'.format(oport))
|
||||
usage_cb(out, 'port {} is not valid'.format(oport))
|
||||
|
||||
aconf.host = host
|
||||
aconf.port = port
|
||||
@ -672,8 +845,16 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
|
||||
|
||||
# If a file containing a list of targets was given, read it.
|
||||
if aconf.target_file is not None:
|
||||
with open(aconf.target_file, 'r') as f:
|
||||
aconf.target_list = f.readlines()
|
||||
try:
|
||||
with open(aconf.target_file, 'r', encoding='utf-8') as f:
|
||||
aconf.target_list = f.readlines()
|
||||
except PermissionError as e:
|
||||
# If installed as a Snap package, print a more useful message with potential work-arounds.
|
||||
if SNAP_PACKAGE:
|
||||
print(SNAP_PERMISSIONS_ERROR)
|
||||
else:
|
||||
print("Error: insufficient permissions: %s" % str(e))
|
||||
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||
|
||||
# Strip out whitespace from each line in target file, and skip empty lines.
|
||||
aconf.target_list = [target.strip() for target in aconf.target_list if target not in ("", "\n")]
|
||||
@ -682,10 +863,10 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
|
||||
if (aconf.policy_file is not None) and (aconf.make_policy is False):
|
||||
|
||||
# First, see if this is a built-in policy name. If not, assume a file path was provided, and try to load it from disk.
|
||||
aconf.policy = Policy.load_builtin_policy(aconf.policy_file)
|
||||
aconf.policy = Policy.load_builtin_policy(aconf.policy_file, json_output=aconf.json)
|
||||
if aconf.policy is None:
|
||||
try:
|
||||
aconf.policy = Policy(policy_file=aconf.policy_file)
|
||||
aconf.policy = Policy(policy_file=aconf.policy_file, json_output=aconf.json)
|
||||
except Exception as e:
|
||||
out.fail("Error while loading policy file: %s: %s" % (str(e), traceback.format_exc()))
|
||||
out.write()
|
||||
@ -706,7 +887,7 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
|
||||
return aconf
|
||||
|
||||
|
||||
def build_struct(target_host: str, banner: Optional['Banner'], kex: Optional['SSH2_Kex'] = None, pkm: Optional['SSH1_PublicKeyMessage'] = None, client_host: Optional[str] = None) -> Any:
|
||||
def build_struct(target_host: str, banner: Optional['Banner'], cves: List[Dict[str, Union[str, float]]], kex: Optional['SSH2_Kex'] = None, pkm: Optional['SSH1_PublicKeyMessage'] = None, client_host: Optional[str] = None, software: Optional[Software] = None, algorithms: Optional[Algorithms] = None, algorithm_recommendation_suppress_list: Optional[List[str]] = None) -> Any: # pylint: disable=too-many-arguments
|
||||
|
||||
banner_str = ''
|
||||
banner_protocol = None
|
||||
@ -737,28 +918,37 @@ def build_struct(target_host: str, banner: Optional['Banner'], kex: Optional['SS
|
||||
res['compression'] = kex.server.compression
|
||||
|
||||
res['kex'] = []
|
||||
alg_sizes = kex.dh_modulus_sizes()
|
||||
dh_alg_sizes = kex.dh_modulus_sizes()
|
||||
for algorithm in kex.kex_algorithms:
|
||||
entry: Any = {
|
||||
'algorithm': algorithm,
|
||||
}
|
||||
if algorithm in alg_sizes:
|
||||
hostkey_size, ca_size = alg_sizes[algorithm]
|
||||
if algorithm in dh_alg_sizes:
|
||||
hostkey_size = dh_alg_sizes[algorithm]
|
||||
entry['keysize'] = hostkey_size
|
||||
if ca_size > 0:
|
||||
entry['casize'] = ca_size
|
||||
res['kex'].append(entry)
|
||||
|
||||
res['key'] = []
|
||||
alg_sizes = kex.rsa_key_sizes()
|
||||
host_keys = kex.host_keys()
|
||||
for algorithm in kex.key_algorithms:
|
||||
entry = {
|
||||
'algorithm': algorithm,
|
||||
}
|
||||
if algorithm in alg_sizes:
|
||||
hostkey_size, ca_size = alg_sizes[algorithm]
|
||||
entry['keysize'] = hostkey_size
|
||||
if algorithm in host_keys:
|
||||
hostkey_info = host_keys[algorithm]
|
||||
hostkey_size = cast(int, hostkey_info['hostkey_size'])
|
||||
|
||||
ca_type = ''
|
||||
ca_size = 0
|
||||
if 'ca_key_type' in hostkey_info:
|
||||
ca_type = cast(str, hostkey_info['ca_key_type'])
|
||||
if 'ca_key_size' in hostkey_info:
|
||||
ca_size = cast(int, hostkey_info['ca_key_size'])
|
||||
|
||||
if algorithm in HostKeyTest.RSA_FAMILY or algorithm.startswith('ssh-rsa-cert-v0'):
|
||||
entry['keysize'] = hostkey_size
|
||||
if ca_size > 0:
|
||||
entry['ca_algorithm'] = ca_type
|
||||
entry['casize'] = ca_size
|
||||
res['key'].append(entry)
|
||||
|
||||
@ -778,16 +968,23 @@ def build_struct(target_host: str, banner: Optional['Banner'], kex: Optional['SS
|
||||
if host_keys[host_key_type] is None:
|
||||
continue
|
||||
|
||||
fp = Fingerprint(host_keys[host_key_type])
|
||||
fp = Fingerprint(cast(bytes, host_keys[host_key_type]['raw_hostkey_bytes']))
|
||||
|
||||
# Skip over certificate host types (or we would return invalid fingerprints).
|
||||
if '-cert-' in host_key_type:
|
||||
continue
|
||||
entry = {
|
||||
'type': host_key_type,
|
||||
'fp': fp.sha256,
|
||||
}
|
||||
res['fingerprints'].append(entry)
|
||||
|
||||
# Add the SHA256 and MD5 fingerprints.
|
||||
res['fingerprints'].append({
|
||||
'hostkey': host_key_type,
|
||||
'hash_alg': 'SHA256',
|
||||
'hash': fp.sha256[7:]
|
||||
})
|
||||
res['fingerprints'].append({
|
||||
'hostkey': host_key_type,
|
||||
'hash_alg': 'MD5',
|
||||
'hash': fp.md5[4:]
|
||||
})
|
||||
else:
|
||||
pkm_supported_ciphers = None
|
||||
pkm_supported_authentications = None
|
||||
@ -805,6 +1002,12 @@ def build_struct(target_host: str, banner: Optional['Banner'], kex: Optional['SS
|
||||
'fp': pkm_fp,
|
||||
}]
|
||||
|
||||
# Add in the CVE information.
|
||||
res['cves'] = cves
|
||||
|
||||
# Add in the recommendations.
|
||||
res['recommendations'] = get_algorithm_recommendations(algorithms, algorithm_recommendation_suppress_list, software, for_server=True)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
@ -813,15 +1016,18 @@ def audit(out: OutputBuffer, aconf: AuditConf, sshv: Optional[int] = None, print
|
||||
program_retval = exitcodes.GOOD
|
||||
out.batch = aconf.batch
|
||||
out.verbose = aconf.verbose
|
||||
out.debug = aconf.debug
|
||||
out.level = aconf.level
|
||||
out.use_colors = aconf.colors
|
||||
s = SSH_Socket(aconf.host, aconf.port, aconf.ip_version_preference, aconf.timeout, aconf.timeout_set)
|
||||
s = SSH_Socket(out, aconf.host, aconf.port, aconf.ip_version_preference, aconf.timeout, aconf.timeout_set)
|
||||
|
||||
if aconf.client_audit:
|
||||
out.v("Listening for client connection on port %d..." % aconf.port, write_now=True)
|
||||
s.listen_and_accept()
|
||||
else:
|
||||
out.v("Connecting to %s:%d..." % ('[%s]' % aconf.host if Utils.is_ipv6_address(aconf.host) else aconf.host, aconf.port), write_now=True)
|
||||
out.v("Starting audit of %s:%d..." % ('[%s]' % aconf.host if Utils.is_ipv6_address(aconf.host) else aconf.host, aconf.port), write_now=True)
|
||||
err = s.connect()
|
||||
|
||||
if err is not None:
|
||||
out.fail(err)
|
||||
|
||||
@ -850,10 +1056,10 @@ def audit(out: OutputBuffer, aconf: AuditConf, sshv: Optional[int] = None, print
|
||||
if len(payload) > 0:
|
||||
payload_txt = payload.decode('utf-8')
|
||||
else:
|
||||
payload_txt = u'empty'
|
||||
payload_txt = 'empty'
|
||||
except UnicodeDecodeError:
|
||||
payload_txt = u'"{}"'.format(repr(payload).lstrip('b')[1:-1])
|
||||
if payload_txt == u'Protocol major versions differ.':
|
||||
payload_txt = '"{}"'.format(repr(payload).lstrip('b')[1:-1])
|
||||
if payload_txt == 'Protocol major versions differ.':
|
||||
if sshv == 2 and aconf.ssh1:
|
||||
ret = audit(out, aconf, 1)
|
||||
out.write()
|
||||
@ -876,10 +1082,18 @@ def audit(out: OutputBuffer, aconf: AuditConf, sshv: Optional[int] = None, print
|
||||
if sshv == 1:
|
||||
program_retval = output(out, aconf, banner, header, pkm=SSH1_PublicKeyMessage.parse(payload))
|
||||
elif sshv == 2:
|
||||
kex = SSH2_Kex.parse(payload)
|
||||
try:
|
||||
kex = SSH2_Kex.parse(out, payload)
|
||||
except Exception:
|
||||
out.fail("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc()))
|
||||
return exitcodes.CONNECTION_ERROR
|
||||
|
||||
if aconf.client_audit is False:
|
||||
HostKeyTest.run(s, kex)
|
||||
GEXTest.run(s, kex)
|
||||
HostKeyTest.run(out, s, kex)
|
||||
if aconf.gex_test != '':
|
||||
return run_gex_granular_modulus_size_test(out, s, kex, aconf)
|
||||
else:
|
||||
GEXTest.run(out, s, kex)
|
||||
|
||||
# This is a standard audit scan.
|
||||
if (aconf.policy is None) and (aconf.make_policy is False):
|
||||
@ -948,8 +1162,8 @@ def algorithm_lookup(out: OutputBuffer, alg_names: str) -> int:
|
||||
similar_algorithms = [
|
||||
alg_unknown + " --> (" + alg_type + ") " + alg_name
|
||||
for alg_unknown in algorithms_not_found
|
||||
for alg_type in adb
|
||||
for alg_name in adb[alg_type]
|
||||
for alg_type, alg_names in adb.items()
|
||||
for alg_name in alg_names
|
||||
# Perform a case-insensitive comparison using 'casefold'
|
||||
# and match substrings using the 'in' operator.
|
||||
if alg_unknown.casefold() in alg_name.casefold()
|
||||
@ -1018,6 +1232,79 @@ def windows_manual(out: OutputBuffer) -> int:
|
||||
return retval
|
||||
|
||||
|
||||
def get_permitted_syntax_for_gex_test() -> Dict[str, str]:
|
||||
syntax = {
|
||||
'RANGE': r'^\d+-\d+(:\d+)?$',
|
||||
'LIST_WITHOUT_MIN_PREF_MAX': r'^\d+(,\d+)*$',
|
||||
'LIST_WITH_MIN_PREF_MAX': r'^\d+:\d+:\d+(,\d+:\d+:\d+)*$'
|
||||
}
|
||||
return syntax
|
||||
|
||||
|
||||
def run_gex_granular_modulus_size_test(out: OutputBuffer, s: 'SSH_Socket', kex: 'SSH2_Kex', aconf: AuditConf) -> int:
|
||||
'''Extracts the user specified modulus sizes and submits them for testing against the target server. Returns an exitcodes.* flag.'''
|
||||
|
||||
permitted_syntax = get_permitted_syntax_for_gex_test()
|
||||
|
||||
mod_dict: Dict[str, List[int]] = {}
|
||||
|
||||
# Range syntax.
|
||||
if re.search(permitted_syntax['RANGE'], aconf.gex_test):
|
||||
extracted_digits = re.findall(r'\d+', aconf.gex_test)
|
||||
bits_left_bound = int(extracted_digits[0])
|
||||
bits_right_bound = int(extracted_digits[1])
|
||||
|
||||
bits_step = 1
|
||||
if (len(extracted_digits)) == 3:
|
||||
bits_step = int(extracted_digits[2])
|
||||
|
||||
# If the left value is greater than the right value, then the sequence
|
||||
# operates from right to left.
|
||||
if bits_left_bound <= bits_right_bound:
|
||||
bits_in_range_to_test = range(bits_left_bound, bits_right_bound + 1, bits_step)
|
||||
else:
|
||||
bits_in_range_to_test = range(bits_left_bound, bits_right_bound - 1, -abs(bits_step))
|
||||
|
||||
out.v("A separate test will be performed against each of the following modulus sizes: " + ", ".join([str(x) for x in bits_in_range_to_test]) + ".", write_now=True)
|
||||
|
||||
for i_bits in bits_in_range_to_test:
|
||||
program_retval = GEXTest.granular_modulus_size_test(out, s, kex, i_bits, i_bits, i_bits, mod_dict)
|
||||
if program_retval != exitcodes.GOOD:
|
||||
return program_retval
|
||||
|
||||
# Two variations of list syntax.
|
||||
if re.search(permitted_syntax['LIST_WITHOUT_MIN_PREF_MAX'], aconf.gex_test):
|
||||
bits_in_list_to_test = aconf.gex_test.split(',')
|
||||
out.v("A separate test will be performed against each of the following modulus sizes: " + ", ".join([str(x) for x in bits_in_list_to_test]) + ".", write_now=True)
|
||||
for s_bits in bits_in_list_to_test:
|
||||
program_retval = GEXTest.granular_modulus_size_test(out, s, kex, int(s_bits), int(s_bits), int(s_bits), mod_dict)
|
||||
if program_retval != exitcodes.GOOD:
|
||||
return program_retval
|
||||
|
||||
if re.search(permitted_syntax['LIST_WITH_MIN_PREF_MAX'], aconf.gex_test):
|
||||
sets_of_min_pref_max = aconf.gex_test.split(',')
|
||||
out.v("A separate test will be performed against each of the following sets of 'min:pref:max' modulus sizes: " + ', '.join(sets_of_min_pref_max), write_now=True)
|
||||
for set_of_min_pref_max in sets_of_min_pref_max:
|
||||
bits_in_list_to_test = set_of_min_pref_max.split(':')
|
||||
program_retval = GEXTest.granular_modulus_size_test(out, s, kex, int(bits_in_list_to_test[0]), int(bits_in_list_to_test[1]), int(bits_in_list_to_test[2]), mod_dict)
|
||||
if program_retval != exitcodes.GOOD:
|
||||
return program_retval
|
||||
|
||||
if mod_dict:
|
||||
if aconf.json:
|
||||
json_struct = {'dh-gex-modulus-size': mod_dict}
|
||||
out.info(json.dumps(json_struct, indent=4 if aconf.json_print_indent else None, sort_keys=True))
|
||||
else:
|
||||
out.head('# diffie-hellman group exchange modulus size')
|
||||
max_key_len = len(max(mod_dict, key=len))
|
||||
|
||||
for key, value in mod_dict.items():
|
||||
padding = (max_key_len - len(key)) + 1
|
||||
out.info(key + " " * padding + '--> ' + ', '.join([str(i) for i in value]))
|
||||
|
||||
return program_retval
|
||||
|
||||
|
||||
def main() -> int:
|
||||
out = OutputBuffer()
|
||||
aconf = process_commandline(out, sys.argv[1:], usage)
|
||||
@ -1059,7 +1346,7 @@ def main() -> int:
|
||||
host, port = Utils.parse_host_and_port(target, default_port=22)
|
||||
target_servers.append((host, port))
|
||||
|
||||
# A ranked list of return codes. Those with higher indices will take precendence over lower ones. For example, if three servers are scanned, yielding WARNING, GOOD, and UNKNOWN_ERROR, the overall result will be UNKNOWN_ERROR, since its index is the highest. Errors have highest priority, followed by failures, then warnings.
|
||||
# A ranked list of return codes. Those with higher indices will take precedence over lower ones. For example, if three servers are scanned, yielding WARNING, GOOD, and UNKNOWN_ERROR, the overall result will be UNKNOWN_ERROR, since its index is the highest. Errors have highest priority, followed by failures, then warnings.
|
||||
ranked_return_codes = [exitcodes.GOOD, exitcodes.WARNING, exitcodes.FAILURE, exitcodes.CONNECTION_ERROR, exitcodes.UNKNOWN_ERROR]
|
||||
|
||||
# Queue all worker threads.
|
||||
|
@ -52,8 +52,9 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
||||
|
||||
SM_BANNER_SENT = 1
|
||||
|
||||
def __init__(self, host: Optional[str], port: int, ip_version_preference: List[int] = [], timeout: Union[int, float] = 5, timeout_set: bool = False) -> None: # pylint: disable=dangerous-default-value
|
||||
def __init__(self, outputbuffer: 'OutputBuffer', host: Optional[str], port: int, ip_version_preference: List[int] = [], timeout: Union[int, float] = 5, timeout_set: bool = False) -> None: # pylint: disable=dangerous-default-value
|
||||
super(SSH_Socket, self).__init__()
|
||||
self.__outputbuffer = outputbuffer
|
||||
self.__sock: Optional[socket.socket] = None
|
||||
self.__sock_map: Dict[int, socket.socket] = {}
|
||||
self.__block_size = 8
|
||||
@ -85,12 +86,12 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
||||
|
||||
# If the user has a preference for using IPv4 over IPv6 (or vice-versa), then sort the list returned by getaddrinfo() so that the preferred address type comes first.
|
||||
if len(self.__ip_version_preference) == 2:
|
||||
r = sorted(r, key=lambda x: x[0], reverse=(self.__ip_version_preference[0] == 6))
|
||||
r = sorted(r, key=lambda x: x[0], reverse=(self.__ip_version_preference[0] == 6)) # pylint: disable=superfluous-parens
|
||||
for af, socktype, _proto, _canonname, addr in r:
|
||||
if socktype == socket.SOCK_STREAM:
|
||||
yield af, addr
|
||||
except socket.error as e:
|
||||
OutputBuffer().fail('[exception] {}'.format(e)).write()
|
||||
self.__outputbuffer.fail('[exception] {}'.format(e)).write()
|
||||
sys.exit(exitcodes.CONNECTION_ERROR)
|
||||
|
||||
# Listens on a server socket and accepts one connection (used for
|
||||
@ -156,6 +157,7 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
||||
try:
|
||||
s = socket.socket(af, socket.SOCK_STREAM)
|
||||
s.settimeout(self.__timeout)
|
||||
self.__outputbuffer.d(("Connecting to %s:%d..." % ('[%s]' % addr[0] if Utils.is_ipv6_address(addr[0]) else addr[0], addr[1])), write_now=True)
|
||||
s.connect(addr)
|
||||
self.__sock = s
|
||||
return None
|
||||
@ -170,6 +172,8 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
||||
return '[exception] {}'.format(errm)
|
||||
|
||||
def get_banner(self, sshv: int = 2) -> Tuple[Optional['Banner'], List[str], Optional[str]]:
|
||||
self.__outputbuffer.d('Getting banner...', write_now=True)
|
||||
|
||||
if self.__sock is None:
|
||||
return self.__banner, self.__header, 'not connected'
|
||||
if self.__banner is not None:
|
||||
@ -229,8 +233,10 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
||||
def send_kexinit(self, key_exchanges: List[str] = ['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'], hostkeys: List[str] = ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ssh-ed25519'], ciphers: List[str] = ['chacha20-poly1305@openssh.com', 'aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-gcm@openssh.com', 'aes256-gcm@openssh.com'], macs: List[str] = ['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'], compressions: List[str] = ['none', 'zlib@openssh.com'], languages: List[str] = ['']) -> None: # pylint: disable=dangerous-default-value
|
||||
'''Sends the list of supported host keys, key exchanges, ciphers, and MACs. Emulates OpenSSH v8.2.'''
|
||||
|
||||
self.__outputbuffer.d('KEX initialisation...', write_now=True)
|
||||
|
||||
kexparty = SSH2_KexParty(ciphers, macs, compressions, languages)
|
||||
kex = SSH2_Kex(os.urandom(16), key_exchanges, hostkeys, kexparty, kexparty, False, 0)
|
||||
kex = SSH2_Kex(self.__outputbuffer, os.urandom(16), key_exchanges, hostkeys, kexparty, kexparty, False, 0)
|
||||
|
||||
self.write_byte(Protocol.MSG_KEXINIT)
|
||||
kex.write(self)
|
||||
@ -268,7 +274,7 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
||||
payload_length = packet_length - padding_length - 1
|
||||
check_size = 4 + 1 + payload_length + padding_length
|
||||
if check_size % self.__block_size != 0:
|
||||
OutputBuffer().fail('[exception] invalid ssh packet (block size)').write()
|
||||
self.__outputbuffer.fail('[exception] invalid ssh packet (block size)').write()
|
||||
sys.exit(exitcodes.CONNECTION_ERROR)
|
||||
self.ensure_read(payload_length)
|
||||
if sshv == 1:
|
||||
@ -283,7 +289,7 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
||||
if sshv == 1:
|
||||
rcrc = SSH1.crc32(padding + payload)
|
||||
if crc != rcrc:
|
||||
OutputBuffer().fail('[exception] packet checksum CRC32 mismatch.').write()
|
||||
self.__outputbuffer.fail('[exception] packet checksum CRC32 mismatch.').write()
|
||||
sys.exit(exitcodes.CONNECTION_ERROR)
|
||||
else:
|
||||
self.ensure_read(padding_length)
|
||||
@ -319,7 +325,7 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
||||
self.__header = []
|
||||
self.__banner = None
|
||||
|
||||
def _close_socket(self, s: Optional[socket.socket]) -> None: # pylint: disable=no-self-use
|
||||
def _close_socket(self, s: Optional[socket.socket]) -> None:
|
||||
try:
|
||||
if s is not None:
|
||||
s.shutdown(socket.SHUT_RDWR)
|
||||
@ -332,6 +338,6 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
||||
|
||||
def __cleanup(self) -> None:
|
||||
self._close_socket(self.__sock)
|
||||
for fd in self.__sock_map:
|
||||
self._close_socket(self.__sock_map[fd])
|
||||
for sock in self.__sock_map.values():
|
||||
self._close_socket(sock)
|
||||
self.__sock = None
|
||||
|
@ -35,6 +35,7 @@ class VersionVulnerabilityDB: # pylint: disable=too-few-public-methods
|
||||
# then affected = 1 + 4 = 5.
|
||||
CVE: Dict[str, List[List[Any]]] = {
|
||||
'Dropbear SSH': [
|
||||
['0.0', '2020.81', 2, 'CVE-2021-36369', 7.5, 'trivial authentication attack to bypass FIDO tokens and SSH-ASKPASS'],
|
||||
['0.0', '2018.76', 1, 'CVE-2018-15599', 5.0, 'remote users may enumerate users on the system'],
|
||||
['0.0', '2017.74', 5, 'CVE-2017-9079', 4.7, 'local users can read certain files as root'],
|
||||
['0.0', '2017.74', 5, 'CVE-2017-9078', 9.3, 'local users may elevate privileges to root under certain conditions'],
|
||||
@ -66,7 +67,21 @@ class VersionVulnerabilityDB: # pylint: disable=too-few-public-methods
|
||||
['0.4.7', '0.5.2', 1, 'CVE-2012-4560', 7.5, 'cause DoS or execute arbitrary code (buffer overflow)'],
|
||||
['0.4.7', '0.5.2', 1, 'CVE-2012-4559', 6.8, 'cause DoS or execute arbitrary code (double free)']],
|
||||
'OpenSSH': [
|
||||
['1.0', '7.7', 1, 'CVE-2018-15473', 5.3, 'enumerate usernames due to timing discrepencies'],
|
||||
['6.2', '8.7', 5, 'CVE-2021-41617', 7.0, 'privilege escalation via supplemental groups'],
|
||||
['1.0', '8.8', 2, 'CVE-2021-36368', 3.7, 'trivial authentication attack to bypass FIDO tokens and SSH-ASKPASS'],
|
||||
['8.2', '8.4', 2, 'CVE-2021-28041', 7.1, 'double free via ssh-agent'],
|
||||
['1.0', '8.3', 5, 'CVE-2020-15778', 7.8, 'command injection via anomalous argument transfers'],
|
||||
['5.7', '8.3', 2, 'CVE-2020-14145', 5.9, 'information leak via algorithm negotiation'],
|
||||
['8.2', '8.2', 2, 'CVE-2020-12062', 7.5, 'arbitrary files overwrite via scp'],
|
||||
['7.7', '8.0', 7, 'CVE-2019-16905', 7.8, 'memory corruption and local code execution via pre-authentication integer overflow'],
|
||||
['1.0', '7.9', 2, 'CVE-2019-6111', 5.9, 'arbitrary files overwrite via scp'],
|
||||
['1.0', '7.9', 2, 'CVE-2019-6110', 6.8, 'output manipulation'],
|
||||
['1.0', '7.9', 2, 'CVE-2019-6109', 6.8, 'output manipulation'],
|
||||
['1.0', '7.9', 2, 'CVE-2018-20685', 5.3, 'directory permissions modification via scp'],
|
||||
['5.9', '7.8', 1, 'CVE-2018-15919', 5.3, 'username enumeration via GS2'],
|
||||
['1.0', '7.7', 1, 'CVE-2018-15473', 5.3, 'enumerate usernames due to timing discrepancies'],
|
||||
['1.2', '6.292', 1, 'CVE-2017-15906', 5.3, 'readonly bypass via sftp'],
|
||||
['1.0', '8.7', 1, 'CVE-2016-20012', 5.3, 'enumerate usernames via challenge response'],
|
||||
['7.2', '7.2p2', 1, 'CVE-2016-6515', 7.8, 'cause DoS via long password string (crypt CPU consumption)'],
|
||||
['1.2.2', '7.2', 1, 'CVE-2016-3115', 5.5, 'bypass command restrictions via crafted X11 forwarding data'],
|
||||
['5.4', '7.1', 1, 'CVE-2016-1907', 5.0, 'cause DoS via crafted network traffic (out of bounds read)'],
|
||||
@ -125,6 +140,10 @@ class VersionVulnerabilityDB: # pylint: disable=too-few-public-methods
|
||||
['1.2.3', '2.1.1', 1, 'CVE-2001-0361', 4.0, 'recover plaintext from ciphertext'],
|
||||
['1.2', '2.1', 1, 'CVE-2000-0525', 10.0, 'execute arbitrary code (improper privileges)']],
|
||||
'PuTTY': [
|
||||
# info for CVE-2021-36367 - only PuTTY up to 0.71 is affected - see https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/reject-trivial-auth.html
|
||||
['0.0', '0.71', 2, 'CVE-2021-36367', 8.1, 'trivial authentication attack to bypass FIDO tokens and SSH-ASKPASS'],
|
||||
['0.0', '0.74', 2, 'CVE-2021-33500', 5.0, 'denial of service of the complete windows desktop'],
|
||||
['0.68', '0.73', 2, 'CVE-2020-14002', 4.3, 'Observable Discrepancy which allows man-in-the-middle attackers to target initial connection attempts'],
|
||||
['0.54', '0.73', 2, 'CVE-2020-XXXX', 5.0, 'out of bounds memory read'],
|
||||
['0.0', '0.72', 2, 'CVE-2019-17069', 5.0, 'potential DOS by remote SSHv1 server'],
|
||||
['0.71', '0.72', 2, 'CVE-2019-17068', 5.0, 'xterm bracketed paste mode command injection'],
|
||||
|
@ -54,7 +54,7 @@ class WriteBuf:
|
||||
return self.write(v)
|
||||
|
||||
def write_list(self, v: List[str]) -> 'WriteBuf':
|
||||
return self.write_string(u','.join(v))
|
||||
return self.write_string(','.join(v))
|
||||
|
||||
@classmethod
|
||||
def _bitlength(cls, n: int) -> int:
|
||||
|
65
ssh-audit.1
65
ssh-audit.1
@ -1,4 +1,4 @@
|
||||
.TH SSH-AUDIT 1 "February 7, 2021"
|
||||
.TH SSH-AUDIT 1 "March 13, 2022"
|
||||
.SH NAME
|
||||
\fBssh-audit\fP \- SSH server & client configuration auditor
|
||||
.SH SYNOPSIS
|
||||
@ -6,7 +6,7 @@
|
||||
.RI [ options ] " <target_host>"
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\fBssh-audit\fP analyzes the configuration of SSH servers & clients, then warns the user of weak, obsolete, and/or un-tested cryptographic primitives. It is very useful for hardening SSH tunnels, which by default tend to be optimized for compatibility, not security.
|
||||
\fBssh-audit\fP analyzes the configuration of SSH servers & clients, then warns the user of weak, obsolete, and/or untested cryptographic primitives. It is very useful for hardening SSH tunnels, which by default tend to be optimized for compatibility, not security.
|
||||
.PP
|
||||
See <https://www.ssh\-audit.com/> for official hardening guides for common platforms.
|
||||
|
||||
@ -46,10 +46,45 @@ Enables grepable output.
|
||||
.br
|
||||
Starts a server on port 2222 to audit client software configuration. Use -p/--port=<port> to change port and -t/--timeout=<secs> to change listen timeout.
|
||||
|
||||
.TP
|
||||
.B -d, \-\-debug
|
||||
.br
|
||||
Enable debug output.
|
||||
|
||||
.TP
|
||||
.B -g, \-\-gex-test=<x[,y,...] | min1:pref1:max1[,min2:pref2:max2,...] | x-y[:step]>
|
||||
.br
|
||||
Runs a Diffie-Hellman Group Exchange modulus size test against a server.
|
||||
|
||||
Diffie-Hellman requires the client and server to agree on a generator value and a modulus value. In the "Group Exchange" implementation of Diffie-Hellman, the client specifies the size of the modulus in bits by providing the server with minimum, preferred and maximum values. The server then finds a group that best matches the client's request, returning the corresponding generator and modulus. For a full explanation of this process see RFC 4419 and its successors.
|
||||
|
||||
This test acts as a client by providing an SSH server with the size of a modulus and then obtains the size of the modulus returned by the server.
|
||||
|
||||
Three types of syntax are supported:
|
||||
|
||||
1. <x[,y,...]>
|
||||
|
||||
A comma delimited list of modulus sizes.
|
||||
A test is performed against each value in the list where it acts as the minimum, preferred and maximum modulus size.
|
||||
|
||||
2. <min:pref:max[,min:pref:max,...]>
|
||||
|
||||
A set of three colon delimited values denoting minimum, preferred and maximum modulus size.
|
||||
A test is performed against each set.
|
||||
Multiple sets can specified as a comma separated list.
|
||||
|
||||
3. <x-y[:step]>
|
||||
|
||||
A range of modulus sizes with an optional step value. Step defaults to 1 if omitted.
|
||||
If the left value is greater than the right value, then the sequence operates from right to left.
|
||||
A test is performed against each value in the range where it acts as the minimum, preferred and maximum modulus size.
|
||||
|
||||
Duplicates are excluded from the return value.
|
||||
|
||||
.TP
|
||||
.B -j, \-\-json
|
||||
.br
|
||||
Output results in JSON format.
|
||||
Output results in JSON format. Specify twice (-jj) to enable indent printing (useful for debugging).
|
||||
|
||||
.TP
|
||||
.B -l, \-\-level=<info|warn|fail>
|
||||
@ -214,6 +249,30 @@ ssh-audit -M new_policy.txt targetserver
|
||||
.fi
|
||||
.RE
|
||||
|
||||
.LP
|
||||
To run a Diffie-Hellman Group Exchange modulus size test using the values 2000 bits, 3000 bits, 4000 bits and 5000 bits:
|
||||
.RS
|
||||
.nf
|
||||
ssh-audit targetserver --gex-test=2000,3000,4000,5000
|
||||
.fi
|
||||
.RE
|
||||
|
||||
.LP
|
||||
To run a Diffie-Hellman Group Exchange modulus size test where 2048 bits is the minimum, 3072 bits is the preferred and 5000 bits is the maximum:
|
||||
.RS
|
||||
.nf
|
||||
ssh-audit targetserver --gex-test=2048:3072:5000
|
||||
.fi
|
||||
.RE
|
||||
|
||||
.LP
|
||||
To run a Diffie-Hellman Group Exchange modulus size test from 0 bits to 5120 bits in increments of 1024 bits:
|
||||
.RS
|
||||
.nf
|
||||
ssh-audit targetserver --gex-test=0-5120:1024
|
||||
.fi
|
||||
.RE
|
||||
|
||||
.SH RETURN VALUES
|
||||
When a successful connection is made and all algorithms are rated as "good", \fBssh-audit\fP returns 0. Other possible return values are:
|
||||
|
||||
|
@ -1 +1,184 @@
|
||||
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-dropbear_2019.78", "software": "dropbear_2019.78"}, "compression": ["zlib@openssh.com", "none"], "enc": ["aes128-ctr", "aes256-ctr", "aes128-cbc", "aes256-cbc", "3des-ctr", "3des-cbc"], "fingerprints": [{"fp": "SHA256:CDfAU12pjQS7/91kg7gYacza0U/6PDbE04Ic3IpYxkM", "type": "ssh-rsa"}], "kex": [{"algorithm": "curve25519-sha256"}, {"algorithm": "curve25519-sha256@libssh.org"}, {"algorithm": "ecdh-sha2-nistp521"}, {"algorithm": "ecdh-sha2-nistp384"}, {"algorithm": "ecdh-sha2-nistp256"}, {"algorithm": "diffie-hellman-group14-sha256"}, {"algorithm": "diffie-hellman-group14-sha1"}, {"algorithm": "kexguess2@matt.ucc.asn.au"}], "key": [{"algorithm": "ecdsa-sha2-nistp256"}, {"algorithm": "ssh-rsa", "keysize": 1024}, {"algorithm": "ssh-dss"}], "mac": ["hmac-sha1-96", "hmac-sha1", "hmac-sha2-256"], "target": "localhost"}
|
||||
{
|
||||
"banner": {
|
||||
"comments": null,
|
||||
"protocol": [
|
||||
2,
|
||||
0
|
||||
],
|
||||
"raw": "SSH-2.0-dropbear_2019.78",
|
||||
"software": "dropbear_2019.78"
|
||||
},
|
||||
"compression": [
|
||||
"zlib@openssh.com",
|
||||
"none"
|
||||
],
|
||||
"cves": [],
|
||||
"enc": [
|
||||
"aes128-ctr",
|
||||
"aes256-ctr",
|
||||
"aes128-cbc",
|
||||
"aes256-cbc",
|
||||
"3des-ctr",
|
||||
"3des-cbc"
|
||||
],
|
||||
"fingerprints": [
|
||||
{
|
||||
"hash": "CDfAU12pjQS7/91kg7gYacza0U/6PDbE04Ic3IpYxkM",
|
||||
"hash_alg": "SHA256",
|
||||
"hostkey": "ssh-rsa"
|
||||
},
|
||||
{
|
||||
"hash": "63:7f:54:f7:0a:28:7f:75:0b:f4:07:0b:fc:66:51:a2",
|
||||
"hash_alg": "MD5",
|
||||
"hostkey": "ssh-rsa"
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"algorithm": "curve25519-sha256"
|
||||
},
|
||||
{
|
||||
"algorithm": "curve25519-sha256@libssh.org"
|
||||
},
|
||||
{
|
||||
"algorithm": "ecdh-sha2-nistp521"
|
||||
},
|
||||
{
|
||||
"algorithm": "ecdh-sha2-nistp384"
|
||||
},
|
||||
{
|
||||
"algorithm": "ecdh-sha2-nistp256"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group14-sha256"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group14-sha1"
|
||||
},
|
||||
{
|
||||
"algorithm": "kexguess2@matt.ucc.asn.au"
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"algorithm": "ecdsa-sha2-nistp256"
|
||||
},
|
||||
{
|
||||
"algorithm": "ssh-rsa",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "ssh-dss"
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
"hmac-sha1-96",
|
||||
"hmac-sha1",
|
||||
"hmac-sha2-256"
|
||||
],
|
||||
"recommendations": {
|
||||
"critical": {
|
||||
"del": {
|
||||
"enc": [
|
||||
{
|
||||
"name": "3des-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "3des-ctr",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group14-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ecdh-sha2-nistp256",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ecdh-sha2-nistp384",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ecdh-sha2-nistp521",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"name": "ecdsa-sha2-nistp256",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ssh-dss",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ssh-rsa",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "hmac-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha1-96",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"informational": {
|
||||
"add": {
|
||||
"enc": [
|
||||
{
|
||||
"name": "twofish128-ctr",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "twofish256-ctr",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group16-sha512",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"del": {
|
||||
"enc": [
|
||||
{
|
||||
"name": "aes128-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "aes256-cbc",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group14-sha256",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "hmac-sha2-256",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"target": "localhost:2222"
|
||||
}
|
||||
|
@ -6,57 +6,55 @@
|
||||
|
||||
[0;36m# key exchange algorithms[0m
|
||||
[0;32m(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76[0m
|
||||
[0;32m(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.5, Dropbear SSH 2013.62[0m
|
||||
[0;31m(kex) ecdh-sha2-nistp521 -- [fail] using weak elliptic curves[0m
|
||||
`- [info] default key exchange since OpenSSH 6.4
|
||||
[0;32m(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62[0m
|
||||
`- [info] default key exchange since OpenSSH 6.4
|
||||
[0;31m(kex) ecdh-sha2-nistp521 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||
[0;31m(kex) ecdh-sha2-nistp384 -- [fail] using weak elliptic curves[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
|
||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||
[0;31m(kex) ecdh-sha2-nistp256 -- [fail] using weak elliptic curves[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
|
||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||
[0;32m(kex) diffie-hellman-group14-sha256 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73[0m
|
||||
[0;33m(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing algorithm[0m
|
||||
[0;33m(kex) diffie-hellman-group14-sha256 -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||
`- [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;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||
`- [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;36m# host-key algorithms[0m
|
||||
[0;31m(key) ecdsa-sha2-nistp256 -- [fail] using weak elliptic curves[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;33m `- [warn] using weak random number generator could reveal the key[0m
|
||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||
[0;31m(key) ssh-rsa (1024-bit) -- [fail] using weak hashing algorithm[0m
|
||||
[0;31m(key) ssh-rsa (1024-bit) -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;31m `- [fail] using small 1024-bit modulus[0m
|
||||
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
|
||||
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2
|
||||
`- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
|
||||
[0;31m(key) ssh-dss -- [fail] using small 1024-bit modulus[0m
|
||||
[0;31m `- [fail] removed (in server) and disabled (in client) since OpenSSH 7.0, weak algorithm[0m
|
||||
[0;33m `- [warn] using weak random number generator could reveal the key[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
|
||||
|
||||
[0;36m# encryption algorithms (ciphers)[0m
|
||||
[0;32m(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
[0;32m(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
[0;31m(enc) aes128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes128-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
||||
[0;31m(enc) aes256-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes256-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47
|
||||
[0;31m(enc) 3des-ctr -- [fail] using weak cipher[0m
|
||||
[0;31m(enc) 3des-ctr -- [fail] using broken & deprecated 3DES cipher[0m
|
||||
`- [info] available since Dropbear SSH 0.52
|
||||
[0;31m(enc) 3des-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.4, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) 3des-cbc -- [fail] using broken & deprecated 3DES cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
|
||||
|
||||
[0;36m# message authentication code algorithms[0m
|
||||
[0;31m(mac) hmac-sha1-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-sha1-96 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47
|
||||
[0;33m(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
[0;31m(mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
[0;33m(mac) hmac-sha2-256 -- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56
|
||||
@ -67,20 +65,21 @@
|
||||
[0;36m# algorithm recommendations (for Dropbear SSH 2019.78)[0m
|
||||
[0;31m(rec) -3des-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -3des-ctr -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes128-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -ecdh-sha2-nistp256 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -ecdh-sha2-nistp384 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -ecdh-sha2-nistp521 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -ecdsa-sha2-nistp256 -- key algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-sha1 -- 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-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) +twofish256-ctr -- enc algorithm to append [0m
|
||||
[0;33m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;33m(rec) -hmac-sha1 -- mac 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) -diffie-hellman-group14-sha256 -- kex algorithm to remove [0m
|
||||
[0;33m(rec) -hmac-sha2-256 -- mac algorithm to remove [0m
|
||||
|
||||
[0;36m# additional info[0m
|
||||
|
@ -1 +1,278 @@
|
||||
{"banner": {"comments": null, "protocol": [1, 99], "raw": "SSH-1.99-OpenSSH_4.0", "software": "OpenSSH_4.0"}, "compression": ["none", "zlib"], "enc": ["aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "arcfour", "aes192-cbc", "aes256-cbc", "rijndael-cbc@lysator.liu.se", "aes128-ctr", "aes192-ctr", "aes256-ctr"], "fingerprints": [{"fp": "SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4", "type": "ssh-rsa"}], "kex": [{"algorithm": "diffie-hellman-group-exchange-sha1", "keysize": 1024}, {"algorithm": "diffie-hellman-group14-sha1"}, {"algorithm": "diffie-hellman-group1-sha1"}], "key": [{"algorithm": "ssh-rsa", "keysize": 1024}, {"algorithm": "ssh-dss"}], "mac": ["hmac-md5", "hmac-sha1", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"}
|
||||
{
|
||||
"banner": {
|
||||
"comments": null,
|
||||
"protocol": [
|
||||
1,
|
||||
99
|
||||
],
|
||||
"raw": "SSH-1.99-OpenSSH_4.0",
|
||||
"software": "OpenSSH_4.0"
|
||||
},
|
||||
"compression": [
|
||||
"none",
|
||||
"zlib"
|
||||
],
|
||||
"cves": [
|
||||
{
|
||||
"cvssv2": 7.8,
|
||||
"description": "command injection via anomalous argument transfers",
|
||||
"name": "CVE-2020-15778"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "enumerate usernames due to timing discrepancies",
|
||||
"name": "CVE-2018-15473"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "readonly bypass via sftp",
|
||||
"name": "CVE-2017-15906"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "enumerate usernames via challenge response",
|
||||
"name": "CVE-2016-20012"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.5,
|
||||
"description": "bypass command restrictions via crafted X11 forwarding data",
|
||||
"name": "CVE-2016-3115"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.5,
|
||||
"description": "cause DoS via triggering error condition (memory corruption)",
|
||||
"name": "CVE-2014-1692"
|
||||
},
|
||||
{
|
||||
"cvssv2": 3.5,
|
||||
"description": "leak data via debug messages",
|
||||
"name": "CVE-2012-0814"
|
||||
},
|
||||
{
|
||||
"cvssv2": 3.5,
|
||||
"description": "cause DoS via large value in certain length field (memory consumption)",
|
||||
"name": "CVE-2011-5000"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.0,
|
||||
"description": "cause DoS via large number of connections (slot exhaustion)",
|
||||
"name": "CVE-2010-5107"
|
||||
},
|
||||
{
|
||||
"cvssv2": 4.0,
|
||||
"description": "cause DoS via crafted glob expression (CPU and memory consumption)",
|
||||
"name": "CVE-2010-4755"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.5,
|
||||
"description": "bypass authentication check via crafted values",
|
||||
"name": "CVE-2010-4478"
|
||||
},
|
||||
{
|
||||
"cvssv2": 2.6,
|
||||
"description": "recover plaintext data from ciphertext",
|
||||
"name": "CVE-2008-5161"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.0,
|
||||
"description": "cause DoS via multiple login attempts (slot exhaustion)",
|
||||
"name": "CVE-2008-4109"
|
||||
},
|
||||
{
|
||||
"cvssv2": 6.5,
|
||||
"description": "bypass command restrictions via modifying session file",
|
||||
"name": "CVE-2008-1657"
|
||||
},
|
||||
{
|
||||
"cvssv2": 6.9,
|
||||
"description": "hijack forwarded X11 connections",
|
||||
"name": "CVE-2008-1483"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.5,
|
||||
"description": "privilege escalation via causing an X client to be trusted",
|
||||
"name": "CVE-2007-4752"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.0,
|
||||
"description": "discover valid usernames through different responses",
|
||||
"name": "CVE-2007-2243"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.0,
|
||||
"description": "discover valid usernames through different responses",
|
||||
"name": "CVE-2006-5052"
|
||||
},
|
||||
{
|
||||
"cvssv2": 9.3,
|
||||
"description": "cause DoS or execute arbitrary code (double free)",
|
||||
"name": "CVE-2006-5051"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.8,
|
||||
"description": "cause DoS via crafted packet (CPU consumption)",
|
||||
"name": "CVE-2006-4924"
|
||||
},
|
||||
{
|
||||
"cvssv2": 4.6,
|
||||
"description": "execute arbitrary code",
|
||||
"name": "CVE-2006-0225"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.0,
|
||||
"description": "leak data about authentication credentials",
|
||||
"name": "CVE-2005-2798"
|
||||
}
|
||||
],
|
||||
"enc": [
|
||||
"aes128-cbc",
|
||||
"3des-cbc",
|
||||
"blowfish-cbc",
|
||||
"cast128-cbc",
|
||||
"arcfour",
|
||||
"aes192-cbc",
|
||||
"aes256-cbc",
|
||||
"rijndael-cbc@lysator.liu.se",
|
||||
"aes128-ctr",
|
||||
"aes192-ctr",
|
||||
"aes256-ctr"
|
||||
],
|
||||
"fingerprints": [
|
||||
{
|
||||
"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4",
|
||||
"hash_alg": "SHA256",
|
||||
"hostkey": "ssh-rsa"
|
||||
},
|
||||
{
|
||||
"hash": "3c:c3:38:f8:55:39:c0:4a:5a:17:89:60:2c:a1:fc:6a",
|
||||
"hash_alg": "MD5",
|
||||
"hostkey": "ssh-rsa"
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"algorithm": "diffie-hellman-group-exchange-sha1",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group14-sha1"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group1-sha1"
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"algorithm": "ssh-rsa",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "ssh-dss"
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
"hmac-md5",
|
||||
"hmac-sha1",
|
||||
"hmac-ripemd160",
|
||||
"hmac-ripemd160@openssh.com",
|
||||
"hmac-sha1-96",
|
||||
"hmac-md5-96"
|
||||
],
|
||||
"recommendations": {
|
||||
"critical": {
|
||||
"del": {
|
||||
"enc": [
|
||||
{
|
||||
"name": "3des-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "blowfish-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "cast128-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "rijndael-cbc@lysator.liu.se",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group14-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "diffie-hellman-group1-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "diffie-hellman-group-exchange-sha1",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"name": "ssh-dss",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ssh-rsa",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "hmac-md5",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-md5-96",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-ripemd160",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-ripemd160@openssh.com",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha1-96",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"del": {
|
||||
"enc": [
|
||||
{
|
||||
"name": "aes128-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "aes192-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "aes256-cbc",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"target": "localhost:2222"
|
||||
}
|
||||
|
@ -6,7 +6,10 @@
|
||||
[0;32m(gen) compression: enabled (zlib)[0m
|
||||
|
||||
[0;36m# security[0m
|
||||
[0;33m(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepencies[0m
|
||||
[0;33m(cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers[0m
|
||||
[0;33m(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepancies[0m
|
||||
[0;33m(cve) CVE-2017-15906 -- (CVSSv2: 5.3) readonly bypass via sftp[0m
|
||||
[0;33m(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response[0m
|
||||
[0;33m(cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data[0m
|
||||
[0;33m(cve) CVE-2014-1692 -- (CVSSv2: 7.5) cause DoS via triggering error condition (memory corruption)[0m
|
||||
[0;33m(cve) CVE-2012-0814 -- (CVSSv2: 3.5) leak data via debug messages[0m
|
||||
@ -29,91 +32,73 @@
|
||||
|
||||
[0;36m# key exchange algorithms[0m
|
||||
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
[0;33m(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing 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
|
||||
`- [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 `- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;31m `- [fail] disabled (in client) since OpenSSH 7.0, logjam attack[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[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
|
||||
`- [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
|
||||
|
||||
[0;36m# host-key algorithms[0m
|
||||
[0;31m(key) ssh-rsa (1024-bit) -- [fail] using weak hashing algorithm[0m
|
||||
[0;31m(key) ssh-rsa (1024-bit) -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;31m `- [fail] using small 1024-bit modulus[0m
|
||||
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
|
||||
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2
|
||||
`- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
|
||||
[0;31m(key) ssh-dss -- [fail] using small 1024-bit modulus[0m
|
||||
[0;31m `- [fail] removed (in server) and disabled (in client) since OpenSSH 7.0, weak algorithm[0m
|
||||
[0;33m `- [warn] using weak random number generator could reveal the key[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
|
||||
|
||||
[0;36m# encryption algorithms (ciphers)[0m
|
||||
[0;31m(enc) aes128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes128-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
||||
[0;31m(enc) 3des-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.4, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) 3des-cbc -- [fail] using broken & deprecated 3DES cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
|
||||
[0;31m(enc) blowfish-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;31m `- [fail] disabled since Dropbear SSH 0.53[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) blowfish-cbc -- [fail] using weak & deprecated Blowfish cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
|
||||
[0;31m(enc) cast128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) cast128-cbc -- [fail] using weak & deprecated CAST cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(enc) arcfour -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(enc) aes192-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes192-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
[0;31m(enc) aes256-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes256-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47
|
||||
[0;31m(enc) rijndael-cbc@lysator.liu.se -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) rijndael-cbc@lysator.liu.se -- [fail] using deprecated & non-standardized Rijndael cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
|
||||
[0;32m(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
[0;32m(enc) aes192-ctr -- [info] available since OpenSSH 3.7[0m
|
||||
[0;32m(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
|
||||
[0;36m# message authentication code algorithms[0m
|
||||
[0;31m(mac) hmac-md5 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-md5 -- [fail] using broken MD5 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
[0;33m(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
[0;31m(mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
[0;31m(mac) hmac-ripemd160 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-ripemd160 -- [fail] using deprecated RIPEMD hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.5.0
|
||||
[0;31m(mac) hmac-ripemd160@openssh.com -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-ripemd160@openssh.com -- [fail] using deprecated RIPEMD hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(mac) hmac-sha1-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-sha1-96 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47
|
||||
[0;31m(mac) hmac-md5-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-md5-96 -- [fail] using broken MD5 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0
|
||||
|
||||
[0;36m# fingerprints[0m
|
||||
@ -121,24 +106,24 @@
|
||||
|
||||
[0;36m# algorithm recommendations (for OpenSSH 4.0)[0m
|
||||
[0;31m(rec) -3des-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes128-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes192-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -blowfish-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -cast128-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-md5 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-md5-96 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-ripemd160 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-sha1-96 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -rijndael-cbc@lysator.liu.se -- enc 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;33m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;33m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
||||
[0;33m(rec) -aes128-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -aes192-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -aes256-cbc -- enc algorithm to remove [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
|
||||
|
@ -1 +1,6 @@
|
||||
{"errors": [], "host": "localhost", "passed": true, "policy": "Docker policy: test1 (version 1)"}
|
||||
{
|
||||
"errors": [],
|
||||
"host": "localhost",
|
||||
"passed": true,
|
||||
"policy": "Docker policy: test1 (version 1)"
|
||||
}
|
||||
|
@ -1 +1,31 @@
|
||||
{"errors": [{"actual": ["3072"], "expected_optional": [""], "expected_required": ["4096"], "mismatched_field": "RSA host key (ssh-rsa-cert-v01@openssh.com) sizes"}, {"actual": ["1024"], "expected_optional": [""], "expected_required": ["4096"], "mismatched_field": "RSA CA key (ssh-rsa-cert-v01@openssh.com) sizes"}], "host": "localhost", "passed": false, "policy": "Docker poliicy: test10 (version 1)"}
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"actual": [
|
||||
"3072"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"4096"
|
||||
],
|
||||
"mismatched_field": "Host key (ssh-rsa-cert-v01@openssh.com) sizes"
|
||||
},
|
||||
{
|
||||
"actual": [
|
||||
"1024"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"4096"
|
||||
],
|
||||
"mismatched_field": "CA signature size (ssh-rsa)"
|
||||
}
|
||||
],
|
||||
"host": "localhost",
|
||||
"passed": false,
|
||||
"policy": "Docker poliicy: test10 (version 1)"
|
||||
}
|
||||
|
@ -1,13 +1,28 @@
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
Host: localhost:2222
|
||||
Policy: Docker poliicy: test10 (version 1)
|
||||
Result: [0;31m❌ Failed![0m
|
||||
[0;33m
|
||||
Errors:
|
||||
* RSA CA key (ssh-rsa-cert-v01@openssh.com) sizes did not match.
|
||||
* CA signature size (ssh-rsa) did not match.
|
||||
- Expected: 4096
|
||||
- Actual: 1024
|
||||
|
||||
* RSA host key (ssh-rsa-cert-v01@openssh.com) sizes did not match.
|
||||
* Host key (ssh-rsa-cert-v01@openssh.com) sizes did not match.
|
||||
- Expected: 4096
|
||||
- Actual: 3072
|
||||
[0m
|
||||
|
@ -1 +1,23 @@
|
||||
{"errors": [{"actual": ["diffie-hellman-group-exchange-sha256", "diffie-hellman-group-exchange-sha1", "diffie-hellman-group14-sha1", "diffie-hellman-group1-sha1"], "expected_optional": [""], "expected_required": ["kex_alg1", "kex_alg2"], "mismatched_field": "Key exchanges"}], "host": "localhost", "passed": false, "policy": "Docker policy: test2 (version 1)"}
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"actual": [
|
||||
"diffie-hellman-group-exchange-sha256",
|
||||
"diffie-hellman-group-exchange-sha1",
|
||||
"diffie-hellman-group14-sha1",
|
||||
"diffie-hellman-group1-sha1"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"kex_alg1",
|
||||
"kex_alg2"
|
||||
],
|
||||
"mismatched_field": "Key exchanges"
|
||||
}
|
||||
],
|
||||
"host": "localhost",
|
||||
"passed": false,
|
||||
"policy": "Docker policy: test2 (version 1)"
|
||||
}
|
||||
|
@ -1 +1,22 @@
|
||||
{"errors": [{"actual": ["ssh-rsa", "ssh-dss"], "expected_optional": [""], "expected_required": ["ssh-rsa", "ssh-dss", "key_alg1"], "mismatched_field": "Host keys"}], "host": "localhost", "passed": false, "policy": "Docker policy: test3 (version 1)"}
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"actual": [
|
||||
"ssh-rsa",
|
||||
"ssh-dss"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"ssh-rsa",
|
||||
"ssh-dss",
|
||||
"key_alg1"
|
||||
],
|
||||
"mismatched_field": "Host keys"
|
||||
}
|
||||
],
|
||||
"host": "localhost",
|
||||
"passed": false,
|
||||
"policy": "Docker policy: test3 (version 1)"
|
||||
}
|
||||
|
@ -1 +1,32 @@
|
||||
{"errors": [{"actual": ["aes128-ctr", "aes192-ctr", "aes256-ctr", "arcfour256", "arcfour128", "aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "aes192-cbc", "aes256-cbc", "arcfour", "rijndael-cbc@lysator.liu.se"], "expected_optional": [""], "expected_required": ["cipher_alg1", "cipher_alg2"], "mismatched_field": "Ciphers"}], "host": "localhost", "passed": false, "policy": "Docker policy: test4 (version 1)"}
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"actual": [
|
||||
"aes128-ctr",
|
||||
"aes192-ctr",
|
||||
"aes256-ctr",
|
||||
"arcfour256",
|
||||
"arcfour128",
|
||||
"aes128-cbc",
|
||||
"3des-cbc",
|
||||
"blowfish-cbc",
|
||||
"cast128-cbc",
|
||||
"aes192-cbc",
|
||||
"aes256-cbc",
|
||||
"arcfour",
|
||||
"rijndael-cbc@lysator.liu.se"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"cipher_alg1",
|
||||
"cipher_alg2"
|
||||
],
|
||||
"mismatched_field": "Ciphers"
|
||||
}
|
||||
],
|
||||
"host": "localhost",
|
||||
"passed": false,
|
||||
"policy": "Docker policy: test4 (version 1)"
|
||||
}
|
||||
|
@ -1 +1,31 @@
|
||||
{"errors": [{"actual": ["hmac-md5", "hmac-sha1", "umac-64@openssh.com", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "expected_optional": [""], "expected_required": ["hmac-md5", "hmac-sha1", "umac-64@openssh.com", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac_alg1", "hmac-md5-96"], "mismatched_field": "MACs"}], "host": "localhost", "passed": false, "policy": "Docker policy: test5 (version 1)"}
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"actual": [
|
||||
"hmac-md5",
|
||||
"hmac-sha1",
|
||||
"umac-64@openssh.com",
|
||||
"hmac-ripemd160",
|
||||
"hmac-ripemd160@openssh.com",
|
||||
"hmac-sha1-96",
|
||||
"hmac-md5-96"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"hmac-md5",
|
||||
"hmac-sha1",
|
||||
"umac-64@openssh.com",
|
||||
"hmac-ripemd160",
|
||||
"hmac-ripemd160@openssh.com",
|
||||
"hmac_alg1",
|
||||
"hmac-md5-96"
|
||||
],
|
||||
"mismatched_field": "MACs"
|
||||
}
|
||||
],
|
||||
"host": "localhost",
|
||||
"passed": false,
|
||||
"policy": "Docker policy: test5 (version 1)"
|
||||
}
|
||||
|
@ -1 +1,6 @@
|
||||
{"errors": [], "host": "localhost", "passed": true, "policy": "Docker poliicy: test7 (version 1)"}
|
||||
{
|
||||
"errors": [],
|
||||
"host": "localhost",
|
||||
"passed": true,
|
||||
"policy": "Docker poliicy: test7 (version 1)"
|
||||
}
|
||||
|
@ -1,3 +1,18 @@
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
Host: localhost:2222
|
||||
Policy: Docker poliicy: test7 (version 1)
|
||||
Result: [0;32m✔ Passed[0m
|
||||
|
@ -1 +1,19 @@
|
||||
{"errors": [{"actual": ["1024"], "expected_optional": [""], "expected_required": ["2048"], "mismatched_field": "RSA CA key (ssh-rsa-cert-v01@openssh.com) sizes"}], "host": "localhost", "passed": false, "policy": "Docker poliicy: test8 (version 1)"}
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"actual": [
|
||||
"1024"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"2048"
|
||||
],
|
||||
"mismatched_field": "CA signature size (ssh-rsa)"
|
||||
}
|
||||
],
|
||||
"host": "localhost",
|
||||
"passed": false,
|
||||
"policy": "Docker poliicy: test8 (version 1)"
|
||||
}
|
||||
|
@ -1,9 +1,24 @@
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
Host: localhost:2222
|
||||
Policy: Docker poliicy: test8 (version 1)
|
||||
Result: [0;31m❌ Failed![0m
|
||||
[0;33m
|
||||
Errors:
|
||||
* RSA CA key (ssh-rsa-cert-v01@openssh.com) sizes did not match.
|
||||
* CA signature size (ssh-rsa) did not match.
|
||||
- Expected: 2048
|
||||
- Actual: 1024
|
||||
[0m
|
||||
|
@ -1 +1,19 @@
|
||||
{"errors": [{"actual": ["3072"], "expected_optional": [""], "expected_required": ["4096"], "mismatched_field": "RSA host key (ssh-rsa-cert-v01@openssh.com) sizes"}], "host": "localhost", "passed": false, "policy": "Docker poliicy: test9 (version 1)"}
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"actual": [
|
||||
"3072"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"4096"
|
||||
],
|
||||
"mismatched_field": "Host key (ssh-rsa-cert-v01@openssh.com) sizes"
|
||||
}
|
||||
],
|
||||
"host": "localhost",
|
||||
"passed": false,
|
||||
"policy": "Docker poliicy: test9 (version 1)"
|
||||
}
|
||||
|
@ -1,9 +1,24 @@
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
Host: localhost:2222
|
||||
Policy: Docker poliicy: test9 (version 1)
|
||||
Result: [0;31m❌ Failed![0m
|
||||
[0;33m
|
||||
Errors:
|
||||
* RSA host key (ssh-rsa-cert-v01@openssh.com) sizes did not match.
|
||||
* Host key (ssh-rsa-cert-v01@openssh.com) sizes did not match.
|
||||
- Expected: 4096
|
||||
- Actual: 3072
|
||||
[0m
|
||||
|
@ -1 +1,272 @@
|
||||
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_5.6", "software": "OpenSSH_5.6"}, "compression": ["none", "zlib@openssh.com"], "enc": ["aes128-ctr", "aes192-ctr", "aes256-ctr", "arcfour256", "arcfour128", "aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "aes192-cbc", "aes256-cbc", "arcfour", "rijndael-cbc@lysator.liu.se"], "fingerprints": [{"fp": "SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4", "type": "ssh-rsa"}], "kex": [{"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 1024}, {"algorithm": "diffie-hellman-group-exchange-sha1", "keysize": 1024}, {"algorithm": "diffie-hellman-group14-sha1"}, {"algorithm": "diffie-hellman-group1-sha1"}], "key": [{"algorithm": "ssh-rsa", "keysize": 1024}, {"algorithm": "ssh-dss"}], "mac": ["hmac-md5", "hmac-sha1", "umac-64@openssh.com", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"}
|
||||
{
|
||||
"banner": {
|
||||
"comments": null,
|
||||
"protocol": [
|
||||
2,
|
||||
0
|
||||
],
|
||||
"raw": "SSH-2.0-OpenSSH_5.6",
|
||||
"software": "OpenSSH_5.6"
|
||||
},
|
||||
"compression": [
|
||||
"none",
|
||||
"zlib@openssh.com"
|
||||
],
|
||||
"cves": [
|
||||
{
|
||||
"cvssv2": 7.8,
|
||||
"description": "command injection via anomalous argument transfers",
|
||||
"name": "CVE-2020-15778"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "enumerate usernames due to timing discrepancies",
|
||||
"name": "CVE-2018-15473"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "readonly bypass via sftp",
|
||||
"name": "CVE-2017-15906"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "enumerate usernames via challenge response",
|
||||
"name": "CVE-2016-20012"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.5,
|
||||
"description": "bypass command restrictions via crafted X11 forwarding data",
|
||||
"name": "CVE-2016-3115"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.0,
|
||||
"description": "cause DoS via crafted network traffic (out of bounds read)",
|
||||
"name": "CVE-2016-1907"
|
||||
},
|
||||
{
|
||||
"cvssv2": 6.9,
|
||||
"description": "privilege escalation via leveraging sshd uid",
|
||||
"name": "CVE-2015-6564"
|
||||
},
|
||||
{
|
||||
"cvssv2": 1.9,
|
||||
"description": "conduct impersonation attack",
|
||||
"name": "CVE-2015-6563"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.8,
|
||||
"description": "bypass environment restrictions via specific string before wildcard",
|
||||
"name": "CVE-2014-2532"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.5,
|
||||
"description": "cause DoS via triggering error condition (memory corruption)",
|
||||
"name": "CVE-2014-1692"
|
||||
},
|
||||
{
|
||||
"cvssv2": 3.5,
|
||||
"description": "leak data via debug messages",
|
||||
"name": "CVE-2012-0814"
|
||||
},
|
||||
{
|
||||
"cvssv2": 3.5,
|
||||
"description": "cause DoS via large value in certain length field (memory consumption)",
|
||||
"name": "CVE-2011-5000"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.0,
|
||||
"description": "cause DoS via large number of connections (slot exhaustion)",
|
||||
"name": "CVE-2010-5107"
|
||||
},
|
||||
{
|
||||
"cvssv2": 4.0,
|
||||
"description": "cause DoS via crafted glob expression (CPU and memory consumption)",
|
||||
"name": "CVE-2010-4755"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.5,
|
||||
"description": "bypass authentication check via crafted values",
|
||||
"name": "CVE-2010-4478"
|
||||
}
|
||||
],
|
||||
"enc": [
|
||||
"aes128-ctr",
|
||||
"aes192-ctr",
|
||||
"aes256-ctr",
|
||||
"arcfour256",
|
||||
"arcfour128",
|
||||
"aes128-cbc",
|
||||
"3des-cbc",
|
||||
"blowfish-cbc",
|
||||
"cast128-cbc",
|
||||
"aes192-cbc",
|
||||
"aes256-cbc",
|
||||
"arcfour",
|
||||
"rijndael-cbc@lysator.liu.se"
|
||||
],
|
||||
"fingerprints": [
|
||||
{
|
||||
"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4",
|
||||
"hash_alg": "SHA256",
|
||||
"hostkey": "ssh-rsa"
|
||||
},
|
||||
{
|
||||
"hash": "3c:c3:38:f8:55:39:c0:4a:5a:17:89:60:2c:a1:fc:6a",
|
||||
"hash_alg": "MD5",
|
||||
"hostkey": "ssh-rsa"
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"algorithm": "diffie-hellman-group-exchange-sha256",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group-exchange-sha1",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group14-sha1"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group1-sha1"
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"algorithm": "ssh-rsa",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "ssh-dss"
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
"hmac-md5",
|
||||
"hmac-sha1",
|
||||
"umac-64@openssh.com",
|
||||
"hmac-ripemd160",
|
||||
"hmac-ripemd160@openssh.com",
|
||||
"hmac-sha1-96",
|
||||
"hmac-md5-96"
|
||||
],
|
||||
"recommendations": {
|
||||
"critical": {
|
||||
"chg": {
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group-exchange-sha256",
|
||||
"notes": "increase modulus size to 3072 bits or larger"
|
||||
}
|
||||
]
|
||||
},
|
||||
"del": {
|
||||
"enc": [
|
||||
{
|
||||
"name": "3des-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour128",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour256",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "blowfish-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "cast128-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "rijndael-cbc@lysator.liu.se",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group14-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "diffie-hellman-group1-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "diffie-hellman-group-exchange-sha1",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"name": "ssh-dss",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ssh-rsa",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "hmac-md5",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-md5-96",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-ripemd160",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-ripemd160@openssh.com",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha1-96",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"del": {
|
||||
"enc": [
|
||||
{
|
||||
"name": "aes128-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "aes192-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "aes256-cbc",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "umac-64@openssh.com",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"target": "localhost:2222"
|
||||
}
|
||||
|
@ -5,7 +5,10 @@
|
||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||
|
||||
[0;36m# security[0m
|
||||
[0;33m(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepencies[0m
|
||||
[0;33m(cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers[0m
|
||||
[0;33m(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepancies[0m
|
||||
[0;33m(cve) CVE-2017-15906 -- (CVSSv2: 5.3) readonly bypass via sftp[0m
|
||||
[0;33m(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response[0m
|
||||
[0;33m(cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data[0m
|
||||
[0;33m(cve) CVE-2016-1907 -- (CVSSv2: 5.0) cause DoS via crafted network traffic (out of bounds read)[0m
|
||||
[0;33m(cve) CVE-2015-6564 -- (CVSSv2: 6.9) privilege escalation via leveraging sshd uid[0m
|
||||
@ -22,113 +25,88 @@
|
||||
[0;31m(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||
`- [info] available since OpenSSH 4.4
|
||||
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
[0;33m(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing 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
|
||||
`- [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 `- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;31m `- [fail] disabled (in client) since OpenSSH 7.0, logjam attack[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[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
|
||||
`- [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
|
||||
|
||||
[0;36m# host-key algorithms[0m
|
||||
[0;31m(key) ssh-rsa (1024-bit) -- [fail] using weak hashing algorithm[0m
|
||||
[0;31m(key) ssh-rsa (1024-bit) -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;31m `- [fail] using small 1024-bit modulus[0m
|
||||
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
|
||||
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2
|
||||
`- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
|
||||
[0;31m(key) ssh-dss -- [fail] using small 1024-bit modulus[0m
|
||||
[0;31m `- [fail] removed (in server) and disabled (in client) since OpenSSH 7.0, weak algorithm[0m
|
||||
[0;33m `- [warn] using weak random number generator could reveal the key[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
|
||||
|
||||
[0;36m# encryption algorithms (ciphers)[0m
|
||||
[0;32m(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
[0;32m(enc) aes192-ctr -- [info] available since OpenSSH 3.7[0m
|
||||
[0;32m(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
[0;31m(enc) arcfour256 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour256 -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 4.2
|
||||
[0;31m(enc) arcfour128 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour128 -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 4.2
|
||||
[0;31m(enc) aes128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes128-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
||||
[0;31m(enc) 3des-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.4, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) 3des-cbc -- [fail] using broken & deprecated 3DES cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
|
||||
[0;31m(enc) blowfish-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;31m `- [fail] disabled since Dropbear SSH 0.53[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) blowfish-cbc -- [fail] using weak & deprecated Blowfish cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
|
||||
[0;31m(enc) cast128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) cast128-cbc -- [fail] using weak & deprecated CAST cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(enc) aes192-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes192-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
[0;31m(enc) aes256-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes256-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47
|
||||
[0;31m(enc) arcfour -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(enc) rijndael-cbc@lysator.liu.se -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) rijndael-cbc@lysator.liu.se -- [fail] using deprecated & non-standardized Rijndael cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
|
||||
|
||||
[0;36m# message authentication code algorithms[0m
|
||||
[0;31m(mac) hmac-md5 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-md5 -- [fail] using broken MD5 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
[0;33m(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
[0;31m(mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
[0;33m(mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using small 64-bit tag size[0m
|
||||
`- [info] available since OpenSSH 4.7
|
||||
[0;31m(mac) hmac-ripemd160 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-ripemd160 -- [fail] using deprecated RIPEMD hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.5.0
|
||||
[0;31m(mac) hmac-ripemd160@openssh.com -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-ripemd160@openssh.com -- [fail] using deprecated RIPEMD hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(mac) hmac-sha1-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-sha1-96 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47
|
||||
[0;31m(mac) hmac-md5-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-md5-96 -- [fail] using broken MD5 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0
|
||||
|
||||
[0;36m# fingerprints[0m
|
||||
[0;32m(fin) ssh-rsa: SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4[0m
|
||||
|
||||
[0;36m# algorithm recommendations (for OpenSSH 5.6)[0m
|
||||
[0;31m(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 2048 bits or larger) [0m
|
||||
[0;31m(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 3072 bits or larger) [0m
|
||||
[0;31m(rec) -3des-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes128-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes192-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour128 -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour256 -- enc algorithm to remove [0m
|
||||
@ -136,16 +114,19 @@
|
||||
[0;31m(rec) -cast128-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-md5 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-md5-96 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-ripemd160 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-sha1-96 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -rijndael-cbc@lysator.liu.se -- enc 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;33m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;33m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
||||
[0;33m(rec) -aes128-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -aes192-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
||||
|
||||
[0;36m# additional info[0m
|
||||
|
@ -1 +1,275 @@
|
||||
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_5.6", "software": "OpenSSH_5.6"}, "compression": ["none", "zlib@openssh.com"], "enc": ["aes128-ctr", "aes192-ctr", "aes256-ctr", "arcfour256", "arcfour128", "aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "aes192-cbc", "aes256-cbc", "arcfour", "rijndael-cbc@lysator.liu.se"], "fingerprints": [{"fp": "SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4", "type": "ssh-rsa"}], "kex": [{"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 1024}, {"algorithm": "diffie-hellman-group-exchange-sha1", "keysize": 1024}, {"algorithm": "diffie-hellman-group14-sha1"}, {"algorithm": "diffie-hellman-group1-sha1"}], "key": [{"algorithm": "ssh-rsa", "keysize": 1024}, {"algorithm": "ssh-rsa-cert-v01@openssh.com", "casize": 1024, "keysize": 1024}], "mac": ["hmac-md5", "hmac-sha1", "umac-64@openssh.com", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"}
|
||||
{
|
||||
"banner": {
|
||||
"comments": null,
|
||||
"protocol": [
|
||||
2,
|
||||
0
|
||||
],
|
||||
"raw": "SSH-2.0-OpenSSH_5.6",
|
||||
"software": "OpenSSH_5.6"
|
||||
},
|
||||
"compression": [
|
||||
"none",
|
||||
"zlib@openssh.com"
|
||||
],
|
||||
"cves": [
|
||||
{
|
||||
"cvssv2": 7.8,
|
||||
"description": "command injection via anomalous argument transfers",
|
||||
"name": "CVE-2020-15778"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "enumerate usernames due to timing discrepancies",
|
||||
"name": "CVE-2018-15473"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "readonly bypass via sftp",
|
||||
"name": "CVE-2017-15906"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "enumerate usernames via challenge response",
|
||||
"name": "CVE-2016-20012"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.5,
|
||||
"description": "bypass command restrictions via crafted X11 forwarding data",
|
||||
"name": "CVE-2016-3115"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.0,
|
||||
"description": "cause DoS via crafted network traffic (out of bounds read)",
|
||||
"name": "CVE-2016-1907"
|
||||
},
|
||||
{
|
||||
"cvssv2": 6.9,
|
||||
"description": "privilege escalation via leveraging sshd uid",
|
||||
"name": "CVE-2015-6564"
|
||||
},
|
||||
{
|
||||
"cvssv2": 1.9,
|
||||
"description": "conduct impersonation attack",
|
||||
"name": "CVE-2015-6563"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.8,
|
||||
"description": "bypass environment restrictions via specific string before wildcard",
|
||||
"name": "CVE-2014-2532"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.5,
|
||||
"description": "cause DoS via triggering error condition (memory corruption)",
|
||||
"name": "CVE-2014-1692"
|
||||
},
|
||||
{
|
||||
"cvssv2": 3.5,
|
||||
"description": "leak data via debug messages",
|
||||
"name": "CVE-2012-0814"
|
||||
},
|
||||
{
|
||||
"cvssv2": 3.5,
|
||||
"description": "cause DoS via large value in certain length field (memory consumption)",
|
||||
"name": "CVE-2011-5000"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.0,
|
||||
"description": "cause DoS via large number of connections (slot exhaustion)",
|
||||
"name": "CVE-2010-5107"
|
||||
},
|
||||
{
|
||||
"cvssv2": 4.0,
|
||||
"description": "cause DoS via crafted glob expression (CPU and memory consumption)",
|
||||
"name": "CVE-2010-4755"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.5,
|
||||
"description": "bypass authentication check via crafted values",
|
||||
"name": "CVE-2010-4478"
|
||||
}
|
||||
],
|
||||
"enc": [
|
||||
"aes128-ctr",
|
||||
"aes192-ctr",
|
||||
"aes256-ctr",
|
||||
"arcfour256",
|
||||
"arcfour128",
|
||||
"aes128-cbc",
|
||||
"3des-cbc",
|
||||
"blowfish-cbc",
|
||||
"cast128-cbc",
|
||||
"aes192-cbc",
|
||||
"aes256-cbc",
|
||||
"arcfour",
|
||||
"rijndael-cbc@lysator.liu.se"
|
||||
],
|
||||
"fingerprints": [
|
||||
{
|
||||
"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4",
|
||||
"hash_alg": "SHA256",
|
||||
"hostkey": "ssh-rsa"
|
||||
},
|
||||
{
|
||||
"hash": "3c:c3:38:f8:55:39:c0:4a:5a:17:89:60:2c:a1:fc:6a",
|
||||
"hash_alg": "MD5",
|
||||
"hostkey": "ssh-rsa"
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"algorithm": "diffie-hellman-group-exchange-sha256",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group-exchange-sha1",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group14-sha1"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group1-sha1"
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"algorithm": "ssh-rsa",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "ssh-rsa-cert-v01@openssh.com",
|
||||
"ca_algorithm": "ssh-rsa",
|
||||
"casize": 1024,
|
||||
"keysize": 1024
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
"hmac-md5",
|
||||
"hmac-sha1",
|
||||
"umac-64@openssh.com",
|
||||
"hmac-ripemd160",
|
||||
"hmac-ripemd160@openssh.com",
|
||||
"hmac-sha1-96",
|
||||
"hmac-md5-96"
|
||||
],
|
||||
"recommendations": {
|
||||
"critical": {
|
||||
"chg": {
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group-exchange-sha256",
|
||||
"notes": "increase modulus size to 3072 bits or larger"
|
||||
}
|
||||
]
|
||||
},
|
||||
"del": {
|
||||
"enc": [
|
||||
{
|
||||
"name": "3des-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour128",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour256",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "blowfish-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "cast128-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "rijndael-cbc@lysator.liu.se",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group14-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "diffie-hellman-group1-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "diffie-hellman-group-exchange-sha1",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"name": "ssh-rsa",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ssh-rsa-cert-v01@openssh.com",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "hmac-md5",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-md5-96",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-ripemd160",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-ripemd160@openssh.com",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha1-96",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"del": {
|
||||
"enc": [
|
||||
{
|
||||
"name": "aes128-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "aes192-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "aes256-cbc",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "umac-64@openssh.com",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"target": "localhost:2222"
|
||||
}
|
||||
|
@ -5,7 +5,10 @@
|
||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||
|
||||
[0;36m# security[0m
|
||||
[0;33m(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepencies[0m
|
||||
[0;33m(cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers[0m
|
||||
[0;33m(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepancies[0m
|
||||
[0;33m(cve) CVE-2017-15906 -- (CVSSv2: 5.3) readonly bypass via sftp[0m
|
||||
[0;33m(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response[0m
|
||||
[0;33m(cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data[0m
|
||||
[0;33m(cve) CVE-2016-1907 -- (CVSSv2: 5.0) cause DoS via crafted network traffic (out of bounds read)[0m
|
||||
[0;33m(cve) CVE-2015-6564 -- (CVSSv2: 6.9) privilege escalation via leveraging sshd uid[0m
|
||||
@ -22,113 +25,89 @@
|
||||
[0;31m(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||
`- [info] available since OpenSSH 4.4
|
||||
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
[0;33m(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing 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
|
||||
`- [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 `- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;31m `- [fail] disabled (in client) since OpenSSH 7.0, logjam attack[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[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
|
||||
`- [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
|
||||
|
||||
[0;36m# host-key algorithms[0m
|
||||
[0;31m(key) ssh-rsa (1024-bit) -- [fail] using weak hashing algorithm[0m
|
||||
[0;31m(key) ssh-rsa (1024-bit) -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;31m `- [fail] using small 1024-bit modulus[0m
|
||||
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
|
||||
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2
|
||||
[0;31m(key) ssh-rsa-cert-v01@openssh.com (1024-bit cert/1024-bit CA) -- [fail] using weak hashing algorithm[0m
|
||||
[0;31m `- [fail] using small 1024-bit modulus[0m
|
||||
`- [info] available since OpenSSH 5.6
|
||||
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2
|
||||
`- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
|
||||
[0;31m(key) ssh-rsa-cert-v01@openssh.com (1024-bit cert/1024-bit RSA CA) -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;31m `- [fail] using small 1024-bit hostkey modulus[0m
|
||||
[0;31m `- [fail] using small 1024-bit CA key modulus[0m
|
||||
`- [info] available since OpenSSH 5.6
|
||||
`- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
|
||||
|
||||
[0;36m# encryption algorithms (ciphers)[0m
|
||||
[0;32m(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
[0;32m(enc) aes192-ctr -- [info] available since OpenSSH 3.7[0m
|
||||
[0;32m(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
[0;31m(enc) arcfour256 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour256 -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 4.2
|
||||
[0;31m(enc) arcfour128 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour128 -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 4.2
|
||||
[0;31m(enc) aes128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes128-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
||||
[0;31m(enc) 3des-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.4, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) 3des-cbc -- [fail] using broken & deprecated 3DES cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
|
||||
[0;31m(enc) blowfish-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;31m `- [fail] disabled since Dropbear SSH 0.53[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) blowfish-cbc -- [fail] using weak & deprecated Blowfish cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
|
||||
[0;31m(enc) cast128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) cast128-cbc -- [fail] using weak & deprecated CAST cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(enc) aes192-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes192-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
[0;31m(enc) aes256-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes256-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47
|
||||
[0;31m(enc) arcfour -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(enc) rijndael-cbc@lysator.liu.se -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) rijndael-cbc@lysator.liu.se -- [fail] using deprecated & non-standardized Rijndael cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
|
||||
|
||||
[0;36m# message authentication code algorithms[0m
|
||||
[0;31m(mac) hmac-md5 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-md5 -- [fail] using broken MD5 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
[0;33m(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
[0;31m(mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
[0;33m(mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using small 64-bit tag size[0m
|
||||
`- [info] available since OpenSSH 4.7
|
||||
[0;31m(mac) hmac-ripemd160 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-ripemd160 -- [fail] using deprecated RIPEMD hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.5.0
|
||||
[0;31m(mac) hmac-ripemd160@openssh.com -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-ripemd160@openssh.com -- [fail] using deprecated RIPEMD hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(mac) hmac-sha1-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-sha1-96 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47
|
||||
[0;31m(mac) hmac-md5-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-md5-96 -- [fail] using broken MD5 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0
|
||||
|
||||
[0;36m# fingerprints[0m
|
||||
[0;32m(fin) ssh-rsa: SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4[0m
|
||||
|
||||
[0;36m# algorithm recommendations (for OpenSSH 5.6)[0m
|
||||
[0;31m(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 2048 bits or larger) [0m
|
||||
[0;31m(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 3072 bits or larger) [0m
|
||||
[0;31m(rec) -3des-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes128-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes192-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour128 -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour256 -- enc algorithm to remove [0m
|
||||
@ -136,16 +115,19 @@
|
||||
[0;31m(rec) -cast128-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-md5 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-md5-96 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-ripemd160 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-sha1-96 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -ssh-rsa -- key algorithm to remove [0m
|
||||
[0;31m(rec) -ssh-rsa-cert-v01@openssh.com -- key algorithm to remove [0m
|
||||
[0;33m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;33m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
||||
[0;33m(rec) -aes128-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -aes192-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
||||
|
||||
[0;36m# additional info[0m
|
||||
|
@ -1 +1,275 @@
|
||||
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_5.6", "software": "OpenSSH_5.6"}, "compression": ["none", "zlib@openssh.com"], "enc": ["aes128-ctr", "aes192-ctr", "aes256-ctr", "arcfour256", "arcfour128", "aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "aes192-cbc", "aes256-cbc", "arcfour", "rijndael-cbc@lysator.liu.se"], "fingerprints": [{"fp": "SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4", "type": "ssh-rsa"}], "kex": [{"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 1024}, {"algorithm": "diffie-hellman-group-exchange-sha1", "keysize": 1024}, {"algorithm": "diffie-hellman-group14-sha1"}, {"algorithm": "diffie-hellman-group1-sha1"}], "key": [{"algorithm": "ssh-rsa", "keysize": 1024}, {"algorithm": "ssh-rsa-cert-v01@openssh.com", "casize": 3072, "keysize": 1024}], "mac": ["hmac-md5", "hmac-sha1", "umac-64@openssh.com", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"}
|
||||
{
|
||||
"banner": {
|
||||
"comments": null,
|
||||
"protocol": [
|
||||
2,
|
||||
0
|
||||
],
|
||||
"raw": "SSH-2.0-OpenSSH_5.6",
|
||||
"software": "OpenSSH_5.6"
|
||||
},
|
||||
"compression": [
|
||||
"none",
|
||||
"zlib@openssh.com"
|
||||
],
|
||||
"cves": [
|
||||
{
|
||||
"cvssv2": 7.8,
|
||||
"description": "command injection via anomalous argument transfers",
|
||||
"name": "CVE-2020-15778"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "enumerate usernames due to timing discrepancies",
|
||||
"name": "CVE-2018-15473"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "readonly bypass via sftp",
|
||||
"name": "CVE-2017-15906"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "enumerate usernames via challenge response",
|
||||
"name": "CVE-2016-20012"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.5,
|
||||
"description": "bypass command restrictions via crafted X11 forwarding data",
|
||||
"name": "CVE-2016-3115"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.0,
|
||||
"description": "cause DoS via crafted network traffic (out of bounds read)",
|
||||
"name": "CVE-2016-1907"
|
||||
},
|
||||
{
|
||||
"cvssv2": 6.9,
|
||||
"description": "privilege escalation via leveraging sshd uid",
|
||||
"name": "CVE-2015-6564"
|
||||
},
|
||||
{
|
||||
"cvssv2": 1.9,
|
||||
"description": "conduct impersonation attack",
|
||||
"name": "CVE-2015-6563"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.8,
|
||||
"description": "bypass environment restrictions via specific string before wildcard",
|
||||
"name": "CVE-2014-2532"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.5,
|
||||
"description": "cause DoS via triggering error condition (memory corruption)",
|
||||
"name": "CVE-2014-1692"
|
||||
},
|
||||
{
|
||||
"cvssv2": 3.5,
|
||||
"description": "leak data via debug messages",
|
||||
"name": "CVE-2012-0814"
|
||||
},
|
||||
{
|
||||
"cvssv2": 3.5,
|
||||
"description": "cause DoS via large value in certain length field (memory consumption)",
|
||||
"name": "CVE-2011-5000"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.0,
|
||||
"description": "cause DoS via large number of connections (slot exhaustion)",
|
||||
"name": "CVE-2010-5107"
|
||||
},
|
||||
{
|
||||
"cvssv2": 4.0,
|
||||
"description": "cause DoS via crafted glob expression (CPU and memory consumption)",
|
||||
"name": "CVE-2010-4755"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.5,
|
||||
"description": "bypass authentication check via crafted values",
|
||||
"name": "CVE-2010-4478"
|
||||
}
|
||||
],
|
||||
"enc": [
|
||||
"aes128-ctr",
|
||||
"aes192-ctr",
|
||||
"aes256-ctr",
|
||||
"arcfour256",
|
||||
"arcfour128",
|
||||
"aes128-cbc",
|
||||
"3des-cbc",
|
||||
"blowfish-cbc",
|
||||
"cast128-cbc",
|
||||
"aes192-cbc",
|
||||
"aes256-cbc",
|
||||
"arcfour",
|
||||
"rijndael-cbc@lysator.liu.se"
|
||||
],
|
||||
"fingerprints": [
|
||||
{
|
||||
"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4",
|
||||
"hash_alg": "SHA256",
|
||||
"hostkey": "ssh-rsa"
|
||||
},
|
||||
{
|
||||
"hash": "3c:c3:38:f8:55:39:c0:4a:5a:17:89:60:2c:a1:fc:6a",
|
||||
"hash_alg": "MD5",
|
||||
"hostkey": "ssh-rsa"
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"algorithm": "diffie-hellman-group-exchange-sha256",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group-exchange-sha1",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group14-sha1"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group1-sha1"
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"algorithm": "ssh-rsa",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "ssh-rsa-cert-v01@openssh.com",
|
||||
"ca_algorithm": "ssh-rsa",
|
||||
"casize": 3072,
|
||||
"keysize": 1024
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
"hmac-md5",
|
||||
"hmac-sha1",
|
||||
"umac-64@openssh.com",
|
||||
"hmac-ripemd160",
|
||||
"hmac-ripemd160@openssh.com",
|
||||
"hmac-sha1-96",
|
||||
"hmac-md5-96"
|
||||
],
|
||||
"recommendations": {
|
||||
"critical": {
|
||||
"chg": {
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group-exchange-sha256",
|
||||
"notes": "increase modulus size to 3072 bits or larger"
|
||||
}
|
||||
]
|
||||
},
|
||||
"del": {
|
||||
"enc": [
|
||||
{
|
||||
"name": "3des-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour128",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour256",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "blowfish-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "cast128-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "rijndael-cbc@lysator.liu.se",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group14-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "diffie-hellman-group1-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "diffie-hellman-group-exchange-sha1",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"name": "ssh-rsa",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ssh-rsa-cert-v01@openssh.com",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "hmac-md5",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-md5-96",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-ripemd160",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-ripemd160@openssh.com",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha1-96",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"del": {
|
||||
"enc": [
|
||||
{
|
||||
"name": "aes128-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "aes192-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "aes256-cbc",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "umac-64@openssh.com",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"target": "localhost:2222"
|
||||
}
|
||||
|
@ -5,7 +5,10 @@
|
||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||
|
||||
[0;36m# security[0m
|
||||
[0;33m(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepencies[0m
|
||||
[0;33m(cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers[0m
|
||||
[0;33m(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepancies[0m
|
||||
[0;33m(cve) CVE-2017-15906 -- (CVSSv2: 5.3) readonly bypass via sftp[0m
|
||||
[0;33m(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response[0m
|
||||
[0;33m(cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data[0m
|
||||
[0;33m(cve) CVE-2016-1907 -- (CVSSv2: 5.0) cause DoS via crafted network traffic (out of bounds read)[0m
|
||||
[0;33m(cve) CVE-2015-6564 -- (CVSSv2: 6.9) privilege escalation via leveraging sshd uid[0m
|
||||
@ -22,113 +25,88 @@
|
||||
[0;31m(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||
`- [info] available since OpenSSH 4.4
|
||||
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
[0;33m(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing 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
|
||||
`- [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 `- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;31m `- [fail] disabled (in client) since OpenSSH 7.0, logjam attack[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[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
|
||||
`- [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
|
||||
|
||||
[0;36m# host-key algorithms[0m
|
||||
[0;31m(key) ssh-rsa (1024-bit) -- [fail] using weak hashing algorithm[0m
|
||||
[0;31m(key) ssh-rsa (1024-bit) -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;31m `- [fail] using small 1024-bit modulus[0m
|
||||
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
|
||||
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2
|
||||
[0;31m(key) ssh-rsa-cert-v01@openssh.com (1024-bit cert/3072-bit CA) -- [fail] using weak hashing algorithm[0m
|
||||
[0;31m `- [fail] using small 1024-bit modulus[0m
|
||||
`- [info] available since OpenSSH 5.6
|
||||
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2
|
||||
`- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
|
||||
[0;31m(key) ssh-rsa-cert-v01@openssh.com (1024-bit cert/3072-bit RSA CA) -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;31m `- [fail] using small 1024-bit hostkey modulus[0m
|
||||
`- [info] available since OpenSSH 5.6
|
||||
`- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
|
||||
|
||||
[0;36m# encryption algorithms (ciphers)[0m
|
||||
[0;32m(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
[0;32m(enc) aes192-ctr -- [info] available since OpenSSH 3.7[0m
|
||||
[0;32m(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
[0;31m(enc) arcfour256 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour256 -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 4.2
|
||||
[0;31m(enc) arcfour128 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour128 -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 4.2
|
||||
[0;31m(enc) aes128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes128-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
||||
[0;31m(enc) 3des-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.4, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) 3des-cbc -- [fail] using broken & deprecated 3DES cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
|
||||
[0;31m(enc) blowfish-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;31m `- [fail] disabled since Dropbear SSH 0.53[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) blowfish-cbc -- [fail] using weak & deprecated Blowfish cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
|
||||
[0;31m(enc) cast128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) cast128-cbc -- [fail] using weak & deprecated CAST cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(enc) aes192-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes192-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
[0;31m(enc) aes256-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes256-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47
|
||||
[0;31m(enc) arcfour -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(enc) rijndael-cbc@lysator.liu.se -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) rijndael-cbc@lysator.liu.se -- [fail] using deprecated & non-standardized Rijndael cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
|
||||
|
||||
[0;36m# message authentication code algorithms[0m
|
||||
[0;31m(mac) hmac-md5 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-md5 -- [fail] using broken MD5 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
[0;33m(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
[0;31m(mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
[0;33m(mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using small 64-bit tag size[0m
|
||||
`- [info] available since OpenSSH 4.7
|
||||
[0;31m(mac) hmac-ripemd160 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-ripemd160 -- [fail] using deprecated RIPEMD hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.5.0
|
||||
[0;31m(mac) hmac-ripemd160@openssh.com -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-ripemd160@openssh.com -- [fail] using deprecated RIPEMD hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(mac) hmac-sha1-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-sha1-96 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47
|
||||
[0;31m(mac) hmac-md5-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-md5-96 -- [fail] using broken MD5 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0
|
||||
|
||||
[0;36m# fingerprints[0m
|
||||
[0;32m(fin) ssh-rsa: SHA256:YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4[0m
|
||||
|
||||
[0;36m# algorithm recommendations (for OpenSSH 5.6)[0m
|
||||
[0;31m(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 2048 bits or larger) [0m
|
||||
[0;31m(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 3072 bits or larger) [0m
|
||||
[0;31m(rec) -3des-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes128-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes192-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour128 -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour256 -- enc algorithm to remove [0m
|
||||
@ -136,16 +114,19 @@
|
||||
[0;31m(rec) -cast128-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-md5 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-md5-96 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-ripemd160 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-sha1-96 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -ssh-rsa -- key algorithm to remove [0m
|
||||
[0;31m(rec) -ssh-rsa-cert-v01@openssh.com -- key algorithm to remove [0m
|
||||
[0;33m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;33m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
||||
[0;33m(rec) -aes128-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -aes192-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
||||
|
||||
[0;36m# additional info[0m
|
||||
|
@ -1 +1,275 @@
|
||||
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_5.6", "software": "OpenSSH_5.6"}, "compression": ["none", "zlib@openssh.com"], "enc": ["aes128-ctr", "aes192-ctr", "aes256-ctr", "arcfour256", "arcfour128", "aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "aes192-cbc", "aes256-cbc", "arcfour", "rijndael-cbc@lysator.liu.se"], "fingerprints": [{"fp": "SHA256:nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244", "type": "ssh-rsa"}], "kex": [{"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 1024}, {"algorithm": "diffie-hellman-group-exchange-sha1", "keysize": 1024}, {"algorithm": "diffie-hellman-group14-sha1"}, {"algorithm": "diffie-hellman-group1-sha1"}], "key": [{"algorithm": "ssh-rsa", "keysize": 3072}, {"algorithm": "ssh-rsa-cert-v01@openssh.com", "casize": 1024, "keysize": 3072}], "mac": ["hmac-md5", "hmac-sha1", "umac-64@openssh.com", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"}
|
||||
{
|
||||
"banner": {
|
||||
"comments": null,
|
||||
"protocol": [
|
||||
2,
|
||||
0
|
||||
],
|
||||
"raw": "SSH-2.0-OpenSSH_5.6",
|
||||
"software": "OpenSSH_5.6"
|
||||
},
|
||||
"compression": [
|
||||
"none",
|
||||
"zlib@openssh.com"
|
||||
],
|
||||
"cves": [
|
||||
{
|
||||
"cvssv2": 7.8,
|
||||
"description": "command injection via anomalous argument transfers",
|
||||
"name": "CVE-2020-15778"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "enumerate usernames due to timing discrepancies",
|
||||
"name": "CVE-2018-15473"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "readonly bypass via sftp",
|
||||
"name": "CVE-2017-15906"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "enumerate usernames via challenge response",
|
||||
"name": "CVE-2016-20012"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.5,
|
||||
"description": "bypass command restrictions via crafted X11 forwarding data",
|
||||
"name": "CVE-2016-3115"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.0,
|
||||
"description": "cause DoS via crafted network traffic (out of bounds read)",
|
||||
"name": "CVE-2016-1907"
|
||||
},
|
||||
{
|
||||
"cvssv2": 6.9,
|
||||
"description": "privilege escalation via leveraging sshd uid",
|
||||
"name": "CVE-2015-6564"
|
||||
},
|
||||
{
|
||||
"cvssv2": 1.9,
|
||||
"description": "conduct impersonation attack",
|
||||
"name": "CVE-2015-6563"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.8,
|
||||
"description": "bypass environment restrictions via specific string before wildcard",
|
||||
"name": "CVE-2014-2532"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.5,
|
||||
"description": "cause DoS via triggering error condition (memory corruption)",
|
||||
"name": "CVE-2014-1692"
|
||||
},
|
||||
{
|
||||
"cvssv2": 3.5,
|
||||
"description": "leak data via debug messages",
|
||||
"name": "CVE-2012-0814"
|
||||
},
|
||||
{
|
||||
"cvssv2": 3.5,
|
||||
"description": "cause DoS via large value in certain length field (memory consumption)",
|
||||
"name": "CVE-2011-5000"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.0,
|
||||
"description": "cause DoS via large number of connections (slot exhaustion)",
|
||||
"name": "CVE-2010-5107"
|
||||
},
|
||||
{
|
||||
"cvssv2": 4.0,
|
||||
"description": "cause DoS via crafted glob expression (CPU and memory consumption)",
|
||||
"name": "CVE-2010-4755"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.5,
|
||||
"description": "bypass authentication check via crafted values",
|
||||
"name": "CVE-2010-4478"
|
||||
}
|
||||
],
|
||||
"enc": [
|
||||
"aes128-ctr",
|
||||
"aes192-ctr",
|
||||
"aes256-ctr",
|
||||
"arcfour256",
|
||||
"arcfour128",
|
||||
"aes128-cbc",
|
||||
"3des-cbc",
|
||||
"blowfish-cbc",
|
||||
"cast128-cbc",
|
||||
"aes192-cbc",
|
||||
"aes256-cbc",
|
||||
"arcfour",
|
||||
"rijndael-cbc@lysator.liu.se"
|
||||
],
|
||||
"fingerprints": [
|
||||
{
|
||||
"hash": "nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244",
|
||||
"hash_alg": "SHA256",
|
||||
"hostkey": "ssh-rsa"
|
||||
},
|
||||
{
|
||||
"hash": "18:e2:51:fe:21:6c:78:d0:b8:cf:32:d4:bd:56:42:e1",
|
||||
"hash_alg": "MD5",
|
||||
"hostkey": "ssh-rsa"
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"algorithm": "diffie-hellman-group-exchange-sha256",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group-exchange-sha1",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group14-sha1"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group1-sha1"
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"algorithm": "ssh-rsa",
|
||||
"keysize": 3072
|
||||
},
|
||||
{
|
||||
"algorithm": "ssh-rsa-cert-v01@openssh.com",
|
||||
"ca_algorithm": "ssh-rsa",
|
||||
"casize": 1024,
|
||||
"keysize": 3072
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
"hmac-md5",
|
||||
"hmac-sha1",
|
||||
"umac-64@openssh.com",
|
||||
"hmac-ripemd160",
|
||||
"hmac-ripemd160@openssh.com",
|
||||
"hmac-sha1-96",
|
||||
"hmac-md5-96"
|
||||
],
|
||||
"recommendations": {
|
||||
"critical": {
|
||||
"chg": {
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group-exchange-sha256",
|
||||
"notes": "increase modulus size to 3072 bits or larger"
|
||||
}
|
||||
]
|
||||
},
|
||||
"del": {
|
||||
"enc": [
|
||||
{
|
||||
"name": "3des-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour128",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour256",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "blowfish-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "cast128-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "rijndael-cbc@lysator.liu.se",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group14-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "diffie-hellman-group1-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "diffie-hellman-group-exchange-sha1",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"name": "ssh-rsa",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ssh-rsa-cert-v01@openssh.com",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "hmac-md5",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-md5-96",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-ripemd160",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-ripemd160@openssh.com",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha1-96",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"del": {
|
||||
"enc": [
|
||||
{
|
||||
"name": "aes128-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "aes192-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "aes256-cbc",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "umac-64@openssh.com",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"target": "localhost:2222"
|
||||
}
|
||||
|
@ -5,7 +5,10 @@
|
||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||
|
||||
[0;36m# security[0m
|
||||
[0;33m(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepencies[0m
|
||||
[0;33m(cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers[0m
|
||||
[0;33m(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepancies[0m
|
||||
[0;33m(cve) CVE-2017-15906 -- (CVSSv2: 5.3) readonly bypass via sftp[0m
|
||||
[0;33m(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response[0m
|
||||
[0;33m(cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data[0m
|
||||
[0;33m(cve) CVE-2016-1907 -- (CVSSv2: 5.0) cause DoS via crafted network traffic (out of bounds read)[0m
|
||||
[0;33m(cve) CVE-2015-6564 -- (CVSSv2: 6.9) privilege escalation via leveraging sshd uid[0m
|
||||
@ -22,112 +25,87 @@
|
||||
[0;31m(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||
`- [info] available since OpenSSH 4.4
|
||||
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
[0;33m(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing 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
|
||||
`- [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 `- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;31m `- [fail] disabled (in client) since OpenSSH 7.0, logjam attack[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[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
|
||||
`- [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
|
||||
|
||||
[0;36m# host-key algorithms[0m
|
||||
[0;31m(key) ssh-rsa (3072-bit) -- [fail] using weak hashing algorithm[0m
|
||||
[0;31m(key) ssh-rsa (3072-bit) -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
|
||||
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2
|
||||
[0;31m(key) ssh-rsa-cert-v01@openssh.com (3072-bit cert/1024-bit CA) -- [fail] using weak hashing algorithm[0m
|
||||
[0;31m `- [fail] using small 1024-bit modulus[0m
|
||||
`- [info] available since OpenSSH 5.6
|
||||
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2
|
||||
`- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
|
||||
[0;31m(key) ssh-rsa-cert-v01@openssh.com (3072-bit cert/1024-bit RSA CA) -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;31m `- [fail] using small 1024-bit CA key modulus[0m
|
||||
`- [info] available since OpenSSH 5.6
|
||||
`- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
|
||||
|
||||
[0;36m# encryption algorithms (ciphers)[0m
|
||||
[0;32m(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
[0;32m(enc) aes192-ctr -- [info] available since OpenSSH 3.7[0m
|
||||
[0;32m(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
[0;31m(enc) arcfour256 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour256 -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 4.2
|
||||
[0;31m(enc) arcfour128 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour128 -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 4.2
|
||||
[0;31m(enc) aes128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes128-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
||||
[0;31m(enc) 3des-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.4, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) 3des-cbc -- [fail] using broken & deprecated 3DES cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
|
||||
[0;31m(enc) blowfish-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;31m `- [fail] disabled since Dropbear SSH 0.53[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) blowfish-cbc -- [fail] using weak & deprecated Blowfish cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
|
||||
[0;31m(enc) cast128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) cast128-cbc -- [fail] using weak & deprecated CAST cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(enc) aes192-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes192-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
[0;31m(enc) aes256-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes256-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47
|
||||
[0;31m(enc) arcfour -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(enc) rijndael-cbc@lysator.liu.se -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) rijndael-cbc@lysator.liu.se -- [fail] using deprecated & non-standardized Rijndael cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
|
||||
|
||||
[0;36m# message authentication code algorithms[0m
|
||||
[0;31m(mac) hmac-md5 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-md5 -- [fail] using broken MD5 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
[0;33m(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
[0;31m(mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
[0;33m(mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using small 64-bit tag size[0m
|
||||
`- [info] available since OpenSSH 4.7
|
||||
[0;31m(mac) hmac-ripemd160 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-ripemd160 -- [fail] using deprecated RIPEMD hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.5.0
|
||||
[0;31m(mac) hmac-ripemd160@openssh.com -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-ripemd160@openssh.com -- [fail] using deprecated RIPEMD hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(mac) hmac-sha1-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-sha1-96 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47
|
||||
[0;31m(mac) hmac-md5-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-md5-96 -- [fail] using broken MD5 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0
|
||||
|
||||
[0;36m# fingerprints[0m
|
||||
[0;32m(fin) ssh-rsa: SHA256:nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244[0m
|
||||
|
||||
[0;36m# algorithm recommendations (for OpenSSH 5.6)[0m
|
||||
[0;31m(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 2048 bits or larger) [0m
|
||||
[0;31m(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 3072 bits or larger) [0m
|
||||
[0;31m(rec) -3des-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes128-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes192-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour128 -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour256 -- enc algorithm to remove [0m
|
||||
@ -135,16 +113,19 @@
|
||||
[0;31m(rec) -cast128-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-md5 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-md5-96 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-ripemd160 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-sha1-96 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -ssh-rsa -- key algorithm to remove [0m
|
||||
[0;31m(rec) -ssh-rsa-cert-v01@openssh.com -- key algorithm to remove [0m
|
||||
[0;33m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;33m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
||||
[0;33m(rec) -aes128-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -aes192-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
||||
|
||||
[0;36m# additional info[0m
|
||||
|
@ -1 +1,275 @@
|
||||
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_5.6", "software": "OpenSSH_5.6"}, "compression": ["none", "zlib@openssh.com"], "enc": ["aes128-ctr", "aes192-ctr", "aes256-ctr", "arcfour256", "arcfour128", "aes128-cbc", "3des-cbc", "blowfish-cbc", "cast128-cbc", "aes192-cbc", "aes256-cbc", "arcfour", "rijndael-cbc@lysator.liu.se"], "fingerprints": [{"fp": "SHA256:nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244", "type": "ssh-rsa"}], "kex": [{"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 1024}, {"algorithm": "diffie-hellman-group-exchange-sha1", "keysize": 1024}, {"algorithm": "diffie-hellman-group14-sha1"}, {"algorithm": "diffie-hellman-group1-sha1"}], "key": [{"algorithm": "ssh-rsa", "keysize": 3072}, {"algorithm": "ssh-rsa-cert-v01@openssh.com", "casize": 3072, "keysize": 3072}], "mac": ["hmac-md5", "hmac-sha1", "umac-64@openssh.com", "hmac-ripemd160", "hmac-ripemd160@openssh.com", "hmac-sha1-96", "hmac-md5-96"], "target": "localhost"}
|
||||
{
|
||||
"banner": {
|
||||
"comments": null,
|
||||
"protocol": [
|
||||
2,
|
||||
0
|
||||
],
|
||||
"raw": "SSH-2.0-OpenSSH_5.6",
|
||||
"software": "OpenSSH_5.6"
|
||||
},
|
||||
"compression": [
|
||||
"none",
|
||||
"zlib@openssh.com"
|
||||
],
|
||||
"cves": [
|
||||
{
|
||||
"cvssv2": 7.8,
|
||||
"description": "command injection via anomalous argument transfers",
|
||||
"name": "CVE-2020-15778"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "enumerate usernames due to timing discrepancies",
|
||||
"name": "CVE-2018-15473"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "readonly bypass via sftp",
|
||||
"name": "CVE-2017-15906"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "enumerate usernames via challenge response",
|
||||
"name": "CVE-2016-20012"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.5,
|
||||
"description": "bypass command restrictions via crafted X11 forwarding data",
|
||||
"name": "CVE-2016-3115"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.0,
|
||||
"description": "cause DoS via crafted network traffic (out of bounds read)",
|
||||
"name": "CVE-2016-1907"
|
||||
},
|
||||
{
|
||||
"cvssv2": 6.9,
|
||||
"description": "privilege escalation via leveraging sshd uid",
|
||||
"name": "CVE-2015-6564"
|
||||
},
|
||||
{
|
||||
"cvssv2": 1.9,
|
||||
"description": "conduct impersonation attack",
|
||||
"name": "CVE-2015-6563"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.8,
|
||||
"description": "bypass environment restrictions via specific string before wildcard",
|
||||
"name": "CVE-2014-2532"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.5,
|
||||
"description": "cause DoS via triggering error condition (memory corruption)",
|
||||
"name": "CVE-2014-1692"
|
||||
},
|
||||
{
|
||||
"cvssv2": 3.5,
|
||||
"description": "leak data via debug messages",
|
||||
"name": "CVE-2012-0814"
|
||||
},
|
||||
{
|
||||
"cvssv2": 3.5,
|
||||
"description": "cause DoS via large value in certain length field (memory consumption)",
|
||||
"name": "CVE-2011-5000"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.0,
|
||||
"description": "cause DoS via large number of connections (slot exhaustion)",
|
||||
"name": "CVE-2010-5107"
|
||||
},
|
||||
{
|
||||
"cvssv2": 4.0,
|
||||
"description": "cause DoS via crafted glob expression (CPU and memory consumption)",
|
||||
"name": "CVE-2010-4755"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.5,
|
||||
"description": "bypass authentication check via crafted values",
|
||||
"name": "CVE-2010-4478"
|
||||
}
|
||||
],
|
||||
"enc": [
|
||||
"aes128-ctr",
|
||||
"aes192-ctr",
|
||||
"aes256-ctr",
|
||||
"arcfour256",
|
||||
"arcfour128",
|
||||
"aes128-cbc",
|
||||
"3des-cbc",
|
||||
"blowfish-cbc",
|
||||
"cast128-cbc",
|
||||
"aes192-cbc",
|
||||
"aes256-cbc",
|
||||
"arcfour",
|
||||
"rijndael-cbc@lysator.liu.se"
|
||||
],
|
||||
"fingerprints": [
|
||||
{
|
||||
"hash": "nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244",
|
||||
"hash_alg": "SHA256",
|
||||
"hostkey": "ssh-rsa"
|
||||
},
|
||||
{
|
||||
"hash": "18:e2:51:fe:21:6c:78:d0:b8:cf:32:d4:bd:56:42:e1",
|
||||
"hash_alg": "MD5",
|
||||
"hostkey": "ssh-rsa"
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"algorithm": "diffie-hellman-group-exchange-sha256",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group-exchange-sha1",
|
||||
"keysize": 1024
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group14-sha1"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group1-sha1"
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"algorithm": "ssh-rsa",
|
||||
"keysize": 3072
|
||||
},
|
||||
{
|
||||
"algorithm": "ssh-rsa-cert-v01@openssh.com",
|
||||
"ca_algorithm": "ssh-rsa",
|
||||
"casize": 3072,
|
||||
"keysize": 3072
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
"hmac-md5",
|
||||
"hmac-sha1",
|
||||
"umac-64@openssh.com",
|
||||
"hmac-ripemd160",
|
||||
"hmac-ripemd160@openssh.com",
|
||||
"hmac-sha1-96",
|
||||
"hmac-md5-96"
|
||||
],
|
||||
"recommendations": {
|
||||
"critical": {
|
||||
"chg": {
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group-exchange-sha256",
|
||||
"notes": "increase modulus size to 3072 bits or larger"
|
||||
}
|
||||
]
|
||||
},
|
||||
"del": {
|
||||
"enc": [
|
||||
{
|
||||
"name": "3des-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour128",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "arcfour256",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "blowfish-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "cast128-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "rijndael-cbc@lysator.liu.se",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group14-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "diffie-hellman-group1-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "diffie-hellman-group-exchange-sha1",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"name": "ssh-rsa",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ssh-rsa-cert-v01@openssh.com",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "hmac-md5",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-md5-96",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-ripemd160",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-ripemd160@openssh.com",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha1-96",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"del": {
|
||||
"enc": [
|
||||
{
|
||||
"name": "aes128-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "aes192-cbc",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "aes256-cbc",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "umac-64@openssh.com",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"target": "localhost:2222"
|
||||
}
|
||||
|
@ -5,7 +5,10 @@
|
||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||
|
||||
[0;36m# security[0m
|
||||
[0;33m(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepencies[0m
|
||||
[0;33m(cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers[0m
|
||||
[0;33m(cve) CVE-2018-15473 -- (CVSSv2: 5.3) enumerate usernames due to timing discrepancies[0m
|
||||
[0;33m(cve) CVE-2017-15906 -- (CVSSv2: 5.3) readonly bypass via sftp[0m
|
||||
[0;33m(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response[0m
|
||||
[0;33m(cve) CVE-2016-3115 -- (CVSSv2: 5.5) bypass command restrictions via crafted X11 forwarding data[0m
|
||||
[0;33m(cve) CVE-2016-1907 -- (CVSSv2: 5.0) cause DoS via crafted network traffic (out of bounds read)[0m
|
||||
[0;33m(cve) CVE-2015-6564 -- (CVSSv2: 6.9) privilege escalation via leveraging sshd uid[0m
|
||||
@ -22,111 +25,86 @@
|
||||
[0;31m(kex) diffie-hellman-group-exchange-sha256 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||
`- [info] available since OpenSSH 4.4
|
||||
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
[0;33m(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing 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
|
||||
`- [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 `- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;31m `- [fail] disabled (in client) since OpenSSH 7.0, logjam attack[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[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
|
||||
`- [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
|
||||
|
||||
[0;36m# host-key algorithms[0m
|
||||
[0;31m(key) ssh-rsa (3072-bit) -- [fail] using weak hashing algorithm[0m
|
||||
[0;31m(key) ssh-rsa (3072-bit) -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
|
||||
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2
|
||||
[0;31m(key) ssh-rsa-cert-v01@openssh.com (3072-bit cert/3072-bit CA) -- [fail] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 5.6
|
||||
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2
|
||||
`- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
|
||||
[0;31m(key) ssh-rsa-cert-v01@openssh.com (3072-bit cert/3072-bit RSA CA) -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
`- [info] available since OpenSSH 5.6
|
||||
`- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
|
||||
|
||||
[0;36m# encryption algorithms (ciphers)[0m
|
||||
[0;32m(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
[0;32m(enc) aes192-ctr -- [info] available since OpenSSH 3.7[0m
|
||||
[0;32m(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
[0;31m(enc) arcfour256 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour256 -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 4.2
|
||||
[0;31m(enc) arcfour128 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour128 -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 4.2
|
||||
[0;31m(enc) aes128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes128-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.28
|
||||
[0;31m(enc) 3des-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.4, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) 3des-cbc -- [fail] using broken & deprecated 3DES cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
|
||||
[0;31m(enc) blowfish-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;31m `- [fail] disabled since Dropbear SSH 0.53[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) blowfish-cbc -- [fail] using weak & deprecated Blowfish cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 1.2.2, Dropbear SSH 0.28
|
||||
[0;31m(enc) cast128-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) cast128-cbc -- [fail] using weak & deprecated CAST cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m `- [warn] using small 64-bit block size[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(enc) aes192-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes192-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
[0;31m(enc) aes256-cbc -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
[0;33m(enc) aes256-cbc -- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0, Dropbear SSH 0.47
|
||||
[0;31m(enc) arcfour -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;33m `- [warn] using weak cipher[0m
|
||||
[0;31m(enc) arcfour -- [fail] using broken RC4 cipher[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(enc) rijndael-cbc@lysator.liu.se -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(enc) rijndael-cbc@lysator.liu.se -- [fail] using deprecated & non-standardized Rijndael cipher[0m
|
||||
[0;33m `- [warn] using weak cipher mode[0m
|
||||
`- [info] available since OpenSSH 2.3.0
|
||||
`- [info] disabled in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0
|
||||
|
||||
[0;36m# message authentication code algorithms[0m
|
||||
[0;31m(mac) hmac-md5 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-md5 -- [fail] using broken MD5 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
[0;33m(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
[0;31m(mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
[0;33m(mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using small 64-bit tag size[0m
|
||||
`- [info] available since OpenSSH 4.7
|
||||
[0;31m(mac) hmac-ripemd160 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-ripemd160 -- [fail] using deprecated RIPEMD hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.5.0
|
||||
[0;31m(mac) hmac-ripemd160@openssh.com -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-ripemd160@openssh.com -- [fail] using deprecated RIPEMD hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.1.0
|
||||
[0;31m(mac) hmac-sha1-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-sha1-96 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.47
|
||||
[0;31m(mac) hmac-md5-96 -- [fail] removed (in server) since OpenSSH 6.7, unsafe algorithm[0m
|
||||
[0;33m `- [warn] disabled (in client) since OpenSSH 7.2, legacy algorithm[0m
|
||||
[0;31m(mac) hmac-md5-96 -- [fail] using broken MD5 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0
|
||||
|
||||
[0;36m# fingerprints[0m
|
||||
[0;32m(fin) ssh-rsa: SHA256:nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244[0m
|
||||
|
||||
[0;36m# algorithm recommendations (for OpenSSH 5.6)[0m
|
||||
[0;31m(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 2048 bits or larger) [0m
|
||||
[0;31m(rec) !diffie-hellman-group-exchange-sha256 -- kex algorithm to change (increase modulus size to 3072 bits or larger) [0m
|
||||
[0;31m(rec) -3des-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes128-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes192-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour128 -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -arcfour256 -- enc algorithm to remove [0m
|
||||
@ -134,16 +112,19 @@
|
||||
[0;31m(rec) -cast128-cbc -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group-exchange-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group1-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-md5 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-md5-96 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-ripemd160 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-ripemd160@openssh.com -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -hmac-sha1-96 -- mac algorithm to remove [0m
|
||||
[0;31m(rec) -rijndael-cbc@lysator.liu.se -- enc algorithm to remove [0m
|
||||
[0;31m(rec) -ssh-rsa -- key algorithm to remove [0m
|
||||
[0;31m(rec) -ssh-rsa-cert-v01@openssh.com -- key algorithm to remove [0m
|
||||
[0;33m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;33m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
||||
[0;33m(rec) -aes128-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -aes192-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -aes256-cbc -- enc algorithm to remove [0m
|
||||
[0;33m(rec) -umac-64@openssh.com -- mac algorithm to remove [0m
|
||||
|
||||
[0;36m# additional info[0m
|
||||
|
@ -1 +1,31 @@
|
||||
{"errors": [], "host": "localhost", "passed": true, "policy": "Hardened OpenSSH Server v8.0 (version 1)"}
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"actual": [
|
||||
"3072"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"4096"
|
||||
],
|
||||
"mismatched_field": "Host key (rsa-sha2-256) sizes"
|
||||
},
|
||||
{
|
||||
"actual": [
|
||||
"3072"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"4096"
|
||||
],
|
||||
"mismatched_field": "Host key (rsa-sha2-512) sizes"
|
||||
}
|
||||
],
|
||||
"host": "localhost",
|
||||
"passed": false,
|
||||
"policy": "Hardened OpenSSH Server v8.0 (version 2)"
|
||||
}
|
||||
|
@ -1,3 +1,13 @@
|
||||
Host: localhost:2222
|
||||
Policy: Hardened OpenSSH Server v8.0 (version 1)
|
||||
Result: [0;32m✔ Passed[0m
|
||||
Policy: Hardened OpenSSH Server v8.0 (version 2)
|
||||
Result: [0;31m❌ Failed![0m
|
||||
[0;33m
|
||||
Errors:
|
||||
* Host key (rsa-sha2-256) sizes did not match.
|
||||
- Expected: 4096
|
||||
- Actual: 3072
|
||||
|
||||
* Host key (rsa-sha2-512) sizes did not match.
|
||||
- Expected: 4096
|
||||
- Actual: 3072
|
||||
[0m
|
||||
|
@ -1 +1,54 @@
|
||||
{"errors": [{"actual": ["umac-64-etm@openssh.com", "umac-128-etm@openssh.com", "hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "hmac-sha1-etm@openssh.com", "umac-64@openssh.com", "umac-128@openssh.com", "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1"], "expected_optional": [""], "expected_required": ["hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "umac-128-etm@openssh.com"], "mismatched_field": "MACs"}], "host": "localhost", "passed": false, "policy": "Hardened OpenSSH Server v8.0 (version 1)"}
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"actual": [
|
||||
"3072"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"4096"
|
||||
],
|
||||
"mismatched_field": "Host key (rsa-sha2-256) sizes"
|
||||
},
|
||||
{
|
||||
"actual": [
|
||||
"3072"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"4096"
|
||||
],
|
||||
"mismatched_field": "Host key (rsa-sha2-512) sizes"
|
||||
},
|
||||
{
|
||||
"actual": [
|
||||
"umac-64-etm@openssh.com",
|
||||
"umac-128-etm@openssh.com",
|
||||
"hmac-sha2-256-etm@openssh.com",
|
||||
"hmac-sha2-512-etm@openssh.com",
|
||||
"hmac-sha1-etm@openssh.com",
|
||||
"umac-64@openssh.com",
|
||||
"umac-128@openssh.com",
|
||||
"hmac-sha2-256",
|
||||
"hmac-sha2-512",
|
||||
"hmac-sha1"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"hmac-sha2-256-etm@openssh.com",
|
||||
"hmac-sha2-512-etm@openssh.com",
|
||||
"umac-128-etm@openssh.com"
|
||||
],
|
||||
"mismatched_field": "MACs"
|
||||
}
|
||||
],
|
||||
"host": "localhost",
|
||||
"passed": false,
|
||||
"policy": "Hardened OpenSSH Server v8.0 (version 2)"
|
||||
}
|
||||
|
@ -1,8 +1,16 @@
|
||||
Host: localhost:2222
|
||||
Policy: Hardened OpenSSH Server v8.0 (version 1)
|
||||
Policy: Hardened OpenSSH Server v8.0 (version 2)
|
||||
Result: [0;31m❌ Failed![0m
|
||||
[0;33m
|
||||
Errors:
|
||||
* Host key (rsa-sha2-256) sizes did not match.
|
||||
- Expected: 4096
|
||||
- Actual: 3072
|
||||
|
||||
* Host key (rsa-sha2-512) sizes did not match.
|
||||
- Expected: 4096
|
||||
- Actual: 3072
|
||||
|
||||
* MACs did not match.
|
||||
- Expected: hmac-sha2-256-etm@openssh.com, hmac-sha2-512-etm@openssh.com, umac-128-etm@openssh.com
|
||||
- Actual: umac-64-etm@openssh.com, umac-128-etm@openssh.com, hmac-sha2-256-etm@openssh.com, hmac-sha2-512-etm@openssh.com, hmac-sha1-etm@openssh.com, umac-64@openssh.com, umac-128@openssh.com, hmac-sha2-256, hmac-sha2-512, hmac-sha1
|
||||
|
@ -1 +1,6 @@
|
||||
{"errors": [], "host": "localhost", "passed": true, "policy": "Docker policy: test11 (version 1)"}
|
||||
{
|
||||
"errors": [],
|
||||
"host": "localhost",
|
||||
"passed": true,
|
||||
"policy": "Docker policy: test11 (version 1)"
|
||||
}
|
||||
|
@ -1,3 +1,12 @@
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
Host: localhost:2222
|
||||
Policy: Docker policy: test11 (version 1)
|
||||
Result: [0;32m✔ Passed[0m
|
||||
|
@ -1 +1,43 @@
|
||||
{"errors": [{"actual": ["3072"], "expected_optional": [""], "expected_required": ["4096"], "mismatched_field": "RSA host key (rsa-sha2-256) sizes"}, {"actual": ["3072"], "expected_optional": [""], "expected_required": ["4096"], "mismatched_field": "RSA host key (rsa-sha2-512) sizes"}, {"actual": ["3072"], "expected_optional": [""], "expected_required": ["4096"], "mismatched_field": "RSA host key (ssh-rsa) sizes"}], "host": "localhost", "passed": false, "policy": "Docker policy: test12 (version 1)"}
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"actual": [
|
||||
"3072"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"4096"
|
||||
],
|
||||
"mismatched_field": "Host key (rsa-sha2-256) sizes"
|
||||
},
|
||||
{
|
||||
"actual": [
|
||||
"3072"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"4096"
|
||||
],
|
||||
"mismatched_field": "Host key (rsa-sha2-512) sizes"
|
||||
},
|
||||
{
|
||||
"actual": [
|
||||
"3072"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"4096"
|
||||
],
|
||||
"mismatched_field": "Host key (ssh-rsa) sizes"
|
||||
}
|
||||
],
|
||||
"host": "localhost",
|
||||
"passed": false,
|
||||
"policy": "Docker policy: test12 (version 1)"
|
||||
}
|
||||
|
@ -1,17 +1,26 @@
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
Host: localhost:2222
|
||||
Policy: Docker policy: test12 (version 1)
|
||||
Result: [0;31m❌ Failed![0m
|
||||
[0;33m
|
||||
Errors:
|
||||
* RSA host key (rsa-sha2-256) sizes did not match.
|
||||
* Host key (rsa-sha2-256) sizes did not match.
|
||||
- Expected: 4096
|
||||
- Actual: 3072
|
||||
|
||||
* RSA host key (rsa-sha2-512) sizes did not match.
|
||||
* Host key (rsa-sha2-512) sizes did not match.
|
||||
- Expected: 4096
|
||||
- Actual: 3072
|
||||
|
||||
* RSA host key (ssh-rsa) sizes did not match.
|
||||
* Host key (ssh-rsa) sizes did not match.
|
||||
- Expected: 4096
|
||||
- Actual: 3072
|
||||
[0m
|
||||
|
@ -1 +1,6 @@
|
||||
{"errors": [], "host": "localhost", "passed": true, "policy": "Docker policy: test13 (version 1)"}
|
||||
{
|
||||
"errors": [],
|
||||
"host": "localhost",
|
||||
"passed": true,
|
||||
"policy": "Docker policy: test13 (version 1)"
|
||||
}
|
||||
|
@ -1,3 +1,15 @@
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
Host: localhost:2222
|
||||
Policy: Docker policy: test13 (version 1)
|
||||
Result: [0;32m✔ Passed[0m
|
||||
|
@ -1 +1,19 @@
|
||||
{"errors": [{"actual": ["2048"], "expected_optional": [""], "expected_required": ["4096"], "mismatched_field": "Group exchange (diffie-hellman-group-exchange-sha256) modulus sizes"}], "host": "localhost", "passed": false, "policy": "Docker policy: test14 (version 1)"}
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"actual": [
|
||||
"2048"
|
||||
],
|
||||
"expected_optional": [
|
||||
""
|
||||
],
|
||||
"expected_required": [
|
||||
"4096"
|
||||
],
|
||||
"mismatched_field": "Group exchange (diffie-hellman-group-exchange-sha256) modulus sizes"
|
||||
}
|
||||
],
|
||||
"host": "localhost",
|
||||
"passed": false,
|
||||
"policy": "Docker policy: test14 (version 1)"
|
||||
}
|
||||
|
@ -1,3 +1,15 @@
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
|
||||
WARNING: this policy is using deprecated features. Future versions of ssh-audit may remove support for them. Re-generating the policy file is perhaps the most straight-forward way of resolving this issue. Manually converting the 'hostkey_size_*', 'cakey_size_*', and 'dh_modulus_size_*' directives into the new format is another option.
|
||||
|
||||
Host: localhost:2222
|
||||
Policy: Docker policy: test14 (version 1)
|
||||
Result: [0;31m❌ Failed![0m
|
||||
|
@ -1 +1,6 @@
|
||||
{"errors": [], "host": "localhost", "passed": true, "policy": "Docker policy: test6 (version 1)"}
|
||||
{
|
||||
"errors": [],
|
||||
"host": "localhost",
|
||||
"passed": true,
|
||||
"policy": "Docker policy: test6 (version 1)"
|
||||
}
|
||||
|
@ -1 +1,209 @@
|
||||
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_8.0", "software": "OpenSSH_8.0"}, "compression": ["none", "zlib@openssh.com"], "enc": ["chacha20-poly1305@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "aes256-gcm@openssh.com"], "fingerprints": [{"fp": "SHA256:UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU", "type": "ssh-ed25519"}, {"fp": "SHA256:nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244", "type": "ssh-rsa"}], "kex": [{"algorithm": "curve25519-sha256"}, {"algorithm": "curve25519-sha256@libssh.org"}, {"algorithm": "ecdh-sha2-nistp256"}, {"algorithm": "ecdh-sha2-nistp384"}, {"algorithm": "ecdh-sha2-nistp521"}, {"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 2048}, {"algorithm": "diffie-hellman-group16-sha512"}, {"algorithm": "diffie-hellman-group18-sha512"}, {"algorithm": "diffie-hellman-group14-sha256"}, {"algorithm": "diffie-hellman-group14-sha1"}], "key": [{"algorithm": "rsa-sha2-512", "keysize": 3072}, {"algorithm": "rsa-sha2-256", "keysize": 3072}, {"algorithm": "ssh-rsa", "keysize": 3072}, {"algorithm": "ecdsa-sha2-nistp256"}, {"algorithm": "ssh-ed25519"}], "mac": ["umac-64-etm@openssh.com", "umac-128-etm@openssh.com", "hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "hmac-sha1-etm@openssh.com", "umac-64@openssh.com", "umac-128@openssh.com", "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1"], "target": "localhost"}
|
||||
{
|
||||
"banner": {
|
||||
"comments": null,
|
||||
"protocol": [
|
||||
2,
|
||||
0
|
||||
],
|
||||
"raw": "SSH-2.0-OpenSSH_8.0",
|
||||
"software": "OpenSSH_8.0"
|
||||
},
|
||||
"compression": [
|
||||
"none",
|
||||
"zlib@openssh.com"
|
||||
],
|
||||
"cves": [
|
||||
{
|
||||
"cvssv2": 7.0,
|
||||
"description": "privilege escalation via supplemental groups",
|
||||
"name": "CVE-2021-41617"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.8,
|
||||
"description": "command injection via anomalous argument transfers",
|
||||
"name": "CVE-2020-15778"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.8,
|
||||
"description": "memory corruption and local code execution via pre-authentication integer overflow",
|
||||
"name": "CVE-2019-16905"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "enumerate usernames via challenge response",
|
||||
"name": "CVE-2016-20012"
|
||||
}
|
||||
],
|
||||
"enc": [
|
||||
"chacha20-poly1305@openssh.com",
|
||||
"aes128-ctr",
|
||||
"aes192-ctr",
|
||||
"aes256-ctr",
|
||||
"aes128-gcm@openssh.com",
|
||||
"aes256-gcm@openssh.com"
|
||||
],
|
||||
"fingerprints": [
|
||||
{
|
||||
"hash": "UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU",
|
||||
"hash_alg": "SHA256",
|
||||
"hostkey": "ssh-ed25519"
|
||||
},
|
||||
{
|
||||
"hash": "1e:0c:7b:34:73:bf:52:41:b0:f9:d1:a9:ab:98:c7:c9",
|
||||
"hash_alg": "MD5",
|
||||
"hostkey": "ssh-ed25519"
|
||||
},
|
||||
{
|
||||
"hash": "nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244",
|
||||
"hash_alg": "SHA256",
|
||||
"hostkey": "ssh-rsa"
|
||||
},
|
||||
{
|
||||
"hash": "18:e2:51:fe:21:6c:78:d0:b8:cf:32:d4:bd:56:42:e1",
|
||||
"hash_alg": "MD5",
|
||||
"hostkey": "ssh-rsa"
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"algorithm": "curve25519-sha256"
|
||||
},
|
||||
{
|
||||
"algorithm": "curve25519-sha256@libssh.org"
|
||||
},
|
||||
{
|
||||
"algorithm": "ecdh-sha2-nistp256"
|
||||
},
|
||||
{
|
||||
"algorithm": "ecdh-sha2-nistp384"
|
||||
},
|
||||
{
|
||||
"algorithm": "ecdh-sha2-nistp521"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group-exchange-sha256",
|
||||
"keysize": 2048
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group16-sha512"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group18-sha512"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group14-sha256"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group14-sha1"
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"algorithm": "rsa-sha2-512",
|
||||
"keysize": 3072
|
||||
},
|
||||
{
|
||||
"algorithm": "rsa-sha2-256",
|
||||
"keysize": 3072
|
||||
},
|
||||
{
|
||||
"algorithm": "ssh-rsa",
|
||||
"keysize": 3072
|
||||
},
|
||||
{
|
||||
"algorithm": "ecdsa-sha2-nistp256"
|
||||
},
|
||||
{
|
||||
"algorithm": "ssh-ed25519"
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
"umac-64-etm@openssh.com",
|
||||
"umac-128-etm@openssh.com",
|
||||
"hmac-sha2-256-etm@openssh.com",
|
||||
"hmac-sha2-512-etm@openssh.com",
|
||||
"hmac-sha1-etm@openssh.com",
|
||||
"umac-64@openssh.com",
|
||||
"umac-128@openssh.com",
|
||||
"hmac-sha2-256",
|
||||
"hmac-sha2-512",
|
||||
"hmac-sha1"
|
||||
],
|
||||
"recommendations": {
|
||||
"critical": {
|
||||
"del": {
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group14-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ecdh-sha2-nistp256",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ecdh-sha2-nistp384",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ecdh-sha2-nistp521",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"name": "ecdsa-sha2-nistp256",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ssh-rsa",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "hmac-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha1-etm@openssh.com",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"del": {
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group14-sha256",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "hmac-sha2-256",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha2-512",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "umac-128@openssh.com",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "umac-64-etm@openssh.com",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "umac-64@openssh.com",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"target": "localhost:2222"
|
||||
}
|
||||
|
@ -4,36 +4,48 @@
|
||||
[0;32m(gen) compatibility: OpenSSH 7.4+, Dropbear SSH 2018.76+[0m
|
||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||
|
||||
[0;36m# security[0m
|
||||
[0;33m(cve) CVE-2021-41617 -- (CVSSv2: 7.0) privilege escalation via supplemental groups[0m
|
||||
[0;33m(cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers[0m
|
||||
[0;33m(cve) CVE-2019-16905 -- (CVSSv2: 7.8) memory corruption and local code execution via pre-authentication integer overflow[0m
|
||||
[0;33m(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response[0m
|
||||
|
||||
[0;36m# key exchange algorithms[0m
|
||||
[0;32m(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76[0m
|
||||
[0;32m(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.5, Dropbear SSH 2013.62[0m
|
||||
[0;31m(kex) ecdh-sha2-nistp256 -- [fail] using weak elliptic curves[0m
|
||||
`- [info] default key exchange since OpenSSH 6.4
|
||||
[0;32m(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62[0m
|
||||
`- [info] default key exchange since OpenSSH 6.4
|
||||
[0;31m(kex) ecdh-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||
[0;31m(kex) ecdh-sha2-nistp384 -- [fail] using weak elliptic curves[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
|
||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||
[0;31m(kex) ecdh-sha2-nistp521 -- [fail] using weak elliptic curves[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
|
||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||
[0;32m(kex) diffie-hellman-group-exchange-sha256 (2048-bit) -- [info] available since OpenSSH 4.4[0m
|
||||
[0;33m(kex) diffie-hellman-group-exchange-sha256 (2048-bit) -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||
`- [info] available since OpenSSH 4.4
|
||||
`- [info] A bug in OpenSSH causes it to fall back to a 2048-bit modulus regardless of server configuration (https://bugzilla.mindrot.org/show_bug.cgi?id=2793)
|
||||
[0;32m(kex) diffie-hellman-group16-sha512 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73[0m
|
||||
[0;32m(kex) diffie-hellman-group18-sha512 -- [info] available since OpenSSH 7.3[0m
|
||||
[0;32m(kex) diffie-hellman-group14-sha256 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73[0m
|
||||
[0;33m(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing algorithm[0m
|
||||
[0;33m(kex) diffie-hellman-group14-sha256 -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||
`- [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;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
||||
|
||||
[0;36m# host-key algorithms[0m
|
||||
[0;32m(key) rsa-sha2-512 (3072-bit) -- [info] available since OpenSSH 7.2[0m
|
||||
[0;32m(key) rsa-sha2-256 (3072-bit) -- [info] available since OpenSSH 7.2[0m
|
||||
[0;31m(key) ssh-rsa (3072-bit) -- [fail] using weak hashing algorithm[0m
|
||||
[0;31m(key) ssh-rsa (3072-bit) -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
|
||||
`- [info] a future deprecation notice has been issued in OpenSSH 8.2: https://www.openssh.com/txt/release-8.2
|
||||
[0;31m(key) ecdsa-sha2-nistp256 -- [fail] using weak elliptic curves[0m
|
||||
`- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
|
||||
[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;33m `- [warn] using weak random number generator could reveal the key[0m
|
||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||
[0;32m(key) ssh-ed25519 -- [info] available since OpenSSH 6.5[0m
|
||||
|
||||
[0;36m# encryption algorithms (ciphers)[0m
|
||||
[0;32m(enc) chacha20-poly1305@openssh.com -- [info] available since OpenSSH 6.5[0m
|
||||
`- [info] default cipher since OpenSSH 6.9.
|
||||
`- [info] default cipher since OpenSSH 6.9
|
||||
[0;32m(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
[0;32m(enc) aes192-ctr -- [info] available since OpenSSH 3.7[0m
|
||||
[0;32m(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
@ -46,7 +58,7 @@
|
||||
[0;32m(mac) umac-128-etm@openssh.com -- [info] available since OpenSSH 6.2[0m
|
||||
[0;32m(mac) hmac-sha2-256-etm@openssh.com -- [info] available since OpenSSH 6.2[0m
|
||||
[0;32m(mac) hmac-sha2-512-etm@openssh.com -- [info] available since OpenSSH 6.2[0m
|
||||
[0;33m(mac) hmac-sha1-etm@openssh.com -- [warn] using weak hashing algorithm[0m
|
||||
[0;31m(mac) hmac-sha1-etm@openssh.com -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
`- [info] available since OpenSSH 6.2
|
||||
[0;33m(mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using small 64-bit tag size[0m
|
||||
@ -57,8 +69,8 @@
|
||||
`- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56
|
||||
[0;33m(mac) hmac-sha2-512 -- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56
|
||||
[0;33m(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
[0;31m(mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
|
||||
[0;36m# fingerprints[0m
|
||||
@ -66,14 +78,15 @@
|
||||
[0;32m(fin) ssh-rsa: SHA256:nsWtdJ9Z67Vrf7OsUzQov7esXhsWAfVppArGh25u244[0m
|
||||
|
||||
[0;36m# algorithm recommendations (for OpenSSH 8.0)[0m
|
||||
[0;31m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -ecdh-sha2-nistp256 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -ecdh-sha2-nistp384 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -ecdh-sha2-nistp521 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -ecdsa-sha2-nistp256 -- key 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) -ssh-rsa -- key algorithm to remove [0m
|
||||
[0;33m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;33m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
||||
[0;33m(rec) -hmac-sha1-etm@openssh.com -- mac 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-512 -- mac algorithm to remove [0m
|
||||
[0;33m(rec) -umac-128@openssh.com -- mac algorithm to remove [0m
|
||||
|
@ -1 +1,193 @@
|
||||
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_8.0", "software": "OpenSSH_8.0"}, "compression": ["none", "zlib@openssh.com"], "enc": ["chacha20-poly1305@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "aes256-gcm@openssh.com"], "fingerprints": [{"fp": "SHA256:UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU", "type": "ssh-ed25519"}], "kex": [{"algorithm": "curve25519-sha256"}, {"algorithm": "curve25519-sha256@libssh.org"}, {"algorithm": "ecdh-sha2-nistp256"}, {"algorithm": "ecdh-sha2-nistp384"}, {"algorithm": "ecdh-sha2-nistp521"}, {"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 2048}, {"algorithm": "diffie-hellman-group16-sha512"}, {"algorithm": "diffie-hellman-group18-sha512"}, {"algorithm": "diffie-hellman-group14-sha256"}, {"algorithm": "diffie-hellman-group14-sha1"}], "key": [{"algorithm": "ssh-ed25519"}, {"algorithm": "ssh-ed25519-cert-v01@openssh.com"}], "mac": ["umac-64-etm@openssh.com", "umac-128-etm@openssh.com", "hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "hmac-sha1-etm@openssh.com", "umac-64@openssh.com", "umac-128@openssh.com", "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1"], "target": "localhost"}
|
||||
{
|
||||
"banner": {
|
||||
"comments": null,
|
||||
"protocol": [
|
||||
2,
|
||||
0
|
||||
],
|
||||
"raw": "SSH-2.0-OpenSSH_8.0",
|
||||
"software": "OpenSSH_8.0"
|
||||
},
|
||||
"compression": [
|
||||
"none",
|
||||
"zlib@openssh.com"
|
||||
],
|
||||
"cves": [
|
||||
{
|
||||
"cvssv2": 7.0,
|
||||
"description": "privilege escalation via supplemental groups",
|
||||
"name": "CVE-2021-41617"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.8,
|
||||
"description": "command injection via anomalous argument transfers",
|
||||
"name": "CVE-2020-15778"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.8,
|
||||
"description": "memory corruption and local code execution via pre-authentication integer overflow",
|
||||
"name": "CVE-2019-16905"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "enumerate usernames via challenge response",
|
||||
"name": "CVE-2016-20012"
|
||||
}
|
||||
],
|
||||
"enc": [
|
||||
"chacha20-poly1305@openssh.com",
|
||||
"aes128-ctr",
|
||||
"aes192-ctr",
|
||||
"aes256-ctr",
|
||||
"aes128-gcm@openssh.com",
|
||||
"aes256-gcm@openssh.com"
|
||||
],
|
||||
"fingerprints": [
|
||||
{
|
||||
"hash": "UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU",
|
||||
"hash_alg": "SHA256",
|
||||
"hostkey": "ssh-ed25519"
|
||||
},
|
||||
{
|
||||
"hash": "1e:0c:7b:34:73:bf:52:41:b0:f9:d1:a9:ab:98:c7:c9",
|
||||
"hash_alg": "MD5",
|
||||
"hostkey": "ssh-ed25519"
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"algorithm": "curve25519-sha256"
|
||||
},
|
||||
{
|
||||
"algorithm": "curve25519-sha256@libssh.org"
|
||||
},
|
||||
{
|
||||
"algorithm": "ecdh-sha2-nistp256"
|
||||
},
|
||||
{
|
||||
"algorithm": "ecdh-sha2-nistp384"
|
||||
},
|
||||
{
|
||||
"algorithm": "ecdh-sha2-nistp521"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group-exchange-sha256",
|
||||
"keysize": 2048
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group16-sha512"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group18-sha512"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group14-sha256"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group14-sha1"
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"algorithm": "ssh-ed25519"
|
||||
},
|
||||
{
|
||||
"algorithm": "ssh-ed25519-cert-v01@openssh.com",
|
||||
"ca_algorithm": "ssh-ed25519",
|
||||
"casize": 256
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
"umac-64-etm@openssh.com",
|
||||
"umac-128-etm@openssh.com",
|
||||
"hmac-sha2-256-etm@openssh.com",
|
||||
"hmac-sha2-512-etm@openssh.com",
|
||||
"hmac-sha1-etm@openssh.com",
|
||||
"umac-64@openssh.com",
|
||||
"umac-128@openssh.com",
|
||||
"hmac-sha2-256",
|
||||
"hmac-sha2-512",
|
||||
"hmac-sha1"
|
||||
],
|
||||
"recommendations": {
|
||||
"critical": {
|
||||
"del": {
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group14-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ecdh-sha2-nistp256",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ecdh-sha2-nistp384",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ecdh-sha2-nistp521",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "hmac-sha1",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha1-etm@openssh.com",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"informational": {
|
||||
"add": {
|
||||
"key": [
|
||||
{
|
||||
"name": "rsa-sha2-256",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "rsa-sha2-512",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"del": {
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group14-sha256",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
{
|
||||
"name": "hmac-sha2-256",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "hmac-sha2-512",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "umac-128@openssh.com",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "umac-64-etm@openssh.com",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "umac-64@openssh.com",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"target": "localhost:2222"
|
||||
}
|
||||
|
@ -4,29 +4,41 @@
|
||||
[0;32m(gen) compatibility: OpenSSH 7.4+, Dropbear SSH 2018.76+[0m
|
||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||
|
||||
[0;36m# security[0m
|
||||
[0;33m(cve) CVE-2021-41617 -- (CVSSv2: 7.0) privilege escalation via supplemental groups[0m
|
||||
[0;33m(cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers[0m
|
||||
[0;33m(cve) CVE-2019-16905 -- (CVSSv2: 7.8) memory corruption and local code execution via pre-authentication integer overflow[0m
|
||||
[0;33m(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response[0m
|
||||
|
||||
[0;36m# key exchange algorithms[0m
|
||||
[0;32m(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76[0m
|
||||
[0;32m(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.5, Dropbear SSH 2013.62[0m
|
||||
[0;31m(kex) ecdh-sha2-nistp256 -- [fail] using weak elliptic curves[0m
|
||||
`- [info] default key exchange since OpenSSH 6.4
|
||||
[0;32m(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62[0m
|
||||
`- [info] default key exchange since OpenSSH 6.4
|
||||
[0;31m(kex) ecdh-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency[0m
|
||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||
[0;31m(kex) ecdh-sha2-nistp384 -- [fail] using weak elliptic curves[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
|
||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||
[0;31m(kex) ecdh-sha2-nistp521 -- [fail] using weak elliptic curves[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
|
||||
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
|
||||
[0;32m(kex) diffie-hellman-group-exchange-sha256 (2048-bit) -- [info] available since OpenSSH 4.4[0m
|
||||
[0;33m(kex) diffie-hellman-group-exchange-sha256 (2048-bit) -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||
`- [info] available since OpenSSH 4.4
|
||||
`- [info] A bug in OpenSSH causes it to fall back to a 2048-bit modulus regardless of server configuration (https://bugzilla.mindrot.org/show_bug.cgi?id=2793)
|
||||
[0;32m(kex) diffie-hellman-group16-sha512 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73[0m
|
||||
[0;32m(kex) diffie-hellman-group18-sha512 -- [info] available since OpenSSH 7.3[0m
|
||||
[0;32m(kex) diffie-hellman-group14-sha256 -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73[0m
|
||||
[0;33m(kex) diffie-hellman-group14-sha1 -- [warn] using weak hashing algorithm[0m
|
||||
[0;33m(kex) diffie-hellman-group14-sha256 -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||
`- [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;33m `- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
|
||||
|
||||
[0;36m# host-key algorithms[0m
|
||||
[0;32m(key) ssh-ed25519 -- [info] available since OpenSSH 6.5[0m
|
||||
[0;32m(key) ssh-ed25519-cert-v01@openssh.com -- [info] available since OpenSSH 6.5[0m
|
||||
[0;32m(key) ssh-ed25519-cert-v01@openssh.com (256-bit cert/256-bit ssh-ed25519 CA) -- [info] available since OpenSSH 6.5[0m
|
||||
|
||||
[0;36m# encryption algorithms (ciphers)[0m
|
||||
[0;32m(enc) chacha20-poly1305@openssh.com -- [info] available since OpenSSH 6.5[0m
|
||||
`- [info] default cipher since OpenSSH 6.9.
|
||||
`- [info] default cipher since OpenSSH 6.9
|
||||
[0;32m(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
[0;32m(enc) aes192-ctr -- [info] available since OpenSSH 3.7[0m
|
||||
[0;32m(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
@ -39,7 +51,7 @@
|
||||
[0;32m(mac) umac-128-etm@openssh.com -- [info] available since OpenSSH 6.2[0m
|
||||
[0;32m(mac) hmac-sha2-256-etm@openssh.com -- [info] available since OpenSSH 6.2[0m
|
||||
[0;32m(mac) hmac-sha2-512-etm@openssh.com -- [info] available since OpenSSH 6.2[0m
|
||||
[0;33m(mac) hmac-sha1-etm@openssh.com -- [warn] using weak hashing algorithm[0m
|
||||
[0;31m(mac) hmac-sha1-etm@openssh.com -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
`- [info] available since OpenSSH 6.2
|
||||
[0;33m(mac) umac-64@openssh.com -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using small 64-bit tag size[0m
|
||||
@ -50,22 +62,23 @@
|
||||
`- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56
|
||||
[0;33m(mac) hmac-sha2-512 -- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56
|
||||
[0;33m(mac) hmac-sha1 -- [warn] using encrypt-and-MAC mode[0m
|
||||
[0;33m `- [warn] using weak hashing algorithm[0m
|
||||
[0;31m(mac) hmac-sha1 -- [fail] using broken SHA-1 hash algorithm[0m
|
||||
[0;33m `- [warn] using encrypt-and-MAC mode[0m
|
||||
`- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
|
||||
|
||||
[0;36m# fingerprints[0m
|
||||
[0;32m(fin) ssh-ed25519: SHA256:UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU[0m
|
||||
|
||||
[0;36m# algorithm recommendations (for OpenSSH 8.0)[0m
|
||||
[0;31m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -ecdh-sha2-nistp256 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -ecdh-sha2-nistp384 -- kex algorithm to remove [0m
|
||||
[0;31m(rec) -ecdh-sha2-nistp521 -- kex 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;32m(rec) +rsa-sha2-256 -- key algorithm to append [0m
|
||||
[0;32m(rec) +rsa-sha2-512 -- key algorithm to append [0m
|
||||
[0;33m(rec) -diffie-hellman-group14-sha1 -- kex algorithm to remove [0m
|
||||
[0;33m(rec) -hmac-sha1 -- mac algorithm to remove [0m
|
||||
[0;33m(rec) -hmac-sha1-etm@openssh.com -- mac 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-512 -- mac algorithm to remove [0m
|
||||
[0;33m(rec) -umac-128@openssh.com -- mac algorithm to remove [0m
|
||||
|
@ -1 +1,106 @@
|
||||
{"banner": {"comments": null, "protocol": [2, 0], "raw": "SSH-2.0-OpenSSH_8.0", "software": "OpenSSH_8.0"}, "compression": ["none", "zlib@openssh.com"], "enc": ["chacha20-poly1305@openssh.com", "aes256-gcm@openssh.com", "aes128-gcm@openssh.com", "aes256-ctr", "aes192-ctr", "aes128-ctr"], "fingerprints": [{"fp": "SHA256:UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU", "type": "ssh-ed25519"}], "kex": [{"algorithm": "curve25519-sha256"}, {"algorithm": "curve25519-sha256@libssh.org"}, {"algorithm": "diffie-hellman-group-exchange-sha256", "keysize": 2048}], "key": [{"algorithm": "ssh-ed25519"}], "mac": ["hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "umac-128-etm@openssh.com"], "target": "localhost"}
|
||||
{
|
||||
"banner": {
|
||||
"comments": null,
|
||||
"protocol": [
|
||||
2,
|
||||
0
|
||||
],
|
||||
"raw": "SSH-2.0-OpenSSH_8.0",
|
||||
"software": "OpenSSH_8.0"
|
||||
},
|
||||
"compression": [
|
||||
"none",
|
||||
"zlib@openssh.com"
|
||||
],
|
||||
"cves": [
|
||||
{
|
||||
"cvssv2": 7.0,
|
||||
"description": "privilege escalation via supplemental groups",
|
||||
"name": "CVE-2021-41617"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.8,
|
||||
"description": "command injection via anomalous argument transfers",
|
||||
"name": "CVE-2020-15778"
|
||||
},
|
||||
{
|
||||
"cvssv2": 7.8,
|
||||
"description": "memory corruption and local code execution via pre-authentication integer overflow",
|
||||
"name": "CVE-2019-16905"
|
||||
},
|
||||
{
|
||||
"cvssv2": 5.3,
|
||||
"description": "enumerate usernames via challenge response",
|
||||
"name": "CVE-2016-20012"
|
||||
}
|
||||
],
|
||||
"enc": [
|
||||
"chacha20-poly1305@openssh.com",
|
||||
"aes256-gcm@openssh.com",
|
||||
"aes128-gcm@openssh.com",
|
||||
"aes256-ctr",
|
||||
"aes192-ctr",
|
||||
"aes128-ctr"
|
||||
],
|
||||
"fingerprints": [
|
||||
{
|
||||
"hash": "UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU",
|
||||
"hash_alg": "SHA256",
|
||||
"hostkey": "ssh-ed25519"
|
||||
},
|
||||
{
|
||||
"hash": "1e:0c:7b:34:73:bf:52:41:b0:f9:d1:a9:ab:98:c7:c9",
|
||||
"hash_alg": "MD5",
|
||||
"hostkey": "ssh-ed25519"
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"algorithm": "curve25519-sha256"
|
||||
},
|
||||
{
|
||||
"algorithm": "curve25519-sha256@libssh.org"
|
||||
},
|
||||
{
|
||||
"algorithm": "diffie-hellman-group-exchange-sha256",
|
||||
"keysize": 2048
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"algorithm": "ssh-ed25519"
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
"hmac-sha2-256-etm@openssh.com",
|
||||
"hmac-sha2-512-etm@openssh.com",
|
||||
"umac-128-etm@openssh.com"
|
||||
],
|
||||
"recommendations": {
|
||||
"informational": {
|
||||
"add": {
|
||||
"kex": [
|
||||
{
|
||||
"name": "diffie-hellman-group16-sha512",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "diffie-hellman-group18-sha512",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"name": "rsa-sha2-256",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "rsa-sha2-512",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"target": "localhost:2222"
|
||||
}
|
||||
|
@ -4,17 +4,27 @@
|
||||
[0;32m(gen) compatibility: OpenSSH 7.4+, Dropbear SSH 2018.76+[0m
|
||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||
|
||||
[0;36m# security[0m
|
||||
[0;33m(cve) CVE-2021-41617 -- (CVSSv2: 7.0) privilege escalation via supplemental groups[0m
|
||||
[0;33m(cve) CVE-2020-15778 -- (CVSSv2: 7.8) command injection via anomalous argument transfers[0m
|
||||
[0;33m(cve) CVE-2019-16905 -- (CVSSv2: 7.8) memory corruption and local code execution via pre-authentication integer overflow[0m
|
||||
[0;33m(cve) CVE-2016-20012 -- (CVSSv2: 5.3) enumerate usernames via challenge response[0m
|
||||
|
||||
[0;36m# key exchange algorithms[0m
|
||||
[0;32m(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76[0m
|
||||
[0;32m(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.5, Dropbear SSH 2013.62[0m
|
||||
[0;32m(kex) diffie-hellman-group-exchange-sha256 (2048-bit) -- [info] available since OpenSSH 4.4[0m
|
||||
`- [info] default key exchange since OpenSSH 6.4
|
||||
[0;32m(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62[0m
|
||||
`- [info] default key exchange since OpenSSH 6.4
|
||||
[0;33m(kex) diffie-hellman-group-exchange-sha256 (2048-bit) -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength[0m
|
||||
`- [info] available since OpenSSH 4.4
|
||||
`- [info] A bug in OpenSSH causes it to fall back to a 2048-bit modulus regardless of server configuration (https://bugzilla.mindrot.org/show_bug.cgi?id=2793)
|
||||
|
||||
[0;36m# host-key algorithms[0m
|
||||
[0;32m(key) ssh-ed25519 -- [info] available since OpenSSH 6.5[0m
|
||||
|
||||
[0;36m# encryption algorithms (ciphers)[0m
|
||||
[0;32m(enc) chacha20-poly1305@openssh.com -- [info] available since OpenSSH 6.5[0m
|
||||
`- [info] default cipher since OpenSSH 6.9.
|
||||
`- [info] default cipher since OpenSSH 6.9
|
||||
[0;32m(enc) aes256-gcm@openssh.com -- [info] available since OpenSSH 6.2[0m
|
||||
[0;32m(enc) aes128-gcm@openssh.com -- [info] available since OpenSSH 6.2[0m
|
||||
[0;32m(enc) aes256-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52[0m
|
||||
@ -30,7 +40,6 @@
|
||||
[0;32m(fin) ssh-ed25519: SHA256:UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU[0m
|
||||
|
||||
[0;36m# algorithm recommendations (for OpenSSH 8.0)[0m
|
||||
[0;32m(rec) +diffie-hellman-group14-sha256 -- kex algorithm to append [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
|
||||
|
@ -1 +1,51 @@
|
||||
{"banner": {"comments": "", "protocol": [2, 0], "raw": "", "software": "tinyssh_noversion"}, "compression": ["none"], "enc": ["chacha20-poly1305@openssh.com"], "fingerprints": [{"fp": "SHA256:89ocln1x7KNqnMgWffGoYtD70ksJ4FrH7BMJHa7SrwU", "type": "ssh-ed25519"}], "kex": [{"algorithm": "curve25519-sha256"}, {"algorithm": "curve25519-sha256@libssh.org"}, {"algorithm": "sntrup4591761x25519-sha512@tinyssh.org"}], "key": [{"algorithm": "ssh-ed25519"}], "mac": ["hmac-sha2-256"], "target": "localhost"}
|
||||
{
|
||||
"banner": {
|
||||
"comments": "",
|
||||
"protocol": [
|
||||
2,
|
||||
0
|
||||
],
|
||||
"raw": "",
|
||||
"software": "tinyssh_noversion"
|
||||
},
|
||||
"compression": [
|
||||
"none"
|
||||
],
|
||||
"cves": [],
|
||||
"enc": [
|
||||
"chacha20-poly1305@openssh.com"
|
||||
],
|
||||
"fingerprints": [
|
||||
{
|
||||
"hash": "89ocln1x7KNqnMgWffGoYtD70ksJ4FrH7BMJHa7SrwU",
|
||||
"hash_alg": "SHA256",
|
||||
"hostkey": "ssh-ed25519"
|
||||
},
|
||||
{
|
||||
"hash": "dd:9c:6d:f9:b0:8c:af:fa:c2:65:81:5d:5d:56:f8:21",
|
||||
"hash_alg": "MD5",
|
||||
"hostkey": "ssh-ed25519"
|
||||
}
|
||||
],
|
||||
"kex": [
|
||||
{
|
||||
"algorithm": "curve25519-sha256"
|
||||
},
|
||||
{
|
||||
"algorithm": "curve25519-sha256@libssh.org"
|
||||
},
|
||||
{
|
||||
"algorithm": "sntrup4591761x25519-sha512@tinyssh.org"
|
||||
}
|
||||
],
|
||||
"key": [
|
||||
{
|
||||
"algorithm": "ssh-ed25519"
|
||||
}
|
||||
],
|
||||
"mac": [
|
||||
"hmac-sha2-256"
|
||||
],
|
||||
"recommendations": {},
|
||||
"target": "localhost:2222"
|
||||
}
|
||||
|
@ -5,16 +5,19 @@
|
||||
|
||||
[0;36m# key exchange algorithms[0m
|
||||
[0;32m(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76[0m
|
||||
[0;32m(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.5, Dropbear SSH 2013.62[0m
|
||||
`- [info] default key exchange since OpenSSH 6.4
|
||||
[0;32m(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62[0m
|
||||
`- [info] default key exchange since OpenSSH 6.4
|
||||
[0;33m(kex) sntrup4591761x25519-sha512@tinyssh.org -- [warn] using experimental algorithm[0m
|
||||
`- [info] available since OpenSSH 8.0
|
||||
`- [info] the sntrup4591761 algorithm was withdrawn, as it may not provide strong post-quantum security
|
||||
|
||||
[0;36m# host-key algorithms[0m
|
||||
[0;32m(key) ssh-ed25519 -- [info] available since OpenSSH 6.5[0m
|
||||
|
||||
[0;36m# encryption algorithms (ciphers)[0m
|
||||
[0;32m(enc) chacha20-poly1305@openssh.com -- [info] available since OpenSSH 6.5[0m
|
||||
`- [info] default cipher since OpenSSH 6.9.
|
||||
`- [info] default cipher since OpenSSH 6.9
|
||||
|
||||
[0;36m# message authentication code algorithms[0m
|
||||
[0;33m(mac) hmac-sha2-256 -- [warn] using encrypt-and-MAC mode[0m
|
||||
|
@ -7,7 +7,7 @@ class TestAuditConf:
|
||||
@pytest.fixture(autouse=True)
|
||||
def init(self, ssh_audit):
|
||||
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
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from ssh_audit.outputbuffer import OutputBuffer
|
||||
from ssh_audit.ssh2_kex import SSH2_Kex
|
||||
from ssh_audit.ssh2_kexparty import SSH2_KexParty
|
||||
|
||||
@ -13,7 +14,7 @@ def kex(ssh_audit):
|
||||
enc, mac, compression, languages = [], [], ['none'], []
|
||||
srv = SSH2_KexParty(enc, mac, compression, languages)
|
||||
cookie = os.urandom(16)
|
||||
kex = SSH2_Kex(cookie, kex_algs, key_algs, cli, srv, 0)
|
||||
kex = SSH2_Kex(OutputBuffer, cookie, kex_algs, key_algs, cli, srv, 0)
|
||||
return kex
|
||||
|
||||
|
||||
@ -25,19 +26,19 @@ def test_prevent_runtime_error_regression(ssh_audit, kex):
|
||||
keys, and an error occurred when iterating and modifying them at the
|
||||
same time.
|
||||
"""
|
||||
kex.set_host_key("ssh-rsa", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00")
|
||||
kex.set_host_key("ssh-rsa1", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00")
|
||||
kex.set_host_key("ssh-rsa2", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00")
|
||||
kex.set_host_key("ssh-rsa3", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00")
|
||||
kex.set_host_key("ssh-rsa4", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00")
|
||||
kex.set_host_key("ssh-rsa5", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00")
|
||||
kex.set_host_key("ssh-rsa6", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00")
|
||||
kex.set_host_key("ssh-rsa7", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00")
|
||||
kex.set_host_key("ssh-rsa8", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00")
|
||||
kex.set_host_key("ssh-rsa", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
|
||||
kex.set_host_key("ssh-rsa1", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
|
||||
kex.set_host_key("ssh-rsa2", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
|
||||
kex.set_host_key("ssh-rsa3", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
|
||||
kex.set_host_key("ssh-rsa4", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
|
||||
kex.set_host_key("ssh-rsa5", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
|
||||
kex.set_host_key("ssh-rsa6", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
|
||||
kex.set_host_key("ssh-rsa7", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
|
||||
kex.set_host_key("ssh-rsa8", b"\x00\x00\x00\x07ssh-rsa\x00\x00\x00", 1024, '', 0)
|
||||
|
||||
rv = ssh_audit.build_struct('localhost', banner=None, kex=kex)
|
||||
rv = ssh_audit.build_struct('localhost', None, [], kex=kex)
|
||||
|
||||
assert len(rv["fingerprints"]) == 9
|
||||
assert len(rv["fingerprints"]) == (9 * 2) # Each host key generates two hash fingerprints: one using SHA256, and one using MD5.
|
||||
|
||||
for key in ['banner', 'compression', 'enc', 'fingerprints', 'kex', 'key', 'mac']:
|
||||
assert key in rv
|
||||
|
@ -2,6 +2,7 @@ import hashlib
|
||||
import pytest
|
||||
from datetime import date
|
||||
|
||||
from ssh_audit.outputbuffer import OutputBuffer
|
||||
from ssh_audit.policy import Policy
|
||||
from ssh_audit.ssh2_kex import SSH2_Kex
|
||||
from ssh_audit.writebuf import WriteBuf
|
||||
@ -10,6 +11,7 @@ from ssh_audit.writebuf import WriteBuf
|
||||
class TestPolicy:
|
||||
@pytest.fixture(autouse=True)
|
||||
def init(self, ssh_audit):
|
||||
self.OutputBuffer = OutputBuffer
|
||||
self.Policy = Policy
|
||||
self.wbuf = WriteBuf
|
||||
self.ssh2_kex = SSH2_Kex
|
||||
@ -32,7 +34,7 @@ class TestPolicy:
|
||||
w.write_list([''])
|
||||
w.write_byte(False)
|
||||
w.write_int(0)
|
||||
return self.ssh2_kex.parse(w.write_flush())
|
||||
return self.ssh2_kex.parse(self.OutputBuffer, w.write_flush())
|
||||
|
||||
|
||||
def test_builtin_policy_consistency(self):
|
||||
@ -41,15 +43,91 @@ class TestPolicy:
|
||||
for policy_name in Policy.BUILTIN_POLICIES:
|
||||
# Ensure that the policy name ends with " (version X)", where X is the 'version' field.
|
||||
version_str = " (version %s)" % Policy.BUILTIN_POLICIES[policy_name]['version']
|
||||
assert(policy_name.endswith(version_str))
|
||||
assert policy_name.endswith(version_str)
|
||||
|
||||
# Ensure that all required fields are present.
|
||||
required_fields = ['version', 'banner', 'compressions', 'host_keys', 'optional_host_keys', 'kex', 'ciphers', 'macs', 'hostkey_sizes', 'dh_modulus_sizes', 'server_policy']
|
||||
for field in required_fields:
|
||||
assert field in Policy.BUILTIN_POLICIES[policy_name]
|
||||
|
||||
# Ensure no extra fields are present.
|
||||
assert len(required_fields) == len(Policy.BUILTIN_POLICIES[policy_name])
|
||||
|
||||
# Ensure that at least one host key is defined.
|
||||
assert type(Policy.BUILTIN_POLICIES[policy_name]['host_keys']) == list
|
||||
assert len(Policy.BUILTIN_POLICIES[policy_name]['host_keys']) > 0
|
||||
|
||||
# Ensure that at least one key exchange is defined.
|
||||
assert type(Policy.BUILTIN_POLICIES[policy_name]['kex']) == list
|
||||
assert len(Policy.BUILTIN_POLICIES[policy_name]['kex']) > 0
|
||||
|
||||
# Ensure that at least one cipher is defined.
|
||||
assert type(Policy.BUILTIN_POLICIES[policy_name]['ciphers']) == list
|
||||
assert len(Policy.BUILTIN_POLICIES[policy_name]['ciphers']) > 0
|
||||
|
||||
# Ensure that at least one MAC is defined
|
||||
assert type(Policy.BUILTIN_POLICIES[policy_name]['macs']) == list
|
||||
assert len(Policy.BUILTIN_POLICIES[policy_name]['macs']) > 0
|
||||
|
||||
# These tests apply to server policies only.
|
||||
if Policy.BUILTIN_POLICIES[policy_name]['server_policy']:
|
||||
assert type(Policy.BUILTIN_POLICIES[policy_name]['hostkey_sizes']) == dict
|
||||
assert len(Policy.BUILTIN_POLICIES[policy_name]['hostkey_sizes']) > 0
|
||||
|
||||
# Examine all the hostkey_sizes entries...
|
||||
for hostkey_type in Policy.BUILTIN_POLICIES[policy_name]['hostkey_sizes']:
|
||||
hostkey_data = Policy.BUILTIN_POLICIES[policy_name]['hostkey_sizes'][hostkey_type]
|
||||
|
||||
# Ensure that 'hostkey_size' is always included and that it is an integer.
|
||||
assert 'hostkey_size' in hostkey_data
|
||||
assert type(hostkey_data['hostkey_size']) == int
|
||||
|
||||
# If this is an ed25519 host key, ensure its size is fixed at 256. If its an RSA host key, ensure the size is 4096.
|
||||
if hostkey_type.find('ed25519') != -1:
|
||||
assert int(hostkey_data['hostkey_size']) == 256
|
||||
elif hostkey_type.startswith('rsa-'):
|
||||
assert int(hostkey_data['hostkey_size']) == 4096
|
||||
else: # Catch unexpected host key types.
|
||||
assert False
|
||||
|
||||
# Ensure either that 'ca_key_type' and 'ca_key_size' are both present, or neither are. Fail cases when only one of the fields are present.
|
||||
assert (('ca_key_type' in hostkey_data) and ('ca_key_size' in hostkey_data)) or (('ca_key_type' not in hostkey_data) and ('ca_key_size' not in hostkey_data))
|
||||
|
||||
# Ensure that the ca_key_type is either ssh-rsa or ssh-ed25519.
|
||||
if 'ca_key_type' in hostkey_data:
|
||||
assert hostkey_data['ca_key_type'] in ['ssh-rsa', 'ssh-ed25519']
|
||||
|
||||
# Ensure RSA CA key sizes are fixed at 4096. Ensure ED25519 CA keys are 256.
|
||||
if 'ca_key_size' in hostkey_data:
|
||||
if 'ca_key_type' == 'ssh-rsa':
|
||||
assert hostkey_data['ca_key_size'] == 4096
|
||||
elif 'ca_key_type' == 'ssh-ed25519':
|
||||
assert hostkey_data['ca_key_size'] == 256
|
||||
|
||||
# Ensure that the 'dh_modulus_size' field is a dict.
|
||||
assert type(Policy.BUILTIN_POLICIES[policy_name]['dh_modulus_sizes']) == dict
|
||||
|
||||
# The 'dh_modulus_size' field should have either one entry, or be empty.
|
||||
assert len(Policy.BUILTIN_POLICIES[policy_name]['dh_modulus_sizes']) in range(0, 2) # The endpoint in range() is not inclusive
|
||||
|
||||
# If 'diffie-hellman-group-exchange-sha256' is in the kex list, ensure that it exists in the 'dh_modulus_sizes' entry. That entry must be defined for 2048 bits or larger.
|
||||
if 'diffie-hellman-group-exchange-sha256' in Policy.BUILTIN_POLICIES[policy_name]['kex']:
|
||||
assert 'diffie-hellman-group-exchange-sha256' in Policy.BUILTIN_POLICIES[policy_name]['dh_modulus_sizes']
|
||||
assert int(Policy.BUILTIN_POLICIES[policy_name]['dh_modulus_sizes']['diffie-hellman-group-exchange-sha256']) >= 2048
|
||||
|
||||
else: # Client-specific tests.
|
||||
|
||||
# These must be set to None for client policies, since they have no meaning otherwise.
|
||||
assert Policy.BUILTIN_POLICIES[policy_name]['hostkey_sizes'] is None
|
||||
assert Policy.BUILTIN_POLICIES[policy_name]['dh_modulus_sizes'] is None
|
||||
|
||||
# Ensure that each built-in policy can be loaded with Policy.load_builtin_policy().
|
||||
assert(Policy.load_builtin_policy(policy_name) is not None)
|
||||
assert Policy.load_builtin_policy(policy_name) is not None
|
||||
|
||||
# Ensure that both server and client policy names are returned.
|
||||
server_policy_names, client_policy_names = Policy.list_builtin_policies()
|
||||
assert(len(server_policy_names) > 0)
|
||||
assert(len(client_policy_names) > 0)
|
||||
assert len(server_policy_names) > 0
|
||||
assert len(client_policy_names) > 0
|
||||
|
||||
|
||||
def test_policy_basic(self):
|
||||
@ -66,7 +144,7 @@ ciphers = cipher_alg1, cipher_alg2, cipher_alg3
|
||||
macs = mac_alg1, mac_alg2, mac_alg3'''
|
||||
|
||||
policy = self.Policy(policy_data=policy_data)
|
||||
assert str(policy) == "Name: [Test Policy]\nVersion: [1]\nBanner: {undefined}\nCompressions: comp_alg1\nHost Keys: key_alg1\nOptional Host Keys: {undefined}\nKey Exchanges: kex_alg1, kex_alg2\nCiphers: cipher_alg1, cipher_alg2, cipher_alg3\nMACs: mac_alg1, mac_alg2, mac_alg3\nHost Key Sizes: {undefined}\nCA Key Sizes: {undefined}\nDH Modulus Sizes: {undefined}\nServer Policy: True"
|
||||
assert str(policy) == "Name: [Test Policy]\nVersion: [1]\nBanner: {undefined}\nCompressions: comp_alg1\nHost Keys: key_alg1\nOptional Host Keys: {undefined}\nKey Exchanges: kex_alg1, kex_alg2\nCiphers: cipher_alg1, cipher_alg2, cipher_alg3\nMACs: mac_alg1, mac_alg2, mac_alg3\nHost Key Sizes: {undefined}\nDH Modulus Sizes: {undefined}\nServer Policy: True"
|
||||
|
||||
|
||||
def test_policy_invalid_1(self):
|
||||
|
@ -8,6 +8,7 @@ class TestResolve:
|
||||
def init(self, ssh_audit):
|
||||
self.AuditConf = ssh_audit.AuditConf
|
||||
self.audit = ssh_audit.audit
|
||||
self.OutputBuffer = ssh_audit.OutputBuffer
|
||||
self.ssh_socket = ssh_audit.SSH_Socket
|
||||
|
||||
def _conf(self):
|
||||
@ -20,7 +21,7 @@ class TestResolve:
|
||||
vsocket = virtual_socket
|
||||
vsocket.gsock.addrinfodata['localhost#22'] = socket.gaierror(8, 'hostname nor servname provided, or not known')
|
||||
conf = self._conf()
|
||||
s = self.ssh_socket('localhost', 22, conf.ip_version_preference)
|
||||
s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference)
|
||||
output_spy.begin()
|
||||
with pytest.raises(SystemExit):
|
||||
list(s._resolve())
|
||||
@ -32,7 +33,7 @@ class TestResolve:
|
||||
vsocket = virtual_socket
|
||||
vsocket.gsock.addrinfodata['localhost#22'] = []
|
||||
conf = self._conf()
|
||||
s = self.ssh_socket('localhost', 22, conf.ip_version_preference)
|
||||
s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference)
|
||||
output_spy.begin()
|
||||
r = list(s._resolve())
|
||||
assert len(r) == 0
|
||||
@ -40,7 +41,7 @@ class TestResolve:
|
||||
def test_resolve_ipv4(self, virtual_socket):
|
||||
conf = self._conf()
|
||||
conf.ipv4 = True
|
||||
s = self.ssh_socket('localhost', 22, conf.ip_version_preference)
|
||||
s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference)
|
||||
r = list(s._resolve())
|
||||
assert len(r) == 1
|
||||
assert r[0] == (socket.AF_INET, ('127.0.0.1', 22))
|
||||
@ -48,14 +49,14 @@ class TestResolve:
|
||||
def test_resolve_ipv6(self, virtual_socket):
|
||||
conf = self._conf()
|
||||
conf.ipv6 = True
|
||||
s = self.ssh_socket('localhost', 22, conf.ip_version_preference)
|
||||
s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference)
|
||||
r = list(s._resolve())
|
||||
assert len(r) == 1
|
||||
assert r[0] == (socket.AF_INET6, ('::1', 22))
|
||||
|
||||
def test_resolve_ipv46_both(self, virtual_socket):
|
||||
conf = self._conf()
|
||||
s = self.ssh_socket('localhost', 22, conf.ip_version_preference)
|
||||
s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference)
|
||||
r = list(s._resolve())
|
||||
assert len(r) == 2
|
||||
assert r[0] == (socket.AF_INET, ('127.0.0.1', 22))
|
||||
@ -65,7 +66,7 @@ class TestResolve:
|
||||
conf = self._conf()
|
||||
conf.ipv4 = True
|
||||
conf.ipv6 = True
|
||||
s = self.ssh_socket('localhost', 22, conf.ip_version_preference)
|
||||
s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference)
|
||||
r = list(s._resolve())
|
||||
assert len(r) == 2
|
||||
assert r[0] == (socket.AF_INET, ('127.0.0.1', 22))
|
||||
@ -73,7 +74,7 @@ class TestResolve:
|
||||
conf = self._conf()
|
||||
conf.ipv6 = True
|
||||
conf.ipv4 = True
|
||||
s = self.ssh_socket('localhost', 22, conf.ip_version_preference)
|
||||
s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference)
|
||||
r = list(s._resolve())
|
||||
assert len(r) == 2
|
||||
assert r[0] == (socket.AF_INET6, ('::1', 22))
|
||||
|
@ -1,5 +1,6 @@
|
||||
import pytest
|
||||
|
||||
from ssh_audit.outputbuffer import OutputBuffer
|
||||
from ssh_audit.ssh_socket import SSH_Socket
|
||||
|
||||
|
||||
@ -7,24 +8,25 @@ from ssh_audit.ssh_socket import SSH_Socket
|
||||
class TestSocket:
|
||||
@pytest.fixture(autouse=True)
|
||||
def init(self, ssh_audit):
|
||||
self.OutputBuffer = OutputBuffer
|
||||
self.ssh_socket = SSH_Socket
|
||||
|
||||
def test_invalid_host(self, virtual_socket):
|
||||
with pytest.raises(ValueError):
|
||||
self.ssh_socket(None, 22)
|
||||
self.ssh_socket(self.OutputBuffer(), None, 22)
|
||||
|
||||
def test_invalid_port(self, virtual_socket):
|
||||
with pytest.raises(ValueError):
|
||||
self.ssh_socket('localhost', 'abc')
|
||||
self.ssh_socket(self.OutputBuffer(), 'localhost', 'abc')
|
||||
with pytest.raises(ValueError):
|
||||
self.ssh_socket('localhost', -1)
|
||||
self.ssh_socket(self.OutputBuffer(), 'localhost', -1)
|
||||
with pytest.raises(ValueError):
|
||||
self.ssh_socket('localhost', 0)
|
||||
self.ssh_socket(self.OutputBuffer(), 'localhost', 0)
|
||||
with pytest.raises(ValueError):
|
||||
self.ssh_socket('localhost', 65536)
|
||||
self.ssh_socket(self.OutputBuffer(), 'localhost', 65536)
|
||||
|
||||
def test_not_connected_socket(self, virtual_socket):
|
||||
sock = self.ssh_socket('localhost', 22)
|
||||
sock = self.ssh_socket(self.OutputBuffer(), 'localhost', 22)
|
||||
banner, header, err = sock.get_banner()
|
||||
assert banner is None
|
||||
assert len(header) == 0
|
||||
|
@ -138,7 +138,7 @@ class TestSSH1:
|
||||
self.audit(out, self._conf())
|
||||
out.write()
|
||||
lines = output_spy.flush()
|
||||
assert len(lines) == 16
|
||||
assert len(lines) == 21
|
||||
|
||||
def test_ssh1_server_invalid_first_packet(self, output_spy, virtual_socket):
|
||||
vsocket = virtual_socket
|
||||
@ -153,7 +153,7 @@ class TestSSH1:
|
||||
out.write()
|
||||
assert ret != 0
|
||||
lines = output_spy.flush()
|
||||
assert len(lines) == 10
|
||||
assert len(lines) == 14
|
||||
assert 'unknown message' in lines[-1]
|
||||
|
||||
def test_ssh1_server_invalid_checksum(self, output_spy, virtual_socket):
|
||||
|
@ -61,8 +61,25 @@ class TestSSH2:
|
||||
w.write_int(0)
|
||||
return w.write_flush()
|
||||
|
||||
def _kex_payload_with_gss(self):
|
||||
w = self.wbuf()
|
||||
w.write(b'\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff')
|
||||
w.write_list(['gss-gex-sha1-dZuIebMjgUqaxvbF7hDbAw==', 'gss-gex-sha1-vz8J1E9PzLr8b1K+0remTg==', 'gss-group14-sha1-dZuIebMjgUqaxvbF7hDbAw==', 'gss-group14-sha1-vz8J1E9PzLr8b1K+0remTg==', 'gss-group14-sha256-dZuIebMjgUqaxvbF7hDbAw==', 'gss-group14-sha256-vz8J1E9PzLr8b1K+0remTg==', 'gss-group16-sha512-dZuIebMjgUqaxvbF7hDbAw==', 'gss-group16-sha512-vz8J1E9PzLr8b1K+0remTg==', 'gss-group18-sha512-dZuIebMjgUqaxvbF7hDbAw==', 'gss-group18-sha512-vz8J1E9PzLr8b1K+0remTg==', 'gss-group1-sha1-dZuIebMjgUqaxvbF7hDbAw==', 'gss-group1-sha1-vz8J1E9PzLr8b1K+0remTg==', 'gss-curve448-sha512-XXX'])
|
||||
w.write_list(['ssh-ed25519'])
|
||||
w.write_list(['chacha20-poly1305@openssh.com'])
|
||||
w.write_list(['chacha20-poly1305@openssh.com'])
|
||||
w.write_list(['hmac-sha2-512-etm@openssh.com'])
|
||||
w.write_list(['hmac-sha2-512-etm@openssh.com'])
|
||||
w.write_list(['none', 'zlib@openssh.com'])
|
||||
w.write_list(['none', 'zlib@openssh.com'])
|
||||
w.write_list([''])
|
||||
w.write_list([''])
|
||||
w.write_byte(False)
|
||||
w.write_int(0)
|
||||
return w.write_flush()
|
||||
|
||||
def test_kex_read(self):
|
||||
kex = self.ssh2_kex.parse(self._kex_payload())
|
||||
kex = self.ssh2_kex.parse(self.OutputBuffer, self._kex_payload())
|
||||
assert kex is not None
|
||||
assert kex.cookie == b'\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff'
|
||||
assert kex.kex_algorithms == ['bogus_kex1', 'bogus_kex2']
|
||||
@ -88,7 +105,7 @@ class TestSSH2:
|
||||
srv = self.ssh2_kexparty(enc, mac, compression, languages)
|
||||
if cookie is None:
|
||||
cookie = os.urandom(16)
|
||||
kex = self.ssh2_kex(cookie, kex_algs, key_algs, cli, srv, 0)
|
||||
kex = self.ssh2_kex(self.OutputBuffer, cookie, kex_algs, key_algs, cli, srv, 0)
|
||||
return kex
|
||||
|
||||
def _get_kex_variat1(self):
|
||||
@ -132,7 +149,7 @@ class TestSSH2:
|
||||
|
||||
def test_key_payload(self):
|
||||
kex1 = self._get_kex_variat1()
|
||||
kex2 = self.ssh2_kex.parse(self._kex_payload())
|
||||
kex2 = self.ssh2_kex.parse(self.OutputBuffer, self._kex_payload())
|
||||
assert kex1.payload == kex2.payload
|
||||
|
||||
def test_ssh2_server_simple(self, output_spy, virtual_socket):
|
||||
@ -161,5 +178,24 @@ class TestSSH2:
|
||||
out.write()
|
||||
assert ret != 0
|
||||
lines = output_spy.flush()
|
||||
assert len(lines) == 5
|
||||
assert len(lines) == 9
|
||||
assert 'unknown message' in lines[-1]
|
||||
|
||||
def test_ssh2_gss_kex(self, output_spy, virtual_socket):
|
||||
'''Ensure that GSS kex algorithms are properly parsed.'''
|
||||
|
||||
vsocket = virtual_socket
|
||||
w = self.wbuf()
|
||||
w.write_byte(self.protocol.MSG_KEXINIT)
|
||||
w.write(self._kex_payload_with_gss()) # Use the kex with GSS algorithms.
|
||||
vsocket.rdata.append(b'SSH-2.0-OpenSSH_7.3 ssh-audit-test\r\n')
|
||||
vsocket.rdata.append(self._create_ssh2_packet(w.write_flush()))
|
||||
output_spy.begin()
|
||||
out = self.OutputBuffer()
|
||||
self.audit(out, self._conf())
|
||||
out.write()
|
||||
lines = output_spy.flush()
|
||||
|
||||
# Ensure that none of the lines are reported as "unknown algorithm".
|
||||
for line in lines:
|
||||
assert line.find('unknown algorithm') == -1
|
||||
|
35
test/test_ssh2_kexdb.py
Normal file
35
test/test_ssh2_kexdb.py
Normal file
@ -0,0 +1,35 @@
|
||||
import pytest
|
||||
|
||||
from ssh_audit.ssh2_kexdb import SSH2_KexDB
|
||||
|
||||
|
||||
class Test_SSH2_KexDB:
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def init(self):
|
||||
self.db = SSH2_KexDB.ALGORITHMS
|
||||
|
||||
def test_ssh2_kexdb(self):
|
||||
'''Ensures that the SSH2_KexDB.ALGORITHMS dictionary is in the right format.'''
|
||||
|
||||
db_keys = list(self.db.keys())
|
||||
db_keys.sort()
|
||||
|
||||
# Ensure only these keys exist in the database.
|
||||
assert db_keys == ['enc', 'kex', 'key', 'mac']
|
||||
|
||||
# For 'enc', 'kex', etc...
|
||||
for alg_type in self.db:
|
||||
|
||||
# Iterate over algorithms within this type (i.e.: all 'enc' algorithms, all 'kex' algorithms, etc).
|
||||
for alg_name in self.db[alg_type]:
|
||||
|
||||
# Get the list of failures, warnings, etc., for this algorithm.
|
||||
alg_data = self.db[alg_type][alg_name]
|
||||
|
||||
# This list must be between 1 and 4 entries long.
|
||||
assert 1 <= len(alg_data) <= 4
|
||||
|
||||
# The first entry denotes the versions when this algorithm was added to OpenSSH, Dropbear, and/or libssh, followed by when it was deprecated, and finally when it was removed. Hence it must have between 0 and 3 entries.
|
||||
added_entry = alg_data[0]
|
||||
assert 0 <= len(added_entry) <= 3
|
34
tox.ini
34
tox.ini
@ -1,19 +1,19 @@
|
||||
[tox]
|
||||
envlist =
|
||||
py{py3}-{test,pylint,flake8,vulture}
|
||||
py{36,37,38,39}-{test,mypy,pylint,flake8,vulture}
|
||||
py{37,38,39,310,311}-{test,mypy,pylint,flake8,vulture}
|
||||
cov
|
||||
skip_missing_interpreters = true
|
||||
|
||||
[testenv]
|
||||
deps =
|
||||
test: pytest<6.0
|
||||
test: pytest
|
||||
test,cov: {[testenv:cov]deps}
|
||||
test,py{36,37,38,39}-{type,mypy}: colorama
|
||||
py{36,37,38,39}-{type,mypy}: {[testenv:mypy]deps}
|
||||
py{py3,36,37,38,39}-{lint,pylint},lint: {[testenv:pylint]deps}
|
||||
py{py3,36,37,38,39}-{lint,flake8},lint: {[testenv:flake8]deps}
|
||||
py{py3,36,37,38,39}-{lint,vulture},lint: {[testenv:vulture]deps}
|
||||
test,py{37,38,39,310,311}-{type,mypy}: colorama
|
||||
py{37,38,39,310,311}-{type,mypy}: {[testenv:mypy]deps}
|
||||
py{py3,37,38,39,310,311}-{lint,pylint},lint: {[testenv:pylint]deps}
|
||||
py{py3,37,38,39,310,311}-{lint,flake8},lint: {[testenv:flake8]deps}
|
||||
py{py3,37,38,39,310,311}-{lint,vulture},lint: {[testenv:vulture]deps}
|
||||
setenv =
|
||||
SSHAUDIT = {toxinidir}/src
|
||||
test: COVERAGE_FILE = {toxinidir}/.coverage.{envname}
|
||||
@ -25,10 +25,10 @@ commands =
|
||||
test: coverage combine
|
||||
test: coverage report --show-missing
|
||||
test: coverage html -d {toxinidir}/reports/html/coverage.{envname}
|
||||
py{36,37,38,39}-{type,mypy}: {[testenv:mypy]commands}
|
||||
py{py3,36,37,38,39}-{lint,pylint},lint: {[testenv:pylint]commands}
|
||||
py{py3,36,37,38,39}-{lint,flake8},lint: {[testenv:flake8]commands}
|
||||
py{py3,36,37,38,39}-{lint,vulture},lint: {[testenv:vulture]commands}
|
||||
py{37,38,39,310,311}-{type,mypy}: {[testenv:mypy]commands}
|
||||
py{py3,37,38,39,310,311}-{lint,pylint},lint: {[testenv:pylint]commands}
|
||||
py{py3,37,38,39,310,311}-{lint,flake8},lint: {[testenv:flake8]commands}
|
||||
py{py3,37,38,39,310,311}-{lint,vulture},lint: {[testenv:vulture]commands}
|
||||
#ignore_outcome =
|
||||
# type: true
|
||||
# lint: true
|
||||
@ -91,14 +91,12 @@ reports = no
|
||||
#output-format = colorized
|
||||
indent-string = " "
|
||||
disable =
|
||||
bad-continuation,
|
||||
broad-except,
|
||||
duplicate-code,
|
||||
fixme,
|
||||
invalid-name,
|
||||
line-too-long,
|
||||
missing-docstring,
|
||||
mixed-indentation,
|
||||
no-else-raise,
|
||||
no-else-return,
|
||||
super-with-arguments, # Can be re-factored, at some point.
|
||||
@ -109,7 +107,7 @@ disable =
|
||||
too-many-lines,
|
||||
too-many-locals,
|
||||
too-many-statements,
|
||||
unsubscriptable-object # This seems to be a local issue on the maintainer's machine only. Could be removed, perhaps, in Jan 2021.
|
||||
consider-using-f-string
|
||||
max-complexity = 15
|
||||
max-args = 8
|
||||
max-locals = 20
|
||||
@ -127,10 +125,10 @@ ignore-long-lines = ^\s*(#\s+type:\s+.*|[A-Z0-9_]+\s+=\s+.*|('.*':\s+)?\[.*\],?|
|
||||
max-module-lines = 2500
|
||||
|
||||
[flake8]
|
||||
ignore =
|
||||
E241, # multiple spaces after operator; should be kept for tabular data
|
||||
E303, # too many blank lines
|
||||
E501, # line too long
|
||||
# E241 = multiple spaces after operator; should be kept for tabular data
|
||||
# E303 = too many blank lines
|
||||
# E501 = line too long
|
||||
ignore = E241, E303, E501
|
||||
|
||||
[pytest]
|
||||
junit_family = xunit1
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
@ -45,7 +45,7 @@
|
||||
#
|
||||
################################################################################
|
||||
|
||||
function usage {
|
||||
usage() {
|
||||
echo >&2 "Usage: $0 [-m <path-to-man-page>] [-g <path-to-globals.py>] [-h]"
|
||||
echo >&2 " -m Specify an alternate man page path (default: ./ssh-audit.1)"
|
||||
echo >&2 " -g Specify an alternate globals.py path (default: ./src/ssh_audit/globals.py)"
|
||||
@ -56,17 +56,17 @@ PLATFORM="$(uname -s)"
|
||||
|
||||
# This script is intended for use on Linux and Cygwin only.
|
||||
case "$PLATFORM" in
|
||||
Linux | CYGWIN*) ;;
|
||||
*) echo "Platform not supported: $PLATFORM"
|
||||
exit 1
|
||||
;;
|
||||
Linux | CYGWIN*) ;;
|
||||
*)
|
||||
echo "Platform not supported: $PLATFORM"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
MAN_PAGE=./ssh-audit.1
|
||||
GLOBALS_PY=./src/ssh_audit/globals.py
|
||||
|
||||
while getopts "m: g: h" OPTION
|
||||
do
|
||||
while getopts "m: g: h" OPTION; do
|
||||
case "$OPTION" in
|
||||
m)
|
||||
MAN_PAGE="$OPTARG"
|
||||
@ -87,11 +87,11 @@ do
|
||||
done
|
||||
|
||||
# Check that the specified files exist.
|
||||
[ -f "$MAN_PAGE" ] || { echo >&2 "man page file not found: $MAN_PAGE"; exit 1; }
|
||||
[ -f "$GLOBALS_PY" ] || { echo >&2 "globals.py file not found: $GLOBALS_PY"; exit 1; }
|
||||
[[ -f "$MAN_PAGE" ]] || { echo >&2 "man page file not found: $MAN_PAGE"; exit 1; }
|
||||
[[ -f "$GLOBALS_PY" ]] || { echo >&2 "globals.py file not found: $GLOBALS_PY"; exit 1; }
|
||||
|
||||
# Check that the 'ul' (do underlining) binary exists.
|
||||
if [[ "$PLATFORM" = Linux ]]; then
|
||||
if [[ "$PLATFORM" == "Linux" ]]; then
|
||||
command -v ul >/dev/null 2>&1 || { echo >&2 "ul not found."; exit 1; }
|
||||
fi
|
||||
|
||||
@ -118,10 +118,10 @@ echo "Processing man page at ${MAN_PAGE} and placing output into ${GLOBALS_PY}..
|
||||
|
||||
echo WINDOWS_MAN_PAGE = '"""' >> "$GLOBALS_PY"
|
||||
|
||||
if [[ "$PLATFORM" = CYGWIN* ]]; then
|
||||
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"
|
||||
MANWIDTH=80 MAN_KEEP_FORMATTING=1 man "$MAN_PAGE" | ul | sed $'s/\u2010/-/g' >> "$GLOBALS_PY"
|
||||
fi
|
||||
|
||||
echo '"""' >> "$GLOBALS_PY"
|
||||
|
Reference in New Issue
Block a user