Implement SSH1 support (cipher, auth, compatibility, texts, etc) #6.

This commit is contained in:
Andris Raugulis 2016-09-17 19:33:03 +03:00
parent fce491767c
commit 5bc31ea70c
1 changed files with 50 additions and 9 deletions

View File

@ -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