Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/lib/utils/hash.py
2989 views
1
#!/usr/bin/env python
2
3
"""
4
Copyright (c) 2006-2025 sqlmap developers (https://sqlmap.org)
5
See the file 'LICENSE' for copying permission
6
"""
7
8
from __future__ import print_function
9
10
try:
11
from crypt import crypt
12
except: # removed ImportError because of https://github.com/sqlmapproject/sqlmap/issues/3171
13
from thirdparty.fcrypt.fcrypt import crypt
14
15
try:
16
from Crypto.Cipher.DES import MODE_CBC as CBC
17
from Crypto.Cipher.DES import new as des
18
except:
19
from thirdparty.pydes.pyDes import CBC
20
from thirdparty.pydes.pyDes import des
21
22
_multiprocessing = None
23
24
import base64
25
import binascii
26
import gc
27
import math
28
import os
29
import re
30
import tempfile
31
import time
32
import zipfile
33
34
from hashlib import md5
35
from hashlib import sha1
36
from hashlib import sha224
37
from hashlib import sha256
38
from hashlib import sha384
39
from hashlib import sha512
40
41
from lib.core.common import Backend
42
from lib.core.common import checkFile
43
from lib.core.common import clearConsoleLine
44
from lib.core.common import dataToStdout
45
from lib.core.common import getFileItems
46
from lib.core.common import getPublicTypeMembers
47
from lib.core.common import getSafeExString
48
from lib.core.common import hashDBRetrieve
49
from lib.core.common import hashDBWrite
50
from lib.core.common import isZipFile
51
from lib.core.common import normalizeUnicode
52
from lib.core.common import openFile
53
from lib.core.common import paths
54
from lib.core.common import readInput
55
from lib.core.common import singleTimeLogMessage
56
from lib.core.common import singleTimeWarnMessage
57
from lib.core.compat import xrange
58
from lib.core.convert import decodeBase64
59
from lib.core.convert import decodeHex
60
from lib.core.convert import encodeHex
61
from lib.core.convert import getBytes
62
from lib.core.convert import getText
63
from lib.core.convert import getUnicode
64
from lib.core.data import conf
65
from lib.core.data import kb
66
from lib.core.data import logger
67
from lib.core.datatype import OrderedSet
68
from lib.core.enums import DBMS
69
from lib.core.enums import HASH
70
from lib.core.enums import MKSTEMP_PREFIX
71
from lib.core.exception import SqlmapDataException
72
from lib.core.exception import SqlmapUserQuitException
73
from lib.core.settings import COMMON_PASSWORD_SUFFIXES
74
from lib.core.settings import COMMON_USER_COLUMNS
75
from lib.core.settings import DEV_EMAIL_ADDRESS
76
from lib.core.settings import DUMMY_USER_PREFIX
77
from lib.core.settings import HASH_BINARY_COLUMNS_REGEX
78
from lib.core.settings import HASH_EMPTY_PASSWORD_MARKER
79
from lib.core.settings import HASH_MOD_ITEM_DISPLAY
80
from lib.core.settings import HASH_RECOGNITION_QUIT_THRESHOLD
81
from lib.core.settings import INVALID_UNICODE_CHAR_FORMAT
82
from lib.core.settings import IS_WIN
83
from lib.core.settings import ITOA64
84
from lib.core.settings import NULL
85
from lib.core.settings import ROTATING_CHARS
86
from lib.core.settings import UNICODE_ENCODING
87
from lib.core.wordlist import Wordlist
88
from thirdparty import six
89
from thirdparty.colorama.initialise import init as coloramainit
90
from thirdparty.six.moves import queue as _queue
91
92
def mysql_passwd(password, uppercase=True):
93
"""
94
Reference(s):
95
https://web.archive.org/web/20120215205312/http://csl.sublevel3.org/mysql-password-function/
96
97
>>> mysql_passwd(password='testpass', uppercase=True)
98
'*00E247AC5F9AF26AE0194B41E1E769DEE1429A29'
99
"""
100
101
password = getBytes(password)
102
103
retVal = "*%s" % sha1(sha1(password).digest()).hexdigest()
104
105
return retVal.upper() if uppercase else retVal.lower()
106
107
def mysql_old_passwd(password, uppercase=True): # prior to version '4.1'
108
"""
109
Reference(s):
110
https://web.archive.org/web/20091205000600/http://www.sfr-fresh.com/unix/privat/tpop3d-1.5.5.tar.gz:a/tpop3d-1.5.5/password.c
111
https://github.com/pwnieexpress/pwn_plug_sources/blob/master/src/darkmysqli/DarkMySQLi.py
112
113
>>> mysql_old_passwd(password='testpass', uppercase=True)
114
'7DCDA0D57290B453'
115
"""
116
117
a, b, c = 1345345333, 7, 0x12345671
118
119
for d in password:
120
if d == ' ' or d == '\t':
121
continue
122
123
e = ord(d)
124
a ^= (((a & 63) + b) * e) + (a << 8)
125
c += (c << 8) ^ a
126
b += e
127
128
retVal = "%08lx%08lx" % (a & ((1 << 31) - 1), c & ((1 << 31) - 1))
129
130
return retVal.upper() if uppercase else retVal.lower()
131
132
def postgres_passwd(password, username, uppercase=False):
133
"""
134
Reference(s):
135
http://pentestmonkey.net/blog/cracking-postgres-hashes/
136
137
>>> postgres_passwd(password='testpass', username='testuser', uppercase=False)
138
'md599e5ea7a6f7c3269995cba3927fd0093'
139
"""
140
141
username = getBytes(username)
142
password = getBytes(password)
143
144
retVal = "md5%s" % md5(password + username).hexdigest()
145
146
return retVal.upper() if uppercase else retVal.lower()
147
148
def mssql_new_passwd(password, salt, uppercase=False): # since version '2012'
149
"""
150
Reference(s):
151
http://hashcat.net/forum/thread-1474.html
152
https://sqlity.net/en/2460/sql-password-hash/
153
154
>>> mssql_new_passwd(password='testpass', salt='4086ceb6', uppercase=False)
155
'0x02004086ceb6eb051cdbc5bdae68ffc66c918d4977e592f6bdfc2b444a7214f71fa31c35902c5b7ae773ed5f4c50676d329120ace32ee6bc81c24f70711eb0fc6400e85ebf25'
156
"""
157
158
binsalt = decodeHex(salt)
159
unistr = b"".join((_.encode(UNICODE_ENCODING) + b"\0") if ord(_) < 256 else _.encode(UNICODE_ENCODING) for _ in password)
160
161
retVal = "0200%s%s" % (salt, sha512(unistr + binsalt).hexdigest())
162
163
return "0x%s" % (retVal.upper() if uppercase else retVal.lower())
164
165
def mssql_passwd(password, salt, uppercase=False): # versions '2005' and '2008'
166
"""
167
Reference(s):
168
http://www.leidecker.info/projects/phrasendrescher/mssql.c
169
https://www.evilfingers.com/tools/GSAuditor.php
170
171
>>> mssql_passwd(password='testpass', salt='4086ceb6', uppercase=False)
172
'0x01004086ceb60c90646a8ab9889fe3ed8e5c150b5460ece8425a'
173
"""
174
175
binsalt = decodeHex(salt)
176
unistr = b"".join((_.encode(UNICODE_ENCODING) + b"\0") if ord(_) < 256 else _.encode(UNICODE_ENCODING) for _ in password)
177
178
retVal = "0100%s%s" % (salt, sha1(unistr + binsalt).hexdigest())
179
180
return "0x%s" % (retVal.upper() if uppercase else retVal.lower())
181
182
def mssql_old_passwd(password, salt, uppercase=True): # version '2000' and before
183
"""
184
Reference(s):
185
www.exploit-db.com/download_pdf/15537/
186
http://www.leidecker.info/projects/phrasendrescher/mssql.c
187
https://www.evilfingers.com/tools/GSAuditor.php
188
189
>>> mssql_old_passwd(password='testpass', salt='4086ceb6', uppercase=True)
190
'0x01004086CEB60C90646A8AB9889FE3ED8E5C150B5460ECE8425AC7BB7255C0C81D79AA5D0E93D4BB077FB9A51DA0'
191
"""
192
193
binsalt = decodeHex(salt)
194
unistr = b"".join((_.encode(UNICODE_ENCODING) + b"\0") if ord(_) < 256 else _.encode(UNICODE_ENCODING) for _ in password)
195
196
retVal = "0100%s%s%s" % (salt, sha1(unistr + binsalt).hexdigest(), sha1(unistr.upper() + binsalt).hexdigest())
197
198
return "0x%s" % (retVal.upper() if uppercase else retVal.lower())
199
200
def oracle_passwd(password, salt, uppercase=True):
201
"""
202
Reference(s):
203
https://www.evilfingers.com/tools/GSAuditor.php
204
http://www.notesbit.com/index.php/scripts-oracle/oracle-11g-new-password-algorithm-is-revealed-by-seclistsorg/
205
http://seclists.org/bugtraq/2007/Sep/304
206
207
>>> oracle_passwd(password='SHAlala', salt='1B7B5F82B7235E9E182C', uppercase=True)
208
'S:2BFCFDF5895014EE9BB2B9BA067B01E0389BB5711B7B5F82B7235E9E182C'
209
"""
210
211
binsalt = decodeHex(salt)
212
password = getBytes(password)
213
214
retVal = "s:%s%s" % (sha1(password + binsalt).hexdigest(), salt)
215
216
return retVal.upper() if uppercase else retVal.lower()
217
218
def oracle_old_passwd(password, username, uppercase=True): # prior to version '11g'
219
"""
220
Reference(s):
221
http://www.notesbit.com/index.php/scripts-oracle/oracle-11g-new-password-algorithm-is-revealed-by-seclistsorg/
222
223
>>> oracle_old_passwd(password='tiger', username='scott', uppercase=True)
224
'F894844C34402B67'
225
"""
226
227
IV, pad = b"\0" * 8, b"\0"
228
229
unistr = b"".join((b"\0" + _.encode(UNICODE_ENCODING)) if ord(_) < 256 else _.encode(UNICODE_ENCODING) for _ in (username + password).upper())
230
231
if des.__module__ == "Crypto.Cipher.DES":
232
unistr += b"\0" * ((8 - len(unistr) % 8) & 7)
233
cipher = des(decodeHex("0123456789ABCDEF"), CBC, iv=IV)
234
encrypted = cipher.encrypt(unistr)
235
cipher = des(encrypted[-8:], CBC, iv=IV)
236
encrypted = cipher.encrypt(unistr)
237
else:
238
cipher = des(decodeHex("0123456789ABCDEF"), CBC, IV, pad)
239
encrypted = cipher.encrypt(unistr)
240
cipher = des(encrypted[-8:], CBC, IV, pad)
241
encrypted = cipher.encrypt(unistr)
242
243
retVal = encodeHex(encrypted[-8:], binary=False)
244
245
return retVal.upper() if uppercase else retVal.lower()
246
247
def md5_generic_passwd(password, uppercase=False):
248
"""
249
>>> md5_generic_passwd(password='testpass', uppercase=False)
250
'179ad45c6ce2cb97cf1029e212046e81'
251
"""
252
253
password = getBytes(password)
254
255
retVal = md5(password).hexdigest()
256
257
return retVal.upper() if uppercase else retVal.lower()
258
259
def sha1_generic_passwd(password, uppercase=False):
260
"""
261
>>> sha1_generic_passwd(password='testpass', uppercase=False)
262
'206c80413b9a96c1312cc346b7d2517b84463edd'
263
"""
264
265
password = getBytes(password)
266
267
retVal = sha1(password).hexdigest()
268
269
return retVal.upper() if uppercase else retVal.lower()
270
271
def apache_sha1_passwd(password, **kwargs):
272
"""
273
>>> apache_sha1_passwd(password='testpass')
274
'{SHA}IGyAQTualsExLMNGt9JRe4RGPt0='
275
"""
276
277
password = getBytes(password)
278
279
return "{SHA}%s" % getText(base64.b64encode(sha1(password).digest()))
280
281
def ssha_passwd(password, salt, **kwargs):
282
"""
283
>>> ssha_passwd(password='testpass', salt='salt')
284
'{SSHA}mU1HPTvnmoXOhE4ROHP6sWfbfoRzYWx0'
285
"""
286
287
password = getBytes(password)
288
salt = getBytes(salt)
289
290
return "{SSHA}%s" % getText(base64.b64encode(sha1(password + salt).digest() + salt))
291
292
def ssha256_passwd(password, salt, **kwargs):
293
"""
294
>>> ssha256_passwd(password='testpass', salt='salt')
295
'{SSHA256}hhubsLrO/Aje9F/kJrgv5ZLE40UmTrVWvI7Dt6InP99zYWx0'
296
"""
297
298
password = getBytes(password)
299
salt = getBytes(salt)
300
301
return "{SSHA256}%s" % getText(base64.b64encode(sha256(password + salt).digest() + salt))
302
303
def ssha512_passwd(password, salt, **kwargs):
304
"""
305
>>> ssha512_passwd(password='testpass', salt='salt')
306
'{SSHA512}mCUSLfPMhXCQOJl9WHW/QMn9v9sjq7Ht/Wk7iVau8vLOfh+PeynkGMikqIE8sStFd0khdfcCD8xZmC6UyjTxsHNhbHQ='
307
"""
308
309
password = getBytes(password)
310
salt = getBytes(salt)
311
312
return "{SSHA512}%s" % getText(base64.b64encode(sha512(password + salt).digest() + salt))
313
314
def sha224_generic_passwd(password, uppercase=False):
315
"""
316
>>> sha224_generic_passwd(password='testpass', uppercase=False)
317
'648db6019764b598f75ab6b7616d2e82563a00eb1531680e19ac4c6f'
318
"""
319
320
retVal = sha224(getBytes(password)).hexdigest()
321
322
return retVal.upper() if uppercase else retVal.lower()
323
324
def sha256_generic_passwd(password, uppercase=False):
325
"""
326
>>> sha256_generic_passwd(password='testpass', uppercase=False)
327
'13d249f2cb4127b40cfa757866850278793f814ded3c587fe5889e889a7a9f6c'
328
"""
329
330
retVal = sha256(getBytes(password)).hexdigest()
331
332
return retVal.upper() if uppercase else retVal.lower()
333
334
def sha384_generic_passwd(password, uppercase=False):
335
"""
336
>>> sha384_generic_passwd(password='testpass', uppercase=False)
337
'6823546e56adf46849343be991d4b1be9b432e42ed1b4bb90635a0e4b930e49b9ca007bc3e04bf0a4e0df6f1f82769bf'
338
"""
339
340
retVal = sha384(getBytes(password)).hexdigest()
341
342
return retVal.upper() if uppercase else retVal.lower()
343
344
def sha512_generic_passwd(password, uppercase=False):
345
"""
346
>>> sha512_generic_passwd(password='testpass', uppercase=False)
347
'78ddc8555bb1677ff5af75ba5fc02cb30bb592b0610277ae15055e189b77fe3fda496e5027a3d99ec85d54941adee1cc174b50438fdc21d82d0a79f85b58cf44'
348
"""
349
350
retVal = sha512(getBytes(password)).hexdigest()
351
352
return retVal.upper() if uppercase else retVal.lower()
353
354
def crypt_generic_passwd(password, salt, **kwargs):
355
"""
356
Reference(s):
357
http://docs.python.org/library/crypt.html
358
http://helpful.knobs-dials.com/index.php/Hashing_notes
359
http://php.net/manual/en/function.crypt.php
360
http://carey.geek.nz/code/python-fcrypt/
361
362
>>> crypt_generic_passwd(password='rasmuslerdorf', salt='rl', uppercase=False)
363
'rl.3StKT.4T8M'
364
"""
365
366
return getText(crypt(password, salt))
367
368
def unix_md5_passwd(password, salt, magic="$1$", **kwargs):
369
"""
370
Reference(s):
371
http://www.sabren.net/code/python/crypt/md5crypt.py
372
373
>>> unix_md5_passwd(password='testpass', salt='aD9ZLmkp')
374
'$1$aD9ZLmkp$DRM5a7rRZGyuuOPOjTEk61'
375
"""
376
377
def _encode64(value, count):
378
output = ""
379
380
while (count - 1 >= 0):
381
count = count - 1
382
output += ITOA64[value & 0x3f]
383
value = value >> 6
384
385
return output
386
387
password = getBytes(password)
388
magic = getBytes(magic)
389
salt = getBytes(salt)
390
391
salt = salt[:8]
392
ctx = password + magic + salt
393
final = md5(password + salt + password).digest()
394
395
for pl in xrange(len(password), 0, -16):
396
if pl > 16:
397
ctx = ctx + final[:16]
398
else:
399
ctx = ctx + final[:pl]
400
401
i = len(password)
402
while i:
403
if i & 1:
404
ctx = ctx + b'\x00' # if ($i & 1) { $ctx->add(pack("C", 0)); }
405
else:
406
ctx = ctx + password[0:1]
407
i = i >> 1
408
409
final = md5(ctx).digest()
410
411
for i in xrange(1000):
412
ctx1 = b""
413
414
if i & 1:
415
ctx1 = ctx1 + password
416
else:
417
ctx1 = ctx1 + final[:16]
418
419
if i % 3:
420
ctx1 = ctx1 + salt
421
422
if i % 7:
423
ctx1 = ctx1 + password
424
425
if i & 1:
426
ctx1 = ctx1 + final[:16]
427
else:
428
ctx1 = ctx1 + password
429
430
final = md5(ctx1).digest()
431
432
hash_ = _encode64((int(ord(final[0:1])) << 16) | (int(ord(final[6:7])) << 8) | (int(ord(final[12:13]))), 4)
433
hash_ = hash_ + _encode64((int(ord(final[1:2])) << 16) | (int(ord(final[7:8])) << 8) | (int(ord(final[13:14]))), 4)
434
hash_ = hash_ + _encode64((int(ord(final[2:3])) << 16) | (int(ord(final[8:9])) << 8) | (int(ord(final[14:15]))), 4)
435
hash_ = hash_ + _encode64((int(ord(final[3:4])) << 16) | (int(ord(final[9:10])) << 8) | (int(ord(final[15:16]))), 4)
436
hash_ = hash_ + _encode64((int(ord(final[4:5])) << 16) | (int(ord(final[10:11])) << 8) | (int(ord(final[5:6]))), 4)
437
hash_ = hash_ + _encode64((int(ord(final[11:12]))), 2)
438
439
return getText(magic + salt + b'$' + getBytes(hash_))
440
441
def joomla_passwd(password, salt, **kwargs):
442
"""
443
Reference: https://stackoverflow.com/a/10428239
444
445
>>> joomla_passwd(password='testpass', salt='6GGlnaquVXI80b3HRmSyE3K1wEFFaBIf')
446
'e3d5794da74e917637332e0d21b76328:6GGlnaquVXI80b3HRmSyE3K1wEFFaBIf'
447
"""
448
449
return "%s:%s" % (md5(getBytes(password) + getBytes(salt)).hexdigest(), salt)
450
451
def django_md5_passwd(password, salt, **kwargs):
452
"""
453
Reference: https://github.com/jay0lee/GAM/blob/master/src/passlib/handlers/django.py
454
455
>>> django_md5_passwd(password='testpass', salt='salt')
456
'md5$salt$972141bcbcb6a0acc96e92309175b3c5'
457
"""
458
459
return "md5$%s$%s" % (salt, md5(getBytes(salt) + getBytes(password)).hexdigest())
460
461
def django_sha1_passwd(password, salt, **kwargs):
462
"""
463
Reference: https://github.com/jay0lee/GAM/blob/master/src/passlib/handlers/django.py
464
465
>>> django_sha1_passwd(password='testpass', salt='salt')
466
'sha1$salt$6ce0e522aba69d8baa873f01420fccd0250fc5b2'
467
"""
468
469
return "sha1$%s$%s" % (salt, sha1(getBytes(salt) + getBytes(password)).hexdigest())
470
471
def vbulletin_passwd(password, salt, **kwargs):
472
"""
473
Reference: https://stackoverflow.com/a/2202810
474
475
>>> vbulletin_passwd(password='testpass', salt='salt')
476
'85c4d8ea77ebef2236fb7e9d24ba9482:salt'
477
"""
478
479
return "%s:%s" % (md5(binascii.hexlify(md5(getBytes(password)).digest()) + getBytes(salt)).hexdigest(), salt)
480
481
def oscommerce_old_passwd(password, salt, **kwargs):
482
"""
483
Reference: http://ryanuber.com/09-24-2010/os-commerce-password-hashing.html
484
485
>>> oscommerce_old_passwd(password='testpass', salt='6b')
486
'16d39816e4545b3179f86f2d2d549af4:6b'
487
"""
488
489
return "%s:%s" % (md5(getBytes(salt) + getBytes(password)).hexdigest(), salt)
490
491
def phpass_passwd(password, salt, count, prefix, **kwargs):
492
"""
493
Reference(s):
494
https://web.archive.org/web/20120219120128/packetstormsecurity.org/files/74448/phpassbrute.py.txt
495
http://scriptserver.mainframe8.com/wordpress_password_hasher.php
496
https://www.openwall.com/phpass/
497
https://github.com/jedie/django-phpBB3/blob/master/django_phpBB3/hashers.py
498
499
>>> phpass_passwd(password='testpass', salt='aD9ZLmkp', count=2048, prefix='$P$')
500
'$P$9aD9ZLmkpsN4A83G8MefaaP888gVKX0'
501
>>> phpass_passwd(password='testpass', salt='Pb1j9gSb', count=2048, prefix='$H$')
502
'$H$9Pb1j9gSb/u3EVQ.4JDZ3LqtN44oIx/'
503
>>> phpass_passwd(password='testpass', salt='iwtD/g.K', count=128, prefix='$S$')
504
'$S$5iwtD/g.KZT2rwC9DASy/mGYAThkSd3lBFdkONi1Ig1IEpBpqG8W'
505
"""
506
507
def _encode64(input_, count):
508
output = ''
509
i = 0
510
511
while i < count:
512
value = (input_[i] if isinstance(input_[i], int) else ord(input_[i]))
513
i += 1
514
output = output + ITOA64[value & 0x3f]
515
516
if i < count:
517
value = value | ((input_[i] if isinstance(input_[i], int) else ord(input_[i])) << 8)
518
519
output = output + ITOA64[(value >> 6) & 0x3f]
520
521
i += 1
522
if i >= count:
523
break
524
525
if i < count:
526
value = value | ((input_[i] if isinstance(input_[i], int) else ord(input_[i])) << 16)
527
528
output = output + ITOA64[(value >> 12) & 0x3f]
529
530
i += 1
531
if i >= count:
532
break
533
534
output = output + ITOA64[(value >> 18) & 0x3f]
535
536
return output
537
538
password = getBytes(password)
539
f = {"$P$": md5, "$H$": md5, "$Q$": sha1, "$S$": sha512}[prefix]
540
541
cipher = f(getBytes(salt))
542
cipher.update(password)
543
hash_ = cipher.digest()
544
545
for i in xrange(count):
546
_ = f(hash_)
547
_.update(password)
548
hash_ = _.digest()
549
550
retVal = "%s%s%s%s" % (prefix, ITOA64[int(math.log(count, 2))], salt, _encode64(hash_, len(hash_)))
551
552
if prefix == "$S$":
553
# Reference: https://api.drupal.org/api/drupal/includes%21password.inc/constant/DRUPAL_HASH_LENGTH/7.x
554
retVal = retVal[:55]
555
556
return retVal
557
558
__functions__ = {
559
HASH.MYSQL: mysql_passwd,
560
HASH.MYSQL_OLD: mysql_old_passwd,
561
HASH.POSTGRES: postgres_passwd,
562
HASH.MSSQL: mssql_passwd,
563
HASH.MSSQL_OLD: mssql_old_passwd,
564
HASH.MSSQL_NEW: mssql_new_passwd,
565
HASH.ORACLE: oracle_passwd,
566
HASH.ORACLE_OLD: oracle_old_passwd,
567
HASH.MD5_GENERIC: md5_generic_passwd,
568
HASH.SHA1_GENERIC: sha1_generic_passwd,
569
HASH.SHA224_GENERIC: sha224_generic_passwd,
570
HASH.SHA256_GENERIC: sha256_generic_passwd,
571
HASH.SHA384_GENERIC: sha384_generic_passwd,
572
HASH.SHA512_GENERIC: sha512_generic_passwd,
573
HASH.CRYPT_GENERIC: crypt_generic_passwd,
574
HASH.JOOMLA: joomla_passwd,
575
HASH.DJANGO_MD5: django_md5_passwd,
576
HASH.DJANGO_SHA1: django_sha1_passwd,
577
HASH.PHPASS: phpass_passwd,
578
HASH.APACHE_MD5_CRYPT: unix_md5_passwd,
579
HASH.UNIX_MD5_CRYPT: unix_md5_passwd,
580
HASH.APACHE_SHA1: apache_sha1_passwd,
581
HASH.VBULLETIN: vbulletin_passwd,
582
HASH.VBULLETIN_OLD: vbulletin_passwd,
583
HASH.OSCOMMERCE_OLD: oscommerce_old_passwd,
584
HASH.SSHA: ssha_passwd,
585
HASH.SSHA256: ssha256_passwd,
586
HASH.SSHA512: ssha512_passwd,
587
HASH.MD5_BASE64: md5_generic_passwd,
588
HASH.SHA1_BASE64: sha1_generic_passwd,
589
HASH.SHA256_BASE64: sha256_generic_passwd,
590
HASH.SHA512_BASE64: sha512_generic_passwd,
591
}
592
593
def _finalize(retVal, results, processes, attack_info=None):
594
if _multiprocessing:
595
gc.enable()
596
597
# NOTE: https://github.com/sqlmapproject/sqlmap/issues/4367
598
# NOTE: https://dzone.com/articles/python-101-creating-multiple-processes
599
for process in processes:
600
try:
601
process.terminate()
602
process.join()
603
except (OSError, AttributeError):
604
pass
605
606
if retVal:
607
removals = set()
608
609
if conf.hashDB:
610
conf.hashDB.beginTransaction()
611
612
while not retVal.empty():
613
user, hash_, word = item = retVal.get(block=False)
614
results.append(item)
615
removals.add((user, hash_))
616
hashDBWrite(hash_, word)
617
618
for item in attack_info or []:
619
if (item[0][0], item[0][1]) in removals:
620
attack_info.remove(item)
621
622
if conf.hashDB:
623
conf.hashDB.endTransaction()
624
625
if hasattr(retVal, "close"):
626
retVal.close()
627
628
def storeHashesToFile(attack_dict):
629
if not attack_dict:
630
return
631
632
items = OrderedSet()
633
634
for user, hashes in attack_dict.items():
635
for hash_ in hashes:
636
hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_
637
if hash_ and hash_ != NULL and hashRecognition(hash_):
638
item = None
639
if user and not user.startswith(DUMMY_USER_PREFIX):
640
item = "%s:%s\n" % (user, hash_)
641
else:
642
item = "%s\n" % hash_
643
644
if item and item not in items:
645
items.add(item)
646
647
if kb.choices.storeHashes is None:
648
message = "do you want to store hashes to a temporary file "
649
message += "for eventual further processing with other tools [y/N] "
650
651
kb.choices.storeHashes = readInput(message, default='N', boolean=True)
652
653
if items and kb.choices.storeHashes:
654
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.HASHES, suffix=".txt")
655
os.close(handle)
656
657
infoMsg = "writing hashes to a temporary file '%s' " % filename
658
logger.info(infoMsg)
659
660
with openFile(filename, "w+") as f:
661
for item in items:
662
try:
663
f.write(item)
664
except (UnicodeError, TypeError):
665
pass
666
667
def attackCachedUsersPasswords():
668
if kb.data.cachedUsersPasswords:
669
results = dictionaryAttack(kb.data.cachedUsersPasswords)
670
671
lut = {}
672
for (_, hash_, password) in results:
673
lut[hash_.lower()] = password
674
675
for user in kb.data.cachedUsersPasswords:
676
for i in xrange(len(kb.data.cachedUsersPasswords[user])):
677
if (kb.data.cachedUsersPasswords[user][i] or "").strip():
678
value = kb.data.cachedUsersPasswords[user][i].lower().split()[0]
679
if value in lut:
680
kb.data.cachedUsersPasswords[user][i] += "%s clear-text password: %s" % ('\n' if kb.data.cachedUsersPasswords[user][i][-1] != '\n' else '', lut[value])
681
682
def attackDumpedTable():
683
if kb.data.dumpedTable:
684
table = kb.data.dumpedTable
685
columns = list(table.keys())
686
count = table["__infos__"]["count"]
687
688
if not count:
689
return
690
691
debugMsg = "analyzing table dump for possible password hashes"
692
logger.debug(debugMsg)
693
694
found = False
695
col_user = ''
696
col_passwords = set()
697
attack_dict = {}
698
binary_fields = OrderedSet()
699
replacements = {}
700
701
for column in sorted(columns, key=len, reverse=True):
702
if column and column.lower() in COMMON_USER_COLUMNS:
703
col_user = column
704
break
705
706
for column in columns:
707
if column != "__infos__" and table[column]["values"]:
708
if all(INVALID_UNICODE_CHAR_FORMAT.split('%')[0] in (value or "") for value in table[column]["values"]):
709
binary_fields.add(column)
710
711
if binary_fields:
712
_ = ','.join(binary_fields)
713
warnMsg = "potential binary fields detected ('%s'). In case of any problems you are " % _
714
warnMsg += "advised to rerun table dump with '--fresh-queries --binary-fields=\"%s\"'" % _
715
logger.warning(warnMsg)
716
717
for i in xrange(count):
718
if not found and i > HASH_RECOGNITION_QUIT_THRESHOLD:
719
break
720
721
for column in columns:
722
if column == col_user or column == "__infos__":
723
continue
724
725
if len(table[column]["values"]) <= i:
726
continue
727
728
if conf.binaryFields and column in conf.binaryFields:
729
continue
730
731
value = table[column]["values"][i]
732
733
if column in binary_fields and re.search(HASH_BINARY_COLUMNS_REGEX, column) is not None:
734
previous = value
735
value = encodeHex(getBytes(value), binary=False)
736
replacements[value] = previous
737
738
if hashRecognition(value):
739
found = True
740
741
if col_user and i < len(table[col_user]["values"]):
742
if table[col_user]["values"][i] not in attack_dict:
743
attack_dict[table[col_user]["values"][i]] = []
744
745
attack_dict[table[col_user]["values"][i]].append(value)
746
else:
747
attack_dict["%s%d" % (DUMMY_USER_PREFIX, i)] = [value]
748
749
col_passwords.add(column)
750
751
if attack_dict:
752
infoMsg = "recognized possible password hashes in column%s " % ("s" if len(col_passwords) > 1 else "")
753
infoMsg += "'%s'" % ", ".join(col for col in col_passwords)
754
logger.info(infoMsg)
755
756
storeHashesToFile(attack_dict)
757
758
message = "do you want to crack them via a dictionary-based attack? %s" % ("[y/N/q]" if conf.multipleTargets else "[Y/n/q]")
759
choice = readInput(message, default='N' if conf.multipleTargets else 'Y').upper()
760
761
if choice == 'N':
762
return
763
elif choice == 'Q':
764
raise SqlmapUserQuitException
765
766
results = dictionaryAttack(attack_dict)
767
lut = dict()
768
769
for (_, hash_, password) in results:
770
if hash_:
771
key = hash_ if hash_ not in replacements else replacements[hash_]
772
lut[key.lower()] = password
773
lut["0x%s" % key.lower()] = password
774
775
debugMsg = "post-processing table dump"
776
logger.debug(debugMsg)
777
778
for i in xrange(count):
779
for column in columns:
780
if not (column == col_user or column == '__infos__' or len(table[column]['values']) <= i):
781
value = table[column]['values'][i]
782
783
if value and value.lower() in lut:
784
table[column]['values'][i] = "%s (%s)" % (getUnicode(table[column]['values'][i]), getUnicode(lut[value.lower()] or HASH_EMPTY_PASSWORD_MARKER))
785
table[column]['length'] = max(table[column]['length'], len(table[column]['values'][i]))
786
787
def hashRecognition(value):
788
"""
789
>>> hashRecognition("179ad45c6ce2cb97cf1029e212046e81") == HASH.MD5_GENERIC
790
True
791
>>> hashRecognition("S:2BFCFDF5895014EE9BB2B9BA067B01E0389BB5711B7B5F82B7235E9E182C") == HASH.ORACLE
792
True
793
>>> hashRecognition("foobar") == None
794
True
795
"""
796
797
retVal = None
798
799
if value and len(value) >= 8 and ' ' not in value: # Note: pre-filter condition (for optimization purposes)
800
isOracle, isMySQL = Backend.isDbms(DBMS.ORACLE), Backend.isDbms(DBMS.MYSQL)
801
802
if kb.cache.hashRegex is None:
803
parts = []
804
805
for name, regex in getPublicTypeMembers(HASH):
806
# Hashes for Oracle and old MySQL look the same hence these checks
807
if isOracle and regex == HASH.MYSQL_OLD or isMySQL and regex == HASH.ORACLE_OLD:
808
continue
809
elif regex == HASH.CRYPT_GENERIC:
810
if any((value.lower() == value, value.upper() == value)):
811
continue
812
else:
813
parts.append("(?P<%s>%s)" % (name, regex))
814
815
kb.cache.hashRegex = ('|'.join(parts)).replace("(?i)", "")
816
817
if isinstance(value, six.string_types):
818
match = re.search(kb.cache.hashRegex, value, re.I)
819
if match:
820
algorithm, _ = [_ for _ in match.groupdict().items() if _[1] is not None][0]
821
retVal = getattr(HASH, algorithm)
822
823
return retVal
824
825
def _bruteProcessVariantA(attack_info, hash_regex, suffix, retVal, proc_id, proc_count, wordlists, custom_wordlist, api):
826
if IS_WIN:
827
coloramainit()
828
829
count = 0
830
rotator = 0
831
hashes = set(item[0][1] for item in attack_info)
832
833
wordlist = Wordlist(wordlists, proc_id, getattr(proc_count, "value", 0), custom_wordlist)
834
835
try:
836
for word in wordlist:
837
if not attack_info:
838
break
839
840
count += 1
841
842
if isinstance(word, six.binary_type):
843
word = getUnicode(word)
844
elif not isinstance(word, six.string_types):
845
continue
846
847
if suffix:
848
word = word + suffix
849
850
try:
851
current = __functions__[hash_regex](password=word, uppercase=False)
852
853
if current in hashes:
854
for item in attack_info[:]:
855
((user, hash_), _) = item
856
857
if hash_ == current:
858
retVal.put((user, hash_, word))
859
860
clearConsoleLine()
861
862
infoMsg = "\r[%s] [INFO] cracked password '%s'" % (time.strftime("%X"), word)
863
864
if user and not user.startswith(DUMMY_USER_PREFIX):
865
infoMsg += " for user '%s'\n" % user
866
else:
867
infoMsg += " for hash '%s'\n" % hash_
868
869
dataToStdout(infoMsg, True)
870
871
attack_info.remove(item)
872
873
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:
874
rotator += 1
875
876
if rotator >= len(ROTATING_CHARS):
877
rotator = 0
878
879
status = "current status: %s... %s" % (word.ljust(5)[:5], ROTATING_CHARS[rotator])
880
881
if not api:
882
dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status))
883
884
except KeyboardInterrupt:
885
raise
886
887
except (UnicodeEncodeError, UnicodeDecodeError):
888
pass # ignore possible encoding problems caused by some words in custom dictionaries
889
890
except Exception as ex:
891
warnMsg = "there was a problem while hashing entry: %s ('%s'). " % (repr(word), getSafeExString(ex))
892
warnMsg += "Please report by e-mail to '%s'" % DEV_EMAIL_ADDRESS
893
logger.critical(warnMsg)
894
895
except KeyboardInterrupt:
896
pass
897
898
finally:
899
if hasattr(proc_count, "value"):
900
with proc_count.get_lock():
901
proc_count.value -= 1
902
903
def _bruteProcessVariantB(user, hash_, kwargs, hash_regex, suffix, retVal, found, proc_id, proc_count, wordlists, custom_wordlist, api):
904
if IS_WIN:
905
coloramainit()
906
907
count = 0
908
rotator = 0
909
910
wordlist = Wordlist(wordlists, proc_id, getattr(proc_count, "value", 0), custom_wordlist)
911
912
try:
913
for word in wordlist:
914
if found.value:
915
break
916
917
count += 1
918
919
if isinstance(word, six.binary_type):
920
word = getUnicode(word)
921
elif not isinstance(word, six.string_types):
922
continue
923
924
if suffix:
925
word = word + suffix
926
927
try:
928
current = __functions__[hash_regex](password=word, uppercase=False, **kwargs)
929
930
if hash_ == current:
931
if hash_regex == HASH.ORACLE_OLD: # only for cosmetic purposes
932
word = word.upper()
933
934
retVal.put((user, hash_, word))
935
936
clearConsoleLine()
937
938
infoMsg = "\r[%s] [INFO] cracked password '%s'" % (time.strftime("%X"), word)
939
940
if user and not user.startswith(DUMMY_USER_PREFIX):
941
infoMsg += " for user '%s'\n" % user
942
else:
943
infoMsg += " for hash '%s'\n" % hash_
944
945
dataToStdout(infoMsg, True)
946
947
found.value = True
948
949
elif (proc_id == 0 or getattr(proc_count, "value", 0) == 1) and count % HASH_MOD_ITEM_DISPLAY == 0:
950
rotator += 1
951
952
if rotator >= len(ROTATING_CHARS):
953
rotator = 0
954
955
status = "current status: %s... %s" % (word.ljust(5)[:5], ROTATING_CHARS[rotator])
956
957
if user and not user.startswith(DUMMY_USER_PREFIX):
958
status += " (user: %s)" % user
959
960
if not api:
961
dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status))
962
963
except KeyboardInterrupt:
964
raise
965
966
except (UnicodeEncodeError, UnicodeDecodeError):
967
pass # ignore possible encoding problems caused by some words in custom dictionaries
968
969
except Exception as ex:
970
warnMsg = "there was a problem while hashing entry: %s ('%s'). " % (repr(word), getSafeExString(ex))
971
warnMsg += "Please report by e-mail to '%s'" % DEV_EMAIL_ADDRESS
972
logger.critical(warnMsg)
973
974
except KeyboardInterrupt:
975
pass
976
977
finally:
978
if hasattr(proc_count, "value"):
979
with proc_count.get_lock():
980
proc_count.value -= 1
981
982
def dictionaryAttack(attack_dict):
983
global _multiprocessing
984
985
suffix_list = [""]
986
custom_wordlist = [""]
987
hash_regexes = []
988
results = []
989
resumes = []
990
user_hash = []
991
processException = False
992
foundHash = False
993
994
if conf.disableMulti:
995
_multiprocessing = None
996
else:
997
# Note: https://github.com/sqlmapproject/sqlmap/issues/4367
998
try:
999
import multiprocessing
1000
1001
# problems on FreeBSD (Reference: https://web.archive.org/web/20110710041353/http://www.eggheadcafe.com/microsoft/Python/35880259/multiprocessing-on-freebsd.aspx)
1002
_ = multiprocessing.Queue()
1003
1004
# problems with ctypes (Reference: https://github.com/sqlmapproject/sqlmap/issues/2952)
1005
_ = multiprocessing.Value('i')
1006
except (ImportError, OSError, AttributeError):
1007
pass
1008
else:
1009
try:
1010
if multiprocessing.cpu_count() > 1:
1011
_multiprocessing = multiprocessing
1012
except NotImplementedError:
1013
pass
1014
1015
for (_, hashes) in attack_dict.items():
1016
for hash_ in hashes:
1017
if not hash_:
1018
continue
1019
1020
hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_
1021
regex = hashRecognition(hash_)
1022
1023
if regex and regex not in hash_regexes:
1024
hash_regexes.append(regex)
1025
infoMsg = "using hash method '%s'" % __functions__[regex].__name__
1026
logger.info(infoMsg)
1027
1028
for hash_regex in hash_regexes:
1029
keys = set()
1030
attack_info = []
1031
1032
for (user, hashes) in attack_dict.items():
1033
for hash_ in hashes:
1034
if not hash_:
1035
continue
1036
1037
foundHash = True
1038
hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_
1039
1040
if re.match(hash_regex, hash_):
1041
try:
1042
item = None
1043
1044
if hash_regex not in (HASH.CRYPT_GENERIC, HASH.JOOMLA, HASH.PHPASS, 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):
1045
hash_ = hash_.lower()
1046
1047
if hash_regex in (HASH.MD5_BASE64, HASH.SHA1_BASE64, HASH.SHA256_BASE64, HASH.SHA512_BASE64):
1048
item = [(user, encodeHex(decodeBase64(hash_, binary=True))), {}]
1049
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):
1050
if hash_.startswith("0x"): # Reference: https://docs.microsoft.com/en-us/sql/t-sql/functions/hashbytes-transact-sql?view=sql-server-2017
1051
hash_ = hash_[2:]
1052
item = [(user, hash_), {}]
1053
elif hash_regex in (HASH.SSHA,):
1054
item = [(user, hash_), {"salt": decodeBase64(hash_, binary=True)[20:]}]
1055
elif hash_regex in (HASH.SSHA256,):
1056
item = [(user, hash_), {"salt": decodeBase64(hash_, binary=True)[32:]}]
1057
elif hash_regex in (HASH.SSHA512,):
1058
item = [(user, hash_), {"salt": decodeBase64(hash_, binary=True)[64:]}]
1059
elif hash_regex in (HASH.ORACLE_OLD, HASH.POSTGRES):
1060
item = [(user, hash_), {'username': user}]
1061
elif hash_regex in (HASH.ORACLE,):
1062
item = [(user, hash_), {"salt": hash_[-20:]}]
1063
elif hash_regex in (HASH.MSSQL, HASH.MSSQL_OLD, HASH.MSSQL_NEW):
1064
item = [(user, hash_), {"salt": hash_[6:14]}]
1065
elif hash_regex in (HASH.CRYPT_GENERIC,):
1066
item = [(user, hash_), {"salt": hash_[0:2]}]
1067
elif hash_regex in (HASH.UNIX_MD5_CRYPT, HASH.APACHE_MD5_CRYPT):
1068
item = [(user, hash_), {"salt": hash_.split('$')[2], "magic": "$%s$" % hash_.split('$')[1]}]
1069
elif hash_regex in (HASH.JOOMLA, HASH.VBULLETIN, HASH.VBULLETIN_OLD, HASH.OSCOMMERCE_OLD):
1070
item = [(user, hash_), {"salt": hash_.split(':')[-1]}]
1071
elif hash_regex in (HASH.DJANGO_MD5, HASH.DJANGO_SHA1):
1072
item = [(user, hash_), {"salt": hash_.split('$')[1]}]
1073
elif hash_regex in (HASH.PHPASS,):
1074
if ITOA64.index(hash_[3]) < 32:
1075
item = [(user, hash_), {"salt": hash_[4:12], "count": 1 << ITOA64.index(hash_[3]), "prefix": hash_[:3]}]
1076
else:
1077
warnMsg = "invalid hash '%s'" % hash_
1078
logger.warning(warnMsg)
1079
1080
if item and hash_ not in keys:
1081
resumed = hashDBRetrieve(hash_)
1082
if not resumed:
1083
attack_info.append(item)
1084
user_hash.append(item[0])
1085
else:
1086
infoMsg = "resuming password '%s' for hash '%s'" % (resumed, hash_)
1087
if user and not user.startswith(DUMMY_USER_PREFIX):
1088
infoMsg += " for user '%s'" % user
1089
logger.info(infoMsg)
1090
resumes.append((user, hash_, resumed))
1091
keys.add(hash_)
1092
1093
except (binascii.Error, TypeError, IndexError):
1094
pass
1095
1096
if not attack_info:
1097
continue
1098
1099
if not kb.wordlists:
1100
while not kb.wordlists:
1101
1102
# the slowest of all methods hence smaller default dict
1103
if hash_regex in (HASH.ORACLE_OLD, HASH.PHPASS):
1104
dictPaths = [paths.SMALL_DICT]
1105
else:
1106
dictPaths = [paths.WORDLIST]
1107
1108
message = "what dictionary do you want to use?\n"
1109
message += "[1] default dictionary file '%s' (press Enter)\n" % dictPaths[0]
1110
message += "[2] custom dictionary file\n"
1111
message += "[3] file with list of dictionary files"
1112
choice = readInput(message, default='1')
1113
1114
try:
1115
if choice == '2':
1116
message = "what's the custom dictionary's location?\n"
1117
dictPath = readInput(message)
1118
if dictPath:
1119
dictPaths = [dictPath]
1120
logger.info("using custom dictionary")
1121
elif choice == '3':
1122
message = "what's the list file location?\n"
1123
listPath = readInput(message)
1124
checkFile(listPath)
1125
dictPaths = getFileItems(listPath)
1126
logger.info("using custom list of dictionaries")
1127
else:
1128
logger.info("using default dictionary")
1129
1130
dictPaths = [_ for _ in dictPaths if _]
1131
1132
for dictPath in dictPaths:
1133
checkFile(dictPath)
1134
1135
if isZipFile(dictPath):
1136
_ = zipfile.ZipFile(dictPath, 'r')
1137
if len(_.namelist()) == 0:
1138
errMsg = "no file(s) inside '%s'" % dictPath
1139
raise SqlmapDataException(errMsg)
1140
else:
1141
_.open(_.namelist()[0])
1142
1143
kb.wordlists = dictPaths
1144
1145
except Exception as ex:
1146
warnMsg = "there was a problem while loading dictionaries"
1147
warnMsg += " ('%s')" % getSafeExString(ex)
1148
logger.critical(warnMsg)
1149
1150
message = "do you want to use common password suffixes? (slow!) [y/N] "
1151
1152
if readInput(message, default='N', boolean=True):
1153
suffix_list += COMMON_PASSWORD_SUFFIXES
1154
1155
infoMsg = "starting dictionary-based cracking (%s)" % __functions__[hash_regex].__name__
1156
logger.info(infoMsg)
1157
1158
for item in attack_info:
1159
((user, _), _) = item
1160
if user and not user.startswith(DUMMY_USER_PREFIX):
1161
custom_wordlist.append(normalizeUnicode(user))
1162
1163
# Algorithms without extra arguments (e.g. salt and/or username)
1164
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):
1165
for suffix in suffix_list:
1166
if not attack_info or processException:
1167
break
1168
1169
if suffix:
1170
clearConsoleLine()
1171
infoMsg = "using suffix '%s'" % suffix
1172
logger.info(infoMsg)
1173
1174
retVal = None
1175
processes = []
1176
1177
try:
1178
if _multiprocessing:
1179
if _multiprocessing.cpu_count() > 1:
1180
infoMsg = "starting %d processes " % _multiprocessing.cpu_count()
1181
singleTimeLogMessage(infoMsg)
1182
1183
gc.disable()
1184
1185
retVal = _multiprocessing.Queue()
1186
count = _multiprocessing.Value('i', _multiprocessing.cpu_count())
1187
1188
for i in xrange(_multiprocessing.cpu_count()):
1189
process = _multiprocessing.Process(target=_bruteProcessVariantA, args=(attack_info, hash_regex, suffix, retVal, i, count, kb.wordlists, custom_wordlist, conf.api))
1190
processes.append(process)
1191
1192
for process in processes:
1193
process.daemon = True
1194
process.start()
1195
1196
while count.value > 0:
1197
time.sleep(0.5)
1198
1199
else:
1200
warnMsg = "multiprocessing hash cracking is currently "
1201
warnMsg += "%s on this platform" % ("not supported" if not conf.disableMulti else "disabled")
1202
singleTimeWarnMessage(warnMsg)
1203
1204
retVal = _queue.Queue()
1205
_bruteProcessVariantA(attack_info, hash_regex, suffix, retVal, 0, 1, kb.wordlists, custom_wordlist, conf.api)
1206
1207
except KeyboardInterrupt:
1208
print()
1209
processException = True
1210
warnMsg = "user aborted during dictionary-based attack phase (Ctrl+C was pressed)"
1211
logger.warning(warnMsg)
1212
1213
finally:
1214
_finalize(retVal, results, processes, attack_info)
1215
1216
clearConsoleLine()
1217
1218
else:
1219
for ((user, hash_), kwargs) in attack_info:
1220
if processException:
1221
break
1222
1223
if any(_[0] == user and _[1] == hash_ for _ in results):
1224
continue
1225
1226
count = 0
1227
found = False
1228
1229
for suffix in suffix_list:
1230
if found or processException:
1231
break
1232
1233
if suffix:
1234
clearConsoleLine()
1235
infoMsg = "using suffix '%s'" % suffix
1236
logger.info(infoMsg)
1237
1238
retVal = None
1239
processes = []
1240
1241
try:
1242
if _multiprocessing:
1243
if _multiprocessing.cpu_count() > 1:
1244
infoMsg = "starting %d processes " % _multiprocessing.cpu_count()
1245
singleTimeLogMessage(infoMsg)
1246
1247
gc.disable()
1248
1249
retVal = _multiprocessing.Queue()
1250
found_ = _multiprocessing.Value('i', False)
1251
count = _multiprocessing.Value('i', _multiprocessing.cpu_count())
1252
1253
for i in xrange(_multiprocessing.cpu_count()):
1254
process = _multiprocessing.Process(target=_bruteProcessVariantB, args=(user, hash_, kwargs, hash_regex, suffix, retVal, found_, i, count, kb.wordlists, custom_wordlist, conf.api))
1255
processes.append(process)
1256
1257
for process in processes:
1258
process.daemon = True
1259
process.start()
1260
1261
while count.value > 0:
1262
time.sleep(0.5)
1263
1264
found = found_.value != 0
1265
1266
else:
1267
warnMsg = "multiprocessing hash cracking is currently "
1268
warnMsg += "%s on this platform" % ("not supported" if not conf.disableMulti else "disabled")
1269
singleTimeWarnMessage(warnMsg)
1270
1271
class Value(object):
1272
pass
1273
1274
retVal = _queue.Queue()
1275
found_ = Value()
1276
found_.value = False
1277
1278
_bruteProcessVariantB(user, hash_, kwargs, hash_regex, suffix, retVal, found_, 0, 1, kb.wordlists, custom_wordlist, conf.api)
1279
1280
found = found_.value
1281
1282
except KeyboardInterrupt:
1283
print()
1284
processException = True
1285
warnMsg = "user aborted during dictionary-based attack phase (Ctrl+C was pressed)"
1286
logger.warning(warnMsg)
1287
1288
for process in processes:
1289
try:
1290
process.terminate()
1291
process.join()
1292
except (OSError, AttributeError):
1293
pass
1294
1295
finally:
1296
_finalize(retVal, results, processes, attack_info)
1297
1298
clearConsoleLine()
1299
1300
results.extend(resumes)
1301
1302
if foundHash and len(hash_regexes) == 0:
1303
warnMsg = "unknown hash format"
1304
logger.warning(warnMsg)
1305
1306
if len(results) == 0:
1307
warnMsg = "no clear password(s) found"
1308
logger.warning(warnMsg)
1309
1310
return results
1311
1312
def crackHashFile(hashFile):
1313
i = 0
1314
attack_dict = {}
1315
1316
check = None
1317
for line in getFileItems(conf.hashFile):
1318
if check is None and not attack_dict and ':' in line:
1319
check = any(re.search(_, line) for _ in getPublicTypeMembers(HASH, True))
1320
1321
if ':' in line and check is False:
1322
user, hash_ = line.split(':', 1)
1323
attack_dict[user] = [hash_]
1324
else:
1325
attack_dict["%s%d" % (DUMMY_USER_PREFIX, i)] = [line]
1326
i += 1
1327
1328
dictionaryAttack(attack_dict)
1329
1330