#!/usr/bin/env python """ $Id$ Copyright (c) 2006-2010 sqlmap developers (http://sqlmap.sourceforge.net/) See the file 'doc/COPYING' for copying permission """ import re import time from hashlib import md5 from hashlib import sha1 from zipfile import ZipFile from extra.pydes.pyDes import des from extra.pydes.pyDes import CBC from lib.core.common import conf from lib.core.common import dataToStdout from lib.core.common import getFileItems from lib.core.common import getPublicTypeMembers from lib.core.common import paths from lib.core.common import readInput from lib.core.convert import hexdecode from lib.core.convert import hexencode from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS from lib.core.enums import HASH 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() 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' """ 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) unistr = "".join("%s\0" % c for c in password) retVal = "0100%s%s" % (salt, sha1(unistr + binsalt).hexdigest()) return "0x%s" % (retVal.upper() if uppercase else retVal.lower()) 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) unistr = "".join("%s\0" % c for c 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 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) retVal="s:%s%s" % (sha1(password + binsalt).hexdigest(), salt) return retVal.upper() if uppercase else retVal.lower() 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' """ IV, pad = "\0"*8, "\0" username = unicode.encode(username, conf.dataEncoding) #pyDes has issues with unicode strings 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() __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.ORACLE: oracle_passwd, HASH.ORACLE_OLD: oracle_old_passwd, HASH.MD5_GENERIC: md5_generic_passwd, HASH.SHA1_GENERIC: sha1_generic_passwd } def dictionaryAttack(): rehash = None attack_info = [] results = [] for (_, hashes) in kb.data.cachedUsersPasswords.items(): for hash_ in hashes: if not hash_: continue hash_ = hash_.split()[0] for _, regex in getPublicTypeMembers(HASH): if re.match(regex, hash_): rehash = regex break if rehash: for (user, hashes) in kb.data.cachedUsersPasswords.items(): for hash_ in hashes: if not hash_: continue hash_ = hash_.split()[0] if re.match(rehash, hash_): hash_ = hash_.lower() if rehash in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC) and kb.dbms != DBMS.ORACLE: attack_info.append([(user, hash_), {}]) elif rehash in (HASH.ORACLE_OLD, HASH.POSTGRES): attack_info.append([(user, hash_), {'username': user}]) elif rehash in (HASH.ORACLE): attack_info.append([(user, hash_), {'salt': hash_[-20:]}]) elif rehash in (HASH.MSSQL, HASH.MSSQL_OLD): attack_info.append([(user, hash_), {'salt': hash_[6:14]}]) infoMsg = "loading dictionary from: '%s'" % paths.WORDLIST_TXT logger.info(infoMsg) wordlist = getFileItems(paths.WORDLIST_TXT, None, False) infoMsg = "running dictionary attack" logger.info(infoMsg) length = len(wordlist) if rehash in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC) and kb.dbms != DBMS.ORACLE: count = 0 for word in wordlist: count += 1 current = __functions__[rehash](password = word, uppercase = False) for item in attack_info: ((user, hash_), _) = item if count % 1117 == 0 or count == length: status = '%d/%d words (%d%s)' % (count, length, round(100.0*count/length), '%') dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status), True) if hash_ == current: results.append((user, hash_, word)) #dataToStdout("\r[%s] [INFO] found: %s:%s\n" % (time.strftime("%X"), user, word), True) attack_info.remove(item) else: for ((user, hash_), kwargs) in attack_info: count = 0 for word in wordlist: current = __functions__[rehash](password = word, uppercase = False, **kwargs) count += 1 if count % 1117 == 0 or count == length: status = '%d/%d words (%d%s)' % (count, length, round(100.0*count/length), '%') dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status), True) if hash_ == current: results.append((user, hash_, word)) #dataToStdout("\r[%s] [INFO] found: %s:%s\n" % (time.strftime("%X"), user, word), True) break dataToStdout("\n", True) blank = " " for (user, hash_, password) in results: for i in xrange(len(kb.data.cachedUsersPasswords[user])): if kb.data.cachedUsersPasswords[user][i] and hash_.lower() in kb.data.cachedUsersPasswords[user][i].lower(): kb.data.cachedUsersPasswords[user][i] += "%s%spassword: %s" % ('\n' if kb.data.cachedUsersPasswords[user][i][-1] != '\n' else '', blank, password)