From 9814d18bafc87ce6a57c6a39de2893fb3257d4cd Mon Sep 17 00:00:00 2001 From: OAM7575 Date: Sun, 24 Nov 2024 11:24:07 +1100 Subject: [PATCH 1/5] 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 --- src/ssh_audit/globals.py | 3 + src/ssh_audit/printconfig.py | 375 +++++++++++++++++++++++++++++++++++ src/ssh_audit/ssh_audit.py | 27 ++- test/test_printconfig.py | 38 ++++ 4 files changed, 440 insertions(+), 3 deletions(-) create mode 100644 src/ssh_audit/printconfig.py create mode 100644 test/test_printconfig.py diff --git a/src/ssh_audit/globals.py b/src/ssh_audit/globals.py index 5dc8fe58..592ba9f2 100644 --- a/src/ssh_audit/globals.py +++ b/src/ssh_audit/globals.py @@ -38,3 +38,6 @@ # 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" diff --git a/src/ssh_audit/printconfig.py b/src/ssh_audit/printconfig.py new file mode 100644 index 00000000..36a3944d --- /dev/null +++ b/src/ssh_audit/printconfig.py @@ -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(" ") diff --git a/src/ssh_audit/ssh_audit.py b/src/ssh_audit/ssh_audit.py index 0837a91b..e848fa1d 100755 --- a/src/ssh_audit/ssh_audit.py +++ b/src/ssh_audit/ssh_audit.py @@ -53,6 +53,7 @@ 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 @@ -816,7 +817,10 @@ def process_commandline(out: OutputBuffer, args: List[str]) -> 'AuditConf': # p parser.add_argument("--skip-rate-test", action="store_true", dest="skip_rate_test", default=False, help="skip the connection rate test during standard audits (used to safely infer whether the DHEat attack is viable)") parser.add_argument("--threads", action="store", dest="threads", metavar="N", type=int, default=32, help="number of threads to use when scanning multiple targets (-T/--targets) (default: %(default)s)") - # The mandatory target option. Or rather, mandatory when -L, -T, or --lookup are not used. + # 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. @@ -828,6 +832,23 @@ def process_commandline(out: OutputBuffer, args: List[str]) -> 'AuditConf': # p 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 @@ -915,8 +936,8 @@ def process_commandline(out: OutputBuffer, args: List[str]) -> 'AuditConf': # p 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: - out.fail("target host must be specified, unless -c, -m, -L, -T, or --lookup are used", write_now=True) + 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: diff --git a/test/test_printconfig.py b/test/test_printconfig.py new file mode 100644 index 00000000..fd822935 --- /dev/null +++ b/test/test_printconfig.py @@ -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) From 48b9ee7deb7910e97a7e3ec23cfe75dd694a0d94 Mon Sep 17 00:00:00 2001 From: OAM7575 Date: Mon, 23 Dec 2024 16:11:06 +1100 Subject: [PATCH 2/5] pr307 update 1 --- .../{printconfig.py => hardeningguides.py} | 179 +++++++++++++----- src/ssh_audit/ssh_audit.py | 32 ++-- ...printconfig.py => test_hardeningguides.py} | 8 +- 3 files changed, 151 insertions(+), 68 deletions(-) rename src/ssh_audit/{printconfig.py => hardeningguides.py} (74%) rename test/{test_printconfig.py => test_hardeningguides.py} (87%) diff --git a/src/ssh_audit/printconfig.py b/src/ssh_audit/hardeningguides.py similarity index 74% rename from src/ssh_audit/printconfig.py rename to src/ssh_audit/hardeningguides.py index 36a3944d..e741d66c 100644 --- a/src/ssh_audit/printconfig.py +++ b/src/ssh_audit/hardeningguides.py @@ -2,83 +2,129 @@ from ssh_audit import exitcodes from ssh_audit.globals import VERSION -from ssh_audit.globals import GUIDES_UPDATED +from ssh_audit.globals import HARDENING_GUIDES +from typing import Any, Dict, List, Optional, Union, Tuple +from typing import Optional, Any, Union, cast -class PrintConfig: +class PrintHardeningGuides: 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() + self.BUILTIN_GUIDES: Dict[str, Dict[str]] = { + + # Server + # Amazon Server + 'Amazon 2023 Client (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', '2024-04-22': 'added connection throttling instructions to counteract the DHEat denial-of-service attack.', '2024-03-15': 'Initial revision'}, 'server_policy': False}, + 'Amazon 2023 Server (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Re-ordered host keys to prioritize ED25519 due to efficiency. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks', '2024-04-22': 'added connection throttling instructions to counteract the DHEat denial-of-service attack.', '2024-03-15': 'Initial revision'}, 'server_policy': True}, + + # Debian Server + 'Debian Bullseye Server (version 1)': {'version': '1', 'changelog': {'2021-09-17': 'Initial Revision.'}, 'server_policy': True}, + 'Debian Bookworm Server (version 1)': {'version': '1', 'changelog': {'2021-09-17': 'Initial Revision.'}, 'server_policy': True}, + + # Rocky Linux + 'Rocky 9 Server (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Re-ordered host keys to prioritize ED25519 due to efficiency. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks', '\n2024-04-24': 'Added connection throttling instructions to counteract the DHEat denial-of-service attack.'}, 'server_policy': True}, + + # Ubuntu Server + 'Ubuntu 2004 Server (version 1)': {'version': '1', 'changelog': {'2024-04-24': '\nAdded connection throttling instructions to counteract the DHEat denial-of-service attack.'}, 'server_policy': True}, + 'Ubuntu 2204 Server (version 1)': {'version': '1', 'changelog': {'2024-10-01': '\nRe-ordered host keys to prioritize ED25519 due to efficiency. \nRe-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks', '\n2024-04-22': '\nAdded connection throttling instructions to counteract the DHEat denial-of-service attack.'}, 'server_policy': True}, + 'Ubuntu 2404 Server (version 1)': {'version': '1', 'changelog': {'2024-10-01': '\nAdded Required RSASize directive to enforce a minimum of 3072-bit user and host-based authentication keys.', '\n2024-04-29': '\nInitial revision. In comparison to Ubuntu 22.04 LTS guide, the following changes were made: \n1.) For key exchanges, diffie-hellman-group18-sha512 and diffie-hellman-group-exchange-sha256 were prioritized over diffie-hellman-group16-sha512 due to greater security strength; GSS algorithms were prioritized over their non-GSS equivalents in order to match the client guide, \n2.) For ciphers, 256-bit AES ciphers were prioritized over 192 and 128-bit AES ciphers due to their increased resistence against quantum computing attacks (previously, weaker GCM ciphers had priority over CTR ciphers), \n3.) The HostbasedAcceptedAlgorithms and PubkeyAcceptedAlgorithms settings are now the same as HostKeyAlgorithms setting, \n4.) The hmac-sha2-512-etm@openssh.com MAC was increased in priority due to its increased resistence against quantum computing attacks, and \n5.) The ED25519 host keys were given priority over RSA host keys due to their greater efficiency.'}, 'server_policy': True}, + + # Client + # Amazon + 'Amazon 2023 Client (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', '2024-04-22': 'added connection throttling instructions to counteract the DHEat denial-of-service attack.', '2024-03-15': 'Initial revision'}, 'server_policy': False}, + + # Debian + 'Debian Bookworm Client (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Added RequiredRSASize directive to enforce a minimum of 3072-bit user and host-based authentication keys. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', '2024-03-15': 'Initial Revision'}, 'server_policy': False}, + + # Rocky Linux + 'Rocky 9 Client (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Added RequiredRSASize directive to enforce a minimum of 3072-bit user and host-based authentication keys. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', '2024-03-15': 'Initial Revision'}, 'server_policy': False}, + + # Mint + 'Mint 20 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, + 'Mint 21 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, + 'Mint 22 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, + + # Ubuntu + 'Ubuntu 2004 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, + 'Ubuntu 2204 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, + 'Ubuntu 2404 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, + + + } + + self.get_config() + + def get_config(self) -> None: - def Get_Config(self) -> None: retval = exitcodes.GOOD os_type = self.os_type os_ver = self.os_ver clientserver = self.clientserver + BUILTIN_GUIDES = self.BUILTIN_GUIDES + policy_name = os_type + " " + os_ver + " " + 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) + PrintHardeningGuides.unknown_variant(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() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.server_modern_common() + PrintHardeningGuides.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() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.server_modern_common() + PrintHardeningGuides.bookworm_server() + PrintHardeningGuides.debian_ubuntu_rate_throttling() sys.exit(retval) elif os_type in ["Debian"] and os_ver in ["Bullseye"]: - PrintConfig.server_modern_common() - PrintConfig.bullseye_server() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.server_modern_common() + PrintHardeningGuides.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() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.server_modern_common() + PrintHardeningGuides.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() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.server_modern_common() + PrintHardeningGuides.ubuntu_server_2404() + PrintHardeningGuides.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() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.server_modern_common() + PrintHardeningGuides.ubuntu_server_2204() + PrintHardeningGuides.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() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.server_modern_common() + PrintHardeningGuides.ubuntu_server_2004() + PrintHardeningGuides.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() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.server_legacy_common() + PrintHardeningGuides.ubuntu_server_1804() sys.exit(retval) else: - PrintConfig.unknown_varient(os_type, os_ver, clientserver) + PrintHardeningGuides.unknown_variant(os_type, os_ver, clientserver) sys.exit(retval) @@ -86,48 +132,58 @@ def Get_Config(self) -> None: if clientserver in ["Client"]: # Amazon if os_type in ["Amazon"] and os_ver in ["2023"]: - PrintConfig.amazon_2023_client() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.amazon_2023_client() sys.exit(retval) # Debian elif os_type in ["Debian"] and os_ver in ["Bookworm"]: - PrintConfig.debian_bookworm_client() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.debian_bookworm_client() sys.exit(retval) # Mint elif os_type in ["Mint"] and os_ver in ["22"]: - PrintConfig.ubuntu_2404_mint_22_client() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.ubuntu_2404_mint_22_client() sys.exit(retval) elif os_type in ["Mint"] and os_ver in ["21"]: - PrintConfig.ubuntu_2204_mint_21_client() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.ubuntu_2204_mint_21_client() sys.exit(retval) elif os_type in ["Mint"] and os_ver in ["20"]: - PrintConfig.ubuntu_2004_mint_20_client() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.ubuntu_2004_mint_20_client() sys.exit(retval) # Rocky elif os_type in ["Rocky"] and os_ver in ["9"]: - PrintConfig.rocky_9_client() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.rocky_9_client() sys.exit(retval) # Ubuntu elif os_type in ["Ubuntu"] and os_ver in ["2404"]: - PrintConfig.ubuntu_2404_mint_22_client() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.ubuntu_2404_mint_22_client() sys.exit(retval) elif os_type in ["Ubuntu"] and os_ver in ["2204"]: - PrintConfig.ubuntu_2204_mint_21_client() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.ubuntu_2204_mint_21_client() sys.exit(retval) elif os_type in ["Ubuntu"] and os_ver in ["2004"]: - PrintConfig.ubuntu_2004_mint_20_client() + PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.ubuntu_2004_mint_20_client() sys.exit(retval) else: - PrintConfig.unknown_varient(os_type, os_ver, clientserver) + PrintHardeningGuides.unknown_variant(os_type, os_ver, clientserver) sys.exit(retval) @staticmethod - def unknown_varient(os_type: str, os_ver: str, clientserver: str) -> None: + def unknown_variant(os_type: str, os_ver: str, clientserver: str) -> None: print(" ") - print(f"\033[1mSSH-Audit Version : {VERSION}\033[0m") + print(f"\033[1mssh-audit Version : {VERSION}\033[0m") print(" ") - print(f"\033[1mGuides Last modified : {GUIDES_UPDATED}\033[0m") + print(f"\033[1mGuides Last modified : {HARDENING_GUIDES}\033[0m") print(" ") print(f"\033[1mError unknown varient : {os_type} {os_ver} {clientserver} \033[0m") print(" ") @@ -153,6 +209,10 @@ def unknown_varient(os_type: str, os_ver: str, clientserver: str) -> None: print(r"Ubuntu 2404 Client") print(r"Ubuntu 2204 Client") print(r"Ubuntu 2004 Client") + print(" ") + print("\033[1mExample Usage : \033[0m ") + print(r"python3 ssh-audit.py --get-hardening-guides Ubuntu 2404 Server") + print(" ") # Client Configurations @@ -373,3 +433,26 @@ def amazon_server_2023() -> None: print("systemctl start iptables") print("systemctl start ip6tables") print(" ") + + @staticmethod + def print_ver_changelog(BUILTIN_GUIDES, policy_name: str) -> None: + '''Returns a Policy with the specified built-in policy name loaded, or None if no policy of that name exists.''' + + for key_name, policy in BUILTIN_GUIDES.items(): + if policy_name in key_name: + + policy_struct = BUILTIN_GUIDES[key_name] + policy_name_without_version = policy_name.split('(')[0] + name = policy_name_without_version # pylint: disable=protected-access + + version = cast(str, policy_struct['version']) # pylint: disable=protected-access + changelog_struct = policy_struct['changelog'] # pylint: disable=protected-access + print(" ") + print(f"\033[1mssh-audit Version : {VERSION}\033[0m") + print(" ") + print(f"\033[1mLocating configuration for {name}\033[0m") + print(" ") + print(f"\033[1mChange Log :\033[0m") + for date, change in changelog_struct.items(): + print(f"\033[1m{date} : {change}\033[0m") + print(" ") \ No newline at end of file diff --git a/src/ssh_audit/ssh_audit.py b/src/ssh_audit/ssh_audit.py index e848fa1d..56e6136c 100755 --- a/src/ssh_audit/ssh_audit.py +++ b/src/ssh_audit/ssh_audit.py @@ -53,7 +53,7 @@ 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.hardeningguides import PrintHardeningGuides from ssh_audit.product import Product from ssh_audit.protocol import Protocol from ssh_audit.software import Software @@ -818,7 +818,7 @@ def process_commandline(out: OutputBuffer, args: List[str]) -> 'AuditConf': # p 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") + 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") # 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") @@ -832,21 +832,21 @@ def process_commandline(out: OutputBuffer, args: List[str]) -> 'AuditConf': # p 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] + if argument.get_hardening_guides is not None: + print_guides = (getattr(argument, 'get_hardening_guides'))[0] + if len(print_guides) <= 2: + print_guides = "OS Version Edition" + print_guides = print_guides.split(" ") + os_type = print_guides[0] + os_ver = print_guides[1] + clientserver = print_guides[2] else: - print_conf = (getattr(argument, 'print_configuration'))[0] - os_type = print_conf[0] - os_ver = print_conf[1] - clientserver = print_conf[2] + print_guides = (getattr(argument, 'get_hardening_guides'))[0] + os_type = print_guides[0] + os_ver = print_guides[1] + clientserver = print_guides[2] - PrintConfig(os_type, os_ver, clientserver) + PrintHardeningGuides(os_type, os_ver, clientserver) # Set simple flags. @@ -936,7 +936,7 @@ def process_commandline(out: OutputBuffer, args: List[str]) -> 'AuditConf': # p 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: + 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: 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) diff --git a/test/test_printconfig.py b/test/test_hardeningguides.py similarity index 87% rename from test/test_printconfig.py rename to test/test_hardeningguides.py index fd822935..aa420491 100644 --- a/test/test_printconfig.py +++ b/test/test_hardeningguides.py @@ -3,7 +3,7 @@ # pylint: disable=attribute-defined-outside-init -class TestAuditConf: +class TestHardeningGuides: @pytest.fixture(autouse=True) def init(self, ssh_audit): self.OutputBuffer = ssh_audit.OutputBuffer() @@ -12,11 +12,11 @@ def init(self, ssh_audit): @staticmethod def _test_conf(conf, **kwargs): options = { - 'print_config': '' + 'get_hardening_guides': '' } for k, v in kwargs.items(): options[k] = v - assert conf.print_config == options['print_config'] + assert conf.get_hardening_guides == options['get_hardening_guides'] def test_printconfig_conf_process_commandline(self): # pylint: disable=too-many-statements @@ -24,7 +24,7 @@ def test_printconfig_conf_process_commandline(self): with pytest.raises(SystemExit): conf = c('') with pytest.raises(SystemExit): - conf = c('--print-config') + conf = c('--get-hardening-guides') self._test_conf(conf) for vendor in ["Amazon", "Debian", "Rocky", "Mint", "Ubuntu", "NoOS"]: From 231a47959ab16724573b03dedcb8093d91cb19e4 Mon Sep 17 00:00:00 2001 From: OAM7575 Date: Mon, 23 Dec 2024 17:43:37 +1100 Subject: [PATCH 3/5] pr307 update 2 --- src/ssh_audit/globals.py | 3 - src/ssh_audit/hardeningguides.py | 167 +++++++++++++++++-------------- src/ssh_audit/ssh_audit.py | 19 ++-- test/test_hardeningguides.py | 13 ++- 4 files changed, 113 insertions(+), 89 deletions(-) diff --git a/src/ssh_audit/globals.py b/src/ssh_audit/globals.py index 592ba9f2..5dc8fe58 100644 --- a/src/ssh_audit/globals.py +++ b/src/ssh_audit/globals.py @@ -38,6 +38,3 @@ # 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" diff --git a/src/ssh_audit/hardeningguides.py b/src/ssh_audit/hardeningguides.py index e741d66c..a6dc1f41 100644 --- a/src/ssh_audit/hardeningguides.py +++ b/src/ssh_audit/hardeningguides.py @@ -1,59 +1,80 @@ +""" + The MIT License (MIT) + + Copyright (C) 2020-2024 Joe Testa (jtesta@positronsecurity.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +""" +from typing import Dict, Any import sys from ssh_audit import exitcodes from ssh_audit.globals import VERSION -from ssh_audit.globals import HARDENING_GUIDES -from typing import Any, Dict, List, Optional, Union, Tuple -from typing import Optional, Any, Union, cast -class PrintHardeningGuides: - 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.BUILTIN_GUIDES: Dict[str, Dict[str]] = { +BUILTIN_GUIDES: Dict[str, Dict[str, Any]] = { - # Server - # Amazon Server - 'Amazon 2023 Client (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', '2024-04-22': 'added connection throttling instructions to counteract the DHEat denial-of-service attack.', '2024-03-15': 'Initial revision'}, 'server_policy': False}, - 'Amazon 2023 Server (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Re-ordered host keys to prioritize ED25519 due to efficiency. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks', '2024-04-22': 'added connection throttling instructions to counteract the DHEat denial-of-service attack.', '2024-03-15': 'Initial revision'}, 'server_policy': True}, + # Server + # Amazon Server + 'Amazon 2023 Server (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Re-ordered host keys to prioritize ED25519 due to efficiency. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks', '2024-04-22': 'added connection throttling instructions to counteract the DHEat denial-of-service attack.', '2024-03-15': 'Initial revision'}, 'server_policy': True}, - # Debian Server - 'Debian Bullseye Server (version 1)': {'version': '1', 'changelog': {'2021-09-17': 'Initial Revision.'}, 'server_policy': True}, - 'Debian Bookworm Server (version 1)': {'version': '1', 'changelog': {'2021-09-17': 'Initial Revision.'}, 'server_policy': True}, + # Debian Server + 'Debian Bullseye Server (version 1)': {'version': '1', 'changelog': {'2021-09-17': 'Initial Revision.'}, 'server_policy': True}, + 'Debian Bookworm Server (version 1)': {'version': '1', 'changelog': {'2021-09-17': 'Initial Revision.'}, 'server_policy': True}, - # Rocky Linux - 'Rocky 9 Server (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Re-ordered host keys to prioritize ED25519 due to efficiency. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks', '\n2024-04-24': 'Added connection throttling instructions to counteract the DHEat denial-of-service attack.'}, 'server_policy': True}, + # Rocky Linux + 'Rocky 9 Server (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Re-ordered host keys to prioritize ED25519 due to efficiency. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks', '\n2024-04-24': 'Added connection throttling instructions to counteract the DHEat denial-of-service attack.'}, 'server_policy': True}, - # Ubuntu Server - 'Ubuntu 2004 Server (version 1)': {'version': '1', 'changelog': {'2024-04-24': '\nAdded connection throttling instructions to counteract the DHEat denial-of-service attack.'}, 'server_policy': True}, - 'Ubuntu 2204 Server (version 1)': {'version': '1', 'changelog': {'2024-10-01': '\nRe-ordered host keys to prioritize ED25519 due to efficiency. \nRe-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks', '\n2024-04-22': '\nAdded connection throttling instructions to counteract the DHEat denial-of-service attack.'}, 'server_policy': True}, - 'Ubuntu 2404 Server (version 1)': {'version': '1', 'changelog': {'2024-10-01': '\nAdded Required RSASize directive to enforce a minimum of 3072-bit user and host-based authentication keys.', '\n2024-04-29': '\nInitial revision. In comparison to Ubuntu 22.04 LTS guide, the following changes were made: \n1.) For key exchanges, diffie-hellman-group18-sha512 and diffie-hellman-group-exchange-sha256 were prioritized over diffie-hellman-group16-sha512 due to greater security strength; GSS algorithms were prioritized over their non-GSS equivalents in order to match the client guide, \n2.) For ciphers, 256-bit AES ciphers were prioritized over 192 and 128-bit AES ciphers due to their increased resistence against quantum computing attacks (previously, weaker GCM ciphers had priority over CTR ciphers), \n3.) The HostbasedAcceptedAlgorithms and PubkeyAcceptedAlgorithms settings are now the same as HostKeyAlgorithms setting, \n4.) The hmac-sha2-512-etm@openssh.com MAC was increased in priority due to its increased resistence against quantum computing attacks, and \n5.) The ED25519 host keys were given priority over RSA host keys due to their greater efficiency.'}, 'server_policy': True}, + # Ubuntu Server + 'Ubuntu 2004 Server (version 1)': {'version': '1', 'changelog': {'2024-04-24': '\nAdded connection throttling instructions to counteract the DHEat denial-of-service attack.'}, 'server_policy': True}, + 'Ubuntu 2204 Server (version 1)': {'version': '1', 'changelog': {'2024-10-01': '\nRe-ordered host keys to prioritize ED25519 due to efficiency. \nRe-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks', '\n2024-04-22': '\nAdded connection throttling instructions to counteract the DHEat denial-of-service attack.'}, 'server_policy': True}, + 'Ubuntu 2404 Server (version 1)': {'version': '1', 'changelog': {'2024-10-01': '\nAdded Required RSASize directive to enforce a minimum of 3072-bit user and host-based authentication keys.', '\n2024-04-29': '\nInitial revision. In comparison to Ubuntu 22.04 LTS guide, the following changes were made: \n1.) For key exchanges, diffie-hellman-group18-sha512 and diffie-hellman-group-exchange-sha256 were prioritized over diffie-hellman-group16-sha512 due to greater security strength; GSS algorithms were prioritized over their non-GSS equivalents in order to match the client guide, \n2.) For ciphers, 256-bit AES ciphers were prioritized over 192 and 128-bit AES ciphers due to their increased resistence against quantum computing attacks (previously, weaker GCM ciphers had priority over CTR ciphers), \n3.) The HostbasedAcceptedAlgorithms and PubkeyAcceptedAlgorithms settings are now the same as HostKeyAlgorithms setting, \n4.) The hmac-sha2-512-etm@openssh.com MAC was increased in priority due to its increased resistence against quantum computing attacks, and \n5.) The ED25519 host keys were given priority over RSA host keys due to their greater efficiency.'}, 'server_policy': True}, - # Client - # Amazon - 'Amazon 2023 Client (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', '2024-04-22': 'added connection throttling instructions to counteract the DHEat denial-of-service attack.', '2024-03-15': 'Initial revision'}, 'server_policy': False}, + # Client + # Amazon + 'Amazon 2023 Client (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', '2024-04-22': 'added connection throttling instructions to counteract the DHEat denial-of-service attack.', '2024-03-15': 'Initial revision'}, 'server_policy': False}, - # Debian - 'Debian Bookworm Client (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Added RequiredRSASize directive to enforce a minimum of 3072-bit user and host-based authentication keys. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', '2024-03-15': 'Initial Revision'}, 'server_policy': False}, + # Debian + 'Debian Bookworm Client (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Added RequiredRSASize directive to enforce a minimum of 3072-bit user and host-based authentication keys. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', '2024-03-15': 'Initial Revision'}, 'server_policy': False}, - # Rocky Linux - 'Rocky 9 Client (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Added RequiredRSASize directive to enforce a minimum of 3072-bit user and host-based authentication keys. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', '2024-03-15': 'Initial Revision'}, 'server_policy': False}, + # Rocky Linux + 'Rocky 9 Client (version 1)': {'version': '1', 'changelog': {'2024-10-01': 'Added RequiredRSASize directive to enforce a minimum of 3072-bit user and host-based authentication keys. Re-ordered cipher list to prioritize larger key sizes as a countermeasure to quantum attacks.', '2024-03-15': 'Initial Revision'}, 'server_policy': False}, - # Mint - 'Mint 20 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, - 'Mint 21 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, - 'Mint 22 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, + # Mint + 'Mint 20 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, + 'Mint 21 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, + 'Mint 22 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, + + # Ubuntu + 'Ubuntu 2004 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, + 'Ubuntu 2204 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, + 'Ubuntu 2404 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, +} - # Ubuntu - 'Ubuntu 2004 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, - 'Ubuntu 2204 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, - 'Ubuntu 2404 Client (version 1)': {'version': '1', 'changelog': {'2020-10-20': 'Initial Revision'}, 'server_policy': False}, - } +class PrintHardeningGuides: + 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() @@ -64,67 +85,70 @@ def get_config(self) -> None: os_type = self.os_type os_ver = self.os_ver clientserver = self.clientserver - BUILTIN_GUIDES = self.BUILTIN_GUIDES policy_name = os_type + " " + os_ver + " " + 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: - PrintHardeningGuides.unknown_variant(os_type, os_ver, clientserver) + print(" ") + print(f"\033[1mssh-audit Version : {VERSION}\033[0m") + print(" ") + print(f"\033[1mConfiguration : {os_type} {os_ver} {clientserver} is not supported\033[0m") + PrintHardeningGuides.supported_varient() sys.exit(retval) # Server Configs if clientserver in ["Server"]: # Amazon Linux if os_type in ["Amazon"] and os_ver in ["2023"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.server_modern_common() PrintHardeningGuides.amazon_server_2023() sys.exit(retval) # Debian elif os_type in ["Debian"] and os_ver in ["Bookworm"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.server_modern_common() PrintHardeningGuides.bookworm_server() PrintHardeningGuides.debian_ubuntu_rate_throttling() sys.exit(retval) elif os_type in ["Debian"] and os_ver in ["Bullseye"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.server_modern_common() PrintHardeningGuides.bullseye_server() sys.exit(retval) # Rocky Linux elif os_type in ["Rocky"] and os_ver in ["9"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.server_modern_common() PrintHardeningGuides.rocky_9_server() sys.exit(retval) # Ubuntu elif os_type in ["Ubuntu"] and os_ver in ["2404"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.server_modern_common() PrintHardeningGuides.ubuntu_server_2404() PrintHardeningGuides.debian_ubuntu_rate_throttling() sys.exit(retval) elif os_type in ["Ubuntu"] and os_ver in ["2204"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.server_modern_common() PrintHardeningGuides.ubuntu_server_2204() PrintHardeningGuides.debian_ubuntu_rate_throttling() sys.exit(retval) elif os_type in ["Ubuntu"] and os_ver in ["2004"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.server_modern_common() PrintHardeningGuides.ubuntu_server_2004() PrintHardeningGuides.debian_ubuntu_rate_throttling() sys.exit(retval) elif os_type in ["Ubuntu"] and os_ver in ["1804"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.server_legacy_common() PrintHardeningGuides.ubuntu_server_1804() sys.exit(retval) else: - PrintHardeningGuides.unknown_variant(os_type, os_ver, clientserver) + PrintHardeningGuides.supported_varient() sys.exit(retval) @@ -132,65 +156,61 @@ def get_config(self) -> None: if clientserver in ["Client"]: # Amazon if os_type in ["Amazon"] and os_ver in ["2023"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.amazon_2023_client() sys.exit(retval) # Debian elif os_type in ["Debian"] and os_ver in ["Bookworm"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.debian_bookworm_client() sys.exit(retval) # Mint elif os_type in ["Mint"] and os_ver in ["22"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.ubuntu_2404_mint_22_client() sys.exit(retval) elif os_type in ["Mint"] and os_ver in ["21"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.ubuntu_2204_mint_21_client() sys.exit(retval) elif os_type in ["Mint"] and os_ver in ["20"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.ubuntu_2004_mint_20_client() sys.exit(retval) # Rocky elif os_type in ["Rocky"] and os_ver in ["9"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.rocky_9_client() sys.exit(retval) # Ubuntu elif os_type in ["Ubuntu"] and os_ver in ["2404"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.ubuntu_2404_mint_22_client() sys.exit(retval) elif os_type in ["Ubuntu"] and os_ver in ["2204"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.ubuntu_2204_mint_21_client() sys.exit(retval) elif os_type in ["Ubuntu"] and os_ver in ["2004"]: - PrintHardeningGuides.print_ver_changelog(BUILTIN_GUIDES, policy_name) + PrintHardeningGuides.print_ver_changelog(policy_name) PrintHardeningGuides.ubuntu_2004_mint_20_client() sys.exit(retval) else: - PrintHardeningGuides.unknown_variant(os_type, os_ver, clientserver) + PrintHardeningGuides.supported_varient() sys.exit(retval) @staticmethod - def unknown_variant(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 : {HARDENING_GUIDES}\033[0m") - print(" ") - print(f"\033[1mError unknown varient : {os_type} {os_ver} {clientserver} \033[0m") + def supported_varient() -> None: + retval = exitcodes.GOOD 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(" ") print(r"Amazon 2023 Server") print(r"Debian Bookworm Server") print(r"Debian Bullseye Server") @@ -213,6 +233,7 @@ def unknown_variant(os_type: str, os_ver: str, clientserver: str) -> None: print("\033[1mExample Usage : \033[0m ") print(r"python3 ssh-audit.py --get-hardening-guides Ubuntu 2404 Server") print(" ") + sys.exit(retval) # Client Configurations @@ -435,24 +456,22 @@ def amazon_server_2023() -> None: print(" ") @staticmethod - def print_ver_changelog(BUILTIN_GUIDES, policy_name: str) -> None: - '''Returns a Policy with the specified built-in policy name loaded, or None if no policy of that name exists.''' + def print_ver_changelog(policy_name: str) -> None: + '''Prints ssh-audit version and change log for a supported configuration''' for key_name, policy in BUILTIN_GUIDES.items(): if policy_name in key_name: - policy_struct = BUILTIN_GUIDES[key_name] + policy_struct = policy policy_name_without_version = policy_name.split('(')[0] name = policy_name_without_version # pylint: disable=protected-access - - version = cast(str, policy_struct['version']) # pylint: disable=protected-access changelog_struct = policy_struct['changelog'] # pylint: disable=protected-access print(" ") print(f"\033[1mssh-audit Version : {VERSION}\033[0m") print(" ") print(f"\033[1mLocating configuration for {name}\033[0m") print(" ") - print(f"\033[1mChange Log :\033[0m") + print("\033[1mChange Log :\033[0m") for date, change in changelog_struct.items(): print(f"\033[1m{date} : {change}\033[0m") - print(" ") \ No newline at end of file + print(" ") diff --git a/src/ssh_audit/ssh_audit.py b/src/ssh_audit/ssh_audit.py index 56e6136c..8ce5e66f 100755 --- a/src/ssh_audit/ssh_audit.py +++ b/src/ssh_audit/ssh_audit.py @@ -818,7 +818,8 @@ def process_commandline(out: OutputBuffer, args: List[str]) -> 'AuditConf': # p 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("--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. parser.add_argument("host", nargs="?", action="store", type=str, default="", help="target hostname or IPv4/IPv6 address") @@ -832,14 +833,18 @@ def process_commandline(out: OutputBuffer, args: List[str]) -> 'AuditConf': # p try: 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] - if len(print_guides) <= 2: - print_guides = "OS Version Edition" - print_guides = print_guides.split(" ") - os_type = print_guides[0] - os_ver = print_guides[1] - clientserver = print_guides[2] + 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] diff --git a/test/test_hardeningguides.py b/test/test_hardeningguides.py index aa420491..929b8c77 100644 --- a/test/test_hardeningguides.py +++ b/test/test_hardeningguides.py @@ -12,7 +12,7 @@ def init(self, ssh_audit): @staticmethod def _test_conf(conf, **kwargs): options = { - 'get_hardening_guides': '' + 'get_hardening_guides': '', } for k, v in kwargs.items(): options[k] = v @@ -26,13 +26,16 @@ def test_printconfig_conf_process_commandline(self): 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"]: + 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"]: + 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"]: + 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}') + conf = c(f'--get-hardening-guides {vendor} {os_ver} {cs_type}') self._test_conf(conf) From 6b8b20aebb7d20c7bc2e48557c5e64916795d759 Mon Sep 17 00:00:00 2001 From: OAM7575 Date: Mon, 23 Dec 2024 17:53:24 +1100 Subject: [PATCH 4/5] pr307 - attempt 2 From 62d41ea35f4d3e55eb668b6132f783aa64f1d0ac Mon Sep 17 00:00:00 2001 From: oam7575 Date: Mon, 23 Dec 2024 18:06:08 +1100 Subject: [PATCH 5/5] Update ssh_audit.py Missed a TAB --- src/ssh_audit/ssh_audit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ssh_audit/ssh_audit.py b/src/ssh_audit/ssh_audit.py index 8ce5e66f..adccd272 100755 --- a/src/ssh_audit/ssh_audit.py +++ b/src/ssh_audit/ssh_audit.py @@ -851,7 +851,7 @@ def process_commandline(out: OutputBuffer, args: List[str]) -> 'AuditConf': # p os_ver = print_guides[1] clientserver = print_guides[2] - PrintHardeningGuides(os_type, os_ver, clientserver) + PrintHardeningGuides(os_type, os_ver, clientserver) # Set simple flags.