Adding support for SSHA, SSHA256 and SSHA512 (Issue #1881)

This commit is contained in:
Miroslav Stampar 2017-10-20 13:32:40 +02:00
parent 311444a4ac
commit 7c874350d2
2 changed files with 79 additions and 37 deletions

View File

@ -133,6 +133,9 @@ class HASH:
APACHE_SHA1 = r'\A\{SHA\}[a-zA-Z0-9+/]+={0,2}\Z'
VBULLETIN = r'\A[0-9a-fA-F]{32}:.{30}\Z'
VBULLETIN_OLD = r'\A[0-9a-fA-F]{32}:.{3}\Z'
SSHA = r'\A\{SSHA\}[a-zA-Z0-9+/]+={0,2}\Z'
SSHA256 = r'\A\{SSHA256\}[a-zA-Z0-9+/]+={0,2}\Z'
SSHA512 = r'\A\{SSHA512\}[a-zA-Z0-9+/]+={0,2}\Z'
# Reference: http://www.zytrax.com/tech/web/mobile_ids.html
class MOBILES:

View File

@ -25,6 +25,8 @@ else:
except NotImplementedError:
pass
import base64
import binascii
import gc
import os
import re
@ -261,7 +263,31 @@ def apache_sha1_passwd(password, **kwargs):
'{SHA}IGyAQTualsExLMNGt9JRe4RGPt0='
"""
return "{SHA}%s" % sha1(password).digest().encode("base64").strip()
return "{SHA}%s" % base64.b64encode(sha1(password).digest())
def ssha_passwd(password, salt, **kwargs):
"""
>>> ssha_passwd(password='testpass', salt='salt')
'{SSHA}mU1HPTvnmoXOhE4ROHP6sWfbfoRzYWx0'
"""
return "{SSHA}%s" % base64.b64encode(sha1(password + salt).digest() + salt)
def ssha256_passwd(password, salt, **kwargs):
"""
>>> ssha256_passwd(password='testpass', salt='salt')
'{SSHA256}hhubsLrO/Aje9F/kJrgv5ZLE40UmTrVWvI7Dt6InP99zYWx0'
"""
return "{SSHA256}%s" % base64.b64encode(sha256(password + salt).digest() + salt)
def ssha512_passwd(password, salt, **kwargs):
"""
>>> ssha512_passwd(password='testpass', salt='salt')
'{SSHA512}mCUSLfPMhXCQOJl9WHW/QMn9v9sjq7Ht/Wk7iVau8vLOfh+PeynkGMikqIE8sStFd0khdfcCD8xZmC6UyjTxsHNhbHQ='
"""
return "{SSHA512}%s" % base64.b64encode(sha512(password + salt).digest() + salt)
def sha224_generic_passwd(password, uppercase=False):
"""
@ -487,6 +513,9 @@ __functions__ = {
HASH.APACHE_SHA1: apache_sha1_passwd,
HASH.VBULLETIN: vbulletin_passwd,
HASH.VBULLETIN_OLD: vbulletin_passwd,
HASH.SSHA: ssha_passwd,
HASH.SSHA256: ssha256_passwd,
HASH.SSHA512: ssha512_passwd,
}
def storeHashesToFile(attack_dict):
@ -829,13 +858,20 @@ def dictionaryAttack(attack_dict):
hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_
if re.match(hash_regex, hash_):
try:
item = None
if hash_regex not in (HASH.CRYPT_GENERIC, HASH.JOOMLA, HASH.WORDPRESS, HASH.UNIX_MD5_CRYPT, HASH.APACHE_MD5_CRYPT, HASH.APACHE_SHA1, HASH.VBULLETIN, HASH.VBULLETIN_OLD):
if hash_regex not in (HASH.CRYPT_GENERIC, HASH.JOOMLA, HASH.WORDPRESS, HASH.UNIX_MD5_CRYPT, HASH.APACHE_MD5_CRYPT, HASH.APACHE_SHA1, HASH.VBULLETIN, HASH.VBULLETIN_OLD, HASH.SSHA, HASH.SSHA256, HASH.SSHA512):
hash_ = hash_.lower()
if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC, HASH.APACHE_SHA1):
item = [(user, hash_), {}]
elif hash_regex in (HASH.SSHA,):
item = [(user, hash_), {'salt': hash_.decode("base64")[20:]}]
elif hash_regex in (HASH.SSHA256,):
item = [(user, hash_), {'salt': hash_.decode("base64")[32:]}]
elif hash_regex in (HASH.SSHA512,):
item = [(user, hash_), {'salt': hash_.decode("base64")[64:]}]
elif hash_regex in (HASH.ORACLE_OLD, HASH.POSTGRES):
item = [(user, hash_), {'username': user}]
elif hash_regex in (HASH.ORACLE,):
@ -868,6 +904,9 @@ def dictionaryAttack(attack_dict):
resumes.append((user, hash_, resumed))
keys.add(hash_)
except (binascii.Error, IndexError):
pass
if not attack_info:
continue
@ -875,7 +914,7 @@ def dictionaryAttack(attack_dict):
while not kb.wordlists:
# the slowest of all methods hence smaller default dict
if hash_regex in (HASH.ORACLE_OLD, HASH.WORDPRESS):
if hash_regex in (HASH.ORACLE_OLD,):
dictPaths = [paths.SMALL_DICT]
else:
dictPaths = [paths.WORDLIST]