mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-31 11:59:04 +00:00
implementing WordPress phpass hash cracking routine
This commit is contained in:
@@ -73,6 +73,7 @@ class HASH:
|
||||
MD5_GENERIC = r'(?i)\A[0-9a-f]{32}\Z'
|
||||
SHA1_GENERIC = r'(?i)\A[0-9a-f]{40}\Z'
|
||||
CRYPT_GENERIC = r'(?i)\A[./0-9A-Za-z]{13}\Z'
|
||||
WORDPRESS = r'(?i)\A\$P\$[./0-9A-Za-z]{31}\Z'
|
||||
|
||||
# Reference: http://www.zytrax.com/tech/web/mobile_ids.html
|
||||
class MOBILES:
|
||||
|
||||
@@ -365,6 +365,9 @@ REFLECTIVE_MISS_THRESHOLD = 20
|
||||
# Regular expression used for extracting HTML title
|
||||
HTML_TITLE_REGEX = "<title>(?P<result>[^<]+)</title>"
|
||||
|
||||
# Table used for Base64 conversion in WordPress hash cracking routine
|
||||
ITOA64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
|
||||
|
||||
# Chars used to quickly distinguish if the user provided tainted parameter values
|
||||
DUMMY_SQL_INJECTION_CHARS = ";()'"
|
||||
|
||||
@@ -402,4 +405,7 @@ PARAMETER_SPLITTING_REGEX = r'[,|;]'
|
||||
UNION_CHAR_REGEX = r'\A\w+\Z'
|
||||
|
||||
# Attribute used for storing original parameter value in special cases (e.g. POST)
|
||||
UNENCODED_ORIGINAL_VALUE = 'original'
|
||||
UNENCODED_ORIGINAL_VALUE = 'original'
|
||||
|
||||
# Common column names containing usernames (used for hash cracking in some cases)
|
||||
COMMON_USER_COLUMNS = ('user', 'username', 'user_name', 'benutzername', 'benutzer', 'utilisateur', 'usager', 'consommateur', 'utente', 'utilizzatore', 'usufrutuario', 'korisnik', 'usuario', 'consumidor')
|
||||
@@ -58,10 +58,12 @@ from lib.core.enums import HASH
|
||||
from lib.core.exception import sqlmapFilePathException
|
||||
from lib.core.exception import sqlmapUserQuitException
|
||||
from lib.core.settings import COMMON_PASSWORD_SUFFIXES
|
||||
from lib.core.settings import COMMON_USER_COLUMNS
|
||||
from lib.core.settings import DUMMY_USER_PREFIX
|
||||
from lib.core.settings import GENERAL_IP_ADDRESS_REGEX
|
||||
from lib.core.settings import HASH_MOD_ITEM_DISPLAY
|
||||
from lib.core.settings import IS_WIN
|
||||
from lib.core.settings import ITOA64
|
||||
from lib.core.settings import PYVERSION
|
||||
from lib.core.settings import ML
|
||||
from lib.core.settings import UNICODE_ENCODING
|
||||
@@ -214,6 +216,7 @@ def sha1_generic_passwd(password, uppercase=False):
|
||||
|
||||
return retVal.upper() if uppercase else retVal.lower()
|
||||
|
||||
|
||||
def crypt_generic_passwd(password, salt, uppercase=False):
|
||||
"""
|
||||
Reference(s):
|
||||
@@ -230,6 +233,60 @@ def crypt_generic_passwd(password, salt, uppercase=False):
|
||||
|
||||
return retVal.upper() if uppercase else retVal
|
||||
|
||||
def wordpress_passwd(password, salt, count, prefix, uppercase=False):
|
||||
"""
|
||||
Reference(s):
|
||||
http://packetstormsecurity.org/files/74448/phpassbrute.py.txt
|
||||
http://scriptserver.mainframe8.com/wordpress_password_hasher.php
|
||||
|
||||
>>> wordpress_passwd(password='testpass', salt='dYPSjeF4', count=2048)
|
||||
''
|
||||
"""
|
||||
|
||||
def _encode64(input_, count):
|
||||
output = ''
|
||||
i = 0
|
||||
|
||||
while i < count:
|
||||
value = ord(input_[i])
|
||||
i += 1
|
||||
output = output + ITOA64[value & 0x3f]
|
||||
|
||||
if i < count:
|
||||
value = value | (ord(input_[i]) << 8)
|
||||
|
||||
output = output + ITOA64[(value>>6) & 0x3f]
|
||||
|
||||
i += 1
|
||||
if i >= count:
|
||||
break
|
||||
|
||||
if i < count:
|
||||
value = value | (ord(input_[i]) << 16)
|
||||
|
||||
output = output + ITOA64[(value>>12) & 0x3f]
|
||||
|
||||
i += 1
|
||||
if i >= count:
|
||||
break
|
||||
|
||||
output = output + ITOA64[(value>>18) & 0x3f]
|
||||
|
||||
return output
|
||||
|
||||
cipher = md5(salt)
|
||||
cipher.update(password)
|
||||
hash_ = cipher.digest()
|
||||
|
||||
for i in xrange(count):
|
||||
_ = md5(hash_)
|
||||
_.update(password)
|
||||
hash_ = _.digest()
|
||||
|
||||
retVal = prefix + _encode64(hash_, 16)
|
||||
|
||||
return retVal.upper() if uppercase else retVal
|
||||
|
||||
__functions__ = {
|
||||
HASH.MYSQL: mysql_passwd,
|
||||
HASH.MYSQL_OLD: mysql_old_passwd,
|
||||
@@ -240,7 +297,8 @@ __functions__ = {
|
||||
HASH.ORACLE_OLD: oracle_old_passwd,
|
||||
HASH.MD5_GENERIC: md5_generic_passwd,
|
||||
HASH.SHA1_GENERIC: sha1_generic_passwd,
|
||||
HASH.CRYPT_GENERIC: crypt_generic_passwd
|
||||
HASH.CRYPT_GENERIC: crypt_generic_passwd,
|
||||
HASH.WORDPRESS: wordpress_passwd
|
||||
}
|
||||
|
||||
def attackCachedUsersPasswords():
|
||||
@@ -268,7 +326,7 @@ def attackDumpedTable():
|
||||
attack_dict = {}
|
||||
|
||||
for column in columns:
|
||||
if column and column.lower() in ('user', 'username', 'user_name'):
|
||||
if column and column.lower() in COMMON_USER_COLUMNS:
|
||||
colUser = column
|
||||
break
|
||||
|
||||
@@ -385,7 +443,7 @@ def __bruteProcessVariantA(attack_info, hash_regex, wordlist, suffix, retVal, pr
|
||||
|
||||
attack_info.remove(item)
|
||||
|
||||
elif proc_id == 0 and count % HASH_MOD_ITEM_DISPLAY == 0 or hash_regex == HASH.ORACLE_OLD or hash_regex == HASH.CRYPT_GENERIC and IS_WIN:
|
||||
elif (proc_id == 0 or getattr(proc_count, 'value', 0) == 1) and count % HASH_MOD_ITEM_DISPLAY == 0 or hash_regex == HASH.ORACLE_OLD or hash_regex == HASH.CRYPT_GENERIC and IS_WIN:
|
||||
rotator += 1
|
||||
if rotator >= len(ROTATING_CHARS):
|
||||
rotator = 0
|
||||
@@ -404,6 +462,10 @@ def __bruteProcessVariantA(attack_info, hash_regex, wordlist, suffix, retVal, pr
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
finally:
|
||||
if hasattr(proc_count, 'value'):
|
||||
proc_count.value -= 1
|
||||
|
||||
def __bruteProcessVariantB(user, hash_, kwargs, hash_regex, wordlist, suffix, retVal, found, proc_id, proc_count):
|
||||
count = 0
|
||||
rotator = 0
|
||||
@@ -441,7 +503,8 @@ def __bruteProcessVariantB(user, hash_, kwargs, hash_regex, wordlist, suffix, re
|
||||
dataToStdout(infoMsg, True)
|
||||
|
||||
found.value = True
|
||||
elif proc_id == 0 and count % HASH_MOD_ITEM_DISPLAY == 0 or hash_regex == HASH.ORACLE_OLD or hash_regex == HASH.CRYPT_GENERIC and IS_WIN:
|
||||
|
||||
elif (proc_id == 0 or getattr(proc_count, 'value', 0) == 1) and count % HASH_MOD_ITEM_DISPLAY == 0 or hash_regex == HASH.ORACLE_OLD or hash_regex == HASH.CRYPT_GENERIC and IS_WIN:
|
||||
rotator += 1
|
||||
if rotator >= len(ROTATING_CHARS):
|
||||
rotator = 0
|
||||
@@ -461,6 +524,9 @@ def __bruteProcessVariantB(user, hash_, kwargs, hash_regex, wordlist, suffix, re
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
finally:
|
||||
if hasattr(proc_count, 'value'):
|
||||
proc_count.value -= 1
|
||||
|
||||
def dictionaryAttack(attack_dict):
|
||||
suffix_list = [""]
|
||||
@@ -491,11 +557,14 @@ def dictionaryAttack(attack_dict):
|
||||
if not hash_:
|
||||
continue
|
||||
|
||||
hash_ = hash_.split()[0].lower()
|
||||
hash_ = hash_.split()[0]
|
||||
|
||||
if getCompiledRegex(hash_regex).match(hash_):
|
||||
item = None
|
||||
|
||||
if hash_regex not in (HASH.CRYPT_GENERIC, HASH.WORDPRESS):
|
||||
hash_ = hash_.lower()
|
||||
|
||||
if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC):
|
||||
item = [(user, hash_), {}]
|
||||
elif hash_regex in (HASH.ORACLE_OLD, HASH.POSTGRES):
|
||||
@@ -506,6 +575,8 @@ def dictionaryAttack(attack_dict):
|
||||
item = [(user, hash_), {'salt': hash_[6:14]}]
|
||||
elif hash_regex in (HASH.CRYPT_GENERIC):
|
||||
item = [(user, hash_), {'salt': hash_[0:2]}]
|
||||
elif hash_regex in (HASH.WORDPRESS):
|
||||
item = [(user, hash_), {'salt': hash_[4:12], 'count': 1<<ITOA64.index(hash_[3]), 'prefix': hash_[:12]}]
|
||||
|
||||
if item and hash_ not in keys:
|
||||
resumed = conf.hashDB.retrieve(hash_)
|
||||
@@ -545,7 +616,7 @@ def dictionaryAttack(attack_dict):
|
||||
logger.info("using custom list of dictionaries")
|
||||
else:
|
||||
# It is the slowest of all methods hence smaller default dict
|
||||
if hash_regex == HASH.ORACLE_OLD:
|
||||
if hash_regex in (HASH.ORACLE_OLD, HASH.WORDPRESS):
|
||||
dictPaths = [paths.SMALL_DICT]
|
||||
else:
|
||||
dictPaths = [paths.WORDLIST]
|
||||
@@ -602,8 +673,10 @@ def dictionaryAttack(attack_dict):
|
||||
singleTimeLogMessage(infoMsg)
|
||||
|
||||
retVal = _multiprocessing.Queue()
|
||||
count = _multiprocessing.Value('i', _multiprocessing.cpu_count())
|
||||
|
||||
for i in xrange(_multiprocessing.cpu_count()):
|
||||
p = _multiprocessing.Process(target=__bruteProcessVariantA, args=(attack_info, hash_regex, kb.wordlist, suffix, retVal, i, _multiprocessing.cpu_count()))
|
||||
p = _multiprocessing.Process(target=__bruteProcessVariantA, args=(attack_info, hash_regex, kb.wordlist, suffix, retVal, i, count))
|
||||
processes.append(p)
|
||||
|
||||
for p in processes:
|
||||
@@ -671,9 +744,10 @@ def dictionaryAttack(attack_dict):
|
||||
|
||||
retVal = _multiprocessing.Queue()
|
||||
found_ = _multiprocessing.Value('i', False)
|
||||
count = _multiprocessing.Value('i', _multiprocessing.cpu_count())
|
||||
|
||||
for i in xrange(_multiprocessing.cpu_count()):
|
||||
p = _multiprocessing.Process(target=__bruteProcessVariantB, args=(user, hash_, kwargs, hash_regex, kb.wordlist, suffix, retVal, found_, i, _multiprocessing.cpu_count()))
|
||||
p = _multiprocessing.Process(target=__bruteProcessVariantB, args=(user, hash_, kwargs, hash_regex, kb.wordlist, suffix, retVal, found_, i, count))
|
||||
processes.append(p)
|
||||
|
||||
for p in processes:
|
||||
|
||||
Reference in New Issue
Block a user