mirror of
https://github.com/jtesta/ssh-audit.git
synced 2026-07-27 12:56:55 +02:00
Compare commits
6
Commits
03c8d0f66f
...
c7bf1adb0e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7bf1adb0e | ||
|
|
a4f508374a | ||
|
|
6f39407a8c | ||
|
|
cb0f6b63d7 | ||
|
|
3313046714 | ||
|
|
aab105c398 |
+12
-9
@@ -1,16 +1,19 @@
|
||||
FROM python:3-slim
|
||||
# syntax=docker/dockerfile:latest
|
||||
FROM scratch AS files
|
||||
|
||||
WORKDIR /
|
||||
# Copy ssh-audit code to temporary container
|
||||
COPY ssh-audit.py /
|
||||
COPY src/ /
|
||||
|
||||
FROM python:3-alpine AS runtime
|
||||
|
||||
# Update the image to remediate any vulnerabilities.
|
||||
RUN apt update && apt -y upgrade && apt -y dist-upgrade && rm -rf /var/lib/apt/lists/*
|
||||
RUN apk upgrade -U --no-cache -a -l && \
|
||||
# Remove suid & sgid bits from all files.
|
||||
find / -xdev -perm /6000 -exec chmod ug-s {} \; 2> /dev/null || true
|
||||
|
||||
# Remove suid & sgid bits from all files.
|
||||
RUN find / -xdev -perm /6000 -exec chmod ug-s {} \; 2> /dev/null || true
|
||||
|
||||
# Copy the ssh-audit code.
|
||||
COPY ssh-audit.py .
|
||||
COPY src/ .
|
||||
# Copy the ssh-audit code from files container.
|
||||
COPY --from=files / /
|
||||
|
||||
# Allow listening on 2222/tcp for client auditing.
|
||||
EXPOSE 2222
|
||||
|
||||
@@ -186,6 +186,8 @@ For convenience, a web front-end on top of the command-line tool is available at
|
||||
- The built-in man page (`-m`, `--manual`) is now available on Docker, PyPI, and Snap builds, in addition to the Windows build.
|
||||
- Snap builds are now architecture-independent.
|
||||
- Gracefully handle rare exceptions (i.e.: crashes) while performing GEX tests.
|
||||
- Added built-in policy for OpenSSH 9.7.
|
||||
- Changed Docker base image from `python:3-slim` to `python:3-alpine`, resulting in a 59% reduction in image size; credit [Daniel Thamdrup](https://github.com/dallemon).
|
||||
|
||||
### v3.1.0 (2023-12-20)
|
||||
- Added test for the Terrapin message prefix truncation vulnerability ([CVE-2023-48795](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-48795)).
|
||||
|
||||
@@ -94,6 +94,8 @@ class Policy:
|
||||
|
||||
'Hardened OpenSSH Server v9.6 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-s', 'kex-strict-s-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 3072}, 'server_policy': True},
|
||||
|
||||
'Hardened OpenSSH Server v9.7 (version 1)': {'version': '1', 'banner': None, 'compressions': None, 'host_keys': ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-ed25519'], 'optional_host_keys': ['sk-ssh-ed25519@openssh.com', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com'], 'kex': ['sntrup761x25519-sha512@openssh.com', 'curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-s', 'kex-strict-s-v00@openssh.com'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': {"rsa-sha2-256": {"hostkey_size": 4096}, "rsa-sha2-256-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "rsa-sha2-512": {"hostkey_size": 4096}, "rsa-sha2-512-cert-v01@openssh.com": {"ca_key_size": 4096, "ca_key_type": "ssh-rsa", "hostkey_size": 4096}, "sk-ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}, "sk-ssh-ed25519@openssh.com": {"hostkey_size": 256}, "ssh-ed25519": {"hostkey_size": 256}, "ssh-ed25519-cert-v01@openssh.com": {"ca_key_size": 256, "ca_key_type": "ssh-ed25519", "hostkey_size": 256}}, 'dh_modulus_sizes': {'diffie-hellman-group-exchange-sha256': 3072}, 'server_policy': True},
|
||||
|
||||
|
||||
# Ubuntu Client policies
|
||||
|
||||
@@ -419,11 +421,11 @@ macs = %s
|
||||
hostkey_types = list(self._hostkey_sizes.keys())
|
||||
hostkey_types.sort() # Sorted to make testing output repeatable.
|
||||
for hostkey_type in hostkey_types:
|
||||
expected_hostkey_size = self._hostkey_sizes[hostkey_type]['hostkey_size']
|
||||
expected_hostkey_size = cast(int, self._hostkey_sizes[hostkey_type]['hostkey_size'])
|
||||
server_host_keys = kex.host_keys()
|
||||
if hostkey_type in server_host_keys:
|
||||
actual_hostkey_size = server_host_keys[hostkey_type]['hostkey_size']
|
||||
if actual_hostkey_size != expected_hostkey_size:
|
||||
actual_hostkey_size = cast(int, server_host_keys[hostkey_type]['hostkey_size'])
|
||||
if actual_hostkey_size < expected_hostkey_size:
|
||||
ret = False
|
||||
self._append_error(errors, 'Host key (%s) sizes' % hostkey_type, [str(expected_hostkey_size)], None, [str(actual_hostkey_size)])
|
||||
|
||||
@@ -439,7 +441,7 @@ macs = %s
|
||||
ret = False
|
||||
self._append_error(errors, 'CA signature type', [expected_ca_key_type], None, [actual_ca_key_type])
|
||||
# Ensure that the actual and expected signature sizes match.
|
||||
elif actual_ca_key_size != expected_ca_key_size:
|
||||
elif actual_ca_key_size < expected_ca_key_size:
|
||||
ret = False
|
||||
self._append_error(errors, 'CA signature size (%s)' % actual_ca_key_type, [str(expected_ca_key_size)], None, [str(actual_ca_key_size)])
|
||||
|
||||
@@ -462,7 +464,7 @@ macs = %s
|
||||
expected_dh_modulus_size = self._dh_modulus_sizes[dh_modulus_type]
|
||||
if dh_modulus_type in kex.dh_modulus_sizes():
|
||||
actual_dh_modulus_size = kex.dh_modulus_sizes()[dh_modulus_type]
|
||||
if expected_dh_modulus_size != actual_dh_modulus_size:
|
||||
if expected_dh_modulus_size > actual_dh_modulus_size:
|
||||
ret = False
|
||||
self._append_error(errors, 'Group exchange (%s) modulus sizes' % dh_modulus_type, [str(expected_dh_modulus_size)], None, [str(actual_dh_modulus_size)])
|
||||
|
||||
|
||||
@@ -365,11 +365,8 @@ def output_recommendations(out: OutputBuffer, algs: Algorithms, algorithm_recomm
|
||||
for cve_list in VersionVulnerabilityDB.CVE['PuTTY']:
|
||||
vuln_version = float(cve_list[1])
|
||||
cvssv2_severity = cve_list[4]
|
||||
|
||||
if vuln_version > max_vuln_version:
|
||||
max_vuln_version = vuln_version
|
||||
if cvssv2_severity > max_cvssv2_severity:
|
||||
max_cvssv2_severity = cvssv2_severity
|
||||
max_vuln_version = max(vuln_version, max_vuln_version)
|
||||
max_cvssv2_severity = max(cvssv2_severity, max_cvssv2_severity)
|
||||
|
||||
fn = out.warn
|
||||
if max_cvssv2_severity > 8.0:
|
||||
|
||||
@@ -246,8 +246,7 @@ class SSH_Socket(ReadBuf, WriteBuf):
|
||||
|
||||
def send_banner(self, banner: str) -> None:
|
||||
self.send(banner.encode() + b'\r\n')
|
||||
if self.__state < self.SM_BANNER_SENT:
|
||||
self.__state = self.SM_BANNER_SENT
|
||||
self.__state = max(self.__state, self.SM_BANNER_SENT)
|
||||
|
||||
def ensure_read(self, size: int) -> None:
|
||||
while self.unread_len < size:
|
||||
|
||||
Reference in New Issue
Block a user