mirror of
https://github.com/jtesta/ssh-audit.git
synced 2024-11-21 18:11:40 +01:00
Algorithm lookup (#53)
* Adding ssh-audit.py to algorithm_lookup_branch * Removed the use of an error handler from algorithm_lookup and implemented suggestions made by jugmac00 and jtesta
This commit is contained in:
parent
0c00b37328
commit
86cb453928
@ -36,6 +36,7 @@ usage: ssh-audit.py [options] <host>
|
|||||||
-j, --json JSON output
|
-j, --json JSON output
|
||||||
-l, --level=<level> minimum output level (info|warn|fail)
|
-l, --level=<level> minimum output level (info|warn|fail)
|
||||||
-L, --list-policies list all the official, built-in policies
|
-L, --list-policies list all the official, built-in policies
|
||||||
|
--lookup=<alg> performs an algorithm lookup (accepts a comma separated list)
|
||||||
-M, --make-policy=<policy.txt> creates a policy based on the target server
|
-M, --make-policy=<policy.txt> creates a policy based on the target server
|
||||||
(i.e.: the target server has the ideal
|
(i.e.: the target server has the ideal
|
||||||
configuration that other servers should
|
configuration that other servers should
|
||||||
|
70
ssh-audit.py
70
ssh-audit.py
@ -79,6 +79,7 @@ def usage(err: Optional[str] = None) -> None:
|
|||||||
uout.info(' -j, --json JSON output')
|
uout.info(' -j, --json JSON output')
|
||||||
uout.info(' -l, --level=<level> minimum output level (info|warn|fail)')
|
uout.info(' -l, --level=<level> minimum output level (info|warn|fail)')
|
||||||
uout.info(' -L, --list-policies list all the official, built-in policies')
|
uout.info(' -L, --list-policies list all the official, built-in policies')
|
||||||
|
uout.info(' --lookup=<alg> performs an algorithm lookup (accepts a comma separated list)')
|
||||||
uout.info(' -M, --make-policy=<policy.txt> creates a policy based on the target server\n (i.e.: the target server has the ideal\n configuration that other servers should\n adhere to)')
|
uout.info(' -M, --make-policy=<policy.txt> creates a policy based on the target server\n (i.e.: the target server has the ideal\n configuration that other servers should\n adhere to)')
|
||||||
uout.info(' -n, --no-colors disable colors')
|
uout.info(' -n, --no-colors disable colors')
|
||||||
uout.info(' -p, --port=<port> port to connect')
|
uout.info(' -p, --port=<port> port to connect')
|
||||||
@ -477,6 +478,7 @@ class AuditConf:
|
|||||||
self.target_file = None # type: Optional[str]
|
self.target_file = None # type: Optional[str]
|
||||||
self.target_list = [] # type: List[str]
|
self.target_list = [] # type: List[str]
|
||||||
self.list_policies = False
|
self.list_policies = False
|
||||||
|
self.lookup = ''
|
||||||
|
|
||||||
def __setattr__(self, name: str, value: Union[str, int, float, bool, Sequence[int]]) -> None:
|
def __setattr__(self, name: str, value: Union[str, int, float, bool, Sequence[int]]) -> None:
|
||||||
valid = False
|
valid = False
|
||||||
@ -518,7 +520,7 @@ class AuditConf:
|
|||||||
if value == -1.0:
|
if value == -1.0:
|
||||||
raise ValueError('invalid timeout: {}'.format(value))
|
raise ValueError('invalid timeout: {}'.format(value))
|
||||||
valid = True
|
valid = True
|
||||||
elif name in ['policy_file', 'policy', 'target_file', 'target_list']:
|
elif name in ['policy_file', 'policy', 'target_file', 'target_list', 'lookup']:
|
||||||
valid = True
|
valid = True
|
||||||
|
|
||||||
if valid:
|
if valid:
|
||||||
@ -530,7 +532,7 @@ class AuditConf:
|
|||||||
aconf = cls()
|
aconf = cls()
|
||||||
try:
|
try:
|
||||||
sopts = 'h1246M:p:P:jbcnvl:t:T:L'
|
sopts = 'h1246M:p:P:jbcnvl:t:T:L'
|
||||||
lopts = ['help', 'ssh1', 'ssh2', 'ipv4', 'ipv6', 'make-policy=', 'port=', 'policy=', 'json', 'batch', 'client-audit', 'no-colors', 'verbose', 'level=', 'timeout=', 'targets=', 'list-policies']
|
lopts = ['help', 'ssh1', 'ssh2', 'ipv4', 'ipv6', 'make-policy=', 'port=', 'policy=', 'json', 'batch', 'client-audit', 'no-colors', 'verbose', 'level=', 'timeout=', 'targets=', 'list-policies', 'lookup=']
|
||||||
opts, args = getopt.gnu_getopt(args, sopts, lopts)
|
opts, args = getopt.gnu_getopt(args, sopts, lopts)
|
||||||
except getopt.GetoptError as err:
|
except getopt.GetoptError as err:
|
||||||
usage_cb(str(err))
|
usage_cb(str(err))
|
||||||
@ -578,10 +580,15 @@ class AuditConf:
|
|||||||
aconf.target_file = a
|
aconf.target_file = a
|
||||||
elif o in ('-L', '--list-policies'):
|
elif o in ('-L', '--list-policies'):
|
||||||
aconf.list_policies = True
|
aconf.list_policies = True
|
||||||
|
elif o in ('--lookup'):
|
||||||
|
aconf.lookup = a
|
||||||
|
|
||||||
if len(args) == 0 and aconf.client_audit is False and aconf.target_file is None and aconf.list_policies is False:
|
if len(args) == 0 and aconf.client_audit is False and aconf.target_file is None and aconf.list_policies is False and aconf.lookup == '':
|
||||||
usage_cb()
|
usage_cb()
|
||||||
|
|
||||||
|
if aconf.lookup != '':
|
||||||
|
return aconf
|
||||||
|
|
||||||
if aconf.list_policies:
|
if aconf.list_policies:
|
||||||
list_policies()
|
list_policies()
|
||||||
sys.exit(PROGRAM_RETVAL_GOOD)
|
sys.exit(PROGRAM_RETVAL_GOOD)
|
||||||
@ -3714,6 +3721,59 @@ def audit(aconf: AuditConf, sshv: Optional[int] = None, print_target: bool = Fal
|
|||||||
return program_retval
|
return program_retval
|
||||||
|
|
||||||
|
|
||||||
|
def algorithm_lookup(alg_names: str) -> int:
|
||||||
|
alg_types = {
|
||||||
|
'kex': 'key exchange algorithms',
|
||||||
|
'key': 'host-key algorithms',
|
||||||
|
'mac': 'message authentication code algorithms',
|
||||||
|
'enc': 'encryption algorithms (ciphers)'
|
||||||
|
}
|
||||||
|
|
||||||
|
algorithm_names = alg_names.split(",")
|
||||||
|
adb = SSH2.KexDB.ALGORITHMS
|
||||||
|
|
||||||
|
# Use nested dictionary comprehension to iterate an outer dictionary where
|
||||||
|
# each key is an alg type that consists of a value (which is itself a
|
||||||
|
# dictionary) of alg names. Filter the alg names against the user supplied
|
||||||
|
# list of names.
|
||||||
|
algorithms_dict = {
|
||||||
|
outer_k: {
|
||||||
|
inner_k
|
||||||
|
for (inner_k, inner_v) in outer_v.items()
|
||||||
|
if inner_k in algorithm_names
|
||||||
|
}
|
||||||
|
for (outer_k, outer_v) in adb.items()
|
||||||
|
}
|
||||||
|
|
||||||
|
unknown_algorithms = [] # type: List[str]
|
||||||
|
padding = len(max(algorithm_names, key=len))
|
||||||
|
|
||||||
|
for alg_type in alg_types:
|
||||||
|
if len(algorithms_dict[alg_type]) > 0:
|
||||||
|
title = str(alg_types.get(alg_type))
|
||||||
|
retval = output_algorithms(title, adb, alg_type, algorithms_dict[alg_type], unknown_algorithms, False, PROGRAM_RETVAL_GOOD, padding)
|
||||||
|
|
||||||
|
algorithms_dict_flattened = [
|
||||||
|
alg_name
|
||||||
|
for val in algorithms_dict.values()
|
||||||
|
for alg_name in val
|
||||||
|
]
|
||||||
|
|
||||||
|
algorithms_not_found = [
|
||||||
|
alg_name
|
||||||
|
for alg_name in algorithm_names
|
||||||
|
if alg_name not in algorithms_dict_flattened
|
||||||
|
]
|
||||||
|
|
||||||
|
if len(algorithms_not_found) > 0:
|
||||||
|
retval = PROGRAM_RETVAL_FAILURE
|
||||||
|
out.head('# unknown algorithms')
|
||||||
|
for algorithm_not_found in algorithms_not_found:
|
||||||
|
out.fail(algorithm_not_found)
|
||||||
|
|
||||||
|
return retval
|
||||||
|
|
||||||
|
|
||||||
utils = Utils()
|
utils = Utils()
|
||||||
out = Output()
|
out = Output()
|
||||||
|
|
||||||
@ -3721,6 +3781,10 @@ out = Output()
|
|||||||
def main() -> int:
|
def main() -> int:
|
||||||
aconf = AuditConf.from_cmdline(sys.argv[1:], usage)
|
aconf = AuditConf.from_cmdline(sys.argv[1:], usage)
|
||||||
|
|
||||||
|
if aconf.lookup != '':
|
||||||
|
retval = algorithm_lookup(aconf.lookup)
|
||||||
|
sys.exit(retval)
|
||||||
|
|
||||||
# If multiple targets were specified...
|
# If multiple targets were specified...
|
||||||
if len(aconf.target_list) > 0:
|
if len(aconf.target_list) > 0:
|
||||||
ret = PROGRAM_RETVAL_GOOD
|
ret = PROGRAM_RETVAL_GOOD
|
||||||
|
Loading…
Reference in New Issue
Block a user