sqlmap/lib/utils/hash.py

1215 lines
43 KiB
Python
Raw Normal View History

#!/usr/bin/env python
"""
2018-01-02 02:48:10 +03:00
Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/)
2017-10-11 15:50:46 +03:00
See the file 'LICENSE' for copying permission
"""
2011-03-27 00:10:31 +03:00
try:
from crypt import crypt
2018-07-09 13:20:18 +03:00
except: # removed ImportError because of https://github.com/sqlmapproject/sqlmap/issues/3171
2012-07-14 19:01:04 +04:00
from thirdparty.fcrypt.fcrypt import crypt
2011-03-27 00:10:31 +03:00
_multiprocessing = None
try:
import multiprocessing
2011-07-20 17:00:34 +04:00
2011-07-27 01:28:48 +04:00
# problems on FreeBSD (Reference: http://www.eggheadcafe.com/microsoft/Python/35880259/multiprocessing-on-freebsd.aspx)
2011-07-28 03:26:36 +04:00
_ = multiprocessing.Queue()
2018-02-28 11:44:45 +03:00
# problems with ctypes (Reference: https://github.com/sqlmapproject/sqlmap/issues/2952)
_ = multiprocessing.Value('i')
2011-07-31 12:52:48 +04:00
except (ImportError, OSError):
pass
2011-07-28 03:26:36 +04:00
else:
2014-12-02 12:23:10 +03:00
try:
if multiprocessing.cpu_count() > 1:
_multiprocessing = multiprocessing
except NotImplementedError:
pass
import base64
import binascii
2013-03-19 15:27:49 +04:00
import gc
import os
import re
import tempfile
import time
2016-05-03 12:38:47 +03:00
import zipfile
from hashlib import md5
from hashlib import sha1
2013-03-05 14:04:46 +04:00
from hashlib import sha224
from hashlib import sha256
2013-03-05 14:04:46 +04:00
from hashlib import sha384
from hashlib import sha512
from Queue import Queue
from lib.core.common import Backend
from lib.core.common import checkFile
from lib.core.common import clearConsoleLine
from lib.core.common import dataToStdout
from lib.core.common import getFileItems
from lib.core.common import getPublicTypeMembers
from lib.core.common import getSafeExString
2016-04-12 23:10:26 +03:00
from lib.core.common import getUnicode
from lib.core.common import hashDBRetrieve
from lib.core.common import hashDBWrite
from lib.core.common import normalizeUnicode
from lib.core.common import paths
from lib.core.common import readInput
from lib.core.common import singleTimeLogMessage
from lib.core.common import singleTimeWarnMessage
from lib.core.convert import hexdecode
from lib.core.convert import hexencode
from lib.core.convert import utf8encode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.enums import DBMS
from lib.core.enums import HASH
2016-05-31 14:02:26 +03:00
from lib.core.enums import MKSTEMP_PREFIX
2016-05-03 12:38:47 +03:00
from lib.core.exception import SqlmapDataException
from lib.core.exception import SqlmapUserQuitException
from lib.core.settings import COMMON_PASSWORD_SUFFIXES
from lib.core.settings import COMMON_USER_COLUMNS
2017-10-31 12:10:22 +03:00
from lib.core.settings import DEV_EMAIL_ADDRESS
from lib.core.settings import DUMMY_USER_PREFIX
from lib.core.settings import HASH_EMPTY_PASSWORD_MARKER
2011-03-29 16:08:07 +04:00
from lib.core.settings import HASH_MOD_ITEM_DISPLAY
2011-12-23 00:54:20 +04:00
from lib.core.settings import HASH_RECOGNITION_QUIT_THRESHOLD
from lib.core.settings import IS_WIN
from lib.core.settings import ITOA64
2012-12-04 20:04:32 +04:00
from lib.core.settings import NULL
from lib.core.settings import UNICODE_ENCODING
from lib.core.settings import ROTATING_CHARS
2012-02-16 13:46:41 +04:00
from lib.core.wordlist import Wordlist
from thirdparty.colorama.initialise import init as coloramainit
2017-12-13 12:22:25 +03:00
from thirdparty.oset.pyoset import oset
2012-07-14 19:01:04 +04:00
from thirdparty.pydes.pyDes import des
from thirdparty.pydes.pyDes import CBC
def mysql_passwd(password, uppercase=True):
"""
Reference(s):
http://csl.sublevel3.org/mysql-password-function/
>>> mysql_passwd(password='testpass', uppercase=True)
'*00E247AC5F9AF26AE0194B41E1E769DEE1429A29'
"""
retVal = "*%s" % sha1(sha1(password).digest()).hexdigest()
return retVal.upper() if uppercase else retVal.lower()
2013-01-10 16:18:44 +04:00
def mysql_old_passwd(password, uppercase=True): # prior to version '4.1'
"""
Reference(s):
http://www.sfr-fresh.com/unix/privat/tpop3d-1.5.5.tar.gz:a/tpop3d-1.5.5/password.c
http://voidnetwork.org/5ynL0rd/darkc0de/python_script/darkMySQLi.html
>>> mysql_old_passwd(password='testpass', uppercase=True)
'7DCDA0D57290B453'
"""
a, b, c = 1345345333, 7, 0x12345671
for d in password:
if d == ' ' or d == '\t':
continue
e = ord(d)
a ^= (((a & 63) + b) * e) + (a << 8)
c += (c << 8) ^ a
b += e
retVal = "%08lx%08lx" % (a & ((1 << 31) - 1), c & ((1 << 31) - 1))
return retVal.upper() if uppercase else retVal.lower()
def postgres_passwd(password, username, uppercase=False):
"""
Reference(s):
http://pentestmonkey.net/blog/cracking-postgres-hashes/
>>> postgres_passwd(password='testpass', username='testuser', uppercase=False)
'md599e5ea7a6f7c3269995cba3927fd0093'
"""
2016-01-04 14:09:08 +03:00
if isinstance(username, unicode):
username = unicode.encode(username, UNICODE_ENCODING)
if isinstance(password, unicode):
password = unicode.encode(password, UNICODE_ENCODING)
retVal = "md5%s" % md5(password + username).hexdigest()
return retVal.upper() if uppercase else retVal.lower()
def mssql_passwd(password, salt, uppercase=False):
"""
Reference(s):
http://www.leidecker.info/projects/phrasendrescher/mssql.c
https://www.evilfingers.com/tools/GSAuditor.php
>>> mssql_passwd(password='testpass', salt='4086ceb6', uppercase=False)
'0x01004086ceb60c90646a8ab9889fe3ed8e5c150b5460ece8425a'
"""
binsalt = hexdecode(salt)
2017-11-10 15:03:24 +03:00
unistr = "".join(("%s\0" if ord(_) < 256 else "%s") % utf8encode(_) for _ in password)
retVal = "0100%s%s" % (salt, sha1(unistr + binsalt).hexdigest())
return "0x%s" % (retVal.upper() if uppercase else retVal.lower())
2013-01-10 16:18:44 +04:00
def mssql_old_passwd(password, salt, uppercase=True): # prior to version '2005'
"""
Reference(s):
www.exploit-db.com/download_pdf/15537/
http://www.leidecker.info/projects/phrasendrescher/mssql.c
https://www.evilfingers.com/tools/GSAuditor.php
>>> mssql_old_passwd(password='testpass', salt='4086ceb6', uppercase=True)
'0x01004086CEB60C90646A8AB9889FE3ED8E5C150B5460ECE8425AC7BB7255C0C81D79AA5D0E93D4BB077FB9A51DA0'
"""
binsalt = hexdecode(salt)
2017-11-10 15:03:24 +03:00
unistr = "".join(("%s\0" if ord(_) < 256 else "%s") % utf8encode(_) for _ in password)
retVal = "0100%s%s%s" % (salt, sha1(unistr + binsalt).hexdigest(), sha1(unistr.upper() + binsalt).hexdigest())
return "0x%s" % (retVal.upper() if uppercase else retVal.lower())
def mssql_new_passwd(password, salt, uppercase=False):
"""
Reference(s):
http://hashcat.net/forum/thread-1474.html
>>> mssql_new_passwd(password='testpass', salt='4086ceb6', uppercase=False)
'0x02004086ceb6eb051cdbc5bdae68ffc66c918d4977e592f6bdfc2b444a7214f71fa31c35902c5b7ae773ed5f4c50676d329120ace32ee6bc81c24f70711eb0fc6400e85ebf25'
"""
binsalt = hexdecode(salt)
2017-11-10 15:03:24 +03:00
unistr = "".join(("%s\0" if ord(_) < 256 else "%s") % utf8encode(_) for _ in password)
retVal = "0200%s%s" % (salt, sha512(unistr + binsalt).hexdigest())
return "0x%s" % (retVal.upper() if uppercase else retVal.lower())
def oracle_passwd(password, salt, uppercase=True):
"""
Reference(s):
https://www.evilfingers.com/tools/GSAuditor.php
http://www.notesbit.com/index.php/scripts-oracle/oracle-11g-new-password-algorithm-is-revealed-by-seclistsorg/
http://seclists.org/bugtraq/2007/Sep/304
>>> oracle_passwd(password='SHAlala', salt='1B7B5F82B7235E9E182C', uppercase=True)
'S:2BFCFDF5895014EE9BB2B9BA067B01E0389BB5711B7B5F82B7235E9E182C'
"""
binsalt = hexdecode(salt)
2013-01-10 16:18:44 +04:00
retVal = "s:%s%s" % (sha1(utf8encode(password) + binsalt).hexdigest(), salt)
return retVal.upper() if uppercase else retVal.lower()
2013-01-10 16:18:44 +04:00
def oracle_old_passwd(password, username, uppercase=True): # prior to version '11g'
"""
Reference(s):
http://www.notesbit.com/index.php/scripts-oracle/oracle-11g-new-password-algorithm-is-revealed-by-seclistsorg/
>>> oracle_old_passwd(password='tiger', username='scott', uppercase=True)
'F894844C34402B67'
"""
2011-11-22 02:12:24 +04:00
2013-01-10 16:18:44 +04:00
IV, pad = "\0" * 8, "\0"
if isinstance(username, unicode):
2016-01-04 14:09:08 +03:00
username = unicode.encode(username, UNICODE_ENCODING)
2015-11-29 21:40:14 +03:00
if isinstance(password, unicode):
password = unicode.encode(password, UNICODE_ENCODING)
unistr = "".join("\0%s" % c for c in (username + password).upper())
cipher = des(hexdecode("0123456789ABCDEF"), CBC, IV, pad)
encrypted = cipher.encrypt(unistr)
cipher = des(encrypted[-8:], CBC, IV, pad)
encrypted = cipher.encrypt(unistr)
retVal = hexencode(encrypted[-8:])
return retVal.upper() if uppercase else retVal.lower()
def md5_generic_passwd(password, uppercase=False):
"""
>>> md5_generic_passwd(password='testpass', uppercase=False)
'179ad45c6ce2cb97cf1029e212046e81'
"""
retVal = md5(password).hexdigest()
return retVal.upper() if uppercase else retVal.lower()
def sha1_generic_passwd(password, uppercase=False):
"""
>>> sha1_generic_passwd(password='testpass', uppercase=False)
'206c80413b9a96c1312cc346b7d2517b84463edd'
"""
retVal = sha1(password).hexdigest()
return retVal.upper() if uppercase else retVal.lower()
def apache_sha1_passwd(password, **kwargs):
"""
>>> apache_sha1_passwd(password='testpass')
'{SHA}IGyAQTualsExLMNGt9JRe4RGPt0='
"""
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)
2013-03-05 14:04:46 +04:00
def sha224_generic_passwd(password, uppercase=False):
"""
>>> sha224_generic_passwd(password='testpass', uppercase=False)
'648db6019764b598f75ab6b7616d2e82563a00eb1531680e19ac4c6f'
"""
retVal = sha224(password).hexdigest()
return retVal.upper() if uppercase else retVal.lower()
def sha256_generic_passwd(password, uppercase=False):
"""
>>> sha256_generic_passwd(password='testpass', uppercase=False)
'13d249f2cb4127b40cfa757866850278793f814ded3c587fe5889e889a7a9f6c'
"""
retVal = sha256(password).hexdigest()
return retVal.upper() if uppercase else retVal.lower()
2013-03-05 14:04:46 +04:00
def sha384_generic_passwd(password, uppercase=False):
"""
>>> sha384_generic_passwd(password='testpass', uppercase=False)
'6823546e56adf46849343be991d4b1be9b432e42ed1b4bb90635a0e4b930e49b9ca007bc3e04bf0a4e0df6f1f82769bf'
"""
retVal = sha384(password).hexdigest()
return retVal.upper() if uppercase else retVal.lower()
def sha512_generic_passwd(password, uppercase=False):
"""
>>> sha512_generic_passwd(password='testpass', uppercase=False)
'78ddc8555bb1677ff5af75ba5fc02cb30bb592b0610277ae15055e189b77fe3fda496e5027a3d99ec85d54941adee1cc174b50438fdc21d82d0a79f85b58cf44'
"""
retVal = sha512(password).hexdigest()
return retVal.upper() if uppercase else retVal.lower()
def crypt_generic_passwd(password, salt, **kwargs):
"""
Reference(s):
http://docs.python.org/library/crypt.html
http://helpful.knobs-dials.com/index.php/Hashing_notes
http://php.net/manual/en/function.crypt.php
http://carey.geek.nz/code/python-fcrypt/
>>> crypt_generic_passwd(password='rasmuslerdorf', salt='rl', uppercase=False)
'rl.3StKT.4T8M'
"""
return crypt(password, salt)
def unix_md5_passwd(password, salt, magic="$1$", **kwargs):
"""
Reference(s):
http://www.sabren.net/code/python/crypt/md5crypt.py
>>> unix_md5_passwd(password='testpass', salt='aD9ZLmkp')
'$1$aD9ZLmkp$DRM5a7rRZGyuuOPOjTEk61'
"""
def _encode64(value, count):
output = ""
while (count - 1 >= 0):
count = count - 1
output += ITOA64[value & 0x3f]
value = value >> 6
return output
if isinstance(password, unicode):
password = password.encode(UNICODE_ENCODING)
2017-12-01 12:32:44 +03:00
if isinstance(magic, unicode):
magic = magic.encode(UNICODE_ENCODING)
if isinstance(salt, unicode):
salt = salt.encode(UNICODE_ENCODING)
salt = salt[:8]
ctx = password + magic + salt
final = md5(password + salt + password).digest()
for pl in xrange(len(password), 0, -16):
if pl > 16:
ctx = ctx + final[:16]
else:
ctx = ctx + final[:pl]
i = len(password)
while i:
if i & 1:
ctx = ctx + chr(0) # if ($i & 1) { $ctx->add(pack("C", 0)); }
else:
ctx = ctx + password[0]
i = i >> 1
final = md5(ctx).digest()
for i in xrange(1000):
ctx1 = ""
if i & 1:
ctx1 = ctx1 + password
else:
ctx1 = ctx1 + final[:16]
if i % 3:
ctx1 = ctx1 + salt
if i % 7:
ctx1 = ctx1 + password
if i & 1:
ctx1 = ctx1 + final[:16]
else:
ctx1 = ctx1 + password
final = md5(ctx1).digest()
hash_ = _encode64((int(ord(final[0])) << 16) | (int(ord(final[6])) << 8) | (int(ord(final[12]))), 4)
hash_ = hash_ + _encode64((int(ord(final[1])) << 16) | (int(ord(final[7])) << 8) | (int(ord(final[13]))), 4)
hash_ = hash_ + _encode64((int(ord(final[2])) << 16) | (int(ord(final[8])) << 8) | (int(ord(final[14]))), 4)
hash_ = hash_ + _encode64((int(ord(final[3])) << 16) | (int(ord(final[9])) << 8) | (int(ord(final[15]))), 4)
hash_ = hash_ + _encode64((int(ord(final[4])) << 16) | (int(ord(final[10])) << 8) | (int(ord(final[5]))), 4)
hash_ = hash_ + _encode64((int(ord(final[11]))), 2)
return "%s%s$%s" % (magic, salt, hash_)
def joomla_passwd(password, salt, **kwargs):
"""
Reference: https://stackoverflow.com/a/10428239
>>> joomla_passwd(password='testpass', salt='6GGlnaquVXI80b3HRmSyE3K1wEFFaBIf')
'e3d5794da74e917637332e0d21b76328:6GGlnaquVXI80b3HRmSyE3K1wEFFaBIf'
"""
return "%s:%s" % (md5("%s%s" % (password, salt)).hexdigest(), salt)
def django_md5_passwd(password, salt, **kwargs):
"""
Reference: https://github.com/jay0lee/GAM/blob/master/src/passlib/handlers/django.py
>>> django_md5_passwd(password='testpass', salt='salt')
'md5$salt$972141bcbcb6a0acc96e92309175b3c5'
"""
return "md5$%s$%s" % (salt, md5("%s%s" % (salt, password)).hexdigest())
def django_sha1_passwd(password, salt, **kwargs):
"""
Reference: https://github.com/jay0lee/GAM/blob/master/src/passlib/handlers/django.py
>>> django_sha1_passwd(password='testpass', salt='salt')
'sha1$salt$6ce0e522aba69d8baa873f01420fccd0250fc5b2'
"""
return "sha1$%s$%s" % (salt, sha1("%s%s" % (salt, password)).hexdigest())
def vbulletin_passwd(password, salt, **kwargs):
"""
Reference: https://stackoverflow.com/a/2202810
>>> vbulletin_passwd(password='testpass', salt='salt')
'85c4d8ea77ebef2236fb7e9d24ba9482:salt'
"""
return "%s:%s" % (md5("%s%s" % (md5(password).hexdigest(), salt)).hexdigest(), salt)
def wordpress_passwd(password, salt, count, prefix, **kwargs):
"""
Reference(s):
http://packetstormsecurity.org/files/74448/phpassbrute.py.txt
http://scriptserver.mainframe8.com/wordpress_password_hasher.php
>>> wordpress_passwd(password='testpass', salt='aD9ZLmkp', count=2048, prefix='$P$9aD9ZLmkp')
2011-11-22 02:12:24 +04:00
'$P$9aD9ZLmkpsN4A83G8MefaaP888gVKX0'
"""
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)
2013-01-10 16:18:44 +04:00
output = output + ITOA64[(value >> 6) & 0x3f]
i += 1
if i >= count:
break
if i < count:
value = value | (ord(input_[i]) << 16)
2013-01-10 16:18:44 +04:00
output = output + ITOA64[(value >> 12) & 0x3f]
i += 1
if i >= count:
break
2013-01-10 16:18:44 +04:00
output = output + ITOA64[(value >> 18) & 0x3f]
return output
2015-11-29 21:40:14 +03:00
if isinstance(password, unicode):
password = password.encode(UNICODE_ENCODING)
2015-09-29 11:10:39 +03:00
cipher = md5(salt)
2015-09-29 11:10:39 +03:00
cipher.update(password)
hash_ = cipher.digest()
for i in xrange(count):
_ = md5(hash_)
_.update(password)
hash_ = _.digest()
return "%s%s" % (prefix, _encode64(hash_, 16))
__functions__ = {
HASH.MYSQL: mysql_passwd,
HASH.MYSQL_OLD: mysql_old_passwd,
HASH.POSTGRES: postgres_passwd,
HASH.MSSQL: mssql_passwd,
HASH.MSSQL_OLD: mssql_old_passwd,
HASH.MSSQL_NEW: mssql_new_passwd,
HASH.ORACLE: oracle_passwd,
HASH.ORACLE_OLD: oracle_old_passwd,
HASH.MD5_GENERIC: md5_generic_passwd,
HASH.SHA1_GENERIC: sha1_generic_passwd,
HASH.SHA224_GENERIC: sha224_generic_passwd,
HASH.SHA256_GENERIC: sha256_generic_passwd,
HASH.SHA384_GENERIC: sha384_generic_passwd,
HASH.SHA512_GENERIC: sha512_generic_passwd,
HASH.CRYPT_GENERIC: crypt_generic_passwd,
HASH.JOOMLA: joomla_passwd,
HASH.DJANGO_MD5: django_md5_passwd,
HASH.DJANGO_SHA1: django_sha1_passwd,
HASH.WORDPRESS: wordpress_passwd,
HASH.APACHE_MD5_CRYPT: unix_md5_passwd,
HASH.UNIX_MD5_CRYPT: unix_md5_passwd,
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,
HASH.MD5_BASE64: md5_generic_passwd,
HASH.SHA1_BASE64: sha1_generic_passwd,
HASH.SHA256_BASE64: sha256_generic_passwd,
HASH.SHA512_BASE64: sha512_generic_passwd,
}
2012-12-04 19:47:34 +04:00
def storeHashesToFile(attack_dict):
if not attack_dict:
return
2017-12-13 12:22:25 +03:00
items = oset()
for user, hashes in attack_dict.items():
for hash_ in hashes:
hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_
if hash_ and hash_ != NULL and hashRecognition(hash_):
item = None
if user and not user.startswith(DUMMY_USER_PREFIX):
item = "%s:%s\n" % (user.encode(UNICODE_ENCODING), hash_.encode(UNICODE_ENCODING))
else:
item = "%s\n" % hash_.encode(UNICODE_ENCODING)
if item and item not in items:
items.add(item)
if kb.storeHashesChoice is None:
message = "do you want to store hashes to a temporary file "
message += "for eventual further processing with other tools [y/N] "
2017-04-18 16:48:05 +03:00
kb.storeHashesChoice = readInput(message, default='N', boolean=True)
2017-12-14 17:45:14 +03:00
if items and kb.storeHashesChoice:
2017-12-13 12:22:25 +03:00
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.HASHES, suffix=".txt")
os.close(handle)
2017-12-13 12:22:25 +03:00
infoMsg = "writing hashes to a temporary file '%s' " % filename
logger.info(infoMsg)
2013-02-13 18:10:31 +04:00
2017-12-13 12:22:25 +03:00
with open(filename, "w+") as f:
for item in items:
f.write(item)
2012-12-04 19:47:34 +04:00
def attackCachedUsersPasswords():
if kb.data.cachedUsersPasswords:
results = dictionaryAttack(kb.data.cachedUsersPasswords)
2013-02-04 20:43:58 +04:00
lut = {}
2011-11-01 23:58:22 +04:00
for (_, hash_, password) in results:
2013-02-04 20:43:58 +04:00
lut[hash_.lower()] = password
for user in kb.data.cachedUsersPasswords.keys():
for i in xrange(len(kb.data.cachedUsersPasswords[user])):
2014-12-14 01:32:18 +03:00
if (kb.data.cachedUsersPasswords[user][i] or "").strip():
value = kb.data.cachedUsersPasswords[user][i].lower().split()[0]
if value in lut:
kb.data.cachedUsersPasswords[user][i] += "%s clear-text password: %s" % ('\n' if kb.data.cachedUsersPasswords[user][i][-1] != '\n' else '', lut[value])
def attackDumpedTable():
if kb.data.dumpedTable:
table = kb.data.dumpedTable
columns = table.keys()
count = table["__infos__"]["count"]
2012-01-07 21:45:45 +04:00
if not count:
return
2017-10-31 13:48:17 +03:00
debugMsg = "analyzing table dump for possible password hashes"
logger.debug(debugMsg)
2012-01-07 21:45:45 +04:00
2011-12-23 00:54:20 +04:00
found = False
col_user = ''
col_passwords = set()
attack_dict = {}
2018-12-17 19:03:51 +03:00
for column in sorted(columns, key=lambda _: len(_), reverse=True):
if column and column.lower() in COMMON_USER_COLUMNS:
col_user = column
break
2011-07-26 00:17:44 +04:00
for i in xrange(count):
2011-12-23 00:54:20 +04:00
if not found and i > HASH_RECOGNITION_QUIT_THRESHOLD:
break
for column in columns:
if column == col_user or column == "__infos__":
continue
if len(table[column]["values"]) <= i:
continue
value = table[column]["values"][i]
2011-10-26 15:24:15 +04:00
if hashRecognition(value):
2011-12-23 00:54:20 +04:00
found = True
if col_user and i < len(table[col_user]["values"]):
if table[col_user]["values"][i] not in attack_dict:
attack_dict[table[col_user]["values"][i]] = []
attack_dict[table[col_user]["values"][i]].append(value)
else:
attack_dict["%s%d" % (DUMMY_USER_PREFIX, i)] = [value]
col_passwords.add(column)
if attack_dict:
2012-12-04 19:47:34 +04:00
infoMsg = "recognized possible password hashes in column%s " % ("s" if len(col_passwords) > 1 else "")
infoMsg += "'%s'" % ", ".join(col for col in col_passwords)
logger.info(infoMsg)
storeHashesToFile(attack_dict)
message = "do you want to crack them via a dictionary-based attack? %s" % ("[y/N/q]" if conf.multipleTargets else "[Y/n/q]")
2017-04-19 15:46:27 +03:00
choice = readInput(message, default='N' if conf.multipleTargets else 'Y').upper()
2017-04-18 16:48:05 +03:00
if choice == 'N':
return
2017-04-18 16:48:05 +03:00
elif choice == 'Q':
raise SqlmapUserQuitException
results = dictionaryAttack(attack_dict)
2011-11-01 23:58:22 +04:00
lut = dict()
2011-10-26 14:30:32 +04:00
for (_, hash_, password) in results:
2011-11-01 23:58:22 +04:00
if hash_:
2016-06-17 18:07:44 +03:00
lut[hash_.lower()] = password
2011-10-26 14:30:32 +04:00
2017-10-31 13:48:17 +03:00
debugMsg = "post-processing table dump"
logger.debug(debugMsg)
2011-11-02 11:06:07 +04:00
2011-11-01 23:58:22 +04:00
for i in xrange(count):
for column in columns:
if not (column == col_user or column == '__infos__' or len(table[column]['values']) <= i):
2011-11-01 23:58:22 +04:00
value = table[column]['values'][i]
2011-11-01 23:58:22 +04:00
if value and value.lower() in lut:
table[column]['values'][i] = "%s (%s)" % (getUnicode(table[column]['values'][i]), getUnicode(lut[value.lower()] or HASH_EMPTY_PASSWORD_MARKER))
2011-11-01 23:58:22 +04:00
table[column]['length'] = max(table[column]['length'], len(table[column]['values'][i]))
2011-10-26 15:24:15 +04:00
def hashRecognition(value):
retVal = None
2011-10-26 15:24:15 +04:00
isOracle, isMySQL = Backend.isDbms(DBMS.ORACLE), Backend.isDbms(DBMS.MYSQL)
2011-04-06 12:30:50 +04:00
if isinstance(value, basestring):
for name, regex in getPublicTypeMembers(HASH):
# Hashes for Oracle and old MySQL look the same hence these checks
2018-01-31 12:50:34 +03:00
if isOracle and regex == HASH.MYSQL_OLD or isMySQL and regex == HASH.ORACLE_OLD:
continue
elif regex == HASH.CRYPT_GENERIC:
2011-12-27 16:31:29 +04:00
if any((value.lower() == value, value.upper() == value)):
continue
elif re.match(regex, value):
retVal = regex
break
return retVal
2017-04-20 11:29:05 +03:00
def _bruteProcessVariantA(attack_info, hash_regex, suffix, retVal, proc_id, proc_count, wordlists, custom_wordlist, api):
if IS_WIN:
coloramainit()
count = 0
rotator = 0
2018-01-31 12:50:34 +03:00
hashes = set(item[0][1] for item in attack_info)
2012-07-18 15:32:34 +04:00
wordlist = Wordlist(wordlists, proc_id, getattr(proc_count, "value", 0), custom_wordlist)
try:
for word in wordlist:
if not attack_info:
break
2018-03-03 01:38:07 +03:00
count += 1
if not isinstance(word, basestring):
continue
if suffix:
word = word + suffix
try:
2013-01-10 16:18:44 +04:00
current = __functions__[hash_regex](password=word, uppercase=False)
if current in hashes:
2011-12-20 20:08:17 +04:00
for item in attack_info[:]:
((user, hash_), _) = item
2011-10-26 13:29:41 +04:00
if hash_ == current:
retVal.put((user, hash_, word))
clearConsoleLine()
infoMsg = "\r[%s] [INFO] cracked password '%s'" % (time.strftime("%X"), word)
if user and not user.startswith(DUMMY_USER_PREFIX):
infoMsg += " for user '%s'\n" % user
else:
infoMsg += " for hash '%s'\n" % hash_
dataToStdout(infoMsg, True)
attack_info.remove(item)
2012-07-18 15:32:34 +04:00
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
2018-01-31 12:50:34 +03:00
status = "current status: %s... %s" % (word.ljust(5)[:5], ROTATING_CHARS[rotator])
2017-04-20 11:29:05 +03:00
if not api:
dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status))
except KeyboardInterrupt:
raise
2011-11-22 02:19:52 +04:00
except (UnicodeEncodeError, UnicodeDecodeError):
2013-01-10 16:18:44 +04:00
pass # ignore possible encoding problems caused by some words in custom dictionaries
2011-11-22 02:12:24 +04:00
2013-02-08 16:46:18 +04:00
except Exception, e:
warnMsg = "there was a problem while hashing entry: %s (%s). " % (repr(word), e)
2017-10-31 12:10:22 +03:00
warnMsg += "Please report by e-mail to '%s'" % DEV_EMAIL_ADDRESS
logger.critical(warnMsg)
except KeyboardInterrupt:
pass
finally:
2013-02-05 19:13:33 +04:00
if hasattr(proc_count, "value"):
with proc_count.get_lock():
proc_count.value -= 1
2017-04-20 11:29:05 +03:00
def _bruteProcessVariantB(user, hash_, kwargs, hash_regex, suffix, retVal, found, proc_id, proc_count, wordlists, custom_wordlist, api):
if IS_WIN:
coloramainit()
count = 0
rotator = 0
2012-07-18 15:32:34 +04:00
wordlist = Wordlist(wordlists, proc_id, getattr(proc_count, "value", 0), custom_wordlist)
try:
for word in wordlist:
2011-07-13 00:32:19 +04:00
if found.value:
break
count += 1
if not isinstance(word, basestring):
continue
if suffix:
word = word + suffix
try:
2018-03-03 01:38:07 +03:00
current = __functions__[hash_regex](password=word, uppercase=False, **kwargs)
if hash_ == current:
2013-01-10 16:18:44 +04:00
if hash_regex == HASH.ORACLE_OLD: # only for cosmetic purposes
word = word.upper()
retVal.put((user, hash_, word))
clearConsoleLine()
2011-10-26 13:29:41 +04:00
infoMsg = "\r[%s] [INFO] cracked password '%s'" % (time.strftime("%X"), word)
if user and not user.startswith(DUMMY_USER_PREFIX):
infoMsg += " for user '%s'\n" % user
else:
infoMsg += " for hash '%s'\n" % hash_
dataToStdout(infoMsg, True)
found.value = True
elif (proc_id == 0 or getattr(proc_count, "value", 0) == 1) and count % HASH_MOD_ITEM_DISPLAY == 0:
rotator += 1
2018-01-31 12:50:34 +03:00
if rotator >= len(ROTATING_CHARS):
rotator = 0
2018-01-31 12:50:34 +03:00
status = "current status: %s... %s" % (word.ljust(5)[:5], ROTATING_CHARS[rotator])
2014-12-26 01:05:34 +03:00
if user and not user.startswith(DUMMY_USER_PREFIX):
2018-01-31 12:50:34 +03:00
status += " (user: %s)" % user
2017-04-20 11:29:05 +03:00
if not api:
dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status))
except KeyboardInterrupt:
raise
2011-11-22 02:19:52 +04:00
except (UnicodeEncodeError, UnicodeDecodeError):
2013-01-10 16:18:44 +04:00
pass # ignore possible encoding problems caused by some words in custom dictionaries
2011-11-22 02:12:24 +04:00
2012-12-17 17:29:19 +04:00
except Exception, e:
warnMsg = "there was a problem while hashing entry: %s (%s). " % (repr(word), e)
2017-10-31 12:10:22 +03:00
warnMsg += "Please report by e-mail to '%s'" % DEV_EMAIL_ADDRESS
logger.critical(warnMsg)
except KeyboardInterrupt:
pass
finally:
2013-02-05 19:13:33 +04:00
if hasattr(proc_count, "value"):
with proc_count.get_lock():
proc_count.value -= 1
def dictionaryAttack(attack_dict):
suffix_list = [""]
2014-12-30 18:11:33 +03:00
custom_wordlist = [""]
hash_regexes = []
results = []
2011-11-01 23:58:22 +04:00
resumes = []
user_hash = []
2015-08-23 21:27:01 +03:00
processException = False
foundHash = False
for (_, hashes) in attack_dict.items():
for hash_ in hashes:
if not hash_:
continue
2014-11-05 11:56:50 +03:00
hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_
regex = hashRecognition(hash_)
if regex and regex not in hash_regexes:
hash_regexes.append(regex)
2011-07-13 00:49:27 +04:00
infoMsg = "using hash method '%s'" % __functions__[regex].func_name
logger.info(infoMsg)
for hash_regex in hash_regexes:
2011-10-27 01:56:26 +04:00
keys = set()
attack_info = []
for (user, hashes) in attack_dict.items():
for hash_ in hashes:
if not hash_:
continue
2015-08-23 21:27:01 +03:00
foundHash = True
2014-11-05 11:56:50 +03:00
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, HASH.SSHA, HASH.SSHA256, HASH.SSHA512, HASH.DJANGO_MD5, HASH.DJANGO_SHA1, HASH.MD5_BASE64, HASH.SHA1_BASE64, HASH.SHA256_BASE64, HASH.SHA512_BASE64):
hash_ = hash_.lower()
if hash_regex in (HASH.MD5_BASE64, HASH.SHA1_BASE64, HASH.SHA256_BASE64, HASH.SHA512_BASE64):
item = [(user, hash_.decode("base64").encode("hex")), {}]
elif hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC, HASH.SHA224_GENERIC, HASH.SHA256_GENERIC, HASH.SHA384_GENERIC, HASH.SHA512_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,):
item = [(user, hash_), {"salt": hash_[-20:]}]
elif hash_regex in (HASH.MSSQL, HASH.MSSQL_OLD, HASH.MSSQL_NEW):
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.UNIX_MD5_CRYPT, HASH.APACHE_MD5_CRYPT):
item = [(user, hash_), {"salt": hash_.split('$')[2], "magic": "$%s$" % hash_.split('$')[1]}]
elif hash_regex in (HASH.JOOMLA, HASH.VBULLETIN, HASH.VBULLETIN_OLD):
item = [(user, hash_), {"salt": hash_.split(':')[-1]}]
2017-10-31 13:39:12 +03:00
elif hash_regex in (HASH.DJANGO_MD5, HASH.DJANGO_SHA1):
item = [(user, hash_), {"salt": hash_.split('$')[1]}]
elif hash_regex in (HASH.WORDPRESS,):
if ITOA64.index(hash_[3]) < 32:
item = [(user, hash_), {"salt": hash_[4:12], "count": 1 << ITOA64.index(hash_[3]), "prefix": hash_[:12]}]
else:
warnMsg = "invalid hash '%s'" % hash_
logger.warn(warnMsg)
if item and hash_ not in keys:
resumed = hashDBRetrieve(hash_)
if not resumed:
attack_info.append(item)
user_hash.append(item[0])
else:
infoMsg = "resuming password '%s' for hash '%s'" % (resumed, hash_)
if user and not user.startswith(DUMMY_USER_PREFIX):
infoMsg += " for user '%s'" % user
logger.info(infoMsg)
resumes.append((user, hash_, resumed))
keys.add(hash_)
except (binascii.Error, IndexError):
pass
if not attack_info:
continue
2012-07-18 15:32:34 +04:00
if not kb.wordlists:
while not kb.wordlists:
2011-11-22 02:27:47 +04:00
# the slowest of all methods hence smaller default dict
if hash_regex in (HASH.ORACLE_OLD,):
2011-11-22 02:27:47 +04:00
dictPaths = [paths.SMALL_DICT]
else:
dictPaths = [paths.WORDLIST]
message = "what dictionary do you want to use?\n"
2011-11-22 02:27:47 +04:00
message += "[1] default dictionary file '%s' (press Enter)\n" % dictPaths[0]
2011-07-01 14:04:34 +04:00
message += "[2] custom dictionary file\n"
message += "[3] file with list of dictionary files"
2017-04-19 14:56:29 +03:00
choice = readInput(message, default='1')
try:
2017-04-19 14:56:29 +03:00
if choice == '2':
message = "what's the custom dictionary's location?\n"
2017-10-12 16:08:09 +03:00
dictPath = readInput(message)
if dictPath:
dictPaths = [dictPath]
2017-04-19 14:56:29 +03:00
logger.info("using custom dictionary")
elif choice == '3':
message = "what's the list file location?\n"
listPath = readInput(message)
checkFile(listPath)
dictPaths = getFileItems(listPath)
2011-07-01 14:04:34 +04:00
logger.info("using custom list of dictionaries")
else:
2011-07-01 14:04:34 +04:00
logger.info("using default dictionary")
2014-10-31 18:45:26 +03:00
dictPaths = filter(None, dictPaths)
for dictPath in dictPaths:
checkFile(dictPath)
2016-05-03 12:38:47 +03:00
if os.path.splitext(dictPath)[1].lower() == ".zip":
_ = zipfile.ZipFile(dictPath, 'r')
if len(_.namelist()) == 0:
errMsg = "no file(s) inside '%s'" % dictPath
raise SqlmapDataException(errMsg)
else:
_.open(_.namelist()[0])
2012-07-18 15:32:34 +04:00
kb.wordlists = dictPaths
2011-10-27 02:37:04 +04:00
2014-12-30 12:35:56 +03:00
except Exception, ex:
warnMsg = "there was a problem while loading dictionaries"
warnMsg += " ('%s')" % getSafeExString(ex)
logger.critical(warnMsg)
message = "do you want to use common password suffixes? (slow!) [y/N] "
2017-04-18 16:48:05 +03:00
if readInput(message, default='N', boolean=True):
suffix_list += COMMON_PASSWORD_SUFFIXES
2011-07-13 00:49:27 +04:00
infoMsg = "starting dictionary-based cracking (%s)" % __functions__[hash_regex].func_name
logger.info(infoMsg)
for item in attack_info:
((user, _), _) = item
2011-10-26 14:30:32 +04:00
if user and not user.startswith(DUMMY_USER_PREFIX):
2012-07-18 15:32:34 +04:00
custom_wordlist.append(normalizeUnicode(user))
# Algorithms without extra arguments (e.g. salt and/or username)
if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC, HASH.SHA224_GENERIC, HASH.SHA256_GENERIC, HASH.SHA384_GENERIC, HASH.SHA512_GENERIC, HASH.APACHE_SHA1, HASH.VBULLETIN, HASH.VBULLETIN_OLD):
for suffix in suffix_list:
2012-11-30 15:13:34 +04:00
if not attack_info or processException:
break
if suffix:
clearConsoleLine()
2011-07-13 00:49:27 +04:00
infoMsg = "using suffix '%s'" % suffix
logger.info(infoMsg)
retVal = None
2011-10-26 15:10:15 +04:00
processes = []
try:
2012-07-18 15:32:34 +04:00
if _multiprocessing:
if _multiprocessing.cpu_count() > 1:
infoMsg = "starting %d processes " % _multiprocessing.cpu_count()
singleTimeLogMessage(infoMsg)
2013-03-19 15:27:49 +04:00
gc.disable()
retVal = _multiprocessing.Queue()
count = _multiprocessing.Value('i', _multiprocessing.cpu_count())
for i in xrange(_multiprocessing.cpu_count()):
2017-04-20 11:29:05 +03:00
process = _multiprocessing.Process(target=_bruteProcessVariantA, args=(attack_info, hash_regex, suffix, retVal, i, count, kb.wordlists, custom_wordlist, conf.api))
processes.append(process)
2017-04-20 11:29:05 +03:00
for process in processes:
process.daemon = True
process.start()
2013-02-05 19:13:33 +04:00
while count.value > 0:
time.sleep(0.5)
else:
warnMsg = "multiprocessing hash cracking is currently "
warnMsg += "not supported on this platform"
singleTimeWarnMessage(warnMsg)
retVal = Queue()
2017-04-20 11:29:05 +03:00
_bruteProcessVariantA(attack_info, hash_regex, suffix, retVal, 0, 1, kb.wordlists, custom_wordlist, conf.api)
except KeyboardInterrupt:
print
processException = True
2011-10-26 13:14:18 +04:00
warnMsg = "user aborted during dictionary-based attack phase (Ctrl+C was pressed)"
logger.warn(warnMsg)
2011-10-26 15:10:15 +04:00
for process in processes:
2012-10-25 12:21:36 +04:00
try:
process.terminate()
process.join()
2014-12-04 15:36:41 +03:00
except (OSError, AttributeError):
2012-10-25 12:21:36 +04:00
pass
2011-10-26 15:10:15 +04:00
2011-11-02 13:57:42 +04:00
finally:
2013-03-19 15:27:49 +04:00
if _multiprocessing:
gc.enable()
2011-11-02 13:57:42 +04:00
if retVal:
2018-12-17 19:38:47 +03:00
if conf.hashDB:
conf.hashDB.beginTransaction()
2011-11-22 02:18:04 +04:00
2011-11-02 13:57:42 +04:00
while not retVal.empty():
2012-11-05 18:10:49 +04:00
user, hash_, word = item = retVal.get(block=False)
attack_info = filter(lambda _: _[0][0] != user or _[0][1] != hash_, attack_info)
hashDBWrite(hash_, word)
2011-11-02 13:57:42 +04:00
results.append(item)
2011-11-22 02:18:04 +04:00
2018-12-17 19:38:47 +03:00
if conf.hashDB:
conf.hashDB.endTransaction()
clearConsoleLine()
else:
for ((user, hash_), kwargs) in attack_info:
2011-10-26 13:14:18 +04:00
if processException:
break
2012-11-05 18:10:49 +04:00
if any(_[0] == user and _[1] == hash_ for _ in results):
continue
count = 0
found = False
for suffix in suffix_list:
if found or processException:
break
if suffix:
clearConsoleLine()
2011-07-13 00:49:27 +04:00
infoMsg = "using suffix '%s'" % suffix
logger.info(infoMsg)
retVal = None
2011-10-26 15:10:15 +04:00
processes = []
try:
2012-07-18 15:32:34 +04:00
if _multiprocessing:
if _multiprocessing.cpu_count() > 1:
infoMsg = "starting %d processes " % _multiprocessing.cpu_count()
singleTimeLogMessage(infoMsg)
2013-03-19 15:27:49 +04:00
gc.disable()
retVal = _multiprocessing.Queue()
found_ = _multiprocessing.Value('i', False)
count = _multiprocessing.Value('i', _multiprocessing.cpu_count())
for i in xrange(_multiprocessing.cpu_count()):
2017-04-20 11:29:05 +03:00
process = _multiprocessing.Process(target=_bruteProcessVariantB, args=(user, hash_, kwargs, hash_regex, suffix, retVal, found_, i, count, kb.wordlists, custom_wordlist, conf.api))
processes.append(process)
2017-04-20 11:29:05 +03:00
for process in processes:
process.daemon = True
process.start()
2013-02-05 19:13:33 +04:00
while count.value > 0:
time.sleep(0.5)
found = found_.value != 0
else:
warnMsg = "multiprocessing hash cracking is currently "
warnMsg += "not supported on this platform"
singleTimeWarnMessage(warnMsg)
class Value():
pass
retVal = Queue()
found_ = Value()
found_.value = False
2017-04-20 11:29:05 +03:00
_bruteProcessVariantB(user, hash_, kwargs, hash_regex, suffix, retVal, found_, 0, 1, kb.wordlists, custom_wordlist, conf.api)
found = found_.value
except KeyboardInterrupt:
print
processException = True
2011-10-26 13:14:18 +04:00
warnMsg = "user aborted during dictionary-based attack phase (Ctrl+C was pressed)"
logger.warn(warnMsg)
2011-10-26 15:10:15 +04:00
for process in processes:
2012-10-25 12:21:36 +04:00
try:
process.terminate()
process.join()
2014-12-04 15:36:41 +03:00
except (OSError, AttributeError):
2012-10-25 12:21:36 +04:00
pass
2011-10-26 15:10:15 +04:00
2011-11-02 13:57:42 +04:00
finally:
2013-03-19 15:27:49 +04:00
if _multiprocessing:
gc.enable()
2018-12-17 19:38:47 +03:00
if retVal and conf.hashDB:
if conf.hashDB:
conf.hashDB.beginTransaction()
2011-11-22 02:18:04 +04:00
2011-11-02 13:57:42 +04:00
while not retVal.empty():
2012-11-05 18:10:49 +04:00
user, hash_, word = item = retVal.get(block=False)
hashDBWrite(hash_, word)
2011-11-02 13:57:42 +04:00
results.append(item)
2011-11-22 02:18:04 +04:00
2018-12-17 19:38:47 +03:00
if conf.hashDB:
conf.hashDB.endTransaction()
clearConsoleLine()
2011-11-01 23:58:22 +04:00
results.extend(resumes)
2015-08-23 21:27:01 +03:00
if foundHash and len(hash_regexes) == 0:
warnMsg = "unknown hash format"
logger.warn(warnMsg)
if len(results) == 0:
2011-04-30 17:20:05 +04:00
warnMsg = "no clear password(s) found"
logger.warn(warnMsg)
return results
2018-12-17 19:38:47 +03:00
def crackHashFile(hashFile):
i = 0
attack_dict = {}
for line in getFileItems(conf.hashFile):
if ':' in line:
user, hash_ = line.split(':', 1)
attack_dict[user] = [hash_]
else:
attack_dict["%s%d" % (DUMMY_USER_PREFIX, i)] = [line]
i += 1
dictionaryAttack(attack_dict)