mirror of https://github.com/jtesta/ssh-audit.git
Implement SSH1 support (cipher, auth, compatibility, texts, etc) #6.
This commit is contained in:
parent
fce491767c
commit
5bc31ea70c
59
ssh-audit.py
59
ssh-audit.py
|
@ -205,13 +205,40 @@ class SSH1(object):
|
||||||
return crc
|
return crc
|
||||||
|
|
||||||
_crc32 = CRC32()
|
_crc32 = CRC32()
|
||||||
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']
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def crc32(cls, v):
|
def crc32(cls, v):
|
||||||
return cls._crc32.calc(v)
|
return cls._crc32.calc(v)
|
||||||
|
|
||||||
|
class KexDB(object):
|
||||||
|
FAIL_PLAINTEXT = 'no encryption/integrity'
|
||||||
|
FAIL_OPENSSH37_REMOVE = 'removed since OpenSSH 3.7'
|
||||||
|
FAIL_NA_BROKEN = 'not implemented in OpenSSH, broken algorithm'
|
||||||
|
FAIL_NA_UNSAFE = 'not implemented in OpenSSH (server), unsafe algorithm'
|
||||||
|
TEXT_CIPHER_IDEA = 'cipher used by commercial SSH'
|
||||||
|
|
||||||
|
ALGORITHMS = {
|
||||||
|
'enc': {
|
||||||
|
'none': [['1.2.2'], [FAIL_PLAINTEXT]],
|
||||||
|
'idea': [[None], [], [], [TEXT_CIPHER_IDEA]],
|
||||||
|
'des': [['2.3.0C'], [FAIL_NA_UNSAFE]],
|
||||||
|
'3des': [['1.2.2']],
|
||||||
|
'tss': [[''], [FAIL_NA_BROKEN]],
|
||||||
|
'rc4': [[], [FAIL_NA_BROKEN]],
|
||||||
|
'blowfish': [['1.2.2']],
|
||||||
|
},
|
||||||
|
'aut': {
|
||||||
|
'rhosts': [['1.2.2', '3.6'], [FAIL_OPENSSH37_REMOVE]],
|
||||||
|
'rsa': [['1.2.2']],
|
||||||
|
'password': [['1.2.2']],
|
||||||
|
'rhosts_rsa': [['1.2.2']],
|
||||||
|
'tis': [['1.2.2']],
|
||||||
|
'kerberos': [['1.2.2', '3.6'], [FAIL_OPENSSH37_REMOVE]],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class PublicKeyMessage(object):
|
class PublicKeyMessage(object):
|
||||||
def __init__(self, cookie, skey, hkey, pflags, cmask, amask):
|
def __init__(self, cookie, skey, hkey, pflags, cmask, amask):
|
||||||
assert len(skey) == 3
|
assert len(skey) == 3
|
||||||
|
@ -274,7 +301,7 @@ class SSH1(object):
|
||||||
@property
|
@property
|
||||||
def supported_authentications(self):
|
def supported_authentications(self):
|
||||||
auths = []
|
auths = []
|
||||||
for i in range(len(SSH1.AUTHS)):
|
for i in range(1, len(SSH1.AUTHS)):
|
||||||
if self.__supported_authentications_mask & (1 << i) != 0:
|
if self.__supported_authentications_mask & (1 << i) != 0:
|
||||||
auths.append(SSH1.AUTHS[i])
|
auths.append(SSH1.AUTHS[i])
|
||||||
return auths
|
return auths
|
||||||
|
@ -597,7 +624,6 @@ class SSH(object):
|
||||||
patch = cls._fix_patch(mx.group(2))
|
patch = cls._fix_patch(mx.group(2))
|
||||||
v, p = 'Allegro Software', 'RomSShell'
|
v, p = 'Allegro Software', 'RomSShell'
|
||||||
return cls(v, p, mx.group(1), patch, None)
|
return cls(v, p, mx.group(1), patch, None)
|
||||||
|
|
||||||
mx = re.match(r'^mpSSH_([\d\.]+\d+)', software)
|
mx = re.match(r'^mpSSH_([\d\.]+\d+)', software)
|
||||||
if mx:
|
if mx:
|
||||||
v, p = 'HP', 'iLO (Integrated Lights-Out) sshd'
|
v, p = 'HP', 'iLO (Integrated Lights-Out) sshd'
|
||||||
|
@ -1115,8 +1141,12 @@ def output_algorithm(alg_db, alg_type, alg_name, alg_max_len=0):
|
||||||
f(' ' * len(prefix + alg_name) + padding + ' `- ' + text)
|
f(' ' * len(prefix + alg_name) + padding + ' `- ' + text)
|
||||||
|
|
||||||
|
|
||||||
def output_compatibility(kex, for_server=True):
|
def output_compatibility(kex, pkm, for_server=True):
|
||||||
alg_pairs = []
|
alg_pairs = []
|
||||||
|
if pkm is not None:
|
||||||
|
alg_pairs.append((SSH1.KexDB.ALGORITHMS,
|
||||||
|
{'enc': pkm.supported_ciphers,
|
||||||
|
'aut': pkm.supported_authentications}))
|
||||||
if kex is not None:
|
if kex is not None:
|
||||||
alg_pairs.append((KexDB.ALGORITHMS,
|
alg_pairs.append((KexDB.ALGORITHMS,
|
||||||
{'kex': kex.kex_algorithms,
|
{'kex': kex.kex_algorithms,
|
||||||
|
@ -1189,8 +1219,8 @@ def output(banner, header, kex=None, pkm=None):
|
||||||
software = SSH.Software.parse(banner)
|
software = SSH.Software.parse(banner)
|
||||||
if software is not None:
|
if software is not None:
|
||||||
out.good('(gen) software: {0}'.format(software))
|
out.good('(gen) software: {0}'.format(software))
|
||||||
|
output_compatibility(kex, pkm)
|
||||||
if kex is not None:
|
if kex is not None:
|
||||||
output_compatibility(kex)
|
|
||||||
compressions = [x for x in kex.server.compression if x != 'none']
|
compressions = [x for x in kex.server.compression if x != 'none']
|
||||||
if len(compressions) > 0:
|
if len(compressions) > 0:
|
||||||
cmptxt = 'enabled ({0})'.format(', '.join(compressions))
|
cmptxt = 'enabled ({0})'.format(', '.join(compressions))
|
||||||
|
@ -1201,15 +1231,26 @@ def output(banner, header, kex=None, pkm=None):
|
||||||
out.head('# general')
|
out.head('# general')
|
||||||
obuf.flush()
|
obuf.flush()
|
||||||
out.sep()
|
out.sep()
|
||||||
|
ml, maxlen = lambda l: max(len(i) for i in l), 0
|
||||||
|
if pkm is not None:
|
||||||
|
maxlen = max(ml(pkm.supported_ciphers),
|
||||||
|
ml(pkm.supported_authentications),
|
||||||
|
maxlen)
|
||||||
if kex is not None:
|
if kex is not None:
|
||||||
ml = lambda l: max(len(i) for i in l)
|
|
||||||
maxlen = max(ml(kex.kex_algorithms),
|
maxlen = max(ml(kex.kex_algorithms),
|
||||||
ml(kex.key_algorithms),
|
ml(kex.key_algorithms),
|
||||||
ml(kex.server.encryption),
|
ml(kex.server.encryption),
|
||||||
ml(kex.server.mac))
|
ml(kex.server.mac),
|
||||||
else:
|
maxlen)
|
||||||
maxlen = 0
|
|
||||||
output_security(banner, maxlen)
|
output_security(banner, maxlen)
|
||||||
|
if pkm is not None:
|
||||||
|
alg_db = SSH1.KexDB.ALGORITHMS
|
||||||
|
ciphers = pkm.supported_ciphers
|
||||||
|
auths = pkm.supported_authentications
|
||||||
|
title, alg_type = 'SSH1 encryption algorithms (ciphers)', 'enc'
|
||||||
|
output_algorithms(title, alg_db, alg_type, ciphers, maxlen)
|
||||||
|
title, alg_type = 'SSH1 authentication types', 'aut'
|
||||||
|
output_algorithms(title, alg_db, alg_type, auths, maxlen)
|
||||||
if kex is None:
|
if kex is None:
|
||||||
return
|
return
|
||||||
alg_db = KexDB.ALGORITHMS
|
alg_db = KexDB.ALGORITHMS
|
||||||
|
|
Loading…
Reference in New Issue