Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7c87435

Browse files
committed
Adding support for SSHA, SSHA256 and SSHA512 (Issue #1881)
1 parent 311444a commit 7c87435

2 files changed

Lines changed: 81 additions & 39 deletions

File tree

lib/core/enums.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ class HASH:
133133
APACHE_SHA1 = r'\A\{SHA\}[a-zA-Z0-9+/]+={0,2}\Z'
134134
VBULLETIN = r'\A[0-9a-fA-F]{32}:.{30}\Z'
135135
VBULLETIN_OLD = r'\A[0-9a-fA-F]{32}:.{3}\Z'
136+
SSHA = r'\A\{SSHA\}[a-zA-Z0-9+/]+={0,2}\Z'
137+
SSHA256 = r'\A\{SSHA256\}[a-zA-Z0-9+/]+={0,2}\Z'
138+
SSHA512 = r'\A\{SSHA512\}[a-zA-Z0-9+/]+={0,2}\Z'
136139

137140
# Reference: http://www.zytrax.com/tech/web/mobile_ids.html
138141
class MOBILES:

lib/utils/hash.py

Lines changed: 78 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
except NotImplementedError:
2626
pass
2727

28+
import base64
29+
import binascii
2830
import gc
2931
import os
3032
import re
@@ -261,7 +263,31 @@ def apache_sha1_passwd(password, **kwargs):
261263
'{SHA}IGyAQTualsExLMNGt9JRe4RGPt0='
262264
"""
263265

264-
return "{SHA}%s" % sha1(password).digest().encode("base64").strip()
266+
return "{SHA}%s" % base64.b64encode(sha1(password).digest())
267+
268+
def ssha_passwd(password, salt, **kwargs):
269+
"""
270+
>>> ssha_passwd(password='testpass', salt='salt')
271+
'{SSHA}mU1HPTvnmoXOhE4ROHP6sWfbfoRzYWx0'
272+
"""
273+
274+
return "{SSHA}%s" % base64.b64encode(sha1(password + salt).digest() + salt)
275+
276+
def ssha256_passwd(password, salt, **kwargs):
277+
"""
278+
>>> ssha256_passwd(password='testpass', salt='salt')
279+
'{SSHA256}hhubsLrO/Aje9F/kJrgv5ZLE40UmTrVWvI7Dt6InP99zYWx0'
280+
"""
281+
282+
return "{SSHA256}%s" % base64.b64encode(sha256(password + salt).digest() + salt)
283+
284+
def ssha512_passwd(password, salt, **kwargs):
285+
"""
286+
>>> ssha512_passwd(password='testpass', salt='salt')
287+
'{SSHA512}mCUSLfPMhXCQOJl9WHW/QMn9v9sjq7Ht/Wk7iVau8vLOfh+PeynkGMikqIE8sStFd0khdfcCD8xZmC6UyjTxsHNhbHQ='
288+
"""
289+
290+
return "{SSHA512}%s" % base64.b64encode(sha512(password + salt).digest() + salt)
265291

266292
def sha224_generic_passwd(password, uppercase=False):
267293
"""
@@ -487,6 +513,9 @@ def _encode64(input_, count):
487513
HASH.APACHE_SHA1: apache_sha1_passwd,
488514
HASH.VBULLETIN: vbulletin_passwd,
489515
HASH.VBULLETIN_OLD: vbulletin_passwd,
516+
HASH.SSHA: ssha_passwd,
517+
HASH.SSHA256: ssha256_passwd,
518+
HASH.SSHA512: ssha512_passwd,
490519
}
491520

492521
def storeHashesToFile(attack_dict):
@@ -829,44 +858,54 @@ def dictionaryAttack(attack_dict):
829858
hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_
830859

831860
if re.match(hash_regex, hash_):
832-
item = None
861+
try:
862+
item = None
863+
864+
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):
865+
hash_ = hash_.lower()
866+
867+
if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC, HASH.APACHE_SHA1):
868+
item = [(user, hash_), {}]
869+
elif hash_regex in (HASH.SSHA,):
870+
item = [(user, hash_), {'salt': hash_.decode("base64")[20:]}]
871+
elif hash_regex in (HASH.SSHA256,):
872+
item = [(user, hash_), {'salt': hash_.decode("base64")[32:]}]
873+
elif hash_regex in (HASH.SSHA512,):
874+
item = [(user, hash_), {'salt': hash_.decode("base64")[64:]}]
875+
elif hash_regex in (HASH.ORACLE_OLD, HASH.POSTGRES):
876+
item = [(user, hash_), {'username': user}]
877+
elif hash_regex in (HASH.ORACLE,):
878+
item = [(user, hash_), {'salt': hash_[-20:]}]
879+
elif hash_regex in (HASH.MSSQL, HASH.MSSQL_OLD, HASH.MSSQL_NEW):
880+
item = [(user, hash_), {'salt': hash_[6:14]}]
881+
elif hash_regex in (HASH.CRYPT_GENERIC,):
882+
item = [(user, hash_), {'salt': hash_[0:2]}]
883+
elif hash_regex in (HASH.UNIX_MD5_CRYPT, HASH.APACHE_MD5_CRYPT):
884+
item = [(user, hash_), {'salt': hash_.split('$')[2], 'magic': '$%s$' % hash_.split('$')[1]}]
885+
elif hash_regex in (HASH.JOOMLA, HASH.VBULLETIN, HASH.VBULLETIN_OLD):
886+
item = [(user, hash_), {'salt': hash_.split(':')[-1]}]
887+
elif hash_regex in (HASH.WORDPRESS,):
888+
if ITOA64.index(hash_[3]) < 32:
889+
item = [(user, hash_), {'salt': hash_[4:12], 'count': 1 << ITOA64.index(hash_[3]), 'prefix': hash_[:12]}]
890+
else:
891+
warnMsg = "invalid hash '%s'" % hash_
892+
logger.warn(warnMsg)
893+
894+
if item and hash_ not in keys:
895+
resumed = hashDBRetrieve(hash_)
896+
if not resumed:
897+
attack_info.append(item)
898+
user_hash.append(item[0])
899+
else:
900+
infoMsg = "resuming password '%s' for hash '%s'" % (resumed, hash_)
901+
if user and not user.startswith(DUMMY_USER_PREFIX):
902+
infoMsg += " for user '%s'" % user
903+
logger.info(infoMsg)
904+
resumes.append((user, hash_, resumed))
905+
keys.add(hash_)
833906

834-
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):
835-
hash_ = hash_.lower()
836-
837-
if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC, HASH.APACHE_SHA1):
838-
item = [(user, hash_), {}]
839-
elif hash_regex in (HASH.ORACLE_OLD, HASH.POSTGRES):
840-
item = [(user, hash_), {'username': user}]
841-
elif hash_regex in (HASH.ORACLE,):
842-
item = [(user, hash_), {'salt': hash_[-20:]}]
843-
elif hash_regex in (HASH.MSSQL, HASH.MSSQL_OLD, HASH.MSSQL_NEW):
844-
item = [(user, hash_), {'salt': hash_[6:14]}]
845-
elif hash_regex in (HASH.CRYPT_GENERIC,):
846-
item = [(user, hash_), {'salt': hash_[0:2]}]
847-
elif hash_regex in (HASH.UNIX_MD5_CRYPT, HASH.APACHE_MD5_CRYPT):
848-
item = [(user, hash_), {'salt': hash_.split('$')[2], 'magic': '$%s$' % hash_.split('$')[1]}]
849-
elif hash_regex in (HASH.JOOMLA, HASH.VBULLETIN, HASH.VBULLETIN_OLD):
850-
item = [(user, hash_), {'salt': hash_.split(':')[-1]}]
851-
elif hash_regex in (HASH.WORDPRESS,):
852-
if ITOA64.index(hash_[3]) < 32:
853-
item = [(user, hash_), {'salt': hash_[4:12], 'count': 1 << ITOA64.index(hash_[3]), 'prefix': hash_[:12]}]
854-
else:
855-
warnMsg = "invalid hash '%s'" % hash_
856-
logger.warn(warnMsg)
857-
858-
if item and hash_ not in keys:
859-
resumed = hashDBRetrieve(hash_)
860-
if not resumed:
861-
attack_info.append(item)
862-
user_hash.append(item[0])
863-
else:
864-
infoMsg = "resuming password '%s' for hash '%s'" % (resumed, hash_)
865-
if user and not user.startswith(DUMMY_USER_PREFIX):
866-
infoMsg += " for user '%s'" % user
867-
logger.info(infoMsg)
868-
resumes.append((user, hash_, resumed))
869-
keys.add(hash_)
907+
except (binascii.Error, IndexError):
908+
pass
870909

871910
if not attack_info:
872911
continue
@@ -875,7 +914,7 @@ def dictionaryAttack(attack_dict):
875914
while not kb.wordlists:
876915

877916
# the slowest of all methods hence smaller default dict
878-
if hash_regex in (HASH.ORACLE_OLD, HASH.WORDPRESS):
917+
if hash_regex in (HASH.ORACLE_OLD,):
879918
dictPaths = [paths.SMALL_DICT]
880919
else:
881920
dictPaths = [paths.WORDLIST]

0 commit comments

Comments
 (0)