mirror of
https://github.com/jtesta/ssh-audit.git
synced 2025-07-06 14:02:49 -05:00
Compare commits
133 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 | |||
f96c0501e9 | |||
446a411424 | |||
b300ad1252 | |||
1bbc3feb57 | |||
8f9771c4e6 | |||
8a8c284d9a | |||
1b7cfbec71 | |||
3c0fc8ead4 | |||
ef831d17e0 | |||
36094611ce | |||
49cf91a902 | |||
11e2e77585 | |||
090b5d760b | |||
7878d66a46 | |||
730d6904c2 | |||
e0f0956edc | |||
d42725652f | |||
6b67a2efb3 | |||
c49a0fb22f | |||
dbe14a075e | |||
13d15baa2a | |||
bbb81e24ab | |||
bbbd75ee69 | |||
60de5e55cb | |||
4e2f9da632 | |||
287c551ff8 | |||
d9a4b49560 | |||
a4c78512d8 | |||
1ba4c7c7ca | |||
338ffc5adb | |||
52d1e8f27b | |||
00dc22b00b | |||
0d9881966c | |||
5c8dc5105b | |||
75be333bd2 |
@ -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
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -22,3 +22,6 @@ reports/
|
||||
/snap/
|
||||
/stage/
|
||||
/ssh-audit_*.snap
|
||||
|
||||
# Your local server config
|
||||
servers.txt
|
||||
|
20
.travis.yml
20
.travis.yml
@ -1,20 +0,0 @@
|
||||
language: python
|
||||
|
||||
python:
|
||||
- "3.5"
|
||||
- "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.8-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
|
52
PACKAGING
52
PACKAGING
@ -1,52 +0,0 @@
|
||||
= PyPI =
|
||||
|
||||
To create package and upload to test server:
|
||||
|
||||
$ sudo apt install python3-virtualenv
|
||||
$ make -f Makefile.pypi
|
||||
$ make -f Makefile.pypi uploadtest
|
||||
|
||||
|
||||
To download from test server and verify:
|
||||
|
||||
$ virtualenv -p /usr/bin/python3 /tmp/pypi_test
|
||||
$ cd /tmp/pypi_test; source bin/activate
|
||||
$ pip3 install --index-url https://test.pypi.org/simple ssh-audit
|
||||
|
||||
|
||||
To upload to production server (hint: use username '__token__' and API token):
|
||||
|
||||
$ make -f Makefile.pypi uploadprod
|
||||
|
||||
|
||||
To download from production server and verify:
|
||||
|
||||
$ virtualenv -p /usr/bin/python3 /tmp/pypi_prod
|
||||
$ cd /tmp/pypi_prod; source bin/activate
|
||||
$ pip3 install ssh-audit
|
||||
|
||||
----
|
||||
|
||||
= Snap =
|
||||
|
||||
To create the snap package, run a fully-updated Ubuntu Server 20.04 VM.
|
||||
|
||||
As root, run (leave all options default):
|
||||
|
||||
# lxd init
|
||||
|
||||
Bump the version number in snapcraft.yaml. Then run:
|
||||
|
||||
# make -f Makefile.snap
|
||||
|
||||
----
|
||||
|
||||
= Docker =
|
||||
|
||||
Build image with:
|
||||
|
||||
$ make -f Makefile.docker
|
||||
|
||||
Then upload them to Dockerhub with:
|
||||
|
||||
$ make -f Makefile.docker upload
|
78
PACKAGING.md
Normal file
78
PACKAGING.md
Normal file
@ -0,0 +1,78 @@
|
||||
# Windows
|
||||
|
||||
An executable can only be made on a Windows host because the PyInstaller tool (https://www.pyinstaller.org/) does not support cross-compilation.
|
||||
|
||||
1.) Install Python v3.11.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/).
|
||||
|
||||
3.) Install/update package dependencies and create the executable with:
|
||||
|
||||
```
|
||||
$ ./build_windows_executable.sh
|
||||
```
|
||||
|
||||
|
||||
# PyPI
|
||||
|
||||
To create package and upload to test server:
|
||||
|
||||
```
|
||||
$ sudo apt install python3-virtualenv
|
||||
$ make -f Makefile.pypi
|
||||
$ make -f Makefile.pypi uploadtest
|
||||
```
|
||||
|
||||
To download from test server and verify:
|
||||
|
||||
```
|
||||
$ virtualenv -p /usr/bin/python3 /tmp/pypi_test
|
||||
$ cd /tmp/pypi_test; source bin/activate
|
||||
$ pip3 install --index-url https://test.pypi.org/simple ssh-audit
|
||||
```
|
||||
|
||||
To upload to production server (hint: use username '\_\_token\_\_' and API token):
|
||||
|
||||
```
|
||||
$ make -f Makefile.pypi uploadprod
|
||||
```
|
||||
|
||||
To download from production server and verify:
|
||||
|
||||
```
|
||||
$ virtualenv -p /usr/bin/python3 /tmp/pypi_prod
|
||||
$ cd /tmp/pypi_prod; source bin/activate
|
||||
$ pip3 install ssh-audit
|
||||
```
|
||||
|
||||
|
||||
# Snap
|
||||
|
||||
To create the snap package, run a fully-updated Ubuntu Server 22.04 VM.
|
||||
|
||||
Create the snap package with:
|
||||
```
|
||||
$ ./build_snap.sh
|
||||
```
|
||||
|
||||
Upload the snap with:
|
||||
|
||||
```
|
||||
$ snapcraft login
|
||||
$ snapcraft upload --release=stable ssh-audit_*.snap
|
||||
```
|
||||
|
||||
|
||||
# Docker
|
||||
|
||||
Build image with:
|
||||
|
||||
```
|
||||
$ make -f Makefile.docker
|
||||
```
|
||||
|
||||
Then upload it to Dockerhub with:
|
||||
|
||||
```
|
||||
$ make -f Makefile.docker upload
|
||||
```
|
106
README.md
106
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,6 +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.7 - 3.11;
|
||||
- no dependencies
|
||||
|
||||
## Usage
|
||||
@ -36,11 +48,16 @@ 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
|
||||
connecting to a server
|
||||
-m, --manual print the man page (Windows only)
|
||||
-M, --make-policy=<policy.txt> creates a policy based on the target server
|
||||
(i.e.: the target server has the ideal
|
||||
configuration that other servers should
|
||||
@ -53,6 +70,8 @@ usage: ssh-audit.py [options] <host>
|
||||
(default: 5)
|
||||
-T, --targets=<hosts.txt> a file containing a list of target hosts (one
|
||||
per line, format HOST[:PORT])
|
||||
--threads=<threads> number of threads to use when scanning multiple
|
||||
targets (-T/--targets) (default: 32)
|
||||
-v, --verbose verbose output
|
||||
```
|
||||
* if both IPv4 and IPv6 are used, order of precedence can be set by using either `-46` or `-64`.
|
||||
@ -86,7 +105,7 @@ To audit a client configuration, with a listener on port 4567:
|
||||
ssh-audit -c -p 4567
|
||||
```
|
||||
|
||||
To list all official built-in policies (hint: use resulting file paths with `-P`/`--policy`):
|
||||
To list all official built-in policies (hint: use resulting policy names with `-P`/`--policy`):
|
||||
```
|
||||
ssh-audit -L
|
||||
```
|
||||
@ -106,17 +125,19 @@ To run a policy audit against many servers:
|
||||
ssh-audit -T servers.txt -P ["policy name" | path/to/server_policy.txt]
|
||||
```
|
||||
|
||||
To create a policy based on a target server (which can be manually edited; see official built-in policies for syntax examples):
|
||||
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:
|
||||

|
||||
|
||||
### Server Policy Audit Example
|
||||
Below is a screen shot of the policy auditing output when connecting to an un-hardened Ubuntu Server 20.04 machine:
|
||||
Below is a screen shot of the policy auditing output when connecting to an un-hardened Ubuntu Server 20.04 machine (hint: use `-L`/`--list-policies` to see names of built-in policies to use with `-P`/`--policy`):
|
||||

|
||||
|
||||
After applying the steps in the hardening guide (see below), the output changes to the following:
|
||||
@ -126,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:
|
||||
```
|
||||
@ -142,21 +163,68 @@ 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).
|
||||
- Added version check for OpenSSH user enumeration (CVE-2018-15473).
|
||||
- Added deprecation note to host key types based on SHA-1.
|
||||
- Added extra warnings for SSHv1.
|
||||
- Added built-in hardened OpenSSH v8.5 policy.
|
||||
- Upgraded warnings to failures for host key types based on SHA-1.
|
||||
- Fixed crash when receiving unexpected response during host key test.
|
||||
- Fixed hang against older Cisco devices during host key test & gex test.
|
||||
- Fixed improper termination while scanning multiple targets when one target returns an error.
|
||||
- Dropped support for Python 3.5 (which reached EOL in Sept. 2020).
|
||||
- Added 1 new key exchange: `sntrup761x25519-sha512@openssh.com`.
|
||||
|
||||
### v2.3.1 (2020-10-28)
|
||||
- Now parses public key sizes for `rsa-sha2-256-cert-v01@openssh.com` and `rsa-sha2-512-cert-v01@openssh.com` host key types.
|
||||
- Flag `ssh-rsa-cert-v01@openssh.com` as a failure due to SHA-1 hash.
|
||||
|
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"
|
125
build_windows_executable.sh
Executable file
125
build_windows_executable.sh
Executable file
@ -0,0 +1,125 @@
|
||||
#!/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_windows_executable.sh
|
||||
#
|
||||
# Builds a Windows executable using PyInstaller.
|
||||
################################################################################
|
||||
|
||||
|
||||
PLATFORM="$(uname -s)"
|
||||
|
||||
# This script is intended for use on Cygwin only.
|
||||
case "$PLATFORM" in
|
||||
CYGWIN*) ;;
|
||||
*)
|
||||
echo "Platform not supported ($PLATFORM). This must be run in Cygwin only."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Ensure that Python 3.x is installed.
|
||||
if [[ "$(python -V)" != "Python 3."* ]]; then
|
||||
echo "Python v3.x not found. Install the latest stable version from: https://www.python.org/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install/update package dependencies.
|
||||
echo "Installing/updating pyinstaller and colorama packages..."
|
||||
pip install -U pyinstaller colorama
|
||||
echo
|
||||
|
||||
# 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
|
||||
echo "Failed to run ./update_windows_man_page.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Do all operations from this point from the main source directory.
|
||||
pushd src/ssh_audit > /dev/null
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
echo -e "\nRunning pyinstaller...\n"
|
||||
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
|
||||
|
||||
# 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
|
233
docker_test.sh
233
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
|
||||
@ -27,6 +32,7 @@ RED="\033[0;31m"
|
||||
YELLOW="\033[0;33m"
|
||||
GREEN="\033[0;32m"
|
||||
REDB="\033[1;31m" # Red + bold
|
||||
YELLOWB="\033[1;33m" # Yellow + bold
|
||||
GREENB="\033[1;32m" # Green + bold
|
||||
|
||||
# Program return values.
|
||||
@ -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
|
||||
|
||||
@ -93,10 +102,10 @@ function compile {
|
||||
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
|
||||
@ -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,10 +257,10 @@ 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
|
||||
wget -O key.asc "$2"
|
||||
|
||||
echo -e "\nImporting ${project} release key...\n"
|
||||
gpg --import key.asc
|
||||
@ -259,40 +268,40 @@ function get_release_key {
|
||||
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
|
||||
@ -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
|
||||
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
|
||||
@ -442,24 +451,37 @@ function run_test {
|
||||
test_name="TinySSH ${version} ${test_number}"
|
||||
fi
|
||||
|
||||
cid=`docker run -d -p 2222:22 ${IMAGE_NAME}:${IMAGE_VERSION} ${server_exec}`
|
||||
cid=$(docker run -d -p 2222:22 "$IMAGE_NAME:$IMAGE_VERSION" ${server_exec})
|
||||
#echo "Running: docker run -d -p 2222:22 $IMAGE_NAME:$IMAGE_VERSION ${server_exec}"
|
||||
if [[ $? != 0 ]]; then
|
||||
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
|
||||
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
|
||||
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
|
||||
@ -474,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}
|
||||
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}
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
diff=`diff -u ${expected_result_json} ${test_result_json}`
|
||||
fi
|
||||
|
||||
diff=$(diff -u "${expected_result_json}" "${test_result_json}")
|
||||
if [[ $? != 0 ]]; then
|
||||
|
||||
# If the user wants to update the tests, then overwrite the expected results with the actual results.
|
||||
if [[ $accept == 1 ]]; then
|
||||
cp "${test_result_json}" "${expected_result_json}"
|
||||
echo -e "${test_name} ${YELLOWB}UPDATED${CLR}\n"
|
||||
else
|
||||
echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n"
|
||||
failed=1
|
||||
num_failures=$((num_failures+1))
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if [[ $failed == 0 ]]; then
|
||||
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.
|
||||
@ -517,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.
|
||||
@ -547,7 +585,7 @@ function run_custom_policy_test {
|
||||
}
|
||||
|
||||
|
||||
function run_policy_test {
|
||||
run_policy_test() {
|
||||
test_name=$1
|
||||
server_exec=$2
|
||||
policy_path=$3
|
||||
@ -556,29 +594,39 @@ 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
|
||||
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
|
||||
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}
|
||||
|
||||
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
|
||||
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}
|
||||
|
||||
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
|
||||
@ -589,18 +637,34 @@ 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
|
||||
|
||||
# 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
|
||||
|
||||
diff=`diff -u ${expected_result_json} ${test_result_json}`
|
||||
fi
|
||||
|
||||
diff=$(diff -u "${expected_result_json}" "${test_result_json}")
|
||||
if [[ $? != 0 ]]; then
|
||||
|
||||
# If the user wants to update the tests, then overwrite the expected results with the actual results.
|
||||
if [[ $accept == 1 ]]; then
|
||||
cp "${test_result_json}" "${expected_result_json}"
|
||||
echo -e "${test_name} ${YELLOWB}UPDATED${CLR}\n"
|
||||
else
|
||||
echo -e "${test_name} ${REDB}FAILED${CLR}.\n\n${diff}\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
echo -e "${test_name} ${GREEN}passed${CLR}."
|
||||
}
|
||||
|
||||
@ -636,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..."
|
||||
@ -646,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..."
|
||||
@ -660,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
|
||||
@ -698,18 +769,18 @@ 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"
|
||||
else
|
||||
echo -e "\n${REDB}${num_failures} TESTS FAILED!${CLR}\n"
|
||||
fi
|
||||
|
||||
rm -rf $TEST_RESULT_DIR
|
||||
exit 0
|
||||
|
@ -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,11 +19,11 @@ classifiers =
|
||||
License :: OSI Approved :: MIT License
|
||||
Operating System :: OS Independent
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.5
|
||||
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
|
||||
@ -32,7 +33,7 @@ classifiers =
|
||||
packages = find:
|
||||
package_dir =
|
||||
= src
|
||||
python_requires = >=3.5,<4
|
||||
python_requires = >=3.7,<4
|
||||
|
||||
[options.packages.find]
|
||||
where = src
|
||||
|
@ -1,21 +1,20 @@
|
||||
name: ssh-audit
|
||||
version: '2.3.1-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
|
||||
@ -131,7 +131,7 @@ class Algorithms:
|
||||
# if version is not None:
|
||||
# software = SSH.Software(None, product, version, None, None)
|
||||
# break
|
||||
rec = {} # type: Dict[int, Dict[str, Dict[str, Dict[str, int]]]]
|
||||
rec: Dict[int, Dict[str, Dict[str, Dict[str, int]]]] = {}
|
||||
if software is None:
|
||||
unknown_software = True
|
||||
for alg_pair in self.values:
|
||||
@ -206,7 +206,7 @@ class Algorithms:
|
||||
def __init__(self, sshv: int, db: Dict[str, Dict[str, List[List[Optional[str]]]]]) -> None:
|
||||
self.__sshv = sshv
|
||||
self.__db = db
|
||||
self.__storage = {} # type: Dict[str, List[str]]
|
||||
self.__storage: Dict[str, List[str]] = {}
|
||||
|
||||
@property
|
||||
def sshv(self) -> int:
|
||||
|
@ -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,45 +41,36 @@ class AuditConf:
|
||||
self.client_audit = False
|
||||
self.colors = True
|
||||
self.json = False
|
||||
self.json_print_indent = False
|
||||
self.verbose = False
|
||||
self.level = 'info'
|
||||
self.ipvo = () # type: Sequence[int]
|
||||
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).
|
||||
self.ipv4 = False
|
||||
self.ipv6 = False
|
||||
self.make_policy = False # When True, creates a policy file from an audit scan.
|
||||
self.policy_file = None # type: Optional[str] # File system path to a policy
|
||||
self.policy = None # type: Optional[Policy] # Policy object
|
||||
self.policy_file: Optional[str] = None # File system path to a policy
|
||||
self.policy: Optional[Policy] = None # Policy object
|
||||
self.timeout = 5.0
|
||||
self.timeout_set = False # Set to True when the user explicitly sets it.
|
||||
self.target_file = None # type: Optional[str]
|
||||
self.target_list = [] # type: List[str]
|
||||
self.target_file: Optional[str] = None
|
||||
self.target_list: List[str] = []
|
||||
self.threads = 32
|
||||
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 ['ssh1', 'ssh2', 'batch', 'client_audit', 'colors', 'verbose', 'timeout_set', 'json', 'make_policy', 'list_policies']:
|
||||
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)
|
||||
if len(self.ip_version_preference) == 2: # Being called more than twice is not valid.
|
||||
valid = False
|
||||
value = bool(value)
|
||||
ipv = 4 if name == 'ipv4' else 6
|
||||
if value:
|
||||
value = tuple(list(self.ipvo) + [ipv])
|
||||
else: # pylint: disable=else-if-used
|
||||
if len(self.ipvo) == 0:
|
||||
value = (6,) if ipv == 4 else (4,)
|
||||
else:
|
||||
value = tuple([x for x in self.ipvo if x != ipv])
|
||||
self.__setattr__('ipvo', value)
|
||||
elif name == 'ipvo':
|
||||
if isinstance(value, (tuple, list)):
|
||||
uniq_value = Utils.unique_seq(value)
|
||||
value = tuple([x for x in uniq_value if x in (4, 6)])
|
||||
valid = True
|
||||
ipv_both = len(value) == 0
|
||||
object.__setattr__(self, 'ipv4', ipv_both or 4 in value)
|
||||
object.__setattr__(self, 'ipv6', ipv_both or 6 in value)
|
||||
elif value:
|
||||
self.ip_version_preference.append(4 if name == 'ipv4' else 6)
|
||||
elif name == 'port':
|
||||
valid, port = True, Utils.parse_int(value)
|
||||
if port < 1 or port > 65535:
|
||||
@ -96,8 +87,13 @@ class AuditConf:
|
||||
if value == -1.0:
|
||||
raise ValueError('invalid timeout: {}'.format(value))
|
||||
valid = True
|
||||
elif name in ['policy_file', 'policy', 'target_file', 'target_list', 'lookup']:
|
||||
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)
|
||||
if num_threads < 1:
|
||||
raise ValueError('invalid number of threads: {}'.format(value))
|
||||
value = num_threads
|
||||
|
||||
if valid:
|
||||
object.__setattr__(self, name, 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-2020 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,17 +21,18 @@
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
import os
|
||||
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.protocol import Protocol
|
||||
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
|
||||
@ -40,37 +41,100 @@ class GEXTest:
|
||||
|
||||
# Creates a new connection to the server. Returns True on success, or False.
|
||||
@staticmethod
|
||||
def reconnect(s: 'SSH_Socket', 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
|
||||
|
||||
unused = None # pylint: disable=unused-variable
|
||||
unused2 = None # pylint: disable=unused-variable
|
||||
unused, unused2, err = s.get_banner()
|
||||
_, _, err = s.get_banner()
|
||||
if err is not None:
|
||||
out.v(err, write_now=True)
|
||||
s.close()
|
||||
return False
|
||||
|
||||
# Parse the server's initial KEX.
|
||||
packet_type = 0 # pylint: disable=unused-variable
|
||||
packet_type, payload = s.read_packet(2)
|
||||
kex = SSH2_Kex.parse(payload)
|
||||
|
||||
# Send our KEX using the specified group-exchange and most of the
|
||||
# server's own values.
|
||||
client_kex = SSH2_Kex(os.urandom(16), [gex_alg], kex.key_algorithms, kex.client, kex.server, False, 0)
|
||||
s.write_byte(Protocol.MSG_KEXINIT)
|
||||
client_kex.write(s)
|
||||
s.send_packet()
|
||||
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)
|
||||
|
||||
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,
|
||||
@ -84,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, 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.
|
||||
@ -102,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()
|
||||
|
||||
@ -117,7 +183,9 @@ class GEXTest:
|
||||
if bits >= smallest_modulus > 0:
|
||||
break
|
||||
|
||||
if GEXTest.reconnect(s, 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
|
||||
|
||||
@ -125,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
|
||||
@ -153,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
|
||||
|
@ -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)
|
||||
|
||||
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,20 @@
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
VERSION = 'v2.3.1'
|
||||
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-2020 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,17 +21,18 @@
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
import os
|
||||
|
||||
# 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 KexDH, KexGroup1, KexGroup14_SHA1, KexGroup14_SHA256, KexCurve25519_SHA256, KexGroup16_SHA512, KexGroup18_SHA512, KexGroupExchange_SHA1, KexGroupExchange_SHA256, KexNISTP256, KexNISTP384, KexNISTP521
|
||||
from ssh_audit.protocol import Protocol
|
||||
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.
|
||||
@ -53,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,
|
||||
@ -78,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
|
||||
|
||||
@ -97,50 +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
|
||||
|
||||
# Parse the server's initial KEX.
|
||||
packet_type = 0 # pylint: disable=unused-variable
|
||||
packet_type, payload = s.read_packet()
|
||||
SSH2_Kex.parse(payload)
|
||||
# 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)
|
||||
|
||||
# Send the server our KEXINIT message, using only our
|
||||
# selected kex and host key type. Send the server's own
|
||||
# list of ciphers and MACs back to it (this doesn't
|
||||
# matter, really).
|
||||
client_kex = SSH2_Kex(os.urandom(16), [kex_str], [host_key_type], server_kex.client, server_kex.server, False, 0)
|
||||
|
||||
s.write_byte(Protocol.MSG_KEXINIT)
|
||||
client_kex.write(s)
|
||||
s.send_packet()
|
||||
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)
|
||||
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)
|
||||
raw_hostkey_bytes = b''
|
||||
try:
|
||||
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.
|
||||
@ -148,29 +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]
|
||||
alg_list.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)
|
||||
alg_list.append(['using small %d-bit modulus' % min_modulus])
|
||||
# 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 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)
|
||||
|
||||
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 = None # type: Optional[bytes]
|
||||
self.__hostkey_type = None # type: Optional[bytes]
|
||||
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,23 +116,44 @@ 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
|
||||
|
||||
# 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)
|
||||
self.__hostkey_n = int(binascii.hexlify(hostkey_n), 16) # pylint: disable=unused-private-member
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
|
||||
@ -142,10 +166,10 @@ class KexDH: # pragma: nocover
|
||||
|
||||
# Skip the key ID (this is the serial number of the
|
||||
# certificate).
|
||||
key_id, key_id_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
key_id, key_id_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
|
||||
|
||||
# The principles, which are... I don't know what.
|
||||
principles, principles_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
principles, principles_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
|
||||
|
||||
# Skip over the timestamp that this certificate is valid after.
|
||||
ptr += 8
|
||||
@ -156,16 +180,16 @@ class KexDH: # pragma: nocover
|
||||
# TODO: validate the principles, and time range.
|
||||
|
||||
# The critical options.
|
||||
critical_options, critical_options_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
critical_options, critical_options_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
|
||||
|
||||
# Certificate extensions.
|
||||
extensions, extensions_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
extensions, extensions_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
|
||||
|
||||
# Another nonce.
|
||||
nonce, nonce_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
nonce, nonce_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
|
||||
|
||||
# Finally, we get to the CA key.
|
||||
ca_key, ca_key_len, ptr = KexDH.__get_bytes(hostkey, ptr)
|
||||
ca_key, ca_key_len, ptr = KexDH.__get_bytes(hostkey, ptr) # pylint: disable=unused-variable
|
||||
|
||||
# Last in the host key blob is the CA signature. It isn't
|
||||
# interesting to us, so we won't bother parsing any further.
|
||||
@ -173,15 +197,24 @@ class KexDH: # pragma: nocover
|
||||
ptr = 0
|
||||
|
||||
# 'ssh-rsa', 'rsa-sha2-256', etc.
|
||||
ca_key_type, ca_key_type_len, ptr = KexDH.__get_bytes(ca_key, ptr)
|
||||
ca_key_type_bytes, ca_key_type_len, ptr = KexDH.__get_bytes(ca_key, ptr) # pylint: disable=unused-variable
|
||||
ca_key_type = ca_key_type_bytes.decode('ascii')
|
||||
self.out.d("Found CA type: [%s]" % ca_key_type)
|
||||
|
||||
# ED25519 CA's don't explicitly include the modulus size in the public key, since its fixed at 32 in all cases.
|
||||
if ca_key_type == 'ssh-ed25519':
|
||||
ca_key_n_len = 32
|
||||
else:
|
||||
# CA's public key exponent.
|
||||
ca_key_e, ca_key_e_len, ptr = KexDH.__get_bytes(ca_key, ptr)
|
||||
ca_key_e, ca_key_e_len, ptr = KexDH.__get_bytes(ca_key, ptr) # pylint: disable=unused-variable
|
||||
|
||||
# CA's modulus. Bingo.
|
||||
ca_key_n, self.__ca_n_len, ptr = KexDH.__get_bytes(ca_key, ptr)
|
||||
ca_key_n, ca_key_n_len, ptr = KexDH.__get_bytes(ca_key, ptr) # pylint: disable=unused-variable
|
||||
|
||||
return hostkey
|
||||
else:
|
||||
self.out.d("Certificate type %u found; this is not usually valid in the context of a host key! Skipping it..." % cert_type)
|
||||
|
||||
return ca_key_type, ca_key_n_len
|
||||
|
||||
@staticmethod
|
||||
def __get_bytes(buf: bytes, ptr: int) -> Tuple[bytes, int, int]:
|
||||
@ -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')
|
||||
|
@ -1,87 +0,0 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
# 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.utils import Utils
|
||||
|
||||
|
||||
class Output:
|
||||
LEVELS = ('info', 'warn', 'fail') # type: Sequence[str]
|
||||
COLORS = {'head': 36, 'good': 32, 'warn': 33, 'fail': 31}
|
||||
|
||||
# Use brighter colors on Windows for better readability.
|
||||
if Utils.is_windows():
|
||||
COLORS = {'head': 96, 'good': 92, 'warn': 93, 'fail': 91}
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.batch = False
|
||||
self.verbose = False
|
||||
self.use_colors = True
|
||||
self.json = False
|
||||
self.__level = 0
|
||||
self.__colsupport = 'colorama' in sys.modules or os.name == 'posix'
|
||||
|
||||
@property
|
||||
def level(self) -> str:
|
||||
if self.__level < len(self.LEVELS):
|
||||
return self.LEVELS[self.__level]
|
||||
return 'unknown'
|
||||
|
||||
@level.setter
|
||||
def level(self, name: str) -> None:
|
||||
self.__level = self.get_level(name)
|
||||
|
||||
def get_level(self, name: str) -> int:
|
||||
cname = 'info' if name == 'good' else name
|
||||
if cname not in self.LEVELS:
|
||||
return sys.maxsize
|
||||
return self.LEVELS.index(cname)
|
||||
|
||||
def sep(self) -> None:
|
||||
if not self.batch:
|
||||
print()
|
||||
|
||||
@property
|
||||
def colors_supported(self) -> bool:
|
||||
return self.__colsupport
|
||||
|
||||
@staticmethod
|
||||
def _colorized(color: str) -> Callable[[str], None]:
|
||||
return lambda x: print(u'{}{}\033[0m'.format(color, x))
|
||||
|
||||
def __getattr__(self, name: str) -> Callable[[str], None]:
|
||||
if name == 'head' and self.batch:
|
||||
return lambda x: None
|
||||
if not self.get_level(name) >= self.__level:
|
||||
return lambda x: None
|
||||
if self.use_colors and self.colors_supported and name in self.COLORS:
|
||||
color = '\033[0;{}m'.format(self.COLORS[name])
|
||||
return self._colorized(color)
|
||||
else:
|
||||
return lambda x: print(u'{}'.format(x))
|
@ -1,7 +1,7 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2017-2020 Joe Testa (jtesta@positronsecurity.com)
|
||||
Copyright (C) 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
|
||||
@ -22,29 +22,164 @@
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
|
||||
# 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.utils import Utils
|
||||
|
||||
class OutputBuffer(List[str]):
|
||||
|
||||
class OutputBuffer:
|
||||
LEVELS: Sequence[str] = ('info', 'warn', 'fail')
|
||||
COLORS = {'head': 36, 'good': 32, 'warn': 33, 'fail': 31}
|
||||
|
||||
# Use brighter colors on Windows for better readability.
|
||||
if Utils.is_windows():
|
||||
COLORS = {'head': 96, 'good': 92, 'warn': 93, 'fail': 91}
|
||||
|
||||
def __init__(self, buffer_output: bool = True) -> None:
|
||||
self.buffer_output = buffer_output
|
||||
self.buffer: List[str] = []
|
||||
self.in_section = False
|
||||
self.section: List[str] = []
|
||||
self.batch = False
|
||||
self.verbose = False
|
||||
self.debug = False
|
||||
self.use_colors = True
|
||||
self.json = False
|
||||
self.__level = 0
|
||||
self.__is_color_supported = ('colorama' in sys.modules) or (os.name == 'posix')
|
||||
self.line_ended = True
|
||||
|
||||
def _print(self, level: str, s: str = '', line_ended: bool = True) -> None:
|
||||
'''Saves output to buffer (if in buffered mode), or immediately prints to stdout otherwise.'''
|
||||
|
||||
# If we're logging only 'warn' or above, and this is an 'info', ignore message.
|
||||
if self.get_level(level) < self.__level:
|
||||
return
|
||||
|
||||
if self.use_colors and self.colors_supported and len(s) > 0 and level != 'info':
|
||||
s = "\033[0;%dm%s\033[0m" % (self.COLORS[level], s)
|
||||
|
||||
if self.buffer_output:
|
||||
# Select which list to add to. If we are in a 'with' statement, then this goes in the section buffer, otherwise the general buffer.
|
||||
buf = self.section if self.in_section else self.buffer
|
||||
|
||||
# Determine if a new line should be added, or if the last line should be appended.
|
||||
if not self.line_ended:
|
||||
last_entry = -1 if len(buf) > 0 else 0
|
||||
buf[last_entry] = buf[last_entry] + s
|
||||
else:
|
||||
buf.append(s)
|
||||
|
||||
# When False, this tells the next call to append to the last line we just added.
|
||||
self.line_ended = line_ended
|
||||
else:
|
||||
print(s)
|
||||
|
||||
def get_buffer(self) -> str:
|
||||
'''Returns all buffered output, then clears the buffer.'''
|
||||
self.flush_section()
|
||||
|
||||
buffer_str = "\n".join(self.buffer)
|
||||
self.buffer = []
|
||||
return buffer_str
|
||||
|
||||
def write(self) -> None:
|
||||
'''Writes the output to stdout.'''
|
||||
self.flush_section()
|
||||
print(self.get_buffer(), flush=True)
|
||||
|
||||
def reset(self) -> None:
|
||||
self.flush_section()
|
||||
self.get_buffer()
|
||||
|
||||
@property
|
||||
def level(self) -> str:
|
||||
'''Returns the minimum level for output.'''
|
||||
if self.__level < len(self.LEVELS):
|
||||
return self.LEVELS[self.__level]
|
||||
return 'unknown'
|
||||
|
||||
@level.setter
|
||||
def level(self, name: str) -> None:
|
||||
'''Sets the minimum level for output (one of: 'info', 'warn', 'fail').'''
|
||||
self.__level = self.get_level(name)
|
||||
|
||||
def get_level(self, name: str) -> int:
|
||||
cname = 'info' if name == 'good' else name
|
||||
if cname not in self.LEVELS:
|
||||
return sys.maxsize
|
||||
return self.LEVELS.index(cname)
|
||||
|
||||
@property
|
||||
def colors_supported(self) -> bool:
|
||||
'''Returns True if the system supports color output.'''
|
||||
return self.__is_color_supported
|
||||
|
||||
# When used in a 'with' block, the output to goes into a section; this can be sorted separately when add_section_to_buffer() is later called.
|
||||
def __enter__(self) -> 'OutputBuffer':
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
self.__buf = io.StringIO()
|
||||
self.__stdout = sys.stdout
|
||||
sys.stdout = self.__buf
|
||||
self.in_section = True
|
||||
return self
|
||||
|
||||
def flush(self, sort_lines: bool = False) -> None:
|
||||
# Lines must be sorted in some cases to ensure consistent testing.
|
||||
if sort_lines:
|
||||
self.sort() # pylint: disable=no-member
|
||||
for line in self: # pylint: disable=not-an-iterable
|
||||
print(line)
|
||||
|
||||
def __exit__(self, *args: Any) -> None:
|
||||
self.extend(self.__buf.getvalue().splitlines()) # pylint: disable=no-member
|
||||
sys.stdout = self.__stdout
|
||||
self.in_section = False
|
||||
|
||||
def flush_section(self, sort_section: bool = False) -> None:
|
||||
'''Appends section output (optionally sorting it first) to the end of the buffer, then clears the section output.'''
|
||||
if sort_section:
|
||||
self.section.sort()
|
||||
|
||||
self.buffer.extend(self.section)
|
||||
self.section = []
|
||||
|
||||
def is_section_empty(self) -> bool:
|
||||
'''Returns True if the section buffer is empty, otherwise False.'''
|
||||
return len(self.section) == 0
|
||||
|
||||
def head(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
|
||||
if not self.batch:
|
||||
self._print('head', s, line_ended)
|
||||
return self
|
||||
|
||||
def fail(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
|
||||
self._print('fail', s, line_ended)
|
||||
return self
|
||||
|
||||
def warn(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
|
||||
self._print('warn', s, line_ended)
|
||||
return self
|
||||
|
||||
def info(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
|
||||
self._print('info', s, line_ended)
|
||||
return self
|
||||
|
||||
def good(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
|
||||
self._print('good', s, line_ended)
|
||||
return self
|
||||
|
||||
def sep(self) -> 'OutputBuffer':
|
||||
if not self.batch:
|
||||
self._print('info')
|
||||
return self
|
||||
|
||||
def v(self, s: str, write_now: bool = False) -> 'OutputBuffer':
|
||||
'''Prints a message if verbose output is enabled.'''
|
||||
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()
|
||||
|
||||
return self
|
||||
|
@ -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,71 +30,100 @@ 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 = {
|
||||
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 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},
|
||||
|
||||
} # type: Dict[str, Dict[str, Union[Optional[str], Optional[List[str]], bool, Dict[str, int]]]]
|
||||
'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},
|
||||
|
||||
}
|
||||
|
||||
def __init__(self, policy_file: Optional[str] = None, policy_data: Optional[str] = None, manual_load: bool = False) -> None:
|
||||
self._name = None # type: Optional[str]
|
||||
self._version = None # type: Optional[str]
|
||||
self._banner = None # type: Optional[str]
|
||||
self._compressions = None # type: Optional[List[str]]
|
||||
self._host_keys = None # type: Optional[List[str]]
|
||||
self._optional_host_keys = None # type: Optional[List[str]]
|
||||
self._kex = None # type: Optional[List[str]]
|
||||
self._ciphers = None # type: Optional[List[str]]
|
||||
self._macs = None # type: Optional[List[str]]
|
||||
self._hostkey_sizes = None # type: Optional[Dict[str, int]]
|
||||
self._cakey_sizes = None # type: Optional[Dict[str, int]]
|
||||
self._dh_modulus_sizes = None # type: Optional[Dict[str, int]]
|
||||
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, json_output: bool = False) -> None:
|
||||
self._name: Optional[str] = None
|
||||
self._version: Optional[str] = None
|
||||
self._banner: Optional[str] = None
|
||||
self._compressions: Optional[List[str]] = None
|
||||
self._host_keys: Optional[List[str]] = None
|
||||
self._optional_host_keys: Optional[List[str]] = None
|
||||
self._kex: Optional[List[str]] = None
|
||||
self._ciphers: Optional[List[str]] = None
|
||||
self._macs: Optional[List[str]] = 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 = '' # type: str
|
||||
self._name_and_version: str = ''
|
||||
|
||||
# If invoked while JSON output is expected, send warnings to stderr instead of stdout (which would corrupt the JSON output).
|
||||
if json_output:
|
||||
self._warning_target = sys.stderr
|
||||
else:
|
||||
self._warning_target = sys.stdout
|
||||
|
||||
# Ensure that only one mode was specified.
|
||||
num_modes = 0
|
||||
@ -111,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:
|
||||
@ -136,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']:
|
||||
@ -155,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(',')
|
||||
@ -179,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
|
||||
|
||||
@ -215,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.'''
|
||||
@ -225,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"
|
||||
@ -244,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 = '''#
|
||||
@ -281,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
|
||||
|
||||
@ -296,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
|
||||
|
||||
@ -305,7 +385,7 @@ macs = %s
|
||||
'''Evaluates a server configuration against this policy. Returns a tuple of a boolean (True if server adheres to policy) and an array of strings that holds error messages.'''
|
||||
|
||||
ret = True
|
||||
errors = [] # type: List[Any]
|
||||
errors: List[Any] = []
|
||||
|
||||
banner_str = str(banner)
|
||||
if (self._banner is not None) and (banner_str != self._banner):
|
||||
@ -333,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:
|
||||
# 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, 'RSA CA key (%s) sizes' % hostkey_type, [str(expected_cakey_size)], None, [str(actual_cakey_size)])
|
||||
self._append_error(errors, 'CA signature type', [expected_ca_key_type], None, [actual_ca_key_type])
|
||||
# Ensure that the actual and expected signature sizes match.
|
||||
elif actual_ca_key_size != expected_ca_key_size:
|
||||
ret = False
|
||||
self._append_error(errors, 'CA signature size (%s)' % actual_ca_key_type, [str(expected_ca_key_size)], None, [str(actual_ca_key_size)])
|
||||
|
||||
if kex.kex_algorithms != self._kex:
|
||||
ret = False
|
||||
@ -369,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)])
|
||||
@ -419,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)
|
||||
@ -431,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
|
||||
@ -447,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
|
||||
|
||||
|
||||
@ -482,7 +569,6 @@ macs = %s
|
||||
ciphers_str = undefined
|
||||
macs_str = undefined
|
||||
hostkey_sizes_str = undefined
|
||||
cakey_sizes_str = undefined
|
||||
dh_modulus_sizes_str = undefined
|
||||
|
||||
|
||||
@ -507,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)
|
||||
|
@ -43,14 +43,14 @@ class ReadBuf:
|
||||
return self._buf.read(size)
|
||||
|
||||
def read_byte(self) -> int:
|
||||
v = struct.unpack('B', self.read(1))[0] # type: int
|
||||
v: int = struct.unpack('B', self.read(1))[0]
|
||||
return v
|
||||
|
||||
def read_bool(self) -> bool:
|
||||
return self.read_byte() != 0
|
||||
|
||||
def read_int(self) -> int:
|
||||
v = struct.unpack('>I', self.read(4))[0] # type: int
|
||||
v: int = struct.unpack('>I', self.read(4))[0]
|
||||
return v
|
||||
|
||||
def read_list(self) -> List[str]:
|
||||
|
@ -180,7 +180,7 @@ class Software:
|
||||
# pylint: disable=too-many-return-statements
|
||||
software = str(banner.software)
|
||||
mx = re.match(r'^dropbear_([\d\.]+\d+)(.*)', software)
|
||||
v = None # type: Optional[str]
|
||||
v: Optional[str] = None
|
||||
if mx is not None:
|
||||
patch = cls._fix_patch(mx.group(2))
|
||||
v, p = 'Matt Johnston', Product.DropbearSSH
|
||||
|
@ -29,7 +29,7 @@ from ssh_audit.ssh1_crc32 import SSH1_CRC32
|
||||
|
||||
|
||||
class SSH1:
|
||||
_crc32 = None # type: Optional[SSH1_CRC32]
|
||||
_crc32: Optional[SSH1_CRC32] = None
|
||||
CIPHERS = ['none', 'idea', 'des', '3des', 'tss', 'rc4', 'blowfish']
|
||||
AUTHS = ['none', 'rhosts', 'rsa', 'password', 'rhosts_rsa', 'tis', 'kerberos']
|
||||
|
||||
|
@ -34,7 +34,7 @@ class SSH1_KexDB: # pylint: disable=too-few-public-methods
|
||||
FAIL_NA_UNSAFE = 'not implemented in OpenSSH (server), unsafe algorithm'
|
||||
TEXT_CIPHER_IDEA = 'cipher used by commercial SSH'
|
||||
|
||||
ALGORITHMS = {
|
||||
ALGORITHMS: Dict[str, Dict[str, List[List[Optional[str]]]]] = {
|
||||
'key': {
|
||||
'ssh-rsa1': [['1.2.2']],
|
||||
},
|
||||
@ -55,4 +55,4 @@ class SSH1_KexDB: # pylint: disable=too-few-public-methods
|
||||
'tis': [['1.2.2']],
|
||||
'kerberos': [['1.2.2', '3.6'], [FAIL_OPENSSH37_REMOVE]],
|
||||
}
|
||||
} # type: Dict[str, Dict[str, List[List[Optional[str]]]]]
|
||||
}
|
||||
|
@ -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 = {} # type: Dict[str, Tuple[int, int]]
|
||||
self.__dh_modulus_sizes = {} # type: Dict[str, Tuple[int, int]]
|
||||
self.__host_keys = {} # type: 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,58 +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'
|
||||
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'
|
||||
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'
|
||||
|
||||
ALGORITHMS = {
|
||||
# Format: 'algorithm_name': [['version_first_appeared_in'], [reason_for_failure1, reason_for_failure2, ...], [warning1, warning2, ...]]
|
||||
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, ...], [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': [[]],
|
||||
@ -89,183 +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'], [], [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'], [WARN_HASH_WEAK]],
|
||||
'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': [[], [], [WARN_HASH_WEAK]],
|
||||
'x509v3-sign-rsa-sha256@ssh.com': [[]],
|
||||
'x509v3-ssh-dss': [[], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH70_WEAK], [WARN_RNDSIG_KEY]],
|
||||
'x509v3-ssh-rsa': [[], [], [WARN_HASH_WEAK]],
|
||||
'ssh-rsa-cert-v00@openssh.com': [['5.4', '6.9'], [FAIL_OPENSSH70_LEGACY], []],
|
||||
'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'], [WARN_HASH_WEAK]],
|
||||
'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]],
|
||||
}
|
||||
}
|
||||
} # type: Dict[str, Dict[str, List[List[Optional[str]]]]]
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -36,7 +36,7 @@ from typing import Callable, Optional, Union, Any # noqa: F401
|
||||
from ssh_audit import exitcodes
|
||||
from ssh_audit.banner import Banner
|
||||
from ssh_audit.globals import SSH_HEADER
|
||||
from ssh_audit.output import Output
|
||||
from ssh_audit.outputbuffer import OutputBuffer
|
||||
from ssh_audit.protocol import Protocol
|
||||
from ssh_audit.readbuf import ReadBuf
|
||||
from ssh_audit.ssh1 import SSH1
|
||||
@ -52,14 +52,15 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
||||
|
||||
SM_BANNER_SENT = 1
|
||||
|
||||
def __init__(self, host: Optional[str], port: int, ipvo: Optional[Sequence[int]] = None, timeout: Union[int, float] = 5, timeout_set: bool = False) -> None:
|
||||
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.__sock = None # type: Optional[socket.socket]
|
||||
self.__sock_map = {} # type: Dict[int, socket.socket]
|
||||
self.__outputbuffer = outputbuffer
|
||||
self.__sock: Optional[socket.socket] = None
|
||||
self.__sock_map: Dict[int, socket.socket] = {}
|
||||
self.__block_size = 8
|
||||
self.__state = 0
|
||||
self.__header = [] # type: List[str]
|
||||
self.__banner = None # type: Optional[Banner]
|
||||
self.__header: List[str] = []
|
||||
self.__banner: Optional[Banner] = None
|
||||
if host is None:
|
||||
raise ValueError('undefined host')
|
||||
nport = Utils.parse_int(port)
|
||||
@ -67,35 +68,30 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
||||
raise ValueError('invalid port: {}'.format(port))
|
||||
self.__host = host
|
||||
self.__port = nport
|
||||
if ipvo is not None:
|
||||
self.__ipvo = ipvo
|
||||
else:
|
||||
self.__ipvo = ()
|
||||
self.__ip_version_preference = ip_version_preference # 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).
|
||||
self.__timeout = timeout
|
||||
self.__timeout_set = timeout_set
|
||||
self.client_host = None # type: Optional[str]
|
||||
self.client_host: Optional[str] = None
|
||||
self.client_port = None
|
||||
|
||||
def _resolve(self, ipvo: Sequence[int]) -> Iterable[Tuple[int, Tuple[Any, ...]]]:
|
||||
ipvo = tuple([x for x in Utils.unique_seq(ipvo) if x in (4, 6)])
|
||||
ipvo_len = len(ipvo)
|
||||
prefer_ipvo = ipvo_len > 0
|
||||
prefer_ipv4 = prefer_ipvo and ipvo[0] == 4
|
||||
if ipvo_len == 1:
|
||||
family = socket.AF_INET if ipvo[0] == 4 else socket.AF_INET6
|
||||
def _resolve(self) -> Iterable[Tuple[int, Tuple[Any, ...]]]:
|
||||
# If __ip_version_preference has only one entry, then it means that ONLY that IP version should be used.
|
||||
if len(self.__ip_version_preference) == 1:
|
||||
family = socket.AF_INET if self.__ip_version_preference[0] == 4 else socket.AF_INET6
|
||||
else:
|
||||
family = socket.AF_UNSPEC
|
||||
try:
|
||||
stype = socket.SOCK_STREAM
|
||||
r = socket.getaddrinfo(self.__host, self.__port, family, stype)
|
||||
if prefer_ipvo:
|
||||
r = sorted(r, key=lambda x: x[0], reverse=not prefer_ipv4)
|
||||
check = any(stype == rline[2] for rline in r)
|
||||
|
||||
# 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)) # pylint: disable=superfluous-parens
|
||||
for af, socktype, _proto, _canonname, addr in r:
|
||||
if not check or socktype == socket.SOCK_STREAM:
|
||||
if socktype == socket.SOCK_STREAM:
|
||||
yield af, addr
|
||||
except socket.error as e:
|
||||
Output().fail('[exception] {}'.format(e))
|
||||
self.__outputbuffer.fail('[exception] {}'.format(e)).write()
|
||||
sys.exit(exitcodes.CONNECTION_ERROR)
|
||||
|
||||
# Listens on a server socket and accepts one connection (used for
|
||||
@ -156,11 +152,12 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
||||
def connect(self) -> Optional[str]:
|
||||
'''Returns None on success, or an error string.'''
|
||||
err = None
|
||||
for af, addr in self._resolve(self.__ipvo):
|
||||
for af, addr in self._resolve():
|
||||
s = None
|
||||
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
|
||||
@ -175,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:
|
||||
@ -230,18 +229,14 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
||||
except socket.error as e:
|
||||
return -1, str(e.args[-1])
|
||||
|
||||
def send_algorithms(self) -> None:
|
||||
# Send a KEXINIT with the lists of key exchanges, hostkeys, ciphers, MACs, compressions, and languages that we "support".
|
||||
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.'''
|
||||
|
||||
key_exchanges = ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'ecdh-sha2-nistp256', 'ecdh-sha2-nistp384', 'ecdh-sha2-nistp521', 'diffie-hellman-group-exchange-sha256', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group14-sha256']
|
||||
hostkeys = ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ssh-ed25519']
|
||||
ciphers = ['chacha20-poly1305@openssh.com', 'aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-gcm@openssh.com', 'aes256-gcm@openssh.com']
|
||||
macs = ['umac-64-etm@openssh.com', 'umac-128-etm@openssh.com', 'hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'hmac-sha1-etm@openssh.com', 'umac-64@openssh.com', 'umac-128@openssh.com', 'hmac-sha2-256', 'hmac-sha2-512', 'hmac-sha1']
|
||||
compressions = ['none', 'zlib@openssh.com']
|
||||
languages = ['']
|
||||
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)
|
||||
@ -279,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:
|
||||
Output().fail('[exception] invalid ssh packet (block size)')
|
||||
self.__outputbuffer.fail('[exception] invalid ssh packet (block size)').write()
|
||||
sys.exit(exitcodes.CONNECTION_ERROR)
|
||||
self.ensure_read(payload_length)
|
||||
if sshv == 1:
|
||||
@ -294,7 +289,7 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
||||
if sshv == 1:
|
||||
rcrc = SSH1.crc32(padding + payload)
|
||||
if crc != rcrc:
|
||||
Output().fail('[exception] packet checksum CRC32 mismatch.')
|
||||
self.__outputbuffer.fail('[exception] packet checksum CRC32 mismatch.').write()
|
||||
sys.exit(exitcodes.CONNECTION_ERROR)
|
||||
else:
|
||||
self.ensure_read(padding_length)
|
||||
@ -330,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)
|
||||
@ -343,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
|
||||
|
@ -30,12 +30,12 @@ from ssh_audit.algorithm import Algorithm
|
||||
|
||||
class Timeframe:
|
||||
def __init__(self) -> None:
|
||||
self.__storage = {} # type: Dict[str, List[Optional[str]]]
|
||||
self.__storage: Dict[str, List[Optional[str]]] = {}
|
||||
|
||||
def __contains__(self, product: str) -> bool:
|
||||
return product in self.__storage
|
||||
|
||||
def __getitem__(self, product): # type: (str) -> Sequence[Optional[str]]
|
||||
def __getitem__(self, product: str) -> Sequence[Optional[str]]:
|
||||
return tuple(self.__storage.get(product, [None] * 4))
|
||||
|
||||
def __str__(self) -> str:
|
||||
@ -51,7 +51,7 @@ class Timeframe:
|
||||
return self[product][1 if bool(for_server) else 3]
|
||||
|
||||
def _update(self, versions: Optional[str], pos: int) -> None:
|
||||
ssh_versions = {} # type: Dict[str, str]
|
||||
ssh_versions: Dict[str, str] = {}
|
||||
for_srv, for_cli = pos < 2, pos > 1
|
||||
for v in (versions or '').split(','):
|
||||
ssh_prod, ssh_ver, is_cli = Algorithm.get_ssh_version(v)
|
||||
|
@ -96,7 +96,7 @@ class Utils:
|
||||
|
||||
@classmethod
|
||||
def unique_seq(cls, seq: Sequence[Any]) -> Sequence[Any]:
|
||||
seen = set() # type: Set[Any]
|
||||
seen: Set[Any] = set()
|
||||
|
||||
def _seen_add(x: Any) -> bool:
|
||||
seen.add(x)
|
||||
@ -129,10 +129,10 @@ class Utils:
|
||||
return -1.0
|
||||
|
||||
@staticmethod
|
||||
def parse_host_and_port(host_and_port: str) -> Tuple[str, int]:
|
||||
def parse_host_and_port(host_and_port: str, default_port: int = 0) -> Tuple[str, int]:
|
||||
'''Parses a string into a tuple of its host and port. The port is 0 if not specified.'''
|
||||
host = host_and_port
|
||||
port = 0
|
||||
port = default_port
|
||||
|
||||
mx = re.match(r'^\[([^\]]+)\](?::(\d+))?$', host_and_port)
|
||||
if mx is not None:
|
||||
|
@ -33,8 +33,9 @@ class VersionVulnerabilityDB: # pylint: disable=too-few-public-methods
|
||||
# Example: if it affects servers, both remote & local, then affected
|
||||
# = 1. If it affects servers, but is a local issue only,
|
||||
# then affected = 1 + 4 = 5.
|
||||
CVE = {
|
||||
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,6 +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': [
|
||||
['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)'],
|
||||
@ -124,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'],
|
||||
@ -139,12 +159,12 @@ class VersionVulnerabilityDB: # pylint: disable=too-few-public-methods
|
||||
['0.0', '0.66', 2, 'CVE-2016-2563', 7.5, 'buffer overflow in SCP command-line utility'],
|
||||
['0.0', '0.65', 2, 'CVE-2015-5309', 4.3, 'integer overflow in terminal-handling code'],
|
||||
]
|
||||
} # type: Dict[str, List[List[Any]]]
|
||||
TXT = {
|
||||
}
|
||||
TXT: Dict[str, List[List[Any]]] = {
|
||||
'Dropbear SSH': [
|
||||
['0.28', '0.34', 1, 'remote root exploit', 'remote format string buffer overflow exploit (exploit-db#387)']],
|
||||
'libssh': [
|
||||
['0.3.3', '0.3.3', 1, 'null pointer check', 'missing null pointer check in "crypt_set_algorithms_server"'],
|
||||
['0.3.3', '0.3.3', 1, 'integer overflow', 'integer overflow in "buffer_get_data"'],
|
||||
['0.3.3', '0.3.3', 3, 'heap overflow', 'heap overflow in "packet_decrypt"']]
|
||||
} # type: Dict[str, List[List[Any]]]
|
||||
}
|
||||
|
@ -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:
|
||||
|
77
ssh-audit.1
77
ssh-audit.1
@ -1,4 +1,4 @@
|
||||
.TH SSH-AUDIT 1 "October 19, 2020"
|
||||
.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>
|
||||
@ -66,6 +101,11 @@ List all official, built-in policies for common systems. Their full names can t
|
||||
.br
|
||||
Look up the security information of an algorithm(s) in the internal database. Does not connect to a server.
|
||||
|
||||
.TP
|
||||
.B -m, \-\-manual
|
||||
.br
|
||||
Print the man page (Windows only).
|
||||
|
||||
.TP
|
||||
.B -M, \-\-make-policy=<custom_policy.txt>
|
||||
.br
|
||||
@ -94,7 +134,12 @@ The timeout, in seconds, for creating connections and reading data from the sock
|
||||
.TP
|
||||
.B -T, \-\-targets=<hosts.txt>
|
||||
.br
|
||||
A file containing a list of target hosts. Each line must have one host, in the format of HOST[:PORT].
|
||||
A file containing a list of target hosts. Each line must have one host, in the format of HOST[:PORT]. Use --threads to control concurrent scans.
|
||||
|
||||
.TP
|
||||
.B \-\-threads=<threads>
|
||||
.br
|
||||
The number of threads to use when scanning multiple targets (with -T/--targets). Default is 32.
|
||||
|
||||
.TP
|
||||
.B -v, \-\-verbose
|
||||
@ -204,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"]}
|
||||
{
|
||||
"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,56 +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;33m `- [warn] using small 1024-bit modulus[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] 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
|
||||
@ -66,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"]}
|
||||
{
|
||||
"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"
|
||||
}
|
||||
|
@ -1,11 +1,15 @@
|
||||
[0;36m# general[0m
|
||||
[0;32m(gen) banner: SSH-1.99-OpenSSH_4.0[0m
|
||||
[0;31m(gen) banner: SSH-1.99-OpenSSH_4.0[0m
|
||||
[0;31m(gen) protocol SSH1 enabled[0m
|
||||
[0;32m(gen) software: OpenSSH 4.0[0m
|
||||
[0;32m(gen) compatibility: OpenSSH 3.9-6.6, Dropbear SSH 0.53+ (some functionality from 0.52)[0m
|
||||
[0;32m(gen) compression: enabled (zlib)[0m
|
||||
|
||||
[0;36m# security[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
|
||||
@ -24,93 +28,77 @@
|
||||
[0;33m(cve) CVE-2006-4924 -- (CVSSv2: 7.8) cause DoS via crafted packet (CPU consumption)[0m
|
||||
[0;33m(cve) CVE-2006-0225 -- (CVSSv2: 4.6) execute arbitrary code[0m
|
||||
[0;33m(cve) CVE-2005-2798 -- (CVSSv2: 5.0) leak data about authentication credentials[0m
|
||||
[0;31m(sec) SSH v1 enabled -- SSH v1 can be exploited to recover plaintext passwords[0m
|
||||
|
||||
[0;36m# key exchange algorithms[0m
|
||||
[0;31m(kex) diffie-hellman-group-exchange-sha1 (1024-bit) -- [fail] using small 1024-bit modulus[0m
|
||||
[0;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;33m `- [warn] using small 1024-bit modulus[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] 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
|
||||
@ -118,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"]}
|
||||
{
|
||||
"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,6 +5,10 @@
|
||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||
|
||||
[0;36m# security[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
|
||||
@ -21,112 +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;33m `- [warn] using small 1024-bit modulus[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] 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
|
||||
@ -134,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"]}
|
||||
{
|
||||
"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,6 +5,10 @@
|
||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||
|
||||
[0;36m# security[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
|
||||
@ -21,111 +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;33m `- [warn] using small 1024-bit modulus[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
|
||||
[0;31m(key) ssh-rsa-cert-v01@openssh.com (1024-bit cert/1024-bit CA) -- [fail] using weak hashing algorithm[0m
|
||||
[0;33m `- [warn] using small 1024-bit modulus[0m
|
||||
`- [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
|
||||
@ -133,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"]}
|
||||
{
|
||||
"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,6 +5,10 @@
|
||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||
|
||||
[0;36m# security[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
|
||||
@ -21,111 +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;33m `- [warn] using small 1024-bit modulus[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
|
||||
[0;31m(key) ssh-rsa-cert-v01@openssh.com (1024-bit cert/3072-bit CA) -- [fail] using weak hashing algorithm[0m
|
||||
[0;33m `- [warn] using small 1024-bit modulus[0m
|
||||
`- [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
|
||||
@ -133,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"]}
|
||||
{
|
||||
"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,6 +5,10 @@
|
||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||
|
||||
[0;36m# security[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
|
||||
@ -21,110 +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
|
||||
[0;31m(key) ssh-rsa-cert-v01@openssh.com (3072-bit cert/1024-bit CA) -- [fail] using weak hashing algorithm[0m
|
||||
[0;33m `- [warn] using small 1024-bit modulus[0m
|
||||
`- [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
|
||||
@ -132,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"]}
|
||||
{
|
||||
"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,6 +5,10 @@
|
||||
[0;32m(gen) compression: enabled (zlib@openssh.com)[0m
|
||||
|
||||
[0;36m# security[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
|
||||
@ -21,109 +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
|
||||
[0;31m(key) ssh-rsa-cert-v01@openssh.com (3072-bit cert/3072-bit CA) -- [fail] using weak hashing algorithm[0m
|
||||
`- [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
|
||||
@ -131,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"]}
|
||||
{
|
||||
"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,35 +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
|
||||
[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
|
||||
@ -45,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
|
||||
@ -56,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
|
||||
@ -65,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"]}
|
||||
{
|
||||
"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"]}
|
||||
{
|
||||
"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"]}
|
||||
{
|
||||
"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"
|
||||
}
|
||||
|
@ -1,20 +1,23 @@
|
||||
[0;36m# general[0m
|
||||
[0;32m(gen) software: TinySSH noversion[0m
|
||||
[0;32m(gen) compatibility: OpenSSH 8.0+, Dropbear SSH 2018.76+[0m
|
||||
[0;32m(gen) compatibility: OpenSSH 8.0-8.4, Dropbear SSH 2018.76+[0m
|
||||
[0;32m(gen) compression: disabled[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
|
||||
`- [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,6 +7,7 @@ class TestAuditConf:
|
||||
@pytest.fixture(autouse=True)
|
||||
def init(self, ssh_audit):
|
||||
self.AuditConf = ssh_audit.AuditConf
|
||||
self.OutputBuffer = ssh_audit.OutputBuffer()
|
||||
self.usage = ssh_audit.usage
|
||||
self.process_commandline = process_commandline
|
||||
|
||||
@ -21,9 +22,8 @@ class TestAuditConf:
|
||||
'colors': True,
|
||||
'verbose': False,
|
||||
'level': 'info',
|
||||
'ipv4': True,
|
||||
'ipv6': True,
|
||||
'ipvo': ()
|
||||
'ipv4': False,
|
||||
'ipv6': False
|
||||
}
|
||||
for k, v in kwargs.items():
|
||||
options[k] = v
|
||||
@ -37,7 +37,6 @@ class TestAuditConf:
|
||||
assert conf.level == options['level']
|
||||
assert conf.ipv4 == options['ipv4']
|
||||
assert conf.ipv6 == options['ipv6']
|
||||
assert conf.ipvo == options['ipvo']
|
||||
|
||||
def test_audit_conf_defaults(self):
|
||||
conf = self.AuditConf()
|
||||
@ -63,57 +62,38 @@ class TestAuditConf:
|
||||
conf.port = port
|
||||
excinfo.match(r'.*invalid port.*')
|
||||
|
||||
def test_audit_conf_ipvo(self):
|
||||
def test_audit_conf_ip_version_preference(self):
|
||||
# ipv4-only
|
||||
conf = self.AuditConf()
|
||||
conf.ipv4 = True
|
||||
assert conf.ipv4 is True
|
||||
assert conf.ipv6 is False
|
||||
assert conf.ipvo == (4,)
|
||||
assert conf.ip_version_preference == [4]
|
||||
# ipv6-only
|
||||
conf = self.AuditConf()
|
||||
conf.ipv6 = True
|
||||
assert conf.ipv4 is False
|
||||
assert conf.ipv6 is True
|
||||
assert conf.ipvo == (6,)
|
||||
# ipv4-only (by removing ipv6)
|
||||
conf = self.AuditConf()
|
||||
conf.ipv6 = False
|
||||
assert conf.ipv4 is True
|
||||
assert conf.ipv6 is False
|
||||
assert conf.ipvo == (4, )
|
||||
# ipv6-only (by removing ipv4)
|
||||
conf = self.AuditConf()
|
||||
conf.ipv4 = False
|
||||
assert conf.ipv4 is False
|
||||
assert conf.ipv6 is True
|
||||
assert conf.ipvo == (6, )
|
||||
assert conf.ip_version_preference == [6]
|
||||
# ipv4-preferred
|
||||
conf = self.AuditConf()
|
||||
conf.ipv4 = True
|
||||
conf.ipv6 = True
|
||||
assert conf.ipv4 is True
|
||||
assert conf.ipv6 is True
|
||||
assert conf.ipvo == (4, 6)
|
||||
assert conf.ip_version_preference == [4, 6]
|
||||
# ipv6-preferred
|
||||
conf = self.AuditConf()
|
||||
conf.ipv6 = True
|
||||
conf.ipv4 = True
|
||||
assert conf.ipv4 is True
|
||||
assert conf.ipv6 is True
|
||||
assert conf.ipvo == (6, 4)
|
||||
# ipvo empty
|
||||
assert conf.ip_version_preference == [6, 4]
|
||||
# defaults
|
||||
conf = self.AuditConf()
|
||||
conf.ipvo = ()
|
||||
assert conf.ipv4 is True
|
||||
assert conf.ipv6 is True
|
||||
assert conf.ipvo == ()
|
||||
# ipvo validation
|
||||
conf = self.AuditConf()
|
||||
conf.ipvo = (1, 2, 3, 4, 5, 6)
|
||||
assert conf.ipvo == (4, 6)
|
||||
conf.ipvo = (4, 4, 4, 6, 6)
|
||||
assert conf.ipvo == (4, 6)
|
||||
assert conf.ipv4 is False
|
||||
assert conf.ipv6 is False
|
||||
assert conf.ip_version_preference == []
|
||||
|
||||
def test_audit_conf_level(self):
|
||||
conf = self.AuditConf()
|
||||
@ -127,7 +107,7 @@ class TestAuditConf:
|
||||
|
||||
def test_audit_conf_process_commandline(self):
|
||||
# pylint: disable=too-many-statements
|
||||
c = lambda x: self.process_commandline(x.split(), self.usage) # noqa
|
||||
c = lambda x: self.process_commandline(self.OutputBuffer, x.split(), self.usage) # noqa
|
||||
with pytest.raises(SystemExit):
|
||||
conf = c('')
|
||||
with pytest.raises(SystemExit):
|
||||
|
@ -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(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,12 +2,15 @@ import socket
|
||||
import errno
|
||||
import pytest
|
||||
|
||||
from ssh_audit.outputbuffer import OutputBuffer
|
||||
|
||||
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
class TestErrors:
|
||||
@pytest.fixture(autouse=True)
|
||||
def init(self, ssh_audit):
|
||||
self.AuditConf = ssh_audit.AuditConf
|
||||
self.OutputBuffer = ssh_audit.OutputBuffer
|
||||
self.audit = ssh_audit.audit
|
||||
|
||||
def _conf(self):
|
||||
@ -21,14 +24,21 @@ class TestErrors:
|
||||
conf = self._conf()
|
||||
spy.begin()
|
||||
|
||||
out = OutputBuffer()
|
||||
if exit_expected:
|
||||
with pytest.raises(SystemExit):
|
||||
self.audit(conf)
|
||||
self.audit(out, conf)
|
||||
else:
|
||||
ret = self.audit(conf)
|
||||
ret = self.audit(out, conf)
|
||||
assert ret != 0
|
||||
|
||||
out.write()
|
||||
lines = spy.flush()
|
||||
|
||||
# If the last line is empty, delete it.
|
||||
if len(lines) > 1 and lines[-1] == '':
|
||||
del lines[-1]
|
||||
|
||||
return lines
|
||||
|
||||
def test_connection_unresolved(self, output_spy, virtual_socket):
|
||||
@ -157,6 +167,6 @@ class TestErrors:
|
||||
conf = self._conf()
|
||||
conf.ssh1, conf.ssh2 = True, False
|
||||
lines = self._audit(output_spy, conf)
|
||||
assert len(lines) == 3
|
||||
assert len(lines) == 4
|
||||
assert 'error reading packet' in lines[-1]
|
||||
assert 'major versions differ' in lines[-1]
|
||||
|
@ -2,102 +2,107 @@ import pytest
|
||||
|
||||
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
class TestOutput:
|
||||
class TestOutputBuffer:
|
||||
@pytest.fixture(autouse=True)
|
||||
def init(self, ssh_audit):
|
||||
self.Output = ssh_audit.Output
|
||||
self.OutputBuffer = ssh_audit.OutputBuffer
|
||||
|
||||
def test_output_buffer_no_lines(self, output_spy):
|
||||
def test_outputbuffer_no_lines(self, output_spy):
|
||||
output_spy.begin()
|
||||
with self.OutputBuffer() as obuf:
|
||||
pass
|
||||
assert output_spy.flush() == []
|
||||
obuf = self.OutputBuffer()
|
||||
obuf.write()
|
||||
assert output_spy.flush() == ['']
|
||||
output_spy.begin()
|
||||
with self.OutputBuffer() as obuf:
|
||||
pass
|
||||
obuf.flush()
|
||||
assert output_spy.flush() == []
|
||||
|
||||
def test_output_buffer_no_flush(self, output_spy):
|
||||
output_spy.begin()
|
||||
with self.OutputBuffer():
|
||||
print('abc')
|
||||
assert output_spy.flush() == []
|
||||
|
||||
def test_output_buffer_flush(self, output_spy):
|
||||
output_spy.begin()
|
||||
with self.OutputBuffer() as obuf:
|
||||
print('abc')
|
||||
print()
|
||||
print('def')
|
||||
obuf.flush()
|
||||
assert output_spy.flush() == ['abc', '', 'def']
|
||||
|
||||
def test_output_defaults(self):
|
||||
out = self.Output()
|
||||
def test_outputbuffer_defaults(self):
|
||||
obuf = self.OutputBuffer()
|
||||
# default: on
|
||||
assert out.batch is False
|
||||
assert out.use_colors is True
|
||||
assert out.level == 'info'
|
||||
assert obuf.batch is False
|
||||
assert obuf.use_colors is True
|
||||
assert obuf.level == 'info'
|
||||
|
||||
def test_output_colors(self, output_spy):
|
||||
out = self.Output()
|
||||
# test without colors
|
||||
def test_outputbuffer_colors(self, output_spy):
|
||||
out = self.OutputBuffer()
|
||||
|
||||
# Test without colors.
|
||||
out.use_colors = False
|
||||
|
||||
output_spy.begin()
|
||||
out.info('info color')
|
||||
out.write()
|
||||
assert output_spy.flush() == ['info color']
|
||||
|
||||
output_spy.begin()
|
||||
out.head('head color')
|
||||
out.write()
|
||||
assert output_spy.flush() == ['head color']
|
||||
|
||||
output_spy.begin()
|
||||
out.good('good color')
|
||||
out.write()
|
||||
assert output_spy.flush() == ['good color']
|
||||
|
||||
output_spy.begin()
|
||||
out.warn('warn color')
|
||||
out.write()
|
||||
assert output_spy.flush() == ['warn color']
|
||||
|
||||
output_spy.begin()
|
||||
out.fail('fail color')
|
||||
out.write()
|
||||
assert output_spy.flush() == ['fail color']
|
||||
|
||||
# If colors aren't supported by this system, skip the color tests.
|
||||
if not out.colors_supported:
|
||||
return
|
||||
# test with colors
|
||||
|
||||
# Test with colors.
|
||||
out.use_colors = True
|
||||
|
||||
output_spy.begin()
|
||||
out.info('info color')
|
||||
out.write()
|
||||
assert output_spy.flush() == ['info color']
|
||||
|
||||
output_spy.begin()
|
||||
out.head('head color')
|
||||
assert output_spy.flush() == ['\x1b[0;36mhead color\x1b[0m']
|
||||
out.write()
|
||||
assert output_spy.flush() in [['\x1b[0;36mhead color\x1b[0m'], ['\x1b[0;96mhead color\x1b[0m']]
|
||||
|
||||
output_spy.begin()
|
||||
out.good('good color')
|
||||
assert output_spy.flush() == ['\x1b[0;32mgood color\x1b[0m']
|
||||
out.write()
|
||||
assert output_spy.flush() in [['\x1b[0;32mgood color\x1b[0m'], ['\x1b[0;92mgood color\x1b[0m']]
|
||||
|
||||
output_spy.begin()
|
||||
out.warn('warn color')
|
||||
assert output_spy.flush() == ['\x1b[0;33mwarn color\x1b[0m']
|
||||
out.write()
|
||||
assert output_spy.flush() in [['\x1b[0;33mwarn color\x1b[0m'], ['\x1b[0;93mwarn color\x1b[0m']]
|
||||
|
||||
output_spy.begin()
|
||||
out.fail('fail color')
|
||||
assert output_spy.flush() == ['\x1b[0;31mfail color\x1b[0m']
|
||||
out.write()
|
||||
assert output_spy.flush() in [['\x1b[0;31mfail color\x1b[0m'], ['\x1b[0;91mfail color\x1b[0m']]
|
||||
|
||||
def test_output_sep(self, output_spy):
|
||||
out = self.Output()
|
||||
def test_outputbuffer_sep(self, output_spy):
|
||||
out = self.OutputBuffer()
|
||||
output_spy.begin()
|
||||
out.sep()
|
||||
out.sep()
|
||||
out.sep()
|
||||
out.write()
|
||||
assert output_spy.flush() == ['', '', '']
|
||||
|
||||
def test_output_levels(self):
|
||||
out = self.Output()
|
||||
def test_outputbuffer_levels(self):
|
||||
out = self.OutputBuffer()
|
||||
assert out.get_level('info') == 0
|
||||
assert out.get_level('good') == 0
|
||||
assert out.get_level('warn') == 1
|
||||
assert out.get_level('fail') == 2
|
||||
assert out.get_level('unknown') > 2
|
||||
|
||||
def test_output_level_property(self):
|
||||
out = self.Output()
|
||||
def test_outputbuffer_level_property(self):
|
||||
out = self.OutputBuffer()
|
||||
out.level = 'info'
|
||||
assert out.level == 'info'
|
||||
out.level = 'good'
|
||||
@ -109,8 +114,8 @@ class TestOutput:
|
||||
out.level = 'invalid level'
|
||||
assert out.level == 'unknown'
|
||||
|
||||
def test_output_level(self, output_spy):
|
||||
out = self.Output()
|
||||
def test_outputbuffer_level(self, output_spy):
|
||||
out = self.OutputBuffer()
|
||||
# visible: all
|
||||
out.level = 'info'
|
||||
output_spy.begin()
|
||||
@ -119,6 +124,7 @@ class TestOutput:
|
||||
out.good('good color')
|
||||
out.warn('warn color')
|
||||
out.fail('fail color')
|
||||
out.write()
|
||||
assert len(output_spy.flush()) == 5
|
||||
# visible: head, warn, fail
|
||||
out.level = 'warn'
|
||||
@ -128,6 +134,7 @@ class TestOutput:
|
||||
out.good('good color')
|
||||
out.warn('warn color')
|
||||
out.fail('fail color')
|
||||
out.write()
|
||||
assert len(output_spy.flush()) == 3
|
||||
# visible: head, fail
|
||||
out.level = 'fail'
|
||||
@ -137,6 +144,7 @@ class TestOutput:
|
||||
out.good('good color')
|
||||
out.warn('warn color')
|
||||
out.fail('fail color')
|
||||
out.write()
|
||||
assert len(output_spy.flush()) == 2
|
||||
# visible: head
|
||||
out.level = 'invalid level'
|
||||
@ -146,10 +154,11 @@ class TestOutput:
|
||||
out.good('good color')
|
||||
out.warn('warn color')
|
||||
out.fail('fail color')
|
||||
out.write()
|
||||
assert len(output_spy.flush()) == 1
|
||||
|
||||
def test_output_batch(self, output_spy):
|
||||
out = self.Output()
|
||||
def test_outputbuffer_batch(self, output_spy):
|
||||
out = self.OutputBuffer()
|
||||
# visible: all
|
||||
output_spy.begin()
|
||||
out.level = 'info'
|
||||
@ -159,6 +168,7 @@ class TestOutput:
|
||||
out.good('good color')
|
||||
out.warn('warn color')
|
||||
out.fail('fail color')
|
||||
out.write()
|
||||
assert len(output_spy.flush()) == 5
|
||||
# visible: all except head
|
||||
output_spy.begin()
|
||||
@ -169,4 +179,5 @@ class TestOutput:
|
||||
out.good('good color')
|
||||
out.warn('warn color')
|
||||
out.fail('fail color')
|
||||
out.write()
|
||||
assert len(output_spy.flush()) == 4
|
@ -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):
|
||||
@ -19,11 +20,11 @@ class TestResolve:
|
||||
def test_resolve_error(self, output_spy, virtual_socket):
|
||||
vsocket = virtual_socket
|
||||
vsocket.gsock.addrinfodata['localhost#22'] = socket.gaierror(8, 'hostname nor servname provided, or not known')
|
||||
s = self.ssh_socket('localhost', 22)
|
||||
conf = self._conf()
|
||||
s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference)
|
||||
output_spy.begin()
|
||||
with pytest.raises(SystemExit):
|
||||
list(s._resolve(conf.ipvo))
|
||||
list(s._resolve())
|
||||
lines = output_spy.flush()
|
||||
assert len(lines) == 1
|
||||
assert 'hostname nor servname provided' in lines[-1]
|
||||
@ -31,49 +32,50 @@ class TestResolve:
|
||||
def test_resolve_hostname_without_records(self, output_spy, virtual_socket):
|
||||
vsocket = virtual_socket
|
||||
vsocket.gsock.addrinfodata['localhost#22'] = []
|
||||
s = self.ssh_socket('localhost', 22)
|
||||
conf = self._conf()
|
||||
s = self.ssh_socket(self.OutputBuffer(), 'localhost', 22, conf.ip_version_preference)
|
||||
output_spy.begin()
|
||||
r = list(s._resolve(conf.ipvo))
|
||||
r = list(s._resolve())
|
||||
assert len(r) == 0
|
||||
|
||||
def test_resolve_ipv4(self, virtual_socket):
|
||||
conf = self._conf()
|
||||
conf.ipv4 = True
|
||||
s = self.ssh_socket('localhost', 22)
|
||||
r = list(s._resolve(conf.ipvo))
|
||||
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))
|
||||
|
||||
def test_resolve_ipv6(self, virtual_socket):
|
||||
s = self.ssh_socket('localhost', 22)
|
||||
conf = self._conf()
|
||||
conf.ipv6 = True
|
||||
r = list(s._resolve(conf.ipvo))
|
||||
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):
|
||||
s = self.ssh_socket('localhost', 22)
|
||||
conf = self._conf()
|
||||
r = list(s._resolve(conf.ipvo))
|
||||
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))
|
||||
assert r[1] == (socket.AF_INET6, ('::1', 22))
|
||||
|
||||
def test_resolve_ipv46_order(self, virtual_socket):
|
||||
s = self.ssh_socket('localhost', 22)
|
||||
conf = self._conf()
|
||||
conf.ipv4 = True
|
||||
conf.ipv6 = True
|
||||
r = list(s._resolve(conf.ipvo))
|
||||
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))
|
||||
assert r[1] == (socket.AF_INET6, ('::1', 22))
|
||||
conf = self._conf()
|
||||
conf.ipv6 = True
|
||||
conf.ipv4 = True
|
||||
r = list(s._resolve(conf.ipvo))
|
||||
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))
|
||||
assert r[1] == (socket.AF_INET, ('127.0.0.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
|
||||
|
@ -3,6 +3,7 @@ import pytest
|
||||
|
||||
from ssh_audit.auditconf import AuditConf
|
||||
from ssh_audit.fingerprint import Fingerprint
|
||||
from ssh_audit.outputbuffer import OutputBuffer
|
||||
from ssh_audit.protocol import Protocol
|
||||
from ssh_audit.readbuf import ReadBuf
|
||||
from ssh_audit.ssh1 import SSH1
|
||||
@ -15,6 +16,7 @@ from ssh_audit.writebuf import WriteBuf
|
||||
class TestSSH1:
|
||||
@pytest.fixture(autouse=True)
|
||||
def init(self, ssh_audit):
|
||||
self.OutputBuffer = OutputBuffer
|
||||
self.protocol = Protocol
|
||||
self.ssh1 = SSH1
|
||||
self.PublicKeyMessage = SSH1_PublicKeyMessage
|
||||
@ -132,9 +134,11 @@ class TestSSH1:
|
||||
vsocket.rdata.append(b'SSH-1.5-OpenSSH_7.2 ssh-audit-test\r\n')
|
||||
vsocket.rdata.append(self._create_ssh1_packet(w.write_flush()))
|
||||
output_spy.begin()
|
||||
self.audit(self._conf())
|
||||
out = self.OutputBuffer()
|
||||
self.audit(out, self._conf())
|
||||
out.write()
|
||||
lines = output_spy.flush()
|
||||
assert len(lines) == 13
|
||||
assert len(lines) == 21
|
||||
|
||||
def test_ssh1_server_invalid_first_packet(self, output_spy, virtual_socket):
|
||||
vsocket = virtual_socket
|
||||
@ -144,10 +148,12 @@ class TestSSH1:
|
||||
vsocket.rdata.append(b'SSH-1.5-OpenSSH_7.2 ssh-audit-test\r\n')
|
||||
vsocket.rdata.append(self._create_ssh1_packet(w.write_flush()))
|
||||
output_spy.begin()
|
||||
ret = self.audit(self._conf())
|
||||
out = self.OutputBuffer()
|
||||
ret = self.audit(out, self._conf())
|
||||
out.write()
|
||||
assert ret != 0
|
||||
lines = output_spy.flush()
|
||||
assert len(lines) == 7
|
||||
assert len(lines) == 14
|
||||
assert 'unknown message' in lines[-1]
|
||||
|
||||
def test_ssh1_server_invalid_checksum(self, output_spy, virtual_socket):
|
||||
@ -158,8 +164,10 @@ class TestSSH1:
|
||||
vsocket.rdata.append(b'SSH-1.5-OpenSSH_7.2 ssh-audit-test\r\n')
|
||||
vsocket.rdata.append(self._create_ssh1_packet(w.write_flush(), False))
|
||||
output_spy.begin()
|
||||
out = self.OutputBuffer()
|
||||
with pytest.raises(SystemExit):
|
||||
self.audit(self._conf())
|
||||
self.audit(out, self._conf())
|
||||
out.write()
|
||||
lines = output_spy.flush()
|
||||
assert len(lines) == 1
|
||||
assert 'checksum' in lines[-1]
|
||||
assert len(lines) == 3
|
||||
assert ('checksum' in lines[0]) or ('checksum' in lines[1]) or ('checksum' in lines[2])
|
||||
|
@ -3,6 +3,7 @@ import struct
|
||||
import pytest
|
||||
|
||||
from ssh_audit.auditconf import AuditConf
|
||||
from ssh_audit.outputbuffer import OutputBuffer
|
||||
from ssh_audit.protocol import Protocol
|
||||
from ssh_audit.readbuf import ReadBuf
|
||||
from ssh_audit.ssh2_kex import SSH2_Kex
|
||||
@ -15,6 +16,7 @@ from ssh_audit.writebuf import WriteBuf
|
||||
class TestSSH2:
|
||||
@pytest.fixture(autouse=True)
|
||||
def init(self, ssh_audit):
|
||||
self.OutputBuffer = OutputBuffer
|
||||
self.protocol = Protocol
|
||||
self.ssh2_kex = SSH2_Kex
|
||||
self.ssh2_kexparty = SSH2_KexParty
|
||||
@ -59,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']
|
||||
@ -86,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):
|
||||
@ -130,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):
|
||||
@ -141,9 +160,11 @@ class TestSSH2:
|
||||
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()
|
||||
self.audit(self._conf())
|
||||
out = self.OutputBuffer()
|
||||
self.audit(out, self._conf())
|
||||
out.write()
|
||||
lines = output_spy.flush()
|
||||
assert len(lines) == 67
|
||||
assert len(lines) == 70
|
||||
|
||||
def test_ssh2_server_invalid_first_packet(self, output_spy, virtual_socket):
|
||||
vsocket = virtual_socket
|
||||
@ -152,8 +173,29 @@ class TestSSH2:
|
||||
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()
|
||||
ret = self.audit(self._conf())
|
||||
out = self.OutputBuffer()
|
||||
ret = self.audit(out, self._conf())
|
||||
out.write()
|
||||
assert ret != 0
|
||||
lines = output_spy.flush()
|
||||
assert len(lines) == 3
|
||||
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
|
44
tox.ini
44
tox.ini
@ -1,19 +1,19 @@
|
||||
[tox]
|
||||
envlist =
|
||||
py{py3}-{test,pylint,flake8,vulture}
|
||||
py{35,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{35,36,37,38,39}-{type,mypy}: colorama
|
||||
py{35,36,37,38,39}-{type,mypy}: {[testenv:mypy]deps}
|
||||
py{py3,35,36,37,38,39}-{lint,pylint},lint: {[testenv:pylint]deps}
|
||||
py{py3,35,36,37,38,39}-{lint,flake8},lint: {[testenv:flake8]deps}
|
||||
py{py3,35,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,13 +25,13 @@ commands =
|
||||
test: coverage combine
|
||||
test: coverage report --show-missing
|
||||
test: coverage html -d {toxinidir}/reports/html/coverage.{envname}
|
||||
py{35,36,37,38,39}-{type,mypy}: {[testenv:mypy]commands}
|
||||
py{py3,35,36,37,38,39}-{lint,pylint},lint: {[testenv:pylint]commands}
|
||||
py{py3,35,36,37,38,39}-{lint,flake8},lint: {[testenv:flake8]commands}
|
||||
py{py3,35,36,37,38,39}-{lint,vulture},lint: {[testenv:vulture]commands}
|
||||
ignore_outcome =
|
||||
type: true
|
||||
lint: true
|
||||
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
|
||||
|
||||
[testenv:cov]
|
||||
deps =
|
||||
@ -51,7 +51,7 @@ deps =
|
||||
lxml
|
||||
mypy
|
||||
commands =
|
||||
-mypy \
|
||||
mypy \
|
||||
--strict \
|
||||
--show-error-context \
|
||||
--html-report {env:MYPYHTML}.py3.{envname} \
|
||||
@ -62,7 +62,7 @@ deps =
|
||||
mccabe
|
||||
pylint
|
||||
commands =
|
||||
-pylint \
|
||||
pylint \
|
||||
--rcfile tox.ini \
|
||||
--load-plugins=pylint.extensions.bad_builtin \
|
||||
--load-plugins=pylint.extensions.check_elif \
|
||||
@ -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
|
||||
|
130
update_windows_man_page.sh
Executable file
130
update_windows_man_page.sh
Executable file
@ -0,0 +1,130 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (C) 2021 Joe Testa (jtesta@positronsecurity.com)
|
||||
# Copyright (C) 2021 Adam Russell (<adam[at]thecliguy[dot]co[dot]uk>)
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
################################################################################
|
||||
# update_windows_man_page.sh
|
||||
#
|
||||
# PURPOSE
|
||||
# Since Windows lacks a manual reader it's necessary to provide an alternative
|
||||
# means of reading the man page.
|
||||
#
|
||||
# This script should be run as part of the ssh-audit packaging process for
|
||||
# Windows. It populates the 'WINDOWS_MAN_PAGE' variable in 'globals.py' with
|
||||
# the contents of the man page. Windows users can then print the content of
|
||||
# 'WINDOWS_MAN_PAGE' by invoking ssh-audit with the manual parameters
|
||||
# (--manual / -m).
|
||||
#
|
||||
# Cygwin is required.
|
||||
#
|
||||
# USAGE
|
||||
# update_windows_man_page.sh [-m <path-to-man-page>] [-g <path-to-globals.py>]
|
||||
#
|
||||
################################################################################
|
||||
|
||||
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)"
|
||||
echo >&2 " -h This help message"
|
||||
}
|
||||
|
||||
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
|
||||
;;
|
||||
esac
|
||||
|
||||
MAN_PAGE=./ssh-audit.1
|
||||
GLOBALS_PY=./src/ssh_audit/globals.py
|
||||
|
||||
while getopts "m: g: h" OPTION; do
|
||||
case "$OPTION" in
|
||||
m)
|
||||
MAN_PAGE="$OPTARG"
|
||||
;;
|
||||
g)
|
||||
GLOBALS_PY="$OPTARG"
|
||||
;;
|
||||
h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo >&2 "Invalid parameter(s) provided"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
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; }
|
||||
|
||||
# Check that the 'ul' (do underlining) binary exists.
|
||||
if [[ "$PLATFORM" == "Linux" ]]; then
|
||||
command -v ul >/dev/null 2>&1 || { echo >&2 "ul not found."; exit 1; }
|
||||
fi
|
||||
|
||||
# Check that the 'sed' (stream editor) binary exists.
|
||||
command -v sed >/dev/null 2>&1 || { echo >&2 "sed not found."; exit 1; }
|
||||
|
||||
# Reset the globals.py file, in case it was modified from a prior run.
|
||||
git checkout $GLOBALS_PY > /dev/null 2>&1
|
||||
|
||||
# Remove the Windows man page placeholder from 'globals.py'.
|
||||
sed -i '/^WINDOWS_MAN_PAGE/d' "$GLOBALS_PY"
|
||||
|
||||
echo "Processing man page at ${MAN_PAGE} and placing output into ${GLOBALS_PY}..."
|
||||
|
||||
# Append the man page content to 'globals.py'.
|
||||
# * man outputs a backspace-overwrite sequence rather than an ANSI escape
|
||||
# sequence.
|
||||
# * 'MAN_KEEP_FORMATTING' preserves the backspace-overwrite sequence when
|
||||
# redirected to a file or a pipe.
|
||||
# * sed converts unicode hyphens into an ASCI equivalent.
|
||||
# * The 'ul' command converts the backspace-overwrite sequence to an ANSI
|
||||
# escape sequence. Not required under Cygwin because man outputs ANSI escape
|
||||
# codes automatically.
|
||||
|
||||
echo WINDOWS_MAN_PAGE = '"""' >> "$GLOBALS_PY"
|
||||
|
||||
if [[ "$PLATFORM" == CYGWIN* ]]; then
|
||||
MANWIDTH=80 MAN_KEEP_FORMATTING=1 man "$MAN_PAGE" | sed $'s/\u2010/-/g' >> "$GLOBALS_PY"
|
||||
else
|
||||
MANWIDTH=80 MAN_KEEP_FORMATTING=1 man "$MAN_PAGE" | ul | sed $'s/\u2010/-/g' >> "$GLOBALS_PY"
|
||||
fi
|
||||
|
||||
echo '"""' >> "$GLOBALS_PY"
|
||||
|
||||
echo "Done."
|
||||
exit 0
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user