7 Commits

Author SHA1 Message Date
OAM7575 9814d18baf print config v2
- printconfig script
 - test_printconfig for tox testing
 - update globals for GUIDES_UPDATED date value
 - update ssh_audit for print_config argument and checks
2024-11-24 11:24:07 +11:00
Joe Testa a01baadfa8 Additional cleanups after merging #304. 2024-11-22 12:28:02 -05:00
oam7575 45abc3aaf4 Argparse v3 - RC1 (#304)
* Argparse v3 - RC1

* Argparse v3 - RC1

Argparse v3 RC1 - post feedback

Argparse v3 - RC2
2024-11-22 12:26:20 -05:00
Joe Testa 99c64787d9 Updated description of -m option. 2024-10-16 16:39:11 -04:00
Joe Testa 3fa62c3ac5 Fixed man page parsing error. (#301) 2024-10-16 16:23:20 -04:00
Joe Testa d7fff591fa Bumped version to v3.4.0-dev. 2024-10-15 18:30:08 -04:00
Joe Testa 84647ecb32 Updated packaging notes. 2024-10-15 18:29:25 -04:00
10 changed files with 644 additions and 235 deletions
+9 -9
View File
@@ -15,10 +15,10 @@ An executable can only be made on a Windows host because the PyInstaller tool (h
# PyPI
To create package and upload to test server (hint: use username '\_\_token\_\_' and API token for test.pypi.org):
To create package and upload to test server (hint: use API token for test.pypi.org):
```
$ sudo apt install python3-virtualenv python3.10-venv
$ sudo apt install python3-virtualenv python3.12-venv
$ make -f Makefile.pypi
$ make -f Makefile.pypi uploadtest
```
@@ -26,12 +26,12 @@ To create package and upload to test server (hint: use username '\_\_token\_\_'
To download from test server and verify:
```
$ virtualenv -p /usr/bin/python3 /tmp/pypi_test
$ virtualenv /tmp/pypi_test
$ cd /tmp/pypi_test; source bin/activate
$ pip3 install --index-url https://test.pypi.org/simple ssh-audit
```
To upload to production server (hint: use username '\_\_token\_\_' and API token for production pypi.org):
To upload to production server (hint: use API token for production pypi.org):
```
$ make -f Makefile.pypi uploadprod
@@ -40,7 +40,7 @@ To upload to production server (hint: use username '\_\_token\_\_' and API token
To download from production server and verify:
```
$ virtualenv -p /usr/bin/python3 /tmp/pypi_prod
$ virtualenv /tmp/pypi_prod
$ cd /tmp/pypi_prod; source bin/activate
$ pip3 install ssh-audit
```
@@ -48,14 +48,14 @@ To download from production server and verify:
# Snap
To create the snap package, run a fully-updated Ubuntu Server 22.04 VM.
To create the Snap package, run a fully-updated Ubuntu Server 24.04 VM.
Create the snap package with:
Create the Snap package with:
```
$ ./build_snap.sh
```
Upload the snap with:
Upload the Snap with:
```
$ snapcraft export-login ~/snap_creds.txt
@@ -68,7 +68,7 @@ Upload the snap with:
# Docker
Ensure that the buildx plugin is available by following the installation instructions available at: https://docs.docker.com/engine/install/ubuntu/
Ensure that the `buildx` plugin is available by following the installation instructions available at: https://docs.docker.com/engine/install/ubuntu/
Build a local image with:
+52 -52
View File
@@ -41,64 +41,61 @@
## Usage
```
usage: ssh-audit.py [options] <host>
usage: ssh-audit.py [-h] [-1] [-2] [-4] [-6] [-b] [-c] [-d]
[-g <min1:pref1:max1[,min2:pref2:max2,...]> / <x-y[:step]>] [-j] [-l {info,warn,fail}] [-L]
[-M custom_policy.txt] [-m] [-n] [-P "Built-In Policy Name" / custom_policy.txt] [-p N]
[-T targets.txt] [-t N] [-v] [--conn-rate-test N[:max_rate]] [--dheat N[:kex[:e_len]]]
[--lookup alg1[,alg2,...]] [--skip-rate-test] [--threads N]
[host]
-h, --help print this help
positional arguments:
host target hostname or IPv4/IPv6 address
optional arguments:
-h, --help show this help message and exit
-1, --ssh1 force ssh version 1 only
-2, --ssh2 force ssh version 2 only
-4, --ipv4 enable IPv4 (order of precedence)
-6, --ipv6 enable IPv6 (order of precedence)
-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 to change timeout)
--conn-rate-test=N[:max_rate] 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.
-d, --debug Enable debug output.
--dheat=N[:kex[:e_len]] continuously perform the DHEat DoS attack
(CVE-2002-20001) against the target using N
concurrent sockets. Optionally, a specific
key exchange algorithm can be specified
instead of allowing it to be automatically
chosen. Additionally, a small length of
the fake e value sent to the server can
be chosen for a more efficient attack (such
as 4).
-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. Use with -v
to view policy change logs.
--lookup=<alg1,alg2,...> looks up an algorithm(s) without
connecting to a server
-m, --manual print the man page (Docker, PyPI, Snap, and Windows
builds 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
adhere to)
-n, --no-colors disable colors
-p, --port=<port> port to connect
-P, --policy=<"policy name" | policy.txt> run a policy test using the
specified policy
--skip-rate-test skip the connection rate test during standard audits
(used to safely infer whether the DHEat attack
is viable)
-t, --timeout=<secs> timeout (in seconds) for connection and reading
(default: 5)
-T, --targets=<hosts.txt> a file containing a list of target hosts (one
per line, format HOST[:PORT]). Use -p/--port
to set the default port for all hosts. Use
--threads to control concurrent scans.
--threads=<threads> number of threads to use when scanning multiple
targets (-T/--targets) (default: 32)
-v, --verbose verbose output
-c, --client-audit starts a server on port 2222 to audit client software config (use -p to change port; use -t
to change timeout)
-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]>
conducts a very customized Diffie-Hellman GEX modulus size test. Tests an array of minimum,
preferred, and maximum values, or a range of values with an optional incremental step amount
-j, --json enable JSON output (use -jj to enable indentation for better readability)
-l {info,warn,fail}, --level {info,warn,fail}
minimum output level (default: info)
-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
creates a policy based on the target server (i.e.: the target server has the ideal
configuration that other servers should adhere to), and stores it in the file path specified
-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
run a policy test using the specified policy (use -L to see built-in policies, or specify
filesystem path to custom policy created by -M)
-p N, --port N the TCP port to connect to (or to listen on when -c is used)
-T targets.txt, --targets targets.txt
a file containing a list of target hosts (one per line, format HOST[:PORT]). Use -p/--port
to set the default port for all hosts. Use --threads to control concurrent scans
-t N, --timeout N timeout (in seconds) for connection and reading (default: 5)
-v, --verbose enable verbose output
--conn-rate-test N[:max_rate]
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
--dheat N[:kex[:e_len]]
continuously perform the DHEat DoS attack (CVE-2002-20001) against the target using N
concurrent sockets. Optionally, a specific key exchange algorithm can be specified instead
of allowing it to be automatically chosen. Additionally, a small length of the fake e value
sent to the server can be chosen for a more efficient attack (such as 4).
--lookup alg1[,alg2,...]
looks up an algorithm(s) without connecting to a server.
--skip-rate-test skip the connection rate test during standard audits (used to safely infer whether the DHEat
attack is viable)
--threads N number of threads to use when scanning multiple targets (-T/--targets) (default: 32)
```
* 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).
@@ -219,6 +216,9 @@ For convenience, a web front-end on top of the command-line tool is available at
## ChangeLog
### v3.4.0-dev
- Migrated from deprecated `getopt` module to `argparse`; partial credit [oam7575](https://github.com/oam7575).
### v3.3.0 (2024-10-15)
- Added Python 3.13 support.
- Added built-in policies for Ubuntu 24.04 LTS server & client, OpenSSH 9.8, and OpenSSH 9.9.
-9
View File
@@ -111,18 +111,9 @@ echo "Processing man page at ${MAN_PAGE} and placing output into ${GLOBALS_PY}..
# * 'MAN_KEEP_FORMATTING' preserves the backspace-overwrite sequence when
# 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 BUILTIN_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."
+4 -1
View File
@@ -22,7 +22,7 @@
THE SOFTWARE.
"""
# The version to display.
VERSION = 'v3.3.0'
VERSION = 'v3.4.0-dev'
# SSH software to impersonate
SSH_HEADER = 'SSH-{0}-OpenSSH_8.2'
@@ -38,3 +38,6 @@ 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"'
# Last update to Hardening Guides
GUIDES_UPDATED = "2024-10-01"
+3 -1
View File
@@ -145,8 +145,10 @@ class OutputBuffer:
self._print('head', s, line_ended)
return self
def fail(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
def fail(self, s: str, line_ended: bool = True, write_now: bool = False) -> 'OutputBuffer':
self._print('fail', s, line_ended)
if write_now:
self.write()
return self
def warn(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
+375
View File
@@ -0,0 +1,375 @@
import sys
from ssh_audit import exitcodes
from ssh_audit.globals import VERSION
from ssh_audit.globals import GUIDES_UPDATED
class PrintConfig:
def __init__(self, os_type: str, os_ver: str, clientserver: str) -> None:
self.os_type = os_type
self.os_ver = os_ver
self.clientserver = clientserver
self.Get_Config()
def Get_Config(self) -> None:
retval = exitcodes.GOOD
os_type = self.os_type
os_ver = self.os_ver
clientserver = self.clientserver
supported_os = ["Amazon", "Debian", "Mint", "Rocky", "Ubuntu"]
supported_edition = ["2404", "2204", "2004", "1804", "2023", "22", "21", "20", "9", "Bookworm", "Bullseye"]
if clientserver not in ["Server", "Client"] or os_type not in supported_os and os_ver not in supported_edition:
PrintConfig.unknown_varient(os_type, os_ver, clientserver)
sys.exit(retval)
else:
print(" ")
print(f"\033[1mSSH-Audit Version : {VERSION}\033[0m")
print(" ")
print(f"\033[1mBGuides Last modified : {GUIDES_UPDATED}\033[0m")
print(" ")
print(f"\033[1mLocating configuration for {os_type} {os_ver} - {clientserver}\033[0m")
print(" ")
# Server Configs
if clientserver in ["Server"]:
# Amazon Linux
if os_type in ["Amazon"] and os_ver in ["2023"]:
PrintConfig.server_modern_common()
PrintConfig.amazon_server_2023()
sys.exit(retval)
# Debian
elif os_type in ["Debian"] and os_ver in ["Bookworm"]:
PrintConfig.server_modern_common()
PrintConfig.bookworm_server()
PrintConfig.debian_ubuntu_rate_throttling()
sys.exit(retval)
elif os_type in ["Debian"] and os_ver in ["Bullseye"]:
PrintConfig.server_modern_common()
PrintConfig.bullseye_server()
sys.exit(retval)
# Rocky Linux
elif os_type in ["Rocky"] and os_ver in ["9"]:
PrintConfig.server_modern_common()
PrintConfig.rocky_9_server()
sys.exit(retval)
# Ubuntu
elif os_type in ["Ubuntu"] and os_ver in ["2404"]:
PrintConfig.server_modern_common()
PrintConfig.ubuntu_server_2404()
PrintConfig.debian_ubuntu_rate_throttling()
sys.exit(retval)
elif os_type in ["Ubuntu"] and os_ver in ["2204"]:
PrintConfig.server_modern_common()
PrintConfig.ubuntu_server_2204()
PrintConfig.debian_ubuntu_rate_throttling()
sys.exit(retval)
elif os_type in ["Ubuntu"] and os_ver in ["2004"]:
PrintConfig.server_modern_common()
PrintConfig.ubuntu_server_2004()
PrintConfig.debian_ubuntu_rate_throttling()
sys.exit(retval)
elif os_type in ["Ubuntu"] and os_ver in ["1804"]:
PrintConfig.server_legacy_common()
PrintConfig.ubuntu_server_1804()
sys.exit(retval)
else:
PrintConfig.unknown_varient(os_type, os_ver, clientserver)
sys.exit(retval)
# Client Configs
if clientserver in ["Client"]:
# Amazon
if os_type in ["Amazon"] and os_ver in ["2023"]:
PrintConfig.amazon_2023_client()
sys.exit(retval)
# Debian
elif os_type in ["Debian"] and os_ver in ["Bookworm"]:
PrintConfig.debian_bookworm_client()
sys.exit(retval)
# Mint
elif os_type in ["Mint"] and os_ver in ["22"]:
PrintConfig.ubuntu_2404_mint_22_client()
sys.exit(retval)
elif os_type in ["Mint"] and os_ver in ["21"]:
PrintConfig.ubuntu_2204_mint_21_client()
sys.exit(retval)
elif os_type in ["Mint"] and os_ver in ["20"]:
PrintConfig.ubuntu_2004_mint_20_client()
sys.exit(retval)
# Rocky
elif os_type in ["Rocky"] and os_ver in ["9"]:
PrintConfig.rocky_9_client()
sys.exit(retval)
# Ubuntu
elif os_type in ["Ubuntu"] and os_ver in ["2404"]:
PrintConfig.ubuntu_2404_mint_22_client()
sys.exit(retval)
elif os_type in ["Ubuntu"] and os_ver in ["2204"]:
PrintConfig.ubuntu_2204_mint_21_client()
sys.exit(retval)
elif os_type in ["Ubuntu"] and os_ver in ["2004"]:
PrintConfig.ubuntu_2004_mint_20_client()
sys.exit(retval)
else:
PrintConfig.unknown_varient(os_type, os_ver, clientserver)
sys.exit(retval)
@staticmethod
def unknown_varient(os_type: str, os_ver: str, clientserver: str) -> None:
print(" ")
print(f"\033[1mSSH-Audit Version : {VERSION}\033[0m")
print(" ")
print(f"\033[1mGuides Last modified : {GUIDES_UPDATED}\033[0m")
print(" ")
print(f"\033[1mError unknown varient : {os_type} {os_ver} {clientserver} \033[0m")
print(" ")
print("For current, community developed and legacy guides")
print("check the website : https://www.ssh-audit.com/hardening_guides.html")
print(" ")
print("\033[1mSupported Server Configurations : \033[0m")
print(r"Amazon 2023 Server")
print(r"Debian Bookworm Server")
print(r"Debian Bullseye Server")
print(r"Rocky 9 Server")
print(r"Ubuntu 2404 Server")
print(r"Ubuntu 2204 Server")
print(r"Ubuntu 2004 Server")
print(" ")
print("\033[1mSupported Client Configurations : \033[0m")
print(r"Amazon 2023 Client")
print(r"Debian Bookworm Client")
print(r"Mint 22 Client")
print(r"Mint 21 Client")
print(r"Mint 20 Client")
print(r"Rocky 9 Client")
print(r"Ubuntu 2404 Client")
print(r"Ubuntu 2204 Client")
print(r"Ubuntu 2004 Client")
# Client Configurations
@staticmethod
def amazon_2023_client() -> None:
print(" ")
print("\033[1mRun the following in a terminal to harden the SSH client for the local user:\033[0m")
print(" ")
print(r'mkdir -p -m 0700 ~/.ssh; echo -e "\nHost *\n Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\n\n KexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,gss-group16-sha512-,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\n\n MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\n\n HostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\n CASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\n GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\n\n HostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\n\n PubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\n\n" >> ~/.ssh/config')
@staticmethod
def debian_bookworm_client() -> None:
print(" ")
print("\033[1mRun the following in a terminal to harden the SSH client for the local user:\033[0m")
print(" ")
print(r'mkdir -p -m 0700 ~/.ssh; echo -e "\nHost *\n Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\n\n KexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,gss-group16-sha512-,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\n\n MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\n\n RequiredRSASize 3072\n\n HostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\n CASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\n GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\n\n HostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\n\n PubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\n\n" >> ~/.ssh/config')
@staticmethod
def rocky_9_client() -> None:
print("\033[1mRun the following in a terminal to harden the SSH client for the local user:\033[0m")
print(" ")
print(r'mkdir -p -m 0700 ~/.ssh; echo -e "\nHost *\n Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\n\n KexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,gss-group16-sha512-,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\n\n MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\n\n RequiredRSASize 3072\n\n HostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\n CASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\n GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\n\n HostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\n\n PubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\n\n" >> ~/.ssh/config')
@staticmethod
def ubuntu_2404_mint_22_client() -> None:
print("\033[1mRun the following in a terminal to harden the SSH client for the local user:\033[0m")
print(" ")
print(r'mkdir -p -m 0700 ~/.ssh; echo -e "\nHost *\n Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\n\n KexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256,gss-group16-sha512-,diffie-hellman-group16-sha512\n\n MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com\n\n RequiredRSASize 3072\n\n HostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\n CASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\n GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\n\n HostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\n PubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\n" >> ~/.ssh/config')
@staticmethod
def ubuntu_2204_mint_21_client() -> None:
print("\033[1mRun the following in a terminal to harden the SSH client for the local user:\033[0m")
print(" ")
print(r'mkdir -p -m 0700 ~/.ssh; echo -e "\nHost *\n Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\n\n KexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,gss-group16-sha512-,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\n\n MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\n\n HostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\n CASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\n GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\n\n HostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\n\n PubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\n\n" >> ~/.ssh/config')
@staticmethod
def ubuntu_2004_mint_20_client() -> None:
print("\033[1mRun the following in a terminal to harden the SSH client for the local user:\033[0m")
print(" ")
print(r'mkdir -p -m 0700 ~/.ssh; echo -e "\nHost *\n Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr\n KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\n MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\n HostKeyAlgorithms 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\n" >> ~/.ssh/config')
# Server Configurations
@staticmethod
def server_modern_common() -> None:
print("\033[1mRe-generate the ED25519 and RSA keys\033[0m")
print(" ")
print("rm /etc/ssh/ssh_host_*")
print(r'ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N ""')
print(r'ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""')
print(" ")
print("\033[1mRemove small Diffie-Hellman moduli\033[0m")
print(" ")
print(r"awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe")
print("mv /etc/ssh/moduli.safe /etc/ssh/moduli")
print(" ")
print("\033[1mEnable the ED25519 and RSA keys\033[0m")
print(" ")
print("Enable the ED25519 and RSA HostKey directives in the /etc/ssh/sshd_config file:")
print(" ")
print(r'echo -e "\nHostKey /etc/ssh/ssh_host_ed25519_key\nHostKey /etc/ssh/ssh_host_rsa_key" >> /etc/ssh/sshd_config')
print(" ")
@staticmethod
def server_legacy_common() -> None:
print("\033[1mRe-generate the ED25519 and RSA keys\033[0m")
print(" ")
print(r"rm /etc/ssh/ssh_host_*")
print(r'ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N ""')
print(r'ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""')
print(" ")
print("\033[1mRemove small Diffie-Hellman moduli\033[0m")
print(" ")
print(r"awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe")
print("mv /etc/ssh/moduli.safe /etc/ssh/moduli")
print(" ")
print("\033[1mDisable the DSA and ECDSA host keys\033[0m")
print(" ")
print("Comment out the DSA and ECDSA HostKey directives in the /etc/ssh/sshd_config file:")
print(" ")
print(r"sed -i 's/^HostKey \/etc\/ssh\/ssh_host_\(dsa\|ecdsa\)_key$/\#HostKey \/etc\/ssh\/ssh_host_\1_key/g' /etc/ssh/sshd_config")
print(" ")
@staticmethod
def debian_ubuntu_rate_throttling() -> None:
print("\033[1mImplement connection rate throttling\033[0m")
print(" ")
print("iptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set")
print("iptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP")
print("ip6tables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set")
print("ip6tables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP")
print(" ")
print("\033[1mEnable persistence of the iptables rules across server reboots: \033[0m")
print(" ")
print("DEBIAN_FRONTEND=noninteractive apt install -q -y netfilter-persistent iptables-persistent service netfilter-persistent save")
print(" ")
print("\033[1mRestart OpenSSH server\033[0m")
print(" ")
print("service ssh restart")
@staticmethod
def ubuntu_server_2404() -> None:
print("\033[1mRestrict supported key exchange, cipher, and MAC algorithms\033[0m")
print(" ")
print(r'echo -e "# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com\n# hardening guide.\nKexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256,gss-group16-sha512-,diffie-hellman-group16-sha512\n\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\n\nMACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com\n\nRequiredRSASize 3072\n\nHostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nCASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nGSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\n\nHostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nPubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256" > /etc/ssh/sshd_config.d/ssh-audit_hardening.conf')
print(" ")
print("\033[1mRestart OpenSSH server\033[0m")
print(" ")
print("service ssh restart")
print(" ")
@staticmethod
def ubuntu_server_2204() -> None:
print("\033[1mRestrict supported key exchange, cipher, and MAC algorithms\033[0m")
print(" ")
print(r'echo -e "# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com\n# hardening guide.\nKexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,gss-curve25519-sha256-,diffie-hellman-group16-sha512,gss-group16-sha512-,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\n\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\n\nMACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\n\nHostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nCASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nGSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\n\nHostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\n\nPubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256" > /etc/ssh/sshd_config.d/ssh-audit_hardening.conf')
print(" ")
print("\033[1mRestart OpenSSH server\033[0m")
print(" ")
print("service ssh restart")
print(" ")
@staticmethod
def ubuntu_server_2004() -> None:
print("\033[1mRestrict supported key exchange, cipher, and MAC algorithms\033[0m")
print(" ")
print(r'echo -e "# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com\n# hardening guide.\nKexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256,gss-group16-sha512-,diffie-hellman-group16-sha512\n\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\n\nMACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com\n\nRequiredRSASize 3072\n\nHostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nCASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nGSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\n\nHostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nPubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256" > /etc/ssh/sshd_config.d/ssh-audit_hardening.conf')
print(" ")
print("\033[1mRestart OpenSSH server\033[0m")
print(" ")
print("service ssh restart")
print(" ")
@staticmethod
def ubuntu_server_1804() -> None:
print("\033[1mRestrict supported key exchange, cipher, and MAC algorithms\033[0m")
print(" ")
print(r'echo -e "# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com\n# hardening guide.\nKexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr\nMACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\nHostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com" >> /etc/ssh/sshd_config')
print(" ")
print("\033[1mRestart OpenSSH server\033[0m")
print(" ")
print("service ssh restart")
print(" ")
@staticmethod
def bookworm_server() -> None:
print("\033[1mRestrict supported key exchange, cipher, and MAC algorithms\033[0m")
print(" ")
print(r'echo -e "# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com\n# hardening guide.\nKexAlgorithms sntrup761x25519-sha512@openssh.com,gss-curve25519-sha256-,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256,gss-group16-sha512-,diffie-hellman-group16-sha512\n\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\n\nMACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com\n\nRequiredRSASize 3072\n\nHostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nCASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nGSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\n\nHostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nPubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256" > /etc/ssh/sshd_config.d/ssh-audit_hardening.conf')
print(" ")
print("\033[1mRestart OpenSSH server\033[0m")
print(" ")
print("service ssh restart")
print(" ")
@staticmethod
def bullseye_server() -> None:
print("\033[1mRestrict supported key exchange, cipher, and MAC algorithms\033[0m")
print(" ")
print(r'echo -e "# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com\n# hardening guide.\nKexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,gss-curve25519-sha256-,diffie-hellman-group16-sha512,gss-group16-sha512-,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\n\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\n\nMACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\n\nHostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nCASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nGSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\n\nHostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\n\nPubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256" > /etc/ssh/sshd_config.d/ssh-audit_hardening.conf')
print(" ")
print("\033[1mRestart OpenSSH server\033[0m")
print(" ")
print("service ssh restart")
print(" ")
@staticmethod
def rocky_9_server() -> None:
print("\033[1mRestrict supported key exchange, cipher, and MAC algorithms\033[0m")
print(" ")
print(r'echo -e "# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com\n# hardening guide.\nKexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,gss-curve25519-sha256-,diffie-hellman-group16-sha512,gss-group16-sha512-,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\n\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\n\nMACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\n\nHostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nRequiredRSASize 3072\n\nCASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nGSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\n\nHostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\n\nPubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\n" > /etc/crypto-policies/back-ends/opensshserver.config')
print(" ")
print("\033[1mRestart OpenSSH server\033[0m")
print(" ")
print("systemctl restart sshd")
print(" ")
print("\033[1mImplement connection rate throttling\033[0m")
print(" ")
print("firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 22 -m state --state NEW -m recent --set")
print("firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 1 -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP")
print("firewall-cmd --permanent --direct --add-rule ipv6 filter INPUT 0 -p tcp --dport 22 -m state --state NEW -m recent --set")
print("firewall-cmd --permanent --direct --add-rule ipv6 filter INPUT 1 -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP")
print(" ")
print("\033[1mReload firewalld to enable new rules:\033[0m")
print(" ")
print("systemctl reload firewalld")
print(" ")
@staticmethod
def amazon_server_2023() -> None:
print("\033[1mRestrict supported key exchange, cipher, and MAC algorithms\033[0m")
print(" ")
print(r'echo -e "# Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com\n# hardening guide.\nKexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,gss-curve25519-sha256-,diffie-hellman-group16-sha512,gss-group16-sha512-,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\n\nCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\n\nMACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\n\nHostKeyAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nCASignatureAlgorithms sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nGSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512-\n\nHostbasedAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\n\nPubkeyAcceptedAlgorithms sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\n" > /etc/crypto-policies/back-ends/opensshserver.config')
print(" ")
print("\033[1mRestart OpenSSH server\033[0m")
print(" ")
print("systemctl restart sshd")
print(" ")
print("\033[1mImplement connection rate throttling\033[0m")
print(" ")
print("dnf install -y iptables")
print("iptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set")
print("iptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP")
print("ip6tables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set")
print("ip6tables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP")
print(" ")
print("\033[1mEnable persistence of the iptables rules across server reboots:\033[0m")
print(" ")
print("dnf install -y iptables-services")
print("iptables-save > /etc/sysconfig/iptables")
print("ip6tables-save > /etc/sysconfig/ip6tables")
print("systemctl enable iptables")
print("systemctl enable ip6tables")
print("systemctl start iptables")
print("systemctl start ip6tables")
print(" ")
+154 -153
View File
@@ -23,9 +23,9 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
import argparse
import concurrent.futures
import copy
import getopt # pylint: disable=deprecated-module
import json
import multiprocessing
import os
@@ -33,6 +33,7 @@ import re
import sys
import traceback
# pylint: disable=unused-import
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
from typing import cast, Callable, Optional, Union, Any # noqa: F401
@@ -52,6 +53,7 @@ from ssh_audit.gextest import GEXTest
from ssh_audit.hostkeytest import HostKeyTest
from ssh_audit.outputbuffer import OutputBuffer
from ssh_audit.policy import Policy
from ssh_audit.printconfig import PrintConfig
from ssh_audit.product import Product
from ssh_audit.protocol import Protocol
from ssh_audit.software import Software
@@ -82,61 +84,6 @@ if sys.platform == 'win32':
# no_idna_workaround = True
def usage(uout: OutputBuffer, err: Optional[str] = None) -> None:
retval = exitcodes.GOOD
p = os.path.basename(sys.argv[0])
uout.head('# {} {}, https://github.com/jtesta/ssh-audit\n'.format(p, VERSION))
if err is not None and len(err) > 0:
uout.fail(err + '\n')
retval = exitcodes.UNKNOWN_ERROR
uout.info('usage: {0} [options] <host>\n'.format(p))
uout.info(' -h, --help print this help')
uout.info(' -1, --ssh1 force ssh version 1 only')
uout.info(' -2, --ssh2 force ssh version 2 only')
uout.info(' -4, --ipv4 enable IPv4 (order of precedence)')
uout.info(' -6, --ipv6 enable IPv6 (order of precedence)')
uout.info(' -b, --batch batch output')
uout.info(' -c, --client-audit starts a server on port 2222 to audit client\n software config (use -p to change port;\n use -t to change timeout)')
uout.info(' --conn-rate-test=N[:max_rate] perform a connection rate test (useful')
uout.info(' for collecting metrics related to')
uout.info(' susceptibility of the DHEat vuln).')
uout.info(' Testing is conducted with N concurrent')
uout.info(' sockets with an optional maximum rate')
uout.info(' of connections per second.')
uout.info(' -d, --debug debug output')
uout.info(' --dheat=N[:kex[:e_len]] continuously perform the DHEat DoS attack')
uout.info(' (CVE-2002-20001) against the target using N')
uout.info(' concurrent sockets. Optionally, a specific')
uout.info(' key exchange algorithm can be specified')
uout.info(' instead of allowing it to be automatically')
uout.info(' chosen. Additionally, a small length of')
uout.info(' the fake e value sent to the server can')
uout.info(' be chosen for a more efficient attack (such')
uout.info(' as 4).')
uout.info(' -g, --gex-test=<x[,y,...]> dh gex modulus size test')
uout.info(' <min1:pref1:max1[,min2:pref2:max2,...]>')
uout.info(' <x-y[:step]>')
uout.info(' -j, --json JSON output (use -jj to enable indents)')
uout.info(' -l, --level=<level> minimum output level (info|warn|fail)')
uout.info(' -L, --list-policies list all the official, built-in policies. Use with -v')
uout.info(' to view policy change logs.')
uout.info(' --lookup=<alg1,alg2,...> looks up an algorithm(s) without\n connecting to a server')
uout.info(' -M, --make-policy=<policy.txt> creates a policy based on the target server\n (i.e.: the target server has the ideal\n configuration that other servers should\n adhere to)')
uout.info(' -m, --manual print the man page (Windows only)')
uout.info(' -n, --no-colors disable colors (automatic when the NO_COLOR')
uout.info(' environment variable is set)')
uout.info(' -p, --port=<port> port to connect')
uout.info(' -P, --policy=<policy.txt> run a policy test using the specified policy')
uout.info(' --skip-rate-test skip the connection rate test during standard audits\n (used to safely infer whether the DHEat attack\n is viable)')
uout.info(' -t, --timeout=<secs> timeout (in seconds) for connection and reading\n (default: 5)')
uout.info(' -T, --targets=<hosts.txt> a file containing a list of target hosts (one\n per line, format HOST[:PORT]). Use -p/--port\n to set the default port for all hosts. Use\n --threads to control concurrent scans.')
uout.info(' --threads=<threads> number of threads to use when scanning multiple\n targets (-T/--targets) (default: 32)')
uout.info(' -v, --verbose verbose output')
uout.sep()
uout.write()
sys.exit(retval)
def output_algorithms(out: OutputBuffer, title: str, alg_db: Dict[str, Dict[str, List[List[Optional[str]]]]], alg_type: str, algorithms: List[str], unknown_algs: List[str], is_json_output: bool, program_retval: int, maxlen: int = 0, host_keys: Optional[Dict[str, Dict[str, Union[bytes, str, int]]]] = None, dh_modulus_sizes: Optional[Dict[str, int]] = None) -> int: # pylint: disable=too-many-arguments
with out:
for algorithm in algorithms:
@@ -371,7 +318,7 @@ def output_recommendations(out: OutputBuffer, algs: Algorithms, algorithm_recomm
notes = " (%s)" % notes
fm = '(rec) {0}{1}{2}-- {3} algorithm to {4}{5} '
fn(fm.format(sg, name, p, alg_type, an, notes))
fn(fm.format(sg, name, p, alg_type, an, notes)) # type: ignore[operator]
if not out.is_section_empty() and not is_json_output:
if software is not None:
@@ -823,7 +770,7 @@ def make_policy(aconf: AuditConf, banner: Optional['Banner'], kex: Optional['SSH
print(err)
def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[..., None]) -> 'AuditConf': # pylint: disable=too-many-statements
def process_commandline(out: OutputBuffer, args: List[str]) -> 'AuditConf': # pylint: disable=too-many-statements
# pylint: disable=too-many-branches
aconf = AuditConf()
@@ -836,82 +783,113 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
aconf.colors = enable_colors
out.use_colors = enable_colors
try:
sopts = 'h1246M:p:P:jbcnvl:t:T:Lmdg:'
lopts = ['help', 'ssh1', 'ssh2', 'ipv4', 'ipv6', 'make-policy=', 'port=', 'policy=', 'json', 'batch', 'client-audit', 'no-colors', 'verbose', 'level=', 'timeout=', 'targets=', 'list-policies', 'lookup=', 'threads=', 'manual', 'debug', 'gex-test=', 'dheat=', 'skip-rate-test', 'conn-rate-test=']
opts, args = getopt.gnu_getopt(args, sopts, lopts)
except getopt.GetoptError as err:
usage_cb(out, str(err))
aconf.ssh1, aconf.ssh2 = False, False
host: str = ''
oport: Optional[str] = None
port: int = 0
for o, a in opts:
if o in ('-h', '--help'):
usage_cb(out)
elif o in ('-1', '--ssh1'):
aconf.ssh1 = True
elif o in ('-2', '--ssh2'):
aconf.ssh2 = True
elif o in ('-4', '--ipv4'):
aconf.ipv4 = True
elif o in ('-6', '--ipv6'):
aconf.ipv6 = True
elif o in ('-p', '--port'):
oport = a
elif o in ('-b', '--batch'):
port: int = 22
parser = argparse.ArgumentParser(description="# {} {}, https://github.com/jtesta/ssh-audit".format(os.path.basename(sys.argv[0]), VERSION), allow_abbrev=False)
# Add short options to the parser
parser.add_argument("-1", "--ssh1", action="store_true", dest="ssh1", default=False, help="force ssh version 1 only")
parser.add_argument("-2", "--ssh2", action="store_true", dest="ssh2", default=False, help="force ssh version 2 only")
parser.add_argument("-4", "--ipv4", action="store_true", dest="ipv4", default=False, help="enable IPv4 (order of precedence)")
parser.add_argument("-6", "--ipv6", action="store_true", dest="ipv6", default=False, help="enable IPv6 (order of precedence)")
parser.add_argument("-b", "--batch", action="store_true", dest="batch", default=False, help="batch output")
parser.add_argument("-c", "--client-audit", action="store_true", dest="client_audit", default=False, help="starts a server on port 2222 to audit client software config (use -p to change port; use -t to change timeout)")
parser.add_argument("-d", "--debug", action="store_true", dest="debug", default=False, help="enable debugging output")
parser.add_argument("-g", "--gex-test", action="store", dest="gex_test", metavar="<min1:pref1:max1[,min2:pref2:max2,...]> / <x-y[:step]>", type=str, default=None, help="conducts a very customized Diffie-Hellman GEX modulus size test. Tests an array of minimum, preferred, and maximum values, or a range of values with an optional incremental step amount")
parser.add_argument("-j", "--json", action="count", dest="json", default=0, help="enable JSON output (use -jj to enable indentation for better readability)")
parser.add_argument("-l", "--level", action="store", dest="level", type=str, choices=["info", "warn", "fail"], default="info", help="minimum output level (default: %(default)s)")
parser.add_argument("-L", "--list-policies", action="store_true", dest="list_policies", default=False, help="list all the official, built-in policies. Combine with -v to view policy change logs")
parser.add_argument("-M", "--make-policy", action="store", dest="make_policy", metavar="custom_policy.txt", type=str, default=None, help="creates a policy based on the target server (i.e.: the target server has the ideal configuration that other servers should adhere to), and stores it in the file path specified")
parser.add_argument("-m", "--manual", action="store_true", dest="manual", default=False, help="print the man page (Docker, PyPI, Snap, and Windows builds only)")
parser.add_argument("-n", "--no-colors", action="store_true", dest="no_colors", default=False, help="disable colors (automatic when the NO_COLOR environment variable is set)")
parser.add_argument("-P", "--policy", action="store", dest="policy", metavar="\"Built-In Policy Name\" / custom_policy.txt", type=str, default=None, help="run a policy test using the specified policy (use -L to see built-in policies, or specify filesystem path to custom policy created by -M)")
parser.add_argument("-p", "--port", action="store", dest="oport", metavar="N", type=int, default=None, help="the TCP port to connect to (or to listen on when -c is used)")
parser.add_argument("-T", "--targets", action="store", dest="targets", metavar="targets.txt", type=str, default=None, help="a file containing a list of target hosts (one per line, format HOST[:PORT]). Use -p/--port to set the default port for all hosts. Use --threads to control concurrent scans")
parser.add_argument("-t", "--timeout", action="store", dest="timeout", metavar="N", type=int, default=5, help="timeout (in seconds) for connection and reading (default: %(default)s)")
parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False, help="enable verbose output")
# Add long options to the parser
parser.add_argument("--conn-rate-test", action="store", dest="conn_rate_test", metavar="N[:max_rate]", type=str, default=None, help="perform a connection rate test (useful for collecting metrics related to susceptibility of the DHEat vuln). Testing is conducted with N concurrent sockets with an optional maximum rate of connections per second")
parser.add_argument("--dheat", action="store", dest="dheat", metavar="N[:kex[:e_len]]", type=str, default=None, help="continuously perform the DHEat DoS attack (CVE-2002-20001) against the target using N concurrent sockets. Optionally, a specific key exchange algorithm can be specified instead of allowing it to be automatically chosen. Additionally, a small length of the fake e value sent to the server can be chosen for a more efficient attack (such as 4).")
parser.add_argument("--lookup", action="store", dest="lookup", metavar="alg1[,alg2,...]", type=str, default=None, help="looks up an algorithm(s) without connecting to a server.")
parser.add_argument("--skip-rate-test", action="store_true", dest="skip_rate_test", default=False, help="skip the connection rate test during standard audits (used to safely infer whether the DHEat attack is viable)")
parser.add_argument("--threads", action="store", dest="threads", metavar="N", type=int, default=32, help="number of threads to use when scanning multiple targets (-T/--targets) (default: %(default)s)")
# Print Suggested Configurations from : https://www.ssh-audit.com/hardening_guides.html
parser.add_argument("--print-config", nargs="*", action="append", metavar="OS Ver Client/Server", dest="print_configuration", type=str, default=None, help="print suggested server or client configurations. Usage Example : Ubuntu 2404 Server")
# The mandatory target option. Or rather, mandatory when -L, -T, --lookup or --print-config are not used.
parser.add_argument("host", nargs="?", action="store", type=str, default="", help="target hostname or IPv4/IPv6 address")
# If no arguments were given, print the help and exit.
if len(args) < 1:
parser.print_help()
sys.exit(exitcodes.UNKNOWN_ERROR)
oport: Optional[int] = None
try:
argument = parser.parse_args(args=args)
if argument.print_configuration is not None:
print_conf = (getattr(argument, 'print_configuration'))[0]
if len(print_conf) <= 2:
print_conf = "OS Version Edition"
print_conf = print_conf.split(" ")
os_type = print_conf[0]
os_ver = print_conf[1]
clientserver = print_conf[2]
else:
print_conf = (getattr(argument, 'print_configuration'))[0]
os_type = print_conf[0]
os_ver = print_conf[1]
clientserver = print_conf[2]
PrintConfig(os_type, os_ver, clientserver)
# Set simple flags.
aconf.client_audit = argument.client_audit
aconf.ipv4 = argument.ipv4
aconf.ipv6 = argument.ipv6
aconf.level = argument.level
aconf.list_policies = argument.list_policies
aconf.manual = argument.manual
aconf.skip_rate_test = argument.skip_rate_test
aconf.ssh1 = argument.ssh1
aconf.ssh2 = argument.ssh2
oport = argument.oport
if argument.batch is True:
aconf.batch = True
aconf.verbose = True
elif o in ('-c', '--client-audit'):
aconf.client_audit = True
elif o in ('-j', '--json'):
if aconf.json: # If specified twice, enable indent printing.
aconf.json_print_indent = True
else:
aconf.json = True
elif o in ('-v', '--verbose'):
aconf.verbose = True
out.verbose = True
elif o in ('-l', '--level'):
if a not in ('info', 'warn', 'fail'):
usage_cb(out, 'level {} is not valid'.format(a))
aconf.level = a
elif o in ('-t', '--timeout'):
aconf.timeout = float(a)
aconf.timeout_set = True
elif o in ('-M', '--make-policy'):
aconf.make_policy = True
aconf.policy_file = a
elif o in ('-P', '--policy'):
aconf.policy_file = a
elif o in ('-T', '--targets'):
aconf.target_file = a
# If we're on Windows, and we can't use the idna workaround, force only one thread to be used (otherwise a crash would occur).
# if no_idna_workaround:
# print("\nWARNING: the idna module was not found on this system, thus only single-threaded scanning will be done (this is a workaround for this Windows-specific crash: https://github.com/python/cpython/issues/73474). Multi-threaded scanning can be enabled by installing the idna module (pip install idna).\n")
# aconf.threads = 1
elif o == '--threads':
aconf.threads = int(a)
# if no_idna_workaround:
# aconf.threads = 1
elif o in ('-L', '--list-policies'):
aconf.list_policies = True
elif o == '--lookup':
aconf.lookup = a
elif o in ('-m', '--manual'):
aconf.manual = True
elif o in ('-d', '--debug'):
# If one -j was given, turn on JSON output. If -jj was given, enable indentation.
aconf.json = argument.json > 0
if argument.json > 1:
aconf.json_print_indent = True
if argument.conn_rate_test is not None:
aconf.conn_rate_test = argument.conn_rate_test
if argument.debug is True:
aconf.debug = True
out.debug = True
elif o in ('-g', '--gex-test'):
if argument.dheat is not None:
aconf.dheat = argument.dheat
if argument.gex_test is not None:
dh_gex = argument.gex_test
permitted_syntax = get_permitted_syntax_for_gex_test()
if not any(re.search(regex_str, a) for regex_str in permitted_syntax.values()):
usage_cb(out, '{} {} is not valid'.format(o, a))
if not any(re.search(regex_str, dh_gex) for regex_str in permitted_syntax.values()):
out.fail('{} is not valid'.format(dh_gex), write_now=True)
sys.exit(exitcodes.UNKNOWN_ERROR)
if re.search(permitted_syntax['RANGE'], a):
extracted_digits = re.findall(r'\d+', a)
if re.search(permitted_syntax['RANGE'], dh_gex):
extracted_digits = re.findall(r'\d+', dh_gex)
bits_left_bound = int(extracted_digits[0])
bits_right_bound = int(extracted_digits[1])
@@ -920,27 +898,52 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
bits_step = int(extracted_digits[2])
if bits_step <= 0:
usage_cb(out, '{} {} is not valid'.format(o, bits_step))
out.fail('the step field cannot be 0 or less: {}'.format(bits_step), write_now=True)
sys.exit(exitcodes.UNKNOWN_ERROR)
if all(x < 0 for x in (bits_left_bound, bits_right_bound)):
usage_cb(out, '{} {} {} is not valid'.format(o, bits_left_bound, bits_right_bound))
out.fail('{} {} {} is not valid'.format(dh_gex, bits_left_bound, bits_right_bound), write_now=True)
sys.exit(exitcodes.UNKNOWN_ERROR)
aconf.gex_test = a
elif o == '--dheat':
aconf.dheat = a
elif o == '--skip-rate-test':
aconf.skip_rate_test = True
elif o == '--conn-rate-test':
aconf.conn_rate_test = a
aconf.gex_test = dh_gex
if argument.lookup is not None:
aconf.lookup = argument.lookup
if len(args) == 0 and aconf.client_audit is False and aconf.target_file is None and aconf.list_policies is False and aconf.lookup == '' and aconf.manual is False:
usage_cb(out)
if argument.make_policy is not None:
aconf.make_policy = True
aconf.policy_file = argument.make_policy
if argument.policy is not None:
aconf.policy_file = argument.policy
if argument.targets is not None:
aconf.target_file = argument.targets
if argument.threads is not None:
aconf.threads = argument.threads
if argument.timeout is not None:
aconf.timeout = float(argument.timeout)
aconf.timeout_set = True
if argument.verbose is True:
aconf.verbose = True
out.verbose = True
except argparse.ArgumentError as err:
out.fail(str(err), write_now=True)
parser.print_help()
sys.exit(exitcodes.UNKNOWN_ERROR)
if argument.host == "" and argument.client_audit is False and argument.targets is None and argument.list_policies is False and argument.lookup is None and argument.manual is False and argument.print_configuration is None:
out.fail("target host must be specified, unless -c, -m, -L, -T, --lookup or --print-configuration are used", write_now=True)
sys.exit(exitcodes.UNKNOWN_ERROR)
if aconf.manual:
return aconf
if aconf.lookup != '':
if aconf.lookup != "":
return aconf
if aconf.list_policies:
@@ -949,25 +952,26 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
if aconf.client_audit is False and aconf.target_file is None:
if oport is not None:
host = args[0]
host = argument.host
else:
host, port = Utils.parse_host_and_port(args[0])
if not host and aconf.target_file is None:
usage_cb(out, 'host is empty')
host, port = Utils.parse_host_and_port(argument.host)
if port == 0 and oport is None:
if aconf.client_audit: # The default port to listen on during a client audit is 2222.
if not host and aconf.target_file is None:
out.fail("target host is not specified", write_now=True)
sys.exit(exitcodes.UNKNOWN_ERROR)
if oport is None and aconf.client_audit: # The default port to listen on during a client audit is 2222.
port = 2222
else:
port = 22
if oport is not None:
port = Utils.parse_int(oport)
if port <= 0 or port > 65535:
usage_cb(out, 'port {} is not valid'.format(oport))
if port < 1 or port > 65535:
out.fail("port must be greater than 0 and less than 65535: {}".format(oport), write_now=True)
sys.exit(exitcodes.UNKNOWN_ERROR)
aconf.host = host
aconf.port = port
if not (aconf.ssh1 or aconf.ssh2):
aconf.ssh1, aconf.ssh2 = True, True
@@ -996,20 +1000,17 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
try:
aconf.policy = Policy(policy_file=aconf.policy_file, json_output=aconf.json)
except Exception as e:
out.fail("Error while loading policy file: %s: %s" % (str(e), traceback.format_exc()))
out.write()
out.fail("Error while loading policy file: %s: %s" % (str(e), traceback.format_exc()), write_now=True)
sys.exit(exitcodes.UNKNOWN_ERROR)
# If the user wants to do a client audit, but provided a server policy, terminate.
if aconf.client_audit and aconf.policy.is_server_policy():
out.fail("Error: client audit selected, but server policy provided.")
out.write()
out.fail("Error: client audit selected, but server policy provided.", write_now=True)
sys.exit(exitcodes.UNKNOWN_ERROR)
# If the user wants to do a server audit, but provided a client policy, terminate.
if aconf.client_audit is False and aconf.policy.is_server_policy() is False:
out.fail("Error: server audit selected, but client policy provided.")
out.write()
out.fail("Error: server audit selected, but client policy provided.", write_now=True)
sys.exit(exitcodes.UNKNOWN_ERROR)
return aconf
@@ -1499,7 +1500,7 @@ def run_gex_granular_modulus_size_test(out: OutputBuffer, s: 'SSH_Socket', kex:
def main() -> int:
out = OutputBuffer()
aconf = process_commandline(out, sys.argv[1:], usage)
aconf = process_commandline(out, sys.argv[1:])
# If we're on Windows, but the colorama module could not be imported, print a warning if we're in verbose mode.
if (sys.platform == 'win32') and ('colorama' not in sys.modules):
+1 -1
View File
@@ -129,7 +129,7 @@ class Utils:
return -1.0
@staticmethod
def parse_host_and_port(host_and_port: str, default_port: int = 0) -> Tuple[str, int]:
def parse_host_and_port(host_and_port: str, default_port: int = 22) -> Tuple[str, int]:
'''Parses a string into a tuple of its host and port. The port is 0 if not specified.'''
host = host_and_port
port = default_port
+1 -2
View File
@@ -8,7 +8,6 @@ class TestAuditConf:
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
@staticmethod
@@ -107,7 +106,7 @@ class TestAuditConf:
def test_audit_conf_process_commandline(self):
# pylint: disable=too-many-statements
c = lambda x: self.process_commandline(self.OutputBuffer, x.split(), self.usage) # noqa
c = lambda x: self.process_commandline(self.OutputBuffer, x.split()) # noqa
with pytest.raises(SystemExit):
conf = c('')
with pytest.raises(SystemExit):
+38
View File
@@ -0,0 +1,38 @@
import pytest
from ssh_audit.ssh_audit import process_commandline
# pylint: disable=attribute-defined-outside-init
class TestAuditConf:
@pytest.fixture(autouse=True)
def init(self, ssh_audit):
self.OutputBuffer = ssh_audit.OutputBuffer()
self.process_commandline = process_commandline
@staticmethod
def _test_conf(conf, **kwargs):
options = {
'print_config': ''
}
for k, v in kwargs.items():
options[k] = v
assert conf.print_config == options['print_config']
def test_printconfig_conf_process_commandline(self):
# pylint: disable=too-many-statements
c = lambda x: self.process_commandline(self.OutputBuffer, x.split()) # noqa
with pytest.raises(SystemExit):
conf = c('')
with pytest.raises(SystemExit):
conf = c('--print-config')
self._test_conf(conf)
for vendor in ["Amazon", "Debian", "Rocky", "Mint", "Ubuntu", "NoOS"]:
vendor = vendor
for os_ver in ["2404", "2204", "2004", "1804", "2023", "22", "21", "20", "9", "Bookworm", "Bullseye", "NoVersion"]:
os_ver = os_ver
for cs_type in ["Client", "Server", "Mistake"]:
cs_type = cs_type
with pytest.raises(SystemExit):
conf = c(f'--print-config {vendor} {os_ver} {cs_type}')
self._test_conf(conf)