mirror of
https://github.com/jtesta/ssh-audit.git
synced 2025-09-03 21:18:22 +02:00
Smoothed out some rough edges from PR #307.
This commit is contained in:
101
README.md
101
README.md
@@ -41,12 +41,18 @@
|
|||||||
## Usage
|
## Usage
|
||||||
```
|
```
|
||||||
usage: ssh-audit.py [-h] [-4] [-6] [-b] [-c] [-d]
|
usage: ssh-audit.py [-h] [-4] [-6] [-b] [-c] [-d]
|
||||||
[-g <min1:pref1:max1[,min2:pref2:max2,...]> / <x-y[:step]>] [-j] [-l {info,warn,fail}] [-L]
|
[-g <min1:pref1:max1[,min2:pref2:max2,...]> / <x-y[:step]>]
|
||||||
[-M custom_policy.txt] [-m] [-n] [-P "Built-In Policy Name" / custom_policy.txt] [-p N]
|
[-j] [-l {info,warn,fail}] [-L] [-M custom_policy.txt]
|
||||||
[-T targets.txt] [-t N] [-v] [--conn-rate-test N[:max_rate]] [--dheat N[:kex[:e_len]]]
|
[-m] [-n] [-P "Built-In Policy Name" / custom_policy.txt]
|
||||||
[--lookup alg1[,alg2,...]] [--skip-rate-test] [--threads N]
|
[-p N] [-T targets.txt] [-t N] [-v]
|
||||||
|
[--conn-rate-test N[:max_rate]] [--dheat N[:kex[:e_len]]]
|
||||||
|
[--get-hardening-guide platform] [--list-hardening-guides]
|
||||||
|
[--lookup alg1[,alg2,...]] [--skip-rate-test]
|
||||||
|
[--threads N]
|
||||||
[host]
|
[host]
|
||||||
|
|
||||||
|
# ssh-audit.py v3.4.0-dev, https://github.com/jtesta/ssh-audit
|
||||||
|
|
||||||
positional arguments:
|
positional arguments:
|
||||||
host target hostname or IPv4/IPv6 address
|
host target hostname or IPv4/IPv6 address
|
||||||
|
|
||||||
@@ -55,44 +61,74 @@ optional arguments:
|
|||||||
-4, --ipv4 enable IPv4 (order of precedence)
|
-4, --ipv4 enable IPv4 (order of precedence)
|
||||||
-6, --ipv6 enable IPv6 (order of precedence)
|
-6, --ipv6 enable IPv6 (order of precedence)
|
||||||
-b, --batch batch output
|
-b, --batch batch output
|
||||||
-c, --client-audit starts a server on port 2222 to audit client software config (use -p to change port; use -t
|
-c, --client-audit starts a server on port 2222 to audit client software
|
||||||
to change timeout)
|
config (use -p to change port; use -t to change
|
||||||
|
timeout)
|
||||||
-d, --debug enable debugging output
|
-d, --debug enable debugging output
|
||||||
-g <min1:pref1:max1[,min2:pref2:max2,...]> / <x-y[:step]>, --gex-test <min1:pref1:max1[,min2:pref2:max2,...]> / <x-y[:step]>
|
-g <min1:pref1:max1[,min2:pref2:max2,...]> / <x-y[:step]>, --gex-test <min1:pref1:max1[,min2:pref2:max2,...]> / <x-y[:step]>
|
||||||
conducts a very customized Diffie-Hellman GEX modulus size test. Tests an array of minimum,
|
conducts a very customized Diffie-Hellman GEX modulus
|
||||||
preferred, and maximum values, or a range of values with an optional incremental step amount
|
size test. Tests an array of minimum, preferred, and
|
||||||
-j, --json enable JSON output (use -jj to enable indentation for better readability)
|
maximum values, or a range of values with an optional
|
||||||
|
incremental step amount
|
||||||
|
-j, --json enable JSON output (use -jj to enable indentation for
|
||||||
|
better readability)
|
||||||
-l {info,warn,fail}, --level {info,warn,fail}
|
-l {info,warn,fail}, --level {info,warn,fail}
|
||||||
minimum output level (default: info)
|
minimum output level (default: info)
|
||||||
-L, --list-policies list all the official, built-in policies. Combine with -v to view policy change logs
|
-L, --list-policies list all the official, built-in policies. Combine with
|
||||||
|
-v to view policy change logs
|
||||||
-M custom_policy.txt, --make-policy custom_policy.txt
|
-M custom_policy.txt, --make-policy custom_policy.txt
|
||||||
creates a policy based on the target server (i.e.: the target server has the ideal
|
creates a policy based on the target server (i.e.: the
|
||||||
configuration that other servers should adhere to), and stores it in the file path specified
|
target server has the ideal configuration that other
|
||||||
-m, --manual print the man page (Docker, PyPI, Snap, and Windows builds only)
|
servers should adhere to), and stores it in the file
|
||||||
-n, --no-colors disable colors (automatic when the NO_COLOR environment variable is set)
|
path specified
|
||||||
|
-m, --manual print the man page (Docker, PyPI, Snap, and Windows
|
||||||
|
builds only)
|
||||||
|
-n, --no-colors disable colors (automatic when the NO_COLOR
|
||||||
|
environment variable is set)
|
||||||
-P "Built-In Policy Name" / custom_policy.txt, --policy "Built-In Policy Name" / custom_policy.txt
|
-P "Built-In Policy Name" / custom_policy.txt, --policy "Built-In Policy Name" / custom_policy.txt
|
||||||
run a policy test using the specified policy (use -L to see built-in policies, or specify
|
run a policy test using the specified policy (use -L
|
||||||
filesystem path to custom policy created by -M)
|
to see built-in policies, or specify filesystem path
|
||||||
-p N, --port N the TCP port to connect to (or to listen on when -c is used)
|
to custom policy created by -M)
|
||||||
|
-p N, --port N the TCP port to connect to (or to listen on when -c is
|
||||||
|
used)
|
||||||
-T targets.txt, --targets targets.txt
|
-T targets.txt, --targets targets.txt
|
||||||
a file containing a list of target hosts (one per line, format HOST[:PORT]). Use -p/--port
|
a file containing a list of target hosts (one per
|
||||||
to set the default port for all hosts. Use --threads to control concurrent scans
|
line, format HOST[:PORT]). Use -p/--port to set the
|
||||||
-t N, --timeout N timeout (in seconds) for connection and reading (default: 5)
|
default port for all hosts. Use --threads to control
|
||||||
|
concurrent scans
|
||||||
|
-t N, --timeout N timeout (in seconds) for connection and reading
|
||||||
|
(default: 5)
|
||||||
-v, --verbose enable verbose output
|
-v, --verbose enable verbose output
|
||||||
--conn-rate-test N[:max_rate]
|
--conn-rate-test N[:max_rate]
|
||||||
perform a connection rate test (useful for collecting metrics related to susceptibility of
|
perform a connection rate test (useful for collecting
|
||||||
the DHEat vuln). Testing is conducted with N concurrent sockets with an optional maximum
|
metrics related to susceptibility of the DHEat vuln).
|
||||||
rate of connections per second
|
Testing is conducted with N concurrent sockets with an
|
||||||
|
optional maximum rate of connections per second
|
||||||
--dheat N[:kex[:e_len]]
|
--dheat N[:kex[:e_len]]
|
||||||
continuously perform the DHEat DoS attack (CVE-2002-20001) against the target using N
|
continuously perform the DHEat DoS attack
|
||||||
concurrent sockets. Optionally, a specific key exchange algorithm can be specified instead
|
(CVE-2002-20001) against the target using N concurrent
|
||||||
of allowing it to be automatically chosen. Additionally, a small length of the fake e value
|
sockets. Optionally, a specific key exchange algorithm
|
||||||
sent to the server can be chosen for a more efficient attack (such as 4).
|
can be specified instead of allowing it to be
|
||||||
|
automatically chosen. Additionally, a small length of
|
||||||
|
the fake e value sent to the server can be chosen for
|
||||||
|
a more efficient attack (such as 4).
|
||||||
|
--get-hardening-guide platform
|
||||||
|
retrieves the hardening guide for the specified
|
||||||
|
platform name (use --list-hardening-guides to see list
|
||||||
|
of available guides).
|
||||||
|
--list-hardening-guides
|
||||||
|
list all official, built-in hardening guides for
|
||||||
|
common systems. Their full names can then be passed to
|
||||||
|
--get-hardening-guide. Add -v to this option to view
|
||||||
|
hardening guide change logs and prior versions.
|
||||||
--lookup alg1[,alg2,...]
|
--lookup alg1[,alg2,...]
|
||||||
looks up an algorithm(s) without connecting to a server.
|
looks up an algorithm(s) without connecting to a
|
||||||
--skip-rate-test skip the connection rate test during standard audits (used to safely infer whether the DHEat
|
server.
|
||||||
attack is viable)
|
--skip-rate-test skip the connection rate test during standard audits
|
||||||
--threads N number of threads to use when scanning multiple targets (-T/--targets) (default: 32)
|
(used to safely infer whether the DHEat attack is
|
||||||
|
viable)
|
||||||
|
--threads N number of threads to use when scanning multiple
|
||||||
|
targets (-T/--targets) (default: 32)
|
||||||
```
|
```
|
||||||
* if both IPv4 and IPv6 are used, order of precedence can be set by using either `-46` or `-64`.
|
* if both IPv4 and IPv6 are used, order of precedence can be set by using either `-46` or `-64`.
|
||||||
* batch flag `-b` will output sections without header and without empty lines (implies verbose flag).
|
* batch flag `-b` will output sections without header and without empty lines (implies verbose flag).
|
||||||
@@ -183,7 +219,7 @@ Below is a screen shot of the client-auditing output when an unhardened OpenSSH
|
|||||||

|

|
||||||
|
|
||||||
## Hardening Guides
|
## Hardening Guides
|
||||||
Guides to harden server & client configuration can be found here: [https://www.ssh-audit.com/hardening_guides.html](https://www.ssh-audit.com/hardening_guides.html)
|
Guides to harden server & client configuration are built into the tool (see `--list-hardening-guides` and `--get-hardening-guide` options). Additionally, they are also available online at: [https://www.ssh-audit.com/hardening_guides.html](https://www.ssh-audit.com/hardening_guides.html)
|
||||||
|
|
||||||
## Pre-Built Packages
|
## Pre-Built Packages
|
||||||
Pre-built packages are available for Windows (see the [Releases](https://github.com/jtesta/ssh-audit/releases) page), PyPI, Snap, and Docker:
|
Pre-built packages are available for Windows (see the [Releases](https://github.com/jtesta/ssh-audit/releases) page), PyPI, Snap, and Docker:
|
||||||
@@ -217,6 +253,7 @@ For convenience, a web front-end on top of the command-line tool is available at
|
|||||||
- BIG THANKS to [realmiwi](https://github.com/realmiwi) for being the project's *very first sponsor!!*
|
- BIG THANKS to [realmiwi](https://github.com/realmiwi) for being the project's *very first sponsor!!*
|
||||||
- Added warning to all key exchanges that do not include protections against quantum attacks due to the Harvest Now, Decrypt Later strategy (see https://en.wikipedia.org/wiki/Harvest_now,_decrypt_later).
|
- Added warning to all key exchanges that do not include protections against quantum attacks due to the Harvest Now, Decrypt Later strategy (see https://en.wikipedia.org/wiki/Harvest_now,_decrypt_later).
|
||||||
- Removed SSHv1 support (rationale is documented in: https://github.com/jtesta/ssh-audit/issues/298).
|
- Removed SSHv1 support (rationale is documented in: https://github.com/jtesta/ssh-audit/issues/298).
|
||||||
|
- Added hardening guides (see `--list-hardening-guides` and `--get-hardening-guide`). Previously, they were only available at <https://ssh-audit.com/hardening_guides.html>, but now they are built-in for convenience; partial credit [oam7575](https://github.com/oam7575).
|
||||||
- Migrated from deprecated `getopt` module to `argparse`; partial credit [oam7575](https://github.com/oam7575).
|
- Migrated from deprecated `getopt` module to `argparse`; partial credit [oam7575](https://github.com/oam7575).
|
||||||
- When running against multiple hosts, now prints each target host regardless of output level.
|
- When running against multiple hosts, now prints each target host regardless of output level.
|
||||||
- Batch mode (`-b`) no longer automatically enables verbose mode, due to sometimes confusing results; users can still explicitly enable verbose mode using the `-v` flag.
|
- Batch mode (`-b`) no longer automatically enables verbose mode, due to sometimes confusing results; users can still explicitly enable verbose mode using the `-v` flag.
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -53,7 +53,7 @@ from ssh_audit.gextest import GEXTest
|
|||||||
from ssh_audit.hostkeytest import HostKeyTest
|
from ssh_audit.hostkeytest import HostKeyTest
|
||||||
from ssh_audit.outputbuffer import OutputBuffer
|
from ssh_audit.outputbuffer import OutputBuffer
|
||||||
from ssh_audit.policy import Policy
|
from ssh_audit.policy import Policy
|
||||||
from ssh_audit.hardeningguides import PrintHardeningGuides
|
from ssh_audit.hardeningguides import Hardening_Guides
|
||||||
from ssh_audit.product import Product
|
from ssh_audit.product import Product
|
||||||
from ssh_audit.protocol import Protocol
|
from ssh_audit.protocol import Protocol
|
||||||
from ssh_audit.software import Software
|
from ssh_audit.software import Software
|
||||||
@@ -790,13 +790,12 @@ def process_commandline(out: OutputBuffer, args: List[str]) -> 'AuditConf': # p
|
|||||||
# Add long options to the parser
|
# Add long options to the parser
|
||||||
parser.add_argument("--conn-rate-test", action="store", dest="conn_rate_test", metavar="N[:max_rate]", type=str, default=None, help="perform a connection rate test (useful for collecting metrics related to susceptibility of the DHEat vuln). Testing is conducted with N concurrent sockets with an optional maximum rate of connections per second")
|
parser.add_argument("--conn-rate-test", action="store", dest="conn_rate_test", metavar="N[:max_rate]", type=str, default=None, help="perform a connection rate test (useful for collecting metrics related to susceptibility of the DHEat vuln). Testing is conducted with N concurrent sockets with an optional maximum rate of connections per second")
|
||||||
parser.add_argument("--dheat", action="store", dest="dheat", metavar="N[:kex[:e_len]]", type=str, default=None, help="continuously perform the DHEat DoS attack (CVE-2002-20001) against the target using N concurrent sockets. Optionally, a specific key exchange algorithm can be specified instead of allowing it to be automatically chosen. Additionally, a small length of the fake e value sent to the server can be chosen for a more efficient attack (such as 4).")
|
parser.add_argument("--dheat", action="store", dest="dheat", metavar="N[:kex[:e_len]]", type=str, default=None, help="continuously perform the DHEat DoS attack (CVE-2002-20001) against the target using N concurrent sockets. Optionally, a specific key exchange algorithm can be specified instead of allowing it to be automatically chosen. Additionally, a small length of the fake e value sent to the server can be chosen for a more efficient attack (such as 4).")
|
||||||
|
parser.add_argument("--get-hardening-guide", action="store", metavar="platform", dest="get_hardening_guide", type=str, default=None, help="retrieves the hardening guide for the specified platform name (use --list-hardening-guides to see list of available guides).")
|
||||||
|
parser.add_argument("--list-hardening-guides", action="store_true", dest="list_hardening_guides", default=False, help="list all official, built-in hardening guides for common systems. Their full names can then be passed to --get-hardening-guide. Add -v to this option to view hardening guide change logs and prior versions.")
|
||||||
parser.add_argument("--lookup", action="store", dest="lookup", metavar="alg1[,alg2,...]", type=str, default=None, help="looks up an algorithm(s) without connecting to a server.")
|
parser.add_argument("--lookup", action="store", dest="lookup", metavar="alg1[,alg2,...]", type=str, default=None, help="looks up an algorithm(s) without connecting to a server.")
|
||||||
parser.add_argument("--skip-rate-test", action="store_true", dest="skip_rate_test", default=False, help="skip the connection rate test during standard audits (used to safely infer whether the DHEat attack is viable)")
|
parser.add_argument("--skip-rate-test", action="store_true", dest="skip_rate_test", default=False, help="skip the connection rate test during standard audits (used to safely infer whether the DHEat attack is viable)")
|
||||||
parser.add_argument("--threads", action="store", dest="threads", metavar="N", type=int, default=32, help="number of threads to use when scanning multiple targets (-T/--targets) (default: %(default)s)")
|
parser.add_argument("--threads", action="store", dest="threads", metavar="N", type=int, default=32, help="number of threads to use when scanning multiple targets (-T/--targets) (default: %(default)s)")
|
||||||
|
|
||||||
# Print Suggested Configurations from : https://www.ssh-audit.com/hardening_guides.html
|
|
||||||
parser.add_argument("--get-hardening-guides", nargs="*", action="append", metavar="OS Ver Client/Server", dest="get_hardening_guides", type=str, default=None, help="Print suggested server or client configurations. Usage Example : Ubuntu 2404 Server")
|
|
||||||
parser.add_argument("--list-hardening-guides", action="store_true", dest="list_hardening_guides", default=False, help="List supported server and client configurations.")
|
|
||||||
|
|
||||||
# The mandatory target option. Or rather, mandatory when -L, -T, --lookup or --print-config are not used.
|
# The mandatory target option. Or rather, mandatory when -L, -T, --lookup or --print-config are not used.
|
||||||
parser.add_argument("host", nargs="?", action="store", type=str, default="", help="target hostname or IPv4/IPv6 address")
|
parser.add_argument("host", nargs="?", action="store", type=str, default="", help="target hostname or IPv4/IPv6 address")
|
||||||
@@ -810,27 +809,6 @@ def process_commandline(out: OutputBuffer, args: List[str]) -> 'AuditConf': # p
|
|||||||
try:
|
try:
|
||||||
argument = parser.parse_args(args=args)
|
argument = parser.parse_args(args=args)
|
||||||
|
|
||||||
if argument.list_hardening_guides is True:
|
|
||||||
PrintHardeningGuides.supported_varient()
|
|
||||||
|
|
||||||
if argument.get_hardening_guides is not None:
|
|
||||||
print_guides = (getattr(argument, 'get_hardening_guides'))[0]
|
|
||||||
arg_len = len(print_guides)
|
|
||||||
if arg_len <= 2:
|
|
||||||
user_arg = ""
|
|
||||||
for i in range(arg_len):
|
|
||||||
user_arg = user_arg + " " + str(print_guides[i])
|
|
||||||
print(f"\033[1mUnsupported configuration : {user_arg}\033[0m")
|
|
||||||
PrintHardeningGuides.supported_varient()
|
|
||||||
else:
|
|
||||||
print_guides = (getattr(argument, 'get_hardening_guides'))[0]
|
|
||||||
os_type = print_guides[0]
|
|
||||||
os_ver = print_guides[1]
|
|
||||||
clientserver = print_guides[2]
|
|
||||||
|
|
||||||
PrintHardeningGuides(os_type, os_ver, clientserver)
|
|
||||||
|
|
||||||
|
|
||||||
# Set simple flags.
|
# Set simple flags.
|
||||||
aconf.client_audit = argument.client_audit
|
aconf.client_audit = argument.client_audit
|
||||||
aconf.ipv4 = argument.ipv4
|
aconf.ipv4 = argument.ipv4
|
||||||
@@ -915,8 +893,8 @@ def process_commandline(out: OutputBuffer, args: List[str]) -> 'AuditConf': # p
|
|||||||
parser.print_help()
|
parser.print_help()
|
||||||
sys.exit(exitcodes.UNKNOWN_ERROR)
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
|
||||||
if argument.host == "" and argument.client_audit is False and argument.targets is None and argument.list_policies is False and argument.lookup is None and argument.manual is False and argument.get_hardening_guides is None:
|
if argument.host == "" and argument.client_audit is False and argument.targets is None and argument.list_policies is False and argument.lookup is None and argument.manual is False and argument.list_hardening_guides is False and argument.get_hardening_guide is None:
|
||||||
out.fail("target host must be specified, unless -c, -m, -L, -T, --lookup or --print-configuration are used", write_now=True)
|
out.fail("target host must be specified, unless -c, -m, -L, -T, --lookup or --list-hardening-guides are used", write_now=True)
|
||||||
sys.exit(exitcodes.UNKNOWN_ERROR)
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
|
||||||
if aconf.manual:
|
if aconf.manual:
|
||||||
@@ -929,6 +907,14 @@ def process_commandline(out: OutputBuffer, args: List[str]) -> 'AuditConf': # p
|
|||||||
list_policies(out, aconf.verbose)
|
list_policies(out, aconf.verbose)
|
||||||
sys.exit(exitcodes.GOOD)
|
sys.exit(exitcodes.GOOD)
|
||||||
|
|
||||||
|
# Print a list of the hardening guides, or the specific guide requested by the user.
|
||||||
|
if argument.list_hardening_guides is True:
|
||||||
|
Hardening_Guides.list_guides(out, aconf.verbose)
|
||||||
|
sys.exit(exitcodes.GOOD)
|
||||||
|
elif argument.get_hardening_guide is not None:
|
||||||
|
Hardening_Guides.print_hardening_guide(out, argument.get_hardening_guide)
|
||||||
|
sys.exit(exitcodes.GOOD)
|
||||||
|
|
||||||
if aconf.client_audit is False and aconf.target_file is None:
|
if aconf.client_audit is False and aconf.target_file is None:
|
||||||
if oport is not None:
|
if oport is not None:
|
||||||
host = argument.host
|
host = argument.host
|
||||||
|
14
ssh-audit.1
14
ssh-audit.1
@@ -1,4 +1,4 @@
|
|||||||
.TH SSH-AUDIT 1 "July 26, 2025"
|
.TH SSH-AUDIT 1 "August 17, 2025"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
\fBssh-audit\fP \- SSH server & client configuration auditor
|
\fBssh-audit\fP \- SSH server & client configuration auditor
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@@ -51,6 +51,11 @@ Enable debug output.
|
|||||||
.br
|
.br
|
||||||
Run the DHEat DoS attack (CVE-2002-20001) against the target server (which will consume all available CPU resources). The number of concurrent sockets, N, needed to achieve this effect will be highly dependent on the CPU resources available on the target, as well as the latency between the source and target machines. The key exchange is automatically chosen based on which would cause maximum effect, unless explicitly chosen in the second field. Lastly, an (experimental) option allows the length in bytes of the fake e value sent to the server to be specified in the third field. Normally, the length of e is roughly the length of the modulus of the Diffie-Hellman exchange (hence, an 8192-bit / 1024-byte value of e is sent in each connection when targeting the diffie-hellman-group18-sha512 algorithm). Instead, it was observed that many SSH implementations accept small values, such as 4 bytes; this results in a much more network-efficient attack.
|
Run the DHEat DoS attack (CVE-2002-20001) against the target server (which will consume all available CPU resources). The number of concurrent sockets, N, needed to achieve this effect will be highly dependent on the CPU resources available on the target, as well as the latency between the source and target machines. The key exchange is automatically chosen based on which would cause maximum effect, unless explicitly chosen in the second field. Lastly, an (experimental) option allows the length in bytes of the fake e value sent to the server to be specified in the third field. Normally, the length of e is roughly the length of the modulus of the Diffie-Hellman exchange (hence, an 8192-bit / 1024-byte value of e is sent in each connection when targeting the diffie-hellman-group18-sha512 algorithm). Instead, it was observed that many SSH implementations accept small values, such as 4 bytes; this results in a much more network-efficient attack.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B \-\-get\-hardening\-guide=<platform_name>
|
||||||
|
.br
|
||||||
|
Retrieves the hardening guide for the specified platform name (use \-\-list\-hardening\-guides to see list of available guides).
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B -g, \-\-gex-test=<x[,y,...] | min1:pref1:max1[,min2:pref2:max2,...] | x-y[:step]>
|
.B -g, \-\-gex-test=<x[,y,...] | min1:pref1:max1[,min2:pref2:max2,...] | x-y[:step]>
|
||||||
.br
|
.br
|
||||||
@@ -91,10 +96,15 @@ Output results in JSON format. Specify twice (-jj) to enable indent printing (u
|
|||||||
.br
|
.br
|
||||||
Specify the minimum output level. Default is info.
|
Specify the minimum output level. Default is info.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B \-\-list-hardening-guides
|
||||||
|
.br
|
||||||
|
List all official, built-in hardening guides for common systems. Their full names can then be passed to \-\-get\-hardening\-guide. Add \-v to this option to view hardening guide change logs and prior versions.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B -L, \-\-list-policies
|
.B -L, \-\-list-policies
|
||||||
.br
|
.br
|
||||||
List all official, built-in policies for common systems. Their full names can then be passed to -P/--policy. Add \-v to \-L to view policy change logs.
|
List all official, built-in policies for common systems. Their full names can then be passed to \-P/\-\-policy. Add \-v to \-L to view policy change logs.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B \-\-lookup=<alg1,alg2,...>
|
.B \-\-lookup=<alg1,alg2,...>
|
||||||
|
@@ -1,41 +1,81 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from ssh_audit.ssh_audit import process_commandline
|
|
||||||
|
from ssh_audit.hardeningguides import Hardening_Guides
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=attribute-defined-outside-init
|
|
||||||
class TestHardeningGuides:
|
class TestHardeningGuides:
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def init(self, ssh_audit):
|
def init(self, ssh_audit):
|
||||||
self.OutputBuffer = ssh_audit.OutputBuffer()
|
self.OutputBuffer = ssh_audit.OutputBuffer()
|
||||||
self.process_commandline = process_commandline
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _test_conf(conf, **kwargs):
|
|
||||||
options = {
|
|
||||||
'get_hardening_guides': '',
|
|
||||||
}
|
|
||||||
for k, v in kwargs.items():
|
|
||||||
options[k] = v
|
|
||||||
assert conf.get_hardening_guides == options['get_hardening_guides']
|
|
||||||
|
|
||||||
def test_printconfig_conf_process_commandline(self):
|
def test_hardening_guides_consistency(self):
|
||||||
# pylint: disable=too-many-statements
|
'''Ensure that the HARDENING_GUIDES struct is consistent.'''
|
||||||
c = lambda x: self.process_commandline(self.OutputBuffer, x.split()) # noqa
|
|
||||||
with pytest.raises(SystemExit):
|
|
||||||
conf = c('')
|
|
||||||
with pytest.raises(SystemExit):
|
|
||||||
conf = c('--get-hardening-guides')
|
|
||||||
self._test_conf(conf)
|
|
||||||
with pytest.raises(SystemExit):
|
|
||||||
conf = c('--list-hardening-guides')
|
|
||||||
self._test_conf(conf)
|
|
||||||
|
|
||||||
for vendor in ["Amazon", "Debian", "Rocky", "Mint", "Ubuntu", "NoOS", " "]:
|
# Required keys in each guide dict.
|
||||||
vendor = vendor
|
required_guide_fields = ["server_guide", "version", "version_date", "change_log", "notes", "commands"]
|
||||||
for os_ver in ["2404", "2204", "2004", "1804", "2023", "22", "21", "20", "9", "Bookworm", "Bullseye", "NoVersion", ""]:
|
|
||||||
os_ver = os_ver
|
# Required keys in the commands dict.
|
||||||
for cs_type in ["Client", "Server", "Mistake", ""]:
|
required_command_fields = ["heading", "comment", "command"]
|
||||||
cs_type = cs_type
|
|
||||||
with pytest.raises(SystemExit):
|
for name, guides in Hardening_Guides.HARDENING_GUIDES.items():
|
||||||
conf = c(f'--get-hardening-guides {vendor} {os_ver} {cs_type}')
|
|
||||||
self._test_conf(conf)
|
# Ensure the key (guide name) is a string.
|
||||||
|
assert type(name) is str
|
||||||
|
|
||||||
|
# Ensure the value (guides) is a list.
|
||||||
|
assert type(guides) is list
|
||||||
|
|
||||||
|
for guide in guides:
|
||||||
|
|
||||||
|
# Ensure each guide is a dict.
|
||||||
|
assert type(guide) is dict
|
||||||
|
|
||||||
|
# Ensure each required key is in this guide.
|
||||||
|
for required_guide_field in required_guide_fields:
|
||||||
|
assert required_guide_field in guide
|
||||||
|
|
||||||
|
# Check the guide values are the correct type.
|
||||||
|
assert type(guide["server_guide"]) is bool
|
||||||
|
assert type(guide["version"]) is int
|
||||||
|
assert type(guide["version_date"]) is str
|
||||||
|
assert type(guide["change_log"]) is str
|
||||||
|
assert type(guide["notes"]) is str
|
||||||
|
assert type(guide["commands"]) is list
|
||||||
|
|
||||||
|
# The version must be creater than zero.
|
||||||
|
assert guide["version"] > 0
|
||||||
|
|
||||||
|
# Ensure the format is "YYYY-MM-DD".
|
||||||
|
version_date = guide["version_date"]
|
||||||
|
date_fields = version_date.split("-")
|
||||||
|
assert len(date_fields) == 3
|
||||||
|
|
||||||
|
# Check that the year is 4 digits and greater than 0.
|
||||||
|
year = date_fields[0]
|
||||||
|
assert len(year) == 4
|
||||||
|
assert int(year) > 0
|
||||||
|
|
||||||
|
# Check that the month is 2 digits and between 1 and 12.
|
||||||
|
month = date_fields[1]
|
||||||
|
assert len(month) == 2
|
||||||
|
assert 1 <= int(month) <= 12
|
||||||
|
|
||||||
|
# Check that the day is 2 digits and between 1 and 31.
|
||||||
|
day = date_fields[2]
|
||||||
|
assert len(day) == 2
|
||||||
|
assert 1 <= int(day) <= 31
|
||||||
|
|
||||||
|
# Check that the change log is filled in.
|
||||||
|
assert len(guide["change_log"]) > 0
|
||||||
|
|
||||||
|
commands = guide["commands"]
|
||||||
|
for command in commands:
|
||||||
|
|
||||||
|
# Ensure each required key is in this command list.
|
||||||
|
for required_command_field in required_command_fields:
|
||||||
|
assert required_command_field in command
|
||||||
|
|
||||||
|
# Check that these fields are not empty.
|
||||||
|
assert len(command["heading"]) > 0
|
||||||
|
assert len(command["command"]) > 0
|
||||||
|
Reference in New Issue
Block a user