Transformed comment type annotations to variable declaration annotations.

This commit is contained in:
Joe Testa 2021-01-21 10:20:48 -05:00
parent 4e2f9da632
commit 60de5e55cb
17 changed files with 67 additions and 66 deletions

View File

@ -161,6 +161,7 @@ For convenience, a web front-end on top of the command-line tool is available at
- Added version check for OpenSSH user enumeration (CVE-2018-15473). - Added version check for OpenSSH user enumeration (CVE-2018-15473).
- Fixed crash when receiving unexpected response during host key test. - Fixed crash when receiving unexpected response during host key test.
- Fixed hang against older Cisco devices during host key test & gex test. - Fixed hang against older Cisco devices during host key test & gex test.
- Dropped support for Python 3.5 (which reached EOL in Sept. 2020).
### v2.3.1 (2020-10-28) ### v2.3.1 (2020-10-28)
- Now parses public key sizes for `rsa-sha2-256-cert-v01@openssh.com` and `rsa-sha2-512-cert-v01@openssh.com` host key types. - Now parses public key sizes for `rsa-sha2-256-cert-v01@openssh.com` and `rsa-sha2-512-cert-v01@openssh.com` host key types.

View File

@ -131,7 +131,7 @@ class Algorithms:
# if version is not None: # if version is not None:
# software = SSH.Software(None, product, version, None, None) # software = SSH.Software(None, product, version, None, None)
# break # break
rec = {} # type: Dict[int, Dict[str, Dict[str, Dict[str, int]]]] rec: Dict[int, Dict[str, Dict[str, Dict[str, int]]]] = {}
if software is None: if software is None:
unknown_software = True unknown_software = True
for alg_pair in self.values: for alg_pair in self.values:
@ -206,7 +206,7 @@ class Algorithms:
def __init__(self, sshv: int, db: Dict[str, Dict[str, List[List[Optional[str]]]]]) -> None: def __init__(self, sshv: int, db: Dict[str, Dict[str, List[List[Optional[str]]]]]) -> None:
self.__sshv = sshv self.__sshv = sshv
self.__db = db self.__db = db
self.__storage = {} # type: Dict[str, List[str]] self.__storage: Dict[str, List[str]] = {}
@property @property
def sshv(self) -> int: def sshv(self) -> int:

View File

@ -43,16 +43,16 @@ class AuditConf:
self.json = False self.json = False
self.verbose = False self.verbose = False
self.level = 'info' self.level = 'info'
self.ipvo = () # type: Sequence[int] self.ipvo: Sequence[int] = ()
self.ipv4 = False self.ipv4 = False
self.ipv6 = False self.ipv6 = False
self.make_policy = False # When True, creates a policy file from an audit scan. self.make_policy = False # When True, creates a policy file from an audit scan.
self.policy_file = None # type: Optional[str] # File system path to a policy self.policy_file: Optional[str] = None # File system path to a policy
self.policy = None # type: Optional[Policy] # Policy object self.policy: Optional[Policy] = None # Policy object
self.timeout = 5.0 self.timeout = 5.0
self.timeout_set = False # Set to True when the user explicitly sets it. self.timeout_set = False # Set to True when the user explicitly sets it.
self.target_file = None # type: Optional[str] self.target_file: Optional[str] = None
self.target_list = [] # type: List[str] self.target_list: List[str] = []
self.list_policies = False self.list_policies = False
self.lookup = '' self.lookup = ''

View File

@ -46,8 +46,8 @@ class KexDH: # pragma: nocover
self.__e = 0 self.__e = 0
self.set_params(g, p) self.set_params(g, p)
self.__ed25519_pubkey = None # type: Optional[bytes] self.__ed25519_pubkey: Optional[bytes] = None
self.__hostkey_type = None # type: Optional[bytes] self.__hostkey_type: Optional[bytes] = None
self.__hostkey_e = 0 self.__hostkey_e = 0
self.__hostkey_n = 0 self.__hostkey_n = 0
self.__hostkey_n_len = 0 # Length of the host key modulus. self.__hostkey_n_len = 0 # Length of the host key modulus.

View File

@ -32,7 +32,7 @@ from ssh_audit.utils import Utils
class Output: class Output:
LEVELS = ('info', 'warn', 'fail') # type: Sequence[str] LEVELS: Sequence[str] = ('info', 'warn', 'fail')
COLORS = {'head': 36, 'good': 32, 'warn': 33, 'fail': 31} COLORS = {'head': 36, 'good': 32, 'warn': 33, 'fail': 31}
# Use brighter colors on Windows for better readability. # Use brighter colors on Windows for better readability.

View File

@ -36,7 +36,7 @@ from ssh_audit.banner import Banner # pylint: disable=unused-import
class Policy: class Policy:
# Each field maps directly to a private member variable of the Policy class. # Each field maps directly to a private member variable of the Policy class.
BUILTIN_POLICIES = { BUILTIN_POLICIES: Dict[str, Dict[str, Union[Optional[str], Optional[List[str]], bool, Dict[str, int]]]] = {
# Ubuntu Server policies # Ubuntu Server policies
@ -74,25 +74,25 @@ class Policy:
'Hardened Ubuntu Client 20.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512', 'rsa-sha2-512-cert-v01@openssh.com'], 'optional_host_keys': None, 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False}, 'Hardened Ubuntu Client 20.04 LTS (version 2)': {'version': '2', 'banner': None, 'compressions': None, 'host_keys': ['ssh-ed25519', 'ssh-ed25519-cert-v01@openssh.com', 'sk-ssh-ed25519@openssh.com', 'sk-ssh-ed25519-cert-v01@openssh.com', 'rsa-sha2-256', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512', 'rsa-sha2-512-cert-v01@openssh.com'], 'optional_host_keys': None, 'kex': ['curve25519-sha256', 'curve25519-sha256@libssh.org', 'diffie-hellman-group16-sha512', 'diffie-hellman-group18-sha512', 'diffie-hellman-group-exchange-sha256', 'ext-info-c'], 'ciphers': ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com', 'aes256-ctr', 'aes192-ctr', 'aes128-ctr'], 'macs': ['hmac-sha2-256-etm@openssh.com', 'hmac-sha2-512-etm@openssh.com', 'umac-128-etm@openssh.com'], 'hostkey_sizes': None, 'cakey_sizes': None, 'dh_modulus_sizes': None, 'server_policy': False},
} # type: Dict[str, Dict[str, Union[Optional[str], Optional[List[str]], bool, Dict[str, int]]]] }
def __init__(self, policy_file: Optional[str] = None, policy_data: Optional[str] = None, manual_load: bool = False) -> None: def __init__(self, policy_file: Optional[str] = None, policy_data: Optional[str] = None, manual_load: bool = False) -> None:
self._name = None # type: Optional[str] self._name: Optional[str] = None
self._version = None # type: Optional[str] self._version: Optional[str] = None
self._banner = None # type: Optional[str] self._banner: Optional[str] = None
self._compressions = None # type: Optional[List[str]] self._compressions: Optional[List[str]] = None
self._host_keys = None # type: Optional[List[str]] self._host_keys: Optional[List[str]] = None
self._optional_host_keys = None # type: Optional[List[str]] self._optional_host_keys: Optional[List[str]] = None
self._kex = None # type: Optional[List[str]] self._kex: Optional[List[str]] = None
self._ciphers = None # type: Optional[List[str]] self._ciphers: Optional[List[str]] = None
self._macs = None # type: Optional[List[str]] self._macs: Optional[List[str]] = None
self._hostkey_sizes = None # type: Optional[Dict[str, int]] self._hostkey_sizes: Optional[Dict[str, int]] = None
self._cakey_sizes = None # type: Optional[Dict[str, int]] self._cakey_sizes: Optional[Dict[str, int]] = None
self._dh_modulus_sizes = None # type: Optional[Dict[str, int]] self._dh_modulus_sizes: Optional[Dict[str, int]] = None
self._server_policy = True self._server_policy = True
self._name_and_version = '' # type: str self._name_and_version: str = ''
# Ensure that only one mode was specified. # Ensure that only one mode was specified.
num_modes = 0 num_modes = 0
@ -305,7 +305,7 @@ macs = %s
'''Evaluates a server configuration against this policy. Returns a tuple of a boolean (True if server adheres to policy) and an array of strings that holds error messages.''' '''Evaluates a server configuration against this policy. Returns a tuple of a boolean (True if server adheres to policy) and an array of strings that holds error messages.'''
ret = True ret = True
errors = [] # type: List[Any] errors: List[Any] = []
banner_str = str(banner) banner_str = str(banner)
if (self._banner is not None) and (banner_str != self._banner): if (self._banner is not None) and (banner_str != self._banner):

View File

@ -43,14 +43,14 @@ class ReadBuf:
return self._buf.read(size) return self._buf.read(size)
def read_byte(self) -> int: def read_byte(self) -> int:
v = struct.unpack('B', self.read(1))[0] # type: int v: int = struct.unpack('B', self.read(1))[0]
return v return v
def read_bool(self) -> bool: def read_bool(self) -> bool:
return self.read_byte() != 0 return self.read_byte() != 0
def read_int(self) -> int: def read_int(self) -> int:
v = struct.unpack('>I', self.read(4))[0] # type: int v: int = struct.unpack('>I', self.read(4))[0]
return v return v
def read_list(self) -> List[str]: def read_list(self) -> List[str]:

View File

@ -180,7 +180,7 @@ class Software:
# pylint: disable=too-many-return-statements # pylint: disable=too-many-return-statements
software = str(banner.software) software = str(banner.software)
mx = re.match(r'^dropbear_([\d\.]+\d+)(.*)', software) mx = re.match(r'^dropbear_([\d\.]+\d+)(.*)', software)
v = None # type: Optional[str] v: Optional[str] = None
if mx is not None: if mx is not None:
patch = cls._fix_patch(mx.group(2)) patch = cls._fix_patch(mx.group(2))
v, p = 'Matt Johnston', Product.DropbearSSH v, p = 'Matt Johnston', Product.DropbearSSH

View File

@ -29,7 +29,7 @@ from ssh_audit.ssh1_crc32 import SSH1_CRC32
class SSH1: class SSH1:
_crc32 = None # type: Optional[SSH1_CRC32] _crc32: Optional[SSH1_CRC32] = None
CIPHERS = ['none', 'idea', 'des', '3des', 'tss', 'rc4', 'blowfish'] CIPHERS = ['none', 'idea', 'des', '3des', 'tss', 'rc4', 'blowfish']
AUTHS = ['none', 'rhosts', 'rsa', 'password', 'rhosts_rsa', 'tis', 'kerberos'] AUTHS = ['none', 'rhosts', 'rsa', 'password', 'rhosts_rsa', 'tis', 'kerberos']

View File

@ -34,7 +34,7 @@ class SSH1_KexDB: # pylint: disable=too-few-public-methods
FAIL_NA_UNSAFE = 'not implemented in OpenSSH (server), unsafe algorithm' FAIL_NA_UNSAFE = 'not implemented in OpenSSH (server), unsafe algorithm'
TEXT_CIPHER_IDEA = 'cipher used by commercial SSH' TEXT_CIPHER_IDEA = 'cipher used by commercial SSH'
ALGORITHMS = { ALGORITHMS: Dict[str, Dict[str, List[List[Optional[str]]]]] = {
'key': { 'key': {
'ssh-rsa1': [['1.2.2']], 'ssh-rsa1': [['1.2.2']],
}, },
@ -55,4 +55,4 @@ class SSH1_KexDB: # pylint: disable=too-few-public-methods
'tis': [['1.2.2']], 'tis': [['1.2.2']],
'kerberos': [['1.2.2', '3.6'], [FAIL_OPENSSH37_REMOVE]], 'kerberos': [['1.2.2', '3.6'], [FAIL_OPENSSH37_REMOVE]],
} }
} # type: Dict[str, Dict[str, List[List[Optional[str]]]]] }

View File

@ -41,9 +41,9 @@ class SSH2_Kex:
self.__follows = follows self.__follows = follows
self.__unused = unused self.__unused = unused
self.__rsa_key_sizes = {} # type: Dict[str, Tuple[int, int]] self.__rsa_key_sizes: Dict[str, Tuple[int, int]] = {}
self.__dh_modulus_sizes = {} # type: Dict[str, Tuple[int, int]] self.__dh_modulus_sizes: Dict[str, Tuple[int, int]] = {}
self.__host_keys = {} # type: Dict[str, bytes] self.__host_keys: Dict[str, bytes] = {}
@property @property
def cookie(self) -> bytes: def cookie(self) -> bytes:

View File

@ -59,7 +59,7 @@ class SSH2_KexDB: # pylint: disable=too-few-public-methods
WARN_OBSOLETE = 'using obsolete algorithm' WARN_OBSOLETE = 'using obsolete algorithm'
WARN_UNTRUSTED = 'using untrusted algorithm' WARN_UNTRUSTED = 'using untrusted algorithm'
ALGORITHMS = { ALGORITHMS: Dict[str, Dict[str, List[List[Optional[str]]]]] = {
# Format: 'algorithm_name': [['version_first_appeared_in'], [reason_for_failure1, reason_for_failure2, ...], [warning1, warning2, ...]] # Format: 'algorithm_name': [['version_first_appeared_in'], [reason_for_failure1, reason_for_failure2, ...], [warning1, warning2, ...]]
'kex': { 'kex': {
'diffie-hellman-group1-sha1': [['2.3.0,d0.28,l10.2', '6.6', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH67_UNSAFE, FAIL_OPENSSH70_LOGJAM], [WARN_HASH_WEAK]], 'diffie-hellman-group1-sha1': [['2.3.0,d0.28,l10.2', '6.6', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_OPENSSH67_UNSAFE, FAIL_OPENSSH70_LOGJAM], [WARN_HASH_WEAK]],
@ -268,4 +268,4 @@ class SSH2_KexDB: # pylint: disable=too-few-public-methods
'chacha20-poly1305@openssh.com': [[]], # Despite the @openssh.com tag, this was never shipped as a MAC in OpenSSH (only as a cipher); it is only implemented as a MAC in Syncplify. 'chacha20-poly1305@openssh.com': [[]], # Despite the @openssh.com tag, this was never shipped as a MAC in OpenSSH (only as a cipher); it is only implemented as a MAC in Syncplify.
'crypticore-mac@ssh.com': [[], [FAIL_UNPROVEN]], 'crypticore-mac@ssh.com': [[], [FAIL_UNPROVEN]],
} }
} # type: Dict[str, Dict[str, List[List[Optional[str]]]]] }

View File

@ -210,13 +210,13 @@ def output_security_sub(sub: str, software: Optional[Software], client_audit: bo
if software is None or software.product not in secdb: if software is None or software.product not in secdb:
return return
for line in secdb[software.product]: for line in secdb[software.product]:
vfrom = '' # type: str vfrom: str = ''
vtill = '' # type: str vtill: str = ''
vfrom, vtill = line[0:2] vfrom, vtill = line[0:2]
if not software.between_versions(vfrom, vtill): if not software.between_versions(vfrom, vtill):
continue continue
target = 0 # type: int target: int = 0
name = '' # type: str name: str = ''
target, name = line[2:4] target, name = line[2:4]
is_server = target & 1 == 1 is_server = target & 1 == 1
is_client = target & 2 == 2 is_client = target & 2 == 2
@ -227,8 +227,8 @@ def output_security_sub(sub: str, software: Optional[Software], client_audit: bo
continue continue
p = '' if out.batch else ' ' * (padlen - len(name)) p = '' if out.batch else ' ' * (padlen - len(name))
if sub == 'cve': if sub == 'cve':
cvss = 0.0 # type: float cvss: float = 0.0
descr = '' # type: str descr: str = ''
cvss, descr = line[4:6] cvss, descr = line[4:6]
# Critical CVSS scores (>= 8.0) are printed as a fail, otherwise they are printed as a warning. # Critical CVSS scores (>= 8.0) are printed as a fail, otherwise they are printed as a warning.
@ -431,7 +431,7 @@ def output(aconf: AuditConf, banner: Optional[Banner], header: List[str], client
maxlen = algs.maxlen + 1 maxlen = algs.maxlen + 1
output_security(banner, client_audit, maxlen, aconf.json) output_security(banner, client_audit, maxlen, aconf.json)
# Filled in by output_algorithms() with unidentified algs. # Filled in by output_algorithms() with unidentified algs.
unknown_algorithms = [] # type: List[str] unknown_algorithms: List[str] = []
if pkm is not None: if pkm is not None:
adb = SSH1_KexDB.ALGORITHMS adb = SSH1_KexDB.ALGORITHMS
ciphers = pkm.supported_ciphers ciphers = pkm.supported_ciphers
@ -529,7 +529,7 @@ def list_policies() -> None:
def make_policy(aconf: AuditConf, banner: Optional['Banner'], kex: Optional['SSH2_Kex'], client_host: Optional[str]) -> None: def make_policy(aconf: AuditConf, banner: Optional['Banner'], kex: Optional['SSH2_Kex'], client_host: Optional[str]) -> None:
# Set the source of this policy to the server host if this is a server audit, otherwise set it to the client address. # Set the source of this policy to the server host if this is a server audit, otherwise set it to the client address.
source = aconf.host # type: Optional[str] source: Optional[str] = aconf.host
if aconf.client_audit: if aconf.client_audit:
source = client_host source = client_host
@ -562,9 +562,9 @@ def process_commandline(args: List[str], usage_cb: Callable[..., None]) -> 'Audi
except getopt.GetoptError as err: except getopt.GetoptError as err:
usage_cb(str(err)) usage_cb(str(err))
aconf.ssh1, aconf.ssh2 = False, False aconf.ssh1, aconf.ssh2 = False, False
host = '' # type: str host: str = ''
oport = None # type: Optional[str] oport: Optional[str] = None
port = 0 # type: int port: int = 0
for o, a in opts: for o, a in opts:
if o in ('-h', '--help'): if o in ('-h', '--help'):
usage_cb() usage_cb()
@ -687,14 +687,14 @@ def build_struct(banner: Optional['Banner'], kex: Optional['SSH2_Kex'] = None, p
banner_software = banner.software banner_software = banner.software
banner_comments = banner.comments banner_comments = banner.comments
res = { res: Any = {
"banner": { "banner": {
"raw": banner_str, "raw": banner_str,
"protocol": banner_protocol, "protocol": banner_protocol,
"software": banner_software, "software": banner_software,
"comments": banner_comments, "comments": banner_comments,
}, },
} # type: Any }
if client_host is not None: if client_host is not None:
res['client_ip'] = client_host res['client_ip'] = client_host
if kex is not None: if kex is not None:
@ -703,9 +703,9 @@ def build_struct(banner: Optional['Banner'], kex: Optional['SSH2_Kex'] = None, p
res['kex'] = [] res['kex'] = []
alg_sizes = kex.dh_modulus_sizes() alg_sizes = kex.dh_modulus_sizes()
for algorithm in kex.kex_algorithms: for algorithm in kex.kex_algorithms:
entry = { entry: Any = {
'algorithm': algorithm, 'algorithm': algorithm,
} # type: Any }
if algorithm in alg_sizes: if algorithm in alg_sizes:
hostkey_size, ca_size = alg_sizes[algorithm] hostkey_size, ca_size = alg_sizes[algorithm]
entry['keysize'] = hostkey_size entry['keysize'] = hostkey_size
@ -879,7 +879,7 @@ def algorithm_lookup(alg_names: str) -> int:
for (outer_k, outer_v) in adb.items() for (outer_k, outer_v) in adb.items()
} }
unknown_algorithms = [] # type: List[str] unknown_algorithms: List[str] = []
padding = len(max(algorithm_names, key=len)) padding = len(max(algorithm_names, key=len))
for alg_type in alg_types: for alg_type in alg_types:

View File

@ -54,12 +54,12 @@ class SSH_Socket(ReadBuf, WriteBuf):
def __init__(self, host: Optional[str], port: int, ipvo: Optional[Sequence[int]] = None, timeout: Union[int, float] = 5, timeout_set: bool = False) -> None: def __init__(self, host: Optional[str], port: int, ipvo: Optional[Sequence[int]] = None, timeout: Union[int, float] = 5, timeout_set: bool = False) -> None:
super(SSH_Socket, self).__init__() super(SSH_Socket, self).__init__()
self.__sock = None # type: Optional[socket.socket] self.__sock: Optional[socket.socket] = None
self.__sock_map = {} # type: Dict[int, socket.socket] self.__sock_map: Dict[int, socket.socket] = {}
self.__block_size = 8 self.__block_size = 8
self.__state = 0 self.__state = 0
self.__header = [] # type: List[str] self.__header: List[str] = []
self.__banner = None # type: Optional[Banner] self.__banner: Optional[Banner] = None
if host is None: if host is None:
raise ValueError('undefined host') raise ValueError('undefined host')
nport = Utils.parse_int(port) nport = Utils.parse_int(port)
@ -73,7 +73,7 @@ class SSH_Socket(ReadBuf, WriteBuf):
self.__ipvo = () self.__ipvo = ()
self.__timeout = timeout self.__timeout = timeout
self.__timeout_set = timeout_set self.__timeout_set = timeout_set
self.client_host = None # type: Optional[str] self.client_host: Optional[str] = None
self.client_port = None self.client_port = None
def _resolve(self, ipvo: Sequence[int]) -> Iterable[Tuple[int, Tuple[Any, ...]]]: def _resolve(self, ipvo: Sequence[int]) -> Iterable[Tuple[int, Tuple[Any, ...]]]:

View File

@ -30,12 +30,12 @@ from ssh_audit.algorithm import Algorithm
class Timeframe: class Timeframe:
def __init__(self) -> None: def __init__(self) -> None:
self.__storage = {} # type: Dict[str, List[Optional[str]]] self.__storage: Dict[str, List[Optional[str]]] = {}
def __contains__(self, product: str) -> bool: def __contains__(self, product: str) -> bool:
return product in self.__storage return product in self.__storage
def __getitem__(self, product): # type: (str) -> Sequence[Optional[str]] def __getitem__(self, product: str) -> Sequence[Optional[str]]:
return tuple(self.__storage.get(product, [None] * 4)) return tuple(self.__storage.get(product, [None] * 4))
def __str__(self) -> str: def __str__(self) -> str:
@ -51,7 +51,7 @@ class Timeframe:
return self[product][1 if bool(for_server) else 3] return self[product][1 if bool(for_server) else 3]
def _update(self, versions: Optional[str], pos: int) -> None: def _update(self, versions: Optional[str], pos: int) -> None:
ssh_versions = {} # type: Dict[str, str] ssh_versions: Dict[str, str] = {}
for_srv, for_cli = pos < 2, pos > 1 for_srv, for_cli = pos < 2, pos > 1
for v in (versions or '').split(','): for v in (versions or '').split(','):
ssh_prod, ssh_ver, is_cli = Algorithm.get_ssh_version(v) ssh_prod, ssh_ver, is_cli = Algorithm.get_ssh_version(v)

View File

@ -96,7 +96,7 @@ class Utils:
@classmethod @classmethod
def unique_seq(cls, seq: Sequence[Any]) -> Sequence[Any]: def unique_seq(cls, seq: Sequence[Any]) -> Sequence[Any]:
seen = set() # type: Set[Any] seen: Set[Any] = set()
def _seen_add(x: Any) -> bool: def _seen_add(x: Any) -> bool:
seen.add(x) seen.add(x)

View File

@ -33,7 +33,7 @@ class VersionVulnerabilityDB: # pylint: disable=too-few-public-methods
# Example: if it affects servers, both remote & local, then affected # Example: if it affects servers, both remote & local, then affected
# = 1. If it affects servers, but is a local issue only, # = 1. If it affects servers, but is a local issue only,
# then affected = 1 + 4 = 5. # then affected = 1 + 4 = 5.
CVE = { CVE: Dict[str, List[List[Any]]] = {
'Dropbear SSH': [ 'Dropbear SSH': [
['0.0', '2018.76', 1, 'CVE-2018-15599', 5.0, 'remote users may enumerate users on the system'], ['0.0', '2018.76', 1, 'CVE-2018-15599', 5.0, 'remote users may enumerate users on the system'],
['0.0', '2017.74', 5, 'CVE-2017-9079', 4.7, 'local users can read certain files as root'], ['0.0', '2017.74', 5, 'CVE-2017-9079', 4.7, 'local users can read certain files as root'],
@ -140,12 +140,12 @@ class VersionVulnerabilityDB: # pylint: disable=too-few-public-methods
['0.0', '0.66', 2, 'CVE-2016-2563', 7.5, 'buffer overflow in SCP command-line utility'], ['0.0', '0.66', 2, 'CVE-2016-2563', 7.5, 'buffer overflow in SCP command-line utility'],
['0.0', '0.65', 2, 'CVE-2015-5309', 4.3, 'integer overflow in terminal-handling code'], ['0.0', '0.65', 2, 'CVE-2015-5309', 4.3, 'integer overflow in terminal-handling code'],
] ]
} # type: Dict[str, List[List[Any]]] }
TXT = { TXT: Dict[str, List[List[Any]]] = {
'Dropbear SSH': [ 'Dropbear SSH': [
['0.28', '0.34', 1, 'remote root exploit', 'remote format string buffer overflow exploit (exploit-db#387)']], ['0.28', '0.34', 1, 'remote root exploit', 'remote format string buffer overflow exploit (exploit-db#387)']],
'libssh': [ 'libssh': [
['0.3.3', '0.3.3', 1, 'null pointer check', 'missing null pointer check in "crypt_set_algorithms_server"'], ['0.3.3', '0.3.3', 1, 'null pointer check', 'missing null pointer check in "crypt_set_algorithms_server"'],
['0.3.3', '0.3.3', 1, 'integer overflow', 'integer overflow in "buffer_get_data"'], ['0.3.3', '0.3.3', 1, 'integer overflow', 'integer overflow in "buffer_get_data"'],
['0.3.3', '0.3.3', 3, 'heap overflow', 'heap overflow in "packet_decrypt"']] ['0.3.3', '0.3.3', 3, 'heap overflow', 'heap overflow in "packet_decrypt"']]
} # type: Dict[str, List[List[Any]]] }