hash_1.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  1. #!/usr/bin/env python
  2. """
  3. Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
  4. See the file 'doc/COPYING' for copying permission
  5. """
  6. try:
  7. from crypt import crypt
  8. except ImportError:
  9. from thirdparty.fcrypt.fcrypt import crypt
  10. _multiprocessing = None
  11. try:
  12. import multiprocessing
  13. # problems on FreeBSD (Reference: http://www.eggheadcafe.com/microsoft/Python/35880259/multiprocessing-on-freebsd.aspx)
  14. _ = multiprocessing.Queue()
  15. except (ImportError, OSError):
  16. pass
  17. else:
  18. try:
  19. if multiprocessing.cpu_count() > 1:
  20. _multiprocessing = multiprocessing
  21. except NotImplementedError:
  22. pass
  23. import gc
  24. import os
  25. import re
  26. import tempfile
  27. import time
  28. import zipfile
  29. from hashlib import md5
  30. from hashlib import sha1
  31. from hashlib import sha224
  32. from hashlib import sha384
  33. from hashlib import sha512
  34. from Queue import Queue
  35. from lib.core.common import Backend
  36. from lib.core.common import checkFile
  37. from lib.core.common import clearConsoleLine
  38. from lib.core.common import dataToStdout
  39. from lib.core.common import getFileItems
  40. from lib.core.common import getPublicTypeMembers
  41. from lib.core.common import getSafeExString
  42. from lib.core.common import getUnicode
  43. from lib.core.common import hashDBRetrieve
  44. from lib.core.common import hashDBWrite
  45. from lib.core.common import normalizeUnicode
  46. from lib.core.common import paths
  47. from lib.core.common import readInput
  48. from lib.core.common import singleTimeLogMessage
  49. from lib.core.common import singleTimeWarnMessage
  50. from lib.core.convert import hexdecode
  51. from lib.core.convert import hexencode
  52. from lib.core.convert import utf8encode
  53. from lib.core.data import conf
  54. from lib.core.data import kb
  55. from lib.core.data import logger
  56. from lib.core.enums import DBMS
  57. from lib.core.enums import HASH
  58. from lib.core.enums import MKSTEMP_PREFIX
  59. from lib.core.exception import SqlmapDataException
  60. from lib.core.exception import SqlmapUserQuitException
  61. from lib.core.settings import COMMON_PASSWORD_SUFFIXES
  62. from lib.core.settings import COMMON_USER_COLUMNS
  63. from lib.core.settings import DUMMY_USER_PREFIX
  64. from lib.core.settings import HASH_MOD_ITEM_DISPLAY
  65. from lib.core.settings import HASH_RECOGNITION_QUIT_THRESHOLD
  66. from lib.core.settings import IS_WIN
  67. from lib.core.settings import ITOA64
  68. from lib.core.settings import NULL
  69. from lib.core.settings import UNICODE_ENCODING
  70. from lib.core.settings import ROTATING_CHARS
  71. from lib.core.wordlist import Wordlist
  72. from thirdparty.colorama.initialise import init as coloramainit
  73. from thirdparty.pydes.pyDes import des
  74. from thirdparty.pydes.pyDes import CBC
  75. def mysql_passwd(password, uppercase=True):
  76. """
  77. Reference(s):
  78. http://csl.sublevel3.org/mysql-password-function/
  79. >>> mysql_passwd(password='testpass', uppercase=True)
  80. '*00E247AC5F9AF26AE0194B41E1E769DEE1429A29'
  81. """
  82. retVal = "*%s" % sha1(sha1(password).digest()).hexdigest()
  83. return retVal.upper() if uppercase else retVal.lower()
  84. def mysql_old_passwd(password, uppercase=True): # prior to version '4.1'
  85. """
  86. Reference(s):
  87. http://www.sfr-fresh.com/unix/privat/tpop3d-1.5.5.tar.gz:a/tpop3d-1.5.5/password.c
  88. http://voidnetwork.org/5ynL0rd/darkc0de/python_script/darkMySQLi.html
  89. >>> mysql_old_passwd(password='testpass', uppercase=True)
  90. '7DCDA0D57290B453'
  91. """
  92. a, b, c = 1345345333, 7, 0x12345671
  93. for d in password:
  94. if d == ' ' or d == '\t':
  95. continue
  96. e = ord(d)
  97. a ^= (((a & 63) + b) * e) + (a << 8)
  98. c += (c << 8) ^ a
  99. b += e
  100. retVal = "%08lx%08lx" % (a & ((1 << 31) - 1), c & ((1 << 31) - 1))
  101. return retVal.upper() if uppercase else retVal.lower()
  102. def postgres_passwd(password, username, uppercase=False):
  103. """
  104. Reference(s):
  105. http://pentestmonkey.net/blog/cracking-postgres-hashes/
  106. >>> postgres_passwd(password='testpass', username='testuser', uppercase=False)
  107. 'md599e5ea7a6f7c3269995cba3927fd0093'
  108. """
  109. if isinstance(username, unicode):
  110. username = unicode.encode(username, UNICODE_ENCODING)
  111. if isinstance(password, unicode):
  112. password = unicode.encode(password, UNICODE_ENCODING)
  113. retVal = "md5%s" % md5(password + username).hexdigest()
  114. return retVal.upper() if uppercase else retVal.lower()
  115. def mssql_passwd(password, salt, uppercase=False):
  116. """
  117. Reference(s):
  118. http://www.leidecker.info/projects/phrasendrescher/mssql.c
  119. https://www.evilfingers.com/tools/GSAuditor.php
  120. >>> mssql_passwd(password='testpass', salt='4086ceb6', uppercase=False)
  121. '0x01004086ceb60c90646a8ab9889fe3ed8e5c150b5460ece8425a'
  122. """
  123. binsalt = hexdecode(salt)
  124. unistr = "".join(map(lambda c: ("%s\0" if ord(c) < 256 else "%s") % utf8encode(c), password))
  125. retVal = "0100%s%s" % (salt, sha1(unistr + binsalt).hexdigest())
  126. return "0x%s" % (retVal.upper() if uppercase else retVal.lower())
  127. def mssql_old_passwd(password, salt, uppercase=True): # prior to version '2005'
  128. """
  129. Reference(s):
  130. www.exploit-db.com/download_pdf/15537/
  131. http://www.leidecker.info/projects/phrasendrescher/mssql.c
  132. https://www.evilfingers.com/tools/GSAuditor.php
  133. >>> mssql_old_passwd(password='testpass', salt='4086ceb6', uppercase=True)
  134. '0x01004086CEB60C90646A8AB9889FE3ED8E5C150B5460ECE8425AC7BB7255C0C81D79AA5D0E93D4BB077FB9A51DA0'
  135. """
  136. binsalt = hexdecode(salt)
  137. unistr = "".join(map(lambda c: ("%s\0" if ord(c) < 256 else "%s") % utf8encode(c), password))
  138. retVal = "0100%s%s%s" % (salt, sha1(unistr + binsalt).hexdigest(), sha1(unistr.upper() + binsalt).hexdigest())
  139. return "0x%s" % (retVal.upper() if uppercase else retVal.lower())
  140. def mssql_new_passwd(password, salt, uppercase=False):
  141. """
  142. Reference(s):
  143. http://hashcat.net/forum/thread-1474.html
  144. >>> mssql_new_passwd(password='testpass', salt='4086ceb6', uppercase=False)
  145. '0x02004086ceb6eb051cdbc5bdae68ffc66c918d4977e592f6bdfc2b444a7214f71fa31c35902c5b7ae773ed5f4c50676d329120ace32ee6bc81c24f70711eb0fc6400e85ebf25'
  146. """
  147. binsalt = hexdecode(salt)
  148. unistr = "".join(map(lambda c: ("%s\0" if ord(c) < 256 else "%s") % utf8encode(c), password))
  149. retVal = "0200%s%s" % (salt, sha512(unistr + binsalt).hexdigest())
  150. return "0x%s" % (retVal.upper() if uppercase else retVal.lower())
  151. def oracle_passwd(password, salt, uppercase=True):
  152. """
  153. Reference(s):
  154. https://www.evilfingers.com/tools/GSAuditor.php
  155. http://www.notesbit.com/index.php/scripts-oracle/oracle-11g-new-password-algorithm-is-revealed-by-seclistsorg/
  156. http://seclists.org/bugtraq/2007/Sep/304
  157. >>> oracle_passwd(password='SHAlala', salt='1B7B5F82B7235E9E182C', uppercase=True)
  158. 'S:2BFCFDF5895014EE9BB2B9BA067B01E0389BB5711B7B5F82B7235E9E182C'
  159. """
  160. binsalt = hexdecode(salt)
  161. retVal = "s:%s%s" % (sha1(utf8encode(password) + binsalt).hexdigest(), salt)
  162. return retVal.upper() if uppercase else retVal.lower()
  163. def oracle_old_passwd(password, username, uppercase=True): # prior to version '11g'
  164. """
  165. Reference(s):
  166. http://www.notesbit.com/index.php/scripts-oracle/oracle-11g-new-password-algorithm-is-revealed-by-seclistsorg/
  167. >>> oracle_old_passwd(password='tiger', username='scott', uppercase=True)
  168. 'F894844C34402B67'
  169. """
  170. IV, pad = "\0" * 8, "\0"
  171. if isinstance(username, unicode):
  172. username = unicode.encode(username, UNICODE_ENCODING)
  173. if isinstance(password, unicode):
  174. password = unicode.encode(password, UNICODE_ENCODING)
  175. unistr = "".join("\0%s" % c for c in (username + password).upper())
  176. cipher = des(hexdecode("0123456789ABCDEF"), CBC, IV, pad)
  177. encrypted = cipher.encrypt(unistr)
  178. cipher = des(encrypted[-8:], CBC, IV, pad)
  179. encrypted = cipher.encrypt(unistr)
  180. retVal = hexencode(encrypted[-8:])
  181. return retVal.upper() if uppercase else retVal.lower()
  182. def md5_generic_passwd(password, uppercase=False):
  183. """
  184. >>> md5_generic_passwd(password='testpass', uppercase=False)
  185. '179ad45c6ce2cb97cf1029e212046e81'
  186. """
  187. retVal = md5(password).hexdigest()
  188. return retVal.upper() if uppercase else retVal.lower()
  189. def sha1_generic_passwd(password, uppercase=False):
  190. """
  191. >>> sha1_generic_passwd(password='testpass', uppercase=False)
  192. '206c80413b9a96c1312cc346b7d2517b84463edd'
  193. """
  194. retVal = sha1(password).hexdigest()
  195. return retVal.upper() if uppercase else retVal.lower()
  196. def sha224_generic_passwd(password, uppercase=False):
  197. """
  198. >>> sha224_generic_passwd(password='testpass', uppercase=False)
  199. '648db6019764b598f75ab6b7616d2e82563a00eb1531680e19ac4c6f'
  200. """
  201. retVal = sha224(password).hexdigest()
  202. return retVal.upper() if uppercase else retVal.lower()
  203. def sha384_generic_passwd(password, uppercase=False):
  204. """
  205. >>> sha384_generic_passwd(password='testpass', uppercase=False)
  206. '6823546e56adf46849343be991d4b1be9b432e42ed1b4bb90635a0e4b930e49b9ca007bc3e04bf0a4e0df6f1f82769bf'
  207. """
  208. retVal = sha384(password).hexdigest()
  209. return retVal.upper() if uppercase else retVal.lower()
  210. def sha512_generic_passwd(password, uppercase=False):
  211. """
  212. >>> sha512_generic_passwd(password='testpass', uppercase=False)
  213. '78ddc8555bb1677ff5af75ba5fc02cb30bb592b0610277ae15055e189b77fe3fda496e5027a3d99ec85d54941adee1cc174b50438fdc21d82d0a79f85b58cf44'
  214. """
  215. retVal = sha512(password).hexdigest()
  216. return retVal.upper() if uppercase else retVal.lower()
  217. def crypt_generic_passwd(password, salt, uppercase=False):
  218. """
  219. Reference(s):
  220. http://docs.python.org/library/crypt.html
  221. http://helpful.knobs-dials.com/index.php/Hashing_notes
  222. http://php.net/manual/en/function.crypt.php
  223. http://carey.geek.nz/code/python-fcrypt/
  224. >>> crypt_generic_passwd(password='rasmuslerdorf', salt='rl', uppercase=False)
  225. 'rl.3StKT.4T8M'
  226. """
  227. retVal = crypt(password, salt)
  228. return retVal.upper() if uppercase else retVal
  229. def wordpress_passwd(password, salt, count, prefix, uppercase=False):
  230. """
  231. Reference(s):
  232. http://packetstormsecurity.org/files/74448/phpassbrute.py.txt
  233. http://scriptserver.mainframe8.com/wordpress_password_hasher.php
  234. >>> wordpress_passwd(password='testpass', salt='aD9ZLmkp', count=2048, prefix='$P$9aD9ZLmkp', uppercase=False)
  235. '$P$9aD9ZLmkpsN4A83G8MefaaP888gVKX0'
  236. """
  237. def _encode64(input_, count):
  238. output = ''
  239. i = 0
  240. while i < count:
  241. value = ord(input_[i])
  242. i += 1
  243. output = output + ITOA64[value & 0x3f]
  244. if i < count:
  245. value = value | (ord(input_[i]) << 8)
  246. output = output + ITOA64[(value >> 6) & 0x3f]
  247. i += 1
  248. if i >= count:
  249. break
  250. if i < count:
  251. value = value | (ord(input_[i]) << 16)
  252. output = output + ITOA64[(value >> 12) & 0x3f]
  253. i += 1
  254. if i >= count:
  255. break
  256. output = output + ITOA64[(value >> 18) & 0x3f]
  257. return output
  258. if isinstance(password, unicode):
  259. password = password.encode(UNICODE_ENCODING)
  260. cipher = md5(salt)
  261. cipher.update(password)
  262. hash_ = cipher.digest()
  263. for i in xrange(count):
  264. _ = md5(hash_)
  265. _.update(password)
  266. hash_ = _.digest()
  267. retVal = prefix + _encode64(hash_, 16)
  268. return retVal.upper() if uppercase else retVal
  269. __functions__ = {
  270. HASH.MYSQL: mysql_passwd,
  271. HASH.MYSQL_OLD: mysql_old_passwd,
  272. HASH.POSTGRES: postgres_passwd,
  273. HASH.MSSQL: mssql_passwd,
  274. HASH.MSSQL_OLD: mssql_old_passwd,
  275. HASH.MSSQL_NEW: mssql_new_passwd,
  276. HASH.ORACLE: oracle_passwd,
  277. HASH.ORACLE_OLD: oracle_old_passwd,
  278. HASH.MD5_GENERIC: md5_generic_passwd,
  279. HASH.SHA1_GENERIC: sha1_generic_passwd,
  280. HASH.SHA224_GENERIC: sha224_generic_passwd,
  281. HASH.SHA384_GENERIC: sha384_generic_passwd,
  282. HASH.SHA512_GENERIC: sha512_generic_passwd,
  283. HASH.CRYPT_GENERIC: crypt_generic_passwd,
  284. HASH.WORDPRESS: wordpress_passwd,
  285. }
  286. def storeHashesToFile(attack_dict):
  287. if not attack_dict:
  288. return
  289. if kb.storeHashesChoice is None:
  290. message = "do you want to store hashes to a temporary file "
  291. message += "for eventual further processing with other tools [y/N] "
  292. test = readInput(message, default="N")
  293. kb.storeHashesChoice = test[0] in ("y", "Y")
  294. if not kb.storeHashesChoice:
  295. return
  296. handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.HASHES, suffix=".txt")
  297. os.close(handle)
  298. infoMsg = "writing hashes to a temporary file '%s' " % filename
  299. logger.info(infoMsg)
  300. items = set()
  301. with open(filename, "w+") as f:
  302. for user, hashes in attack_dict.items():
  303. for hash_ in hashes:
  304. hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_
  305. if hash_ and hash_ != NULL and hashRecognition(hash_):
  306. item = None
  307. if user and not user.startswith(DUMMY_USER_PREFIX):
  308. item = "%s:%s\n" % (user.encode(UNICODE_ENCODING), hash_.encode(UNICODE_ENCODING))
  309. else:
  310. item = "%s\n" % hash_.encode(UNICODE_ENCODING)
  311. if item and item not in items:
  312. f.write(item)
  313. items.add(item)
  314. def attackCachedUsersPasswords():
  315. if kb.data.cachedUsersPasswords:
  316. results = dictionaryAttack(kb.data.cachedUsersPasswords)
  317. lut = {}
  318. for (_, hash_, password) in results:
  319. lut[hash_.lower()] = password
  320. for user in kb.data.cachedUsersPasswords.keys():
  321. for i in xrange(len(kb.data.cachedUsersPasswords[user])):
  322. if (kb.data.cachedUsersPasswords[user][i] or "").strip():
  323. value = kb.data.cachedUsersPasswords[user][i].lower().split()[0]
  324. if value in lut:
  325. kb.data.cachedUsersPasswords[user][i] += "%s clear-text password: %s" % ('\n' if kb.data.cachedUsersPasswords[user][i][-1] != '\n' else '', lut[value])
  326. def attackDumpedTable():
  327. if kb.data.dumpedTable:
  328. table = kb.data.dumpedTable
  329. columns = table.keys()
  330. count = table["__infos__"]["count"]
  331. if not count:
  332. return
  333. infoMsg = "analyzing table dump for possible password hashes"
  334. logger.info(infoMsg)
  335. found = False
  336. col_user = ''
  337. col_passwords = set()
  338. attack_dict = {}
  339. for column in columns:
  340. if column and column.lower() in COMMON_USER_COLUMNS:
  341. col_user = column
  342. break
  343. for i in xrange(count):
  344. if not found and i > HASH_RECOGNITION_QUIT_THRESHOLD:
  345. break
  346. for column in columns:
  347. if column == col_user or column == '__infos__':
  348. continue
  349. if len(table[column]['values']) <= i:
  350. continue
  351. value = table[column]['values'][i]
  352. if hashRecognition(value):
  353. found = True
  354. if col_user and i < len(table[col_user]['values']):
  355. if table[col_user]['values'][i] not in attack_dict:
  356. attack_dict[table[col_user]['values'][i]] = []
  357. attack_dict[table[col_user]['values'][i]].append(value)
  358. else:
  359. attack_dict['%s%d' % (DUMMY_USER_PREFIX, i)] = [value]
  360. col_passwords.add(column)
  361. if attack_dict:
  362. infoMsg = "recognized possible password hashes in column%s " % ("s" if len(col_passwords) > 1 else "")
  363. infoMsg += "'%s'" % ", ".join(col for col in col_passwords)
  364. logger.info(infoMsg)
  365. storeHashesToFile(attack_dict)
  366. message = "do you want to crack them via a dictionary-based attack? %s" % ("[y/N/q]" if conf.multipleTargets else "[Y/n/q]")
  367. test = readInput(message, default="N" if conf.multipleTargets else "Y")
  368. if test[0] in ("n", "N"):
  369. return
  370. elif test[0] in ("q", "Q"):
  371. raise SqlmapUserQuitException
  372. results = dictionaryAttack(attack_dict)
  373. lut = dict()
  374. for (_, hash_, password) in results:
  375. if hash_:
  376. lut[hash_.lower()] = password
  377. infoMsg = "postprocessing table dump"
  378. logger.info(infoMsg)
  379. for i in xrange(count):
  380. for column in columns:
  381. if not (column == col_user or column == '__infos__' or len(table[column]['values']) <= i):
  382. value = table[column]['values'][i]
  383. if value and value.lower() in lut:
  384. table[column]['values'][i] = "%s (%s)" % (getUnicode(table[column]['values'][i]), getUnicode(lut[value.lower()]))
  385. table[column]['length'] = max(table[column]['length'], len(table[column]['values'][i]))
  386. def hashRecognition(value):
  387. retVal = None
  388. isOracle, isMySQL = Backend.isDbms(DBMS.ORACLE), Backend.isDbms(DBMS.MYSQL)
  389. if isinstance(value, basestring):
  390. for name, regex in getPublicTypeMembers(HASH):
  391. # Hashes for Oracle and old MySQL look the same hence these checks
  392. if isOracle and regex == HASH.MYSQL_OLD:
  393. continue
  394. elif isMySQL and regex == HASH.ORACLE_OLD:
  395. continue
  396. elif regex == HASH.CRYPT_GENERIC:
  397. if any((value.lower() == value, value.upper() == value)):
  398. continue
  399. elif re.match(regex, value):
  400. retVal = regex
  401. break
  402. return retVal
  403. def _bruteProcessVariantA(attack_info, hash_regex, suffix, retVal, proc_id, proc_count, wordlists, custom_wordlist):
  404. if IS_WIN:
  405. coloramainit()
  406. count = 0
  407. rotator = 0
  408. hashes = set([item[0][1] for item in attack_info])
  409. wordlist = Wordlist(wordlists, proc_id, getattr(proc_count, "value", 0), custom_wordlist)
  410. try:
  411. for word in wordlist:
  412. if not attack_info:
  413. break
  414. if not isinstance(word, basestring):
  415. continue
  416. if suffix:
  417. word = word + suffix
  418. try:
  419. current = __functions__[hash_regex](password=word, uppercase=False)
  420. count += 1
  421. if current in hashes:
  422. for item in attack_info[:]:
  423. ((user, hash_), _) = item
  424. if hash_ == current:
  425. retVal.put((user, hash_, word))
  426. clearConsoleLine()
  427. infoMsg = "\r[%s] [INFO] cracked password '%s'" % (time.strftime("%X"), word)
  428. if user and not user.startswith(DUMMY_USER_PREFIX):
  429. infoMsg += " for user '%s'\n" % user
  430. else:
  431. infoMsg += " for hash '%s'\n" % hash_
  432. dataToStdout(infoMsg, True)
  433. attack_info.remove(item)
  434. 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:
  435. rotator += 1
  436. if rotator >= len(ROTATING_CHARS):
  437. rotator = 0
  438. status = 'current status: %s... %s' % (word.ljust(5)[:5], ROTATING_CHARS[rotator])
  439. if not hasattr(conf, "api"):
  440. dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status))
  441. except KeyboardInterrupt:
  442. raise
  443. except (UnicodeEncodeError, UnicodeDecodeError):
  444. pass # ignore possible encoding problems caused by some words in custom dictionaries
  445. except Exception as e:
  446. warnMsg = "there was a problem while hashing entry: %s (%s). " % (repr(word), e)
  447. warnMsg += "Please report by e-mail to 'dev@sqlmap.org'"
  448. logger.critical(warnMsg)
  449. except KeyboardInterrupt:
  450. pass
  451. finally:
  452. if hasattr(proc_count, "value"):
  453. with proc_count.get_lock():
  454. proc_count.value -= 1
  455. def _bruteProcessVariantB(user, hash_, kwargs, hash_regex, suffix, retVal, found, proc_id, proc_count, wordlists, custom_wordlist):
  456. if IS_WIN:
  457. coloramainit()
  458. count = 0
  459. rotator = 0
  460. wordlist = Wordlist(wordlists, proc_id, getattr(proc_count, "value", 0), custom_wordlist)
  461. try:
  462. for word in wordlist:
  463. if found.value:
  464. break
  465. current = __functions__[hash_regex](password=word, uppercase=False, **kwargs)
  466. count += 1
  467. if not isinstance(word, basestring):
  468. continue
  469. if suffix:
  470. word = word + suffix
  471. try:
  472. if hash_ == current:
  473. if hash_regex == HASH.ORACLE_OLD: # only for cosmetic purposes
  474. word = word.upper()
  475. retVal.put((user, hash_, word))
  476. clearConsoleLine()
  477. infoMsg = "\r[%s] [INFO] cracked password '%s'" % (time.strftime("%X"), word)
  478. if user and not user.startswith(DUMMY_USER_PREFIX):
  479. infoMsg += " for user '%s'\n" % user
  480. else:
  481. infoMsg += " for hash '%s'\n" % hash_
  482. dataToStdout(infoMsg, True)
  483. found.value = True
  484. elif (proc_id == 0 or getattr(proc_count, "value", 0) == 1) and count % HASH_MOD_ITEM_DISPLAY == 0:
  485. rotator += 1
  486. if rotator >= len(ROTATING_CHARS):
  487. rotator = 0
  488. status = 'current status: %s... %s' % (word.ljust(5)[:5], ROTATING_CHARS[rotator])
  489. if user and not user.startswith(DUMMY_USER_PREFIX):
  490. status += ' (user: %s)' % user
  491. if not hasattr(conf, "api"):
  492. dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status))
  493. except KeyboardInterrupt:
  494. raise
  495. except (UnicodeEncodeError, UnicodeDecodeError):
  496. pass # ignore possible encoding problems caused by some words in custom dictionaries
  497. except Exception as e:
  498. warnMsg = "there was a problem while hashing entry: %s (%s). " % (repr(word), e)
  499. warnMsg += "Please report by e-mail to 'dev@sqlmap.org'"
  500. logger.critical(warnMsg)
  501. except KeyboardInterrupt:
  502. pass
  503. finally:
  504. if hasattr(proc_count, "value"):
  505. with proc_count.get_lock():
  506. proc_count.value -= 1
  507. def dictionaryAttack(attack_dict):
  508. suffix_list = [""]
  509. custom_wordlist = [""]
  510. hash_regexes = []
  511. results = []
  512. resumes = []
  513. user_hash = []
  514. processException = False
  515. foundHash = False
  516. for (_, hashes) in attack_dict.items():
  517. for hash_ in hashes:
  518. if not hash_:
  519. continue
  520. hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_
  521. regex = hashRecognition(hash_)
  522. if regex and regex not in hash_regexes:
  523. hash_regexes.append(regex)
  524. infoMsg = "using hash method '%s'" % __functions__[regex].func_name
  525. logger.info(infoMsg)
  526. for hash_regex in hash_regexes:
  527. keys = set()
  528. attack_info = []
  529. for (user, hashes) in attack_dict.items():
  530. for hash_ in hashes:
  531. if not hash_:
  532. continue
  533. foundHash = True
  534. hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_
  535. if re.match(hash_regex, hash_):
  536. item = None
  537. if hash_regex not in (HASH.CRYPT_GENERIC, HASH.WORDPRESS):
  538. hash_ = hash_.lower()
  539. if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC):
  540. item = [(user, hash_), {}]
  541. elif hash_regex in (HASH.ORACLE_OLD, HASH.POSTGRES):
  542. item = [(user, hash_), {'username': user}]
  543. elif hash_regex in (HASH.ORACLE,):
  544. item = [(user, hash_), {'salt': hash_[-20:]}]
  545. elif hash_regex in (HASH.MSSQL, HASH.MSSQL_OLD, HASH.MSSQL_NEW):
  546. item = [(user, hash_), {'salt': hash_[6:14]}]
  547. elif hash_regex in (HASH.CRYPT_GENERIC,):
  548. item = [(user, hash_), {'salt': hash_[0:2]}]
  549. elif hash_regex in (HASH.WORDPRESS,):
  550. if ITOA64.index(hash_[3]) < 32:
  551. item = [(user, hash_), {'salt': hash_[4:12], 'count': 1 << ITOA64.index(hash_[3]), 'prefix': hash_[:12]}]
  552. else:
  553. warnMsg = "invalid hash '%s'" % hash_
  554. logger.warn(warnMsg)
  555. if item and hash_ not in keys:
  556. resumed = hashDBRetrieve(hash_)
  557. if not resumed:
  558. attack_info.append(item)
  559. user_hash.append(item[0])
  560. else:
  561. infoMsg = "resuming password '%s' for hash '%s'" % (resumed, hash_)
  562. if user and not user.startswith(DUMMY_USER_PREFIX):
  563. infoMsg += " for user '%s'" % user
  564. logger.info(infoMsg)
  565. resumes.append((user, hash_, resumed))
  566. keys.add(hash_)
  567. if not attack_info:
  568. continue
  569. if not kb.wordlists:
  570. while not kb.wordlists:
  571. # the slowest of all methods hence smaller default dict
  572. if hash_regex in (HASH.ORACLE_OLD, HASH.WORDPRESS):
  573. dictPaths = [paths.SMALL_DICT]
  574. else:
  575. dictPaths = [paths.WORDLIST]
  576. message = "what dictionary do you want to use?\n"
  577. message += "[1] default dictionary file '%s' (press Enter)\n" % dictPaths[0]
  578. message += "[2] custom dictionary file\n"
  579. message += "[3] file with list of dictionary files"
  580. choice = readInput(message, default="1")
  581. try:
  582. if choice == "2":
  583. message = "what's the custom dictionary's location?\n"
  584. dictPaths = [readInput(message)]
  585. logger.info("using custom dictionary")
  586. elif choice == "3":
  587. message = "what's the list file location?\n"
  588. listPath = readInput(message)
  589. checkFile(listPath)
  590. dictPaths = getFileItems(listPath)
  591. logger.info("using custom list of dictionaries")
  592. else:
  593. logger.info("using default dictionary")
  594. dictPaths = filter(None, dictPaths)
  595. for dictPath in dictPaths:
  596. checkFile(dictPath)
  597. if os.path.splitext(dictPath)[1].lower() == ".zip":
  598. _ = zipfile.ZipFile(dictPath, 'r')
  599. if len(_.namelist()) == 0:
  600. errMsg = "no file(s) inside '%s'" % dictPath
  601. raise SqlmapDataException(errMsg)
  602. else:
  603. _.open(_.namelist()[0])
  604. kb.wordlists = dictPaths
  605. except Exception as ex:
  606. warnMsg = "there was a problem while loading dictionaries"
  607. warnMsg += " ('%s')" % getSafeExString(ex)
  608. logger.critical(warnMsg)
  609. message = "do you want to use common password suffixes? (slow!) [y/N] "
  610. test = readInput(message, default="N")
  611. if test[0] in ("y", "Y"):
  612. suffix_list += COMMON_PASSWORD_SUFFIXES
  613. infoMsg = "starting dictionary-based cracking (%s)" % __functions__[hash_regex].func_name
  614. logger.info(infoMsg)
  615. for item in attack_info:
  616. ((user, _), _) = item
  617. if user and not user.startswith(DUMMY_USER_PREFIX):
  618. custom_wordlist.append(normalizeUnicode(user))
  619. if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC):
  620. for suffix in suffix_list:
  621. if not attack_info or processException:
  622. break
  623. if suffix:
  624. clearConsoleLine()
  625. infoMsg = "using suffix '%s'" % suffix
  626. logger.info(infoMsg)
  627. retVal = None
  628. processes = []
  629. try:
  630. if _multiprocessing:
  631. if _multiprocessing.cpu_count() > 1:
  632. infoMsg = "starting %d processes " % _multiprocessing.cpu_count()
  633. singleTimeLogMessage(infoMsg)
  634. gc.disable()
  635. retVal = _multiprocessing.Queue()
  636. count = _multiprocessing.Value('i', _multiprocessing.cpu_count())
  637. for i in xrange(_multiprocessing.cpu_count()):
  638. p = _multiprocessing.Process(target=_bruteProcessVariantA, args=(attack_info, hash_regex, suffix, retVal, i, count, kb.wordlists, custom_wordlist))
  639. processes.append(p)
  640. for p in processes:
  641. p.daemon = True
  642. p.start()
  643. while count.value > 0:
  644. time.sleep(0.5)
  645. else:
  646. warnMsg = "multiprocessing hash cracking is currently "
  647. warnMsg += "not supported on this platform"
  648. singleTimeWarnMessage(warnMsg)
  649. retVal = Queue()
  650. _bruteProcessVariantA(attack_info, hash_regex, suffix, retVal, 0, 1, kb.wordlists, custom_wordlist)
  651. except KeyboardInterrupt:
  652. print
  653. processException = True
  654. warnMsg = "user aborted during dictionary-based attack phase (Ctrl+C was pressed)"
  655. logger.warn(warnMsg)
  656. for process in processes:
  657. try:
  658. process.terminate()
  659. process.join()
  660. except (OSError, AttributeError):
  661. pass
  662. finally:
  663. if _multiprocessing:
  664. gc.enable()
  665. if retVal:
  666. conf.hashDB.beginTransaction()
  667. while not retVal.empty():
  668. user, hash_, word = item = retVal.get(block=False)
  669. attack_info = filter(lambda _: _[0][0] != user or _[0][1] != hash_, attack_info)
  670. hashDBWrite(hash_, word)
  671. results.append(item)
  672. conf.hashDB.endTransaction()
  673. clearConsoleLine()
  674. else:
  675. for ((user, hash_), kwargs) in attack_info:
  676. if processException:
  677. break
  678. if any(_[0] == user and _[1] == hash_ for _ in results):
  679. continue
  680. count = 0
  681. found = False
  682. for suffix in suffix_list:
  683. if found or processException:
  684. break
  685. if suffix:
  686. clearConsoleLine()
  687. infoMsg = "using suffix '%s'" % suffix
  688. logger.info(infoMsg)
  689. retVal = None
  690. processes = []
  691. try:
  692. if _multiprocessing:
  693. if _multiprocessing.cpu_count() > 1:
  694. infoMsg = "starting %d processes " % _multiprocessing.cpu_count()
  695. singleTimeLogMessage(infoMsg)
  696. gc.disable()
  697. retVal = _multiprocessing.Queue()
  698. found_ = _multiprocessing.Value('i', False)
  699. count = _multiprocessing.Value('i', _multiprocessing.cpu_count())
  700. for i in xrange(_multiprocessing.cpu_count()):
  701. p = _multiprocessing.Process(target=_bruteProcessVariantB, args=(user, hash_, kwargs, hash_regex, suffix, retVal, found_, i, count, kb.wordlists, custom_wordlist))
  702. processes.append(p)
  703. for p in processes:
  704. p.daemon = True
  705. p.start()
  706. while count.value > 0:
  707. time.sleep(0.5)
  708. found = found_.value != 0
  709. else:
  710. warnMsg = "multiprocessing hash cracking is currently "
  711. warnMsg += "not supported on this platform"
  712. singleTimeWarnMessage(warnMsg)
  713. class Value():
  714. pass
  715. retVal = Queue()
  716. found_ = Value()
  717. found_.value = False
  718. _bruteProcessVariantB(user, hash_, kwargs, hash_regex, suffix, retVal, found_, 0, 1, kb.wordlists, custom_wordlist)
  719. found = found_.value
  720. except KeyboardInterrupt:
  721. print
  722. processException = True
  723. warnMsg = "user aborted during dictionary-based attack phase (Ctrl+C was pressed)"
  724. logger.warn(warnMsg)
  725. for process in processes:
  726. try:
  727. process.terminate()
  728. process.join()
  729. except (OSError, AttributeError):
  730. pass
  731. finally:
  732. if _multiprocessing:
  733. gc.enable()
  734. if retVal:
  735. conf.hashDB.beginTransaction()
  736. while not retVal.empty():
  737. user, hash_, word = item = retVal.get(block=False)
  738. hashDBWrite(hash_, word)
  739. results.append(item)
  740. conf.hashDB.endTransaction()
  741. clearConsoleLine()
  742. results.extend(resumes)
  743. if foundHash and len(hash_regexes) == 0:
  744. warnMsg = "unknown hash format"
  745. logger.warn(warnMsg)
  746. if len(results) == 0:
  747. warnMsg = "no clear password(s) found"
  748. logger.warn(warnMsg)
  749. return results