def endElement(self, name): if name == "signature": for version in (self.__version, self.__versionAlt): regObj = getCompiledRegex(" %s[\.\ ]+" % version) if version and regObj.search(self.__banner): self.__feedInfo("dbmsRelease", self.__release) self.__feedInfo("dbmsVersion", self.__version) self.__feedInfo("dbmsServicePack", self.__servicePack) break self.__version = "" self.__versionAlt = None self.__servicePack = "" elif name == "version": self.__inVersion = False self.__version = self.__version.replace(" ", "") regObj = getCompiledRegex(r"\A(?P<major>\d+)\.00\.(?P<build>\d+)\Z") match = regObj.search(self.__version) self.__versionAlt = "%s.0.%s.0" % (match.group('major'), match.group('build')) if match else None elif name == "servicepack": self.__inServicePack = False self.__servicePack = self.__servicePack.replace(" ", "")
def parseResponse(page, headers): """ @param page: the page to parse to feed the knowledge base htmlFp (back-end DBMS fingerprint based upon DBMS error messages return through the web application) list and absFilePaths (absolute file paths) set. """ if headers: headersParser(headers) if page: htmlParser(page) # Detect injectable page absolute system path # NOTE: this regular expression works if the remote web # application is written in PHP and debug/error messages are # enabled for regex in ( r" in <b>(?P<result>.*?)</b> on line", r"(?:>|\s)(?P<result>[A-Za-z]:[\\/][\w.\\/]*)", r"(?:>|\s)(?P<result>/\w[/\w.]+)" ): regObj = getCompiledRegex(regex) for match in regObj.finditer(page): absFilePath = match.group("result").strip() page = page.replace(absFilePath, "") if isWindowsDriveLetterPath(absFilePath): absFilePath = posixToNtSlashes(absFilePath) if absFilePath not in kb.absFilePaths: kb.absFilePaths.add(absFilePath)
def checkPayload(payload): """ This method checks if the generated payload is detectable by the PHPIDS filter rules """ if not payload: return global rules detected = False payload = urldecode(payload) if not rules: xmlrules = readXmlFile(paths.PHPIDS_RULES_XML) rules = [] for xmlrule in xmlrules.getElementsByTagName("filter"): rule = "(?i)%s" % xmlrule.getElementsByTagName('rule')[0].childNodes[0].nodeValue desc = __adjustGrammar(xmlrule.getElementsByTagName('description')[0].childNodes[0].nodeValue) rules.append((rule, desc)) if payload: for rule, desc in rules: regObj = getCompiledRegex(rule) if regObj.search(payload): detected = True logger.warn("highly probable IDS/IPS detection: '%s: %s'" % (desc, payload)) if not detected: logger.warn("payload '%s' possibly gone undetected" % payload)
def replaceVars(item, vars_): retVal = item if item and vars_: for var in re.findall(getCompiledRegex("\$\{([^}]+)\}"), item): if var in vars_: retVal = retVal.replace("${%s}" % var, vars_[var]) return retVal
def checkPayload(payload): """ This method checks if the generated payload is detectable by the PHPIDS filter rules """ global rules detected = False payload = urldecode(payload) if not rules: xmlrules = readXmlFile(paths.PHPIDS_RULES_XML) rules = [] for xmlrule in xmlrules.getElementsByTagName("filter"): rule = "(?i)%s" % xmlrule.getElementsByTagName( 'rule')[0].childNodes[0].nodeValue desc = __adjustGrammar( xmlrule.getElementsByTagName('description') [0].childNodes[0].nodeValue) rules.append((rule, desc)) if payload: for rule, desc in rules: regObj = getCompiledRegex(rule) if regObj.search(payload): detected = True logger.warn("highly probable IDS/IPS detection: '%s: %s'" % (desc, payload)) if not detected: logger.warn("payload '%s' possibly gone undetected" % payload)
def hashRecognition(value): retVal = None if isinstance(value, basestring): for name, regex in getPublicTypeMembers(HASH): # Hashes for Oracle and old MySQL look the same hence these checks if Backend.getIdentifiedDbms() == DBMS.ORACLE and regex == HASH.MYSQL_OLD: continue elif Backend.getIdentifiedDbms() == DBMS.MYSQL and regex == HASH.ORACLE_OLD: continue elif regex == HASH.CRYPT_GENERIC and getCompiledRegex(GENERAL_IP_ADDRESS_REGEX).match(value): continue elif getCompiledRegex(regex).match(value): retVal = regex break return retVal
def getFields(self, query): """ Take in input a query string and return its fields (columns) and more details. Example: Input: SELECT user, password FROM mysql.user Output: user,password @param query: query to be processed @type query: C{str} @return: query fields (columns) and more details @rtype: C{str} """ prefixRegex = "(?:\s+(?:FIRST|SKIP)\s+\d+)*" fieldsSelectTop = getCompiledRegex("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", re.I).search(query) fieldsSelectDistinct = getCompiledRegex("\ASELECT%s\s+DISTINCT\((.+?)\)\s+FROM" % prefixRegex, re.I).search(query) fieldsSelectCase = getCompiledRegex("\ASELECT%s\s+(\(CASE WHEN\s+.+\s+END\))" % prefixRegex, re.I).search(query) fieldsSelectFrom = getCompiledRegex("\ASELECT%s\s+(.+?)\s+FROM\s+" % prefixRegex, re.I).search(query) fieldsExists = getCompiledRegex("EXISTS(.*)", re.I).search(query) fieldsSelect = getCompiledRegex("\ASELECT%s\s+(.*)" % prefixRegex, re.I).search(query) fieldsSubstr = getCompiledRegex("\A(SUBSTR|MID\()", re.I).search(query) fieldsMinMaxstr = getCompiledRegex("(?:MIN|MAX)\(([^\(\)]+)\)", re.I).search(query) fieldsNoSelect = query if fieldsSubstr: fieldsToCastStr = query elif fieldsMinMaxstr: fieldsToCastStr = fieldsMinMaxstr.groups()[0] elif fieldsExists: fieldsToCastStr = fieldsSelect.groups()[0] elif fieldsSelectTop: fieldsToCastStr = fieldsSelectTop.groups()[0] elif fieldsSelectDistinct: fieldsToCastStr = fieldsSelectDistinct.groups()[0] elif fieldsSelectCase: fieldsToCastStr = fieldsSelectCase.groups()[0] elif fieldsSelectFrom: fieldsToCastStr = fieldsSelectFrom.groups()[0] elif fieldsSelect: fieldsToCastStr = fieldsSelect.groups()[0] elif fieldsNoSelect: fieldsToCastStr = fieldsNoSelect # Function if re.search("\A\w+\(.*\)", fieldsToCastStr, re.I) or (fieldsSelectCase and "WHEN use" not in query) or fieldsSubstr: fieldsToCastList = [fieldsToCastStr] else: fieldsToCastList = fieldsToCastStr.replace(", ", ",") fieldsToCastList = fieldsToCastList.split(",") return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, fieldsToCastList, fieldsToCastStr, fieldsExists
def hashRecognition(value): retVal = None if isinstance(value, basestring): for name, regex in getPublicTypeMembers(HASH): # Hashes for Oracle and old MySQL look the same hence these checks if Backend.getIdentifiedDbms( ) == DBMS.ORACLE and regex == HASH.MYSQL_OLD: continue elif Backend.getIdentifiedDbms( ) == DBMS.MYSQL and regex == HASH.ORACLE_OLD: continue elif regex == HASH.CRYPT_GENERIC and getCompiledRegex( GENERAL_IP_ADDRESS_REGEX).match(value): continue elif getCompiledRegex(regex).match(value): retVal = regex break return retVal
def hashRecognition(value): retVal = None isOracle, isMySQL = Backend.isDbms(DBMS.ORACLE), Backend.isDbms(DBMS.MYSQL) if isinstance(value, basestring): for name, regex in getPublicTypeMembers(HASH): # Hashes for Oracle and old MySQL look the same hence these checks if isOracle and regex == HASH.MYSQL_OLD: continue elif isMySQL and regex == HASH.ORACLE_OLD: continue elif regex == HASH.CRYPT_GENERIC: if any([getCompiledRegex(GENERAL_IP_ADDRESS_REGEX).match(value), value.lower() == value, value.upper() == value, value.isdigit()]): continue elif getCompiledRegex(regex).match(value): retVal = regex break return retVal
def replacePayload(self, inpStr, payload): """ Replaces payload inside the input string with a given payload """ retVal = inpStr if inpStr: regObj = getCompiledRegex("(%s.*?%s)" % (PAYLOAD_DELIMITER, PAYLOAD_DELIMITER)) retVal = regObj.sub("%s%s%s" % (PAYLOAD_DELIMITER, payload, PAYLOAD_DELIMITER), inpStr) return retVal
def getRemoteTempPath(self): if not conf.tmpPath: if kb.os == "Windows": conf.tmpPath = "C:/WINDOWS/Temp" else: conf.tmpPath = "/tmp" if getCompiledRegex("(?i)\A[\w]:[\/\\\\]+").search(conf.tmpPath): kb.os = "Windows" conf.tmpPath = normalizePath(conf.tmpPath) conf.tmpPath = ntToPosixSlashes(conf.tmpPath) setRemoteTempPath()
def getRemoteTempPath(self): if not conf.tmpPath: if Backend.isOs(OS.WINDOWS): conf.tmpPath = "C:/WINDOWS/Temp" else: conf.tmpPath = "/tmp" if getCompiledRegex("(?i)\A[\w]:[\/\\\\]+").search(conf.tmpPath): Backend.setOs(OS.WINDOWS) conf.tmpPath = normalizePath(conf.tmpPath) conf.tmpPath = ntToPosixSlashes(conf.tmpPath) setRemoteTempPath()
def extractPayload(self, inpStr): """ Extracts payload from inside of the input string """ retVal = None if inpStr: regObj = getCompiledRegex("%s(?P<result>.*?)%s" % (PAYLOAD_DELIMITER, PAYLOAD_DELIMITER)) match = regObj.search(inpStr) if match: retVal = match.group("result") return retVal
def removePayloadDelimiters(self, inpStr, urlencode_=True): """ Removes payload delimiters from inside the input string """ retVal = inpStr if inpStr: if urlencode_: regObj = getCompiledRegex("(?P<result>%s.*?%s)" % (PAYLOAD_DELIMITER, PAYLOAD_DELIMITER)) for match in regObj.finditer(inpStr): retVal = retVal.replace(match.group("result"), urlencode(match.group("result").strip(PAYLOAD_DELIMITER), convall=True)) else: retVal = retVal.replace(PAYLOAD_DELIMITER, '') return retVal
def dictionaryAttack(attack_dict): suffix_list = [""] hash_regexes = [] results = [] for (_, hashes) in attack_dict.items(): for hash_ in hashes: if not hash_: continue hash_ = hash_.split()[0] regex = hashRecognition(hash_) if regex and regex not in hash_regexes: hash_regexes.append(regex) infoMsg = "using hash method: '%s'" % __functions__[ regex].func_name logger.info(infoMsg) for hash_regex in hash_regexes: attack_info = [] for (user, hashes) in attack_dict.items(): for hash_ in hashes: if not hash_: continue hash_ = hash_.split()[0] if getCompiledRegex(hash_regex).match(hash_): hash_ = hash_.lower() if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC): attack_info.append([(user, hash_), {}]) elif hash_regex in (HASH.ORACLE_OLD, HASH.POSTGRES): attack_info.append([(user, hash_), {'username': user}]) elif hash_regex in (HASH.ORACLE): attack_info.append([(user, hash_), { 'salt': hash_[-20:] }]) elif hash_regex in (HASH.MSSQL, HASH.MSSQL_OLD): attack_info.append([(user, hash_), { 'salt': hash_[6:14] }]) elif hash_regex in (HASH.CRYPT_GENERIC): attack_info.append([(user, hash_), { 'salt': hash_[0:2] }]) if not attack_info: continue if not kb.wordlist: if hash_regex == HASH.ORACLE_OLD: #it's the slowest of all methods hence smaller default dict message = "what's the dictionary's location? [%s]" % paths.ORACLE_DEFAULT_PASSWD dictpath = readInput(message, default=paths.ORACLE_DEFAULT_PASSWD) else: message = "what's the dictionary's location? [%s]" % paths.WORDLIST dictpath = readInput(message, default=paths.WORDLIST) checkFile(dictpath) infoMsg = "loading dictionary from: '%s'" % dictpath logger.info(infoMsg) kb.wordlist = getFileItems(dictpath, None, False) message = "do you want to use common password suffixes? (slow!) [y/N] " test = readInput(message, default="N") if test[0] in ("y", "Y"): suffix_list += COMMON_PASSWORD_SUFFIXES infoMsg = "starting dictionary attack (%s)" % __functions__[ hash_regex].func_name logger.info(infoMsg) for item in attack_info: ((user, _), _) = item kb.wordlist.append(normalizeUnicode(user)) length = len(kb.wordlist) * len(suffix_list) if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC): count = 0 for suffix in suffix_list: if not attack_info: break for word in kb.wordlist: if not attack_info: break count += 1 if suffix: word = word + suffix try: current = __functions__[hash_regex](password=word, uppercase=False) for item in attack_info: ((user, hash_), _) = item if hash_ == current: results.append((user, hash_, word)) clearConsoleLine() infoMsg = "[%s] [INFO] found: '%s'" % ( time.strftime("%X"), word) if user and not user.startswith( DUMMY_USER_PREFIX): infoMsg += " for user: '******'\n" % user else: infoMsg += " for hash: '%s'\n" % hash_ dataToStdout(infoMsg, True) attack_info.remove(item) elif count % HASH_MOD_ITEM_DISPLAY == 0 or count == length or hash_regex in ( HASH.ORACLE_OLD ) or hash_regex == HASH.CRYPT_GENERIC and IS_WIN: status = '%d/%d words (%d%s)' % ( count, length, round( 100.0 * count / length), '%') dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status)) except KeyboardInterrupt: print warnMsg = "user aborted during dictionary attack phase" logger.warn(warnMsg) return results except: warnMsg = "there was a problem while hashing entry: %s. " % repr( word) warnMsg += "Please report by e-mail to %s." % ML logger.critical(warnMsg) clearConsoleLine() else: for ((user, hash_), kwargs) in attack_info: count = 0 found = False for suffix in suffix_list: if found: break for word in kb.wordlist: current = __functions__[hash_regex](password=word, uppercase=False, **kwargs) count += 1 if suffix: word = word + suffix try: if hash_ == current: if regex == HASH.ORACLE_OLD: #only for cosmetic purposes word = word.upper() results.append((user, hash_, word)) clearConsoleLine() infoMsg = "[%s] [INFO] found: '%s'" % ( time.strftime("%X"), word) if user and not user.startswith( DUMMY_USER_PREFIX): infoMsg += " for user: '******'\n" % user else: infoMsg += " for hash: '%s'\n" % hash_ dataToStdout(infoMsg, True) found = True break elif count % HASH_MOD_ITEM_DISPLAY == 0 or count == length or hash_regex in ( HASH.ORACLE_OLD ) or hash_regex == HASH.CRYPT_GENERIC and IS_WIN: status = '%d/%d words (%d%s)' % ( count, length, round( 100.0 * count / length), '%') if not user.startswith(DUMMY_USER_PREFIX): status += ' (user: %s)' % user dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status)) except KeyboardInterrupt: print warnMsg = "user aborted during dictionary attack phase" logger.warn(warnMsg) return results except: warnMsg = "there was a problem while hashing entry: %s. " % repr( word) warnMsg += "Please report by e-mail to %s." % ML logger.critical(warnMsg) clearConsoleLine() if len(hash_regexes) == 0: warnMsg = "unknown hash Format. " warnMsg += "Please report by e-mail to %s." % ML logger.warn(warnMsg) if len(results) == 0: warnMsg = "no clear password(s) found" logger.warn(warnMsg) return results
def resume(expression, payload): """ This function can be called to resume part or entire output of a SQL injection query output. """ try: if "sqlmapfile" in expression or "sqlmapoutput" in expression or conf.freshQueries: return None condition = ( kb.resumedQueries and conf.url in kb.resumedQueries and expression in kb.resumedQueries[conf.url] ) if not condition: return None resumedValue = kb.resumedQueries[conf.url][expression] if not resumedValue: return None resumedValue = restoreDumpMarkedChars(resumedValue, True) if resumedValue[-1] == "]": resumedValue = resumedValue[:-1] infoMsg = "read from file '%s': " % conf.sessionFile logValue = getCompiledRegex("%s(.*?)%s" % (DUMP_START_MARKER, DUMP_STOP_MARKER), re.S).findall(resumedValue) if logValue: if kb.technique == PAYLOAD.TECHNIQUE.UNION: logValue = ", ".join([value.replace(DUMP_DEL_MARKER, ", ") for value in logValue]) else: return None else: logValue = resumedValue if "\n" in logValue: infoMsg += "%s..." % logValue.split("\n")[0] else: infoMsg += logValue if not kb.suppressResumeInfo: dataToStdout("[%s] [INFO] %s\n" % (time.strftime("%X"), infoMsg)) return resumedValue # If we called this function without providing a payload it means # that we have called it from lib/request/inject __goInband() or # from __goError() function so we return to the calling function # so that the query output will be retrieved taking advantage # of either error-based or inband SQL injection vulnerability. if not payload: return None if not Backend.getIdentifiedDbms(): return None substringQuery = queries[Backend.getIdentifiedDbms()].substring.query select = getCompiledRegex("\ASELECT ", re.I).search(expression) _, length, regExpr = queryOutputLength(expression, payload) if not length: return None if len(resumedValue) == int(length): infoMsg = "read from file '%s': " % conf.sessionFile infoMsg += "%s" % resumedValue.split("\n")[0] logger.info(infoMsg) dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injection.place, conf.parameters[kb.injection.place], expression, replaceNewlineTabs(resumedValue))) return resumedValue elif len(resumedValue) < int(length): infoMsg = "resumed from file '%s': " % conf.sessionFile infoMsg += "%s..." % resumedValue.split("\n")[0] logger.info(infoMsg) dataToSessionFile("[%s][%s][%s][%s][%s" % (conf.url, kb.injection.place, conf.parameters[kb.injection.place], expression, replaceNewlineTabs(resumedValue))) if select: newExpr = expression.replace(regExpr, safeStringFormat(substringQuery, (regExpr, len(resumedValue) + 1, int(length))), 1) else: newExpr = safeStringFormat(substringQuery, (expression, len(resumedValue) + 1, int(length))) missingCharsLength = int(length) - len(resumedValue) infoMsg = "retrieving pending %d query " % missingCharsLength infoMsg += "output characters" logger.info(infoMsg) start = time.time() count, finalValue = bisection(payload, newExpr, length=missingCharsLength) debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start)) logger.debug(debugMsg) if len(finalValue) != ( int(length) - len(resumedValue) ): warnMsg = "the total length of the query is not " warnMsg += "right, sqlmap is going to retrieve the " warnMsg += "query value from the beginning now" logger.warn(warnMsg) return None return "%s%s" % (resumedValue, finalValue) return None except ValueError: errMsg = "invalid resume value for expression: '%s'" % expression logger.error(errMsg) return None
def dictionaryAttack(attack_dict): suffix_list = [""] hash_regexes = [] results = [] for (_, hashes) in attack_dict.items(): for hash_ in hashes: if not hash_: continue hash_ = hash_.split()[0] regex = hashRecognition(hash_) if regex and regex not in hash_regexes: hash_regexes.append(regex) infoMsg = "using hash method: '%s'" % __functions__[regex].func_name logger.info(infoMsg) for hash_regex in hash_regexes: attack_info = [] for (user, hashes) in attack_dict.items(): for hash_ in hashes: if not hash_: continue hash_ = hash_.split()[0] if getCompiledRegex(hash_regex).match(hash_): hash_ = hash_.lower() if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC): attack_info.append([(user, hash_), {}]) elif hash_regex in (HASH.ORACLE_OLD, HASH.POSTGRES): attack_info.append([(user, hash_), {'username': user}]) elif hash_regex in (HASH.ORACLE): attack_info.append([(user, hash_), {'salt': hash_[-20:]}]) elif hash_regex in (HASH.MSSQL, HASH.MSSQL_OLD): attack_info.append([(user, hash_), {'salt': hash_[6:14]}]) elif hash_regex in (HASH.CRYPT_GENERIC): attack_info.append([(user, hash_), {'salt': hash_[0:2]}]) if not attack_info: continue if not kb.wordlist: if hash_regex == HASH.ORACLE_OLD: #it's the slowest of all methods hence smaller default dict message = "what's the dictionary's location? [%s]" % paths.ORACLE_DEFAULT_PASSWD dictpath = readInput(message, default=paths.ORACLE_DEFAULT_PASSWD) else: message = "what's the dictionary's location? [%s]" % paths.WORDLIST dictpath = readInput(message, default=paths.WORDLIST) checkFile(dictpath) infoMsg = "loading dictionary from: '%s'" % dictpath logger.info(infoMsg) kb.wordlist = getFileItems(dictpath, None, False) message = "do you want to use common password suffixes? (slow!) [y/N] " test = readInput(message, default="N") if test[0] in ("y", "Y"): suffix_list += COMMON_PASSWORD_SUFFIXES infoMsg = "starting dictionary attack (%s)" % __functions__[hash_regex].func_name logger.info(infoMsg) for item in attack_info: ((user, _), _) = item kb.wordlist.append(normalizeUnicode(user)) length = len(kb.wordlist) * len(suffix_list) if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC): count = 0 for suffix in suffix_list: if not attack_info: break for word in kb.wordlist: if not attack_info: break count += 1 if suffix: word = word + suffix try: current = __functions__[hash_regex](password = word, uppercase = False) for item in attack_info: ((user, hash_), _) = item if hash_ == current: results.append((user, hash_, word)) clearConsoleLine() infoMsg = "[%s] [INFO] found: '%s'" % (time.strftime("%X"), word) if user and not user.startswith(DUMMY_USER_PREFIX): infoMsg += " for user: '******'\n" % user else: infoMsg += " for hash: '%s'\n" % hash_ dataToStdout(infoMsg, True) attack_info.remove(item) elif count % HASH_MOD_ITEM_DISPLAY == 0 or count == length or hash_regex in (HASH.ORACLE_OLD) or hash_regex == HASH.CRYPT_GENERIC and IS_WIN: status = '%d/%d words (%d%s)' % (count, length, round(100.0*count/length), '%') dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status)) except KeyboardInterrupt: print warnMsg = "user aborted during dictionary attack phase" logger.warn(warnMsg) return results except: warnMsg = "there was a problem while hashing entry: %s. " % repr(word) warnMsg += "Please report by e-mail to %s." % ML logger.critical(warnMsg) clearConsoleLine() else: for ((user, hash_), kwargs) in attack_info: count = 0 found = False for suffix in suffix_list: if found: break for word in kb.wordlist: current = __functions__[hash_regex](password = word, uppercase = False, **kwargs) count += 1 if suffix: word = word + suffix try: if hash_ == current: if regex == HASH.ORACLE_OLD: #only for cosmetic purposes word = word.upper() results.append((user, hash_, word)) clearConsoleLine() infoMsg = "[%s] [INFO] found: '%s'" % (time.strftime("%X"), word) if user and not user.startswith(DUMMY_USER_PREFIX): infoMsg += " for user: '******'\n" % user else: infoMsg += " for hash: '%s'\n" % hash_ dataToStdout(infoMsg, True) found = True break elif count % HASH_MOD_ITEM_DISPLAY == 0 or count == length or hash_regex in (HASH.ORACLE_OLD) or hash_regex == HASH.CRYPT_GENERIC and IS_WIN: status = '%d/%d words (%d%s)' % (count, length, round(100.0*count/length), '%') if not user.startswith(DUMMY_USER_PREFIX): status += ' (user: %s)' % user dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status)) except KeyboardInterrupt: print warnMsg = "user aborted during dictionary attack phase" logger.warn(warnMsg) return results except: warnMsg = "there was a problem while hashing entry: %s. " % repr(word) warnMsg += "Please report by e-mail to %s." % ML logger.critical(warnMsg) clearConsoleLine() if len(hash_regexes) == 0: warnMsg = "unknown hash Format. " warnMsg += "Please report by e-mail to %s." % ML logger.warn(warnMsg) if len(results) == 0: warnMsg = "no clear password(s) found" logger.warn(warnMsg) return results
def dictionaryAttack(attack_dict): suffix_list = [""] hash_regexes = [] results = [] resumes = [] processException = False for (_, hashes) in attack_dict.items(): for hash_ in hashes: if not hash_: continue hash_ = hash_.split()[0] regex = hashRecognition(hash_) if regex and regex not in hash_regexes: hash_regexes.append(regex) infoMsg = "using hash method '%s'" % __functions__[regex].func_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 hash_ = hash_.split()[0].lower() if getCompiledRegex(hash_regex).match(hash_): item = None if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC): item = [(user, hash_), {}] 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): item = [(user, hash_), {'salt': hash_[6:14]}] elif hash_regex in (HASH.CRYPT_GENERIC): item = [(user, hash_), {'salt': hash_[0:2]}] if item and hash_ not in keys: resumed = conf.hashDB.retrieve(hash_) if not resumed: attack_info.append(item) 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_) if not attack_info: continue if not kb.wordlist: while not kb.wordlist: message = "what dictionary do you want to use?\n" message += "[1] default dictionary file (press Enter)\n" 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" dictPaths = [readInput(message)] 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: # It is the slowest of all methods hence smaller default dict if hash_regex == HASH.ORACLE_OLD: dictPaths = [paths.SMALL_DICT] else: dictPaths = [paths.WORDLIST] logger.info("using default dictionary") for dictPath in dictPaths: checkFile(dictPath) kb.wordlist = Wordlist(dictPaths) if _multiprocessing: kb.wordlist.lock = _multiprocessing.Lock() except sqlmapFilePathException, msg: warnMsg = "there was a problem while loading dictionaries" warnMsg += " ('%s')" % msg logger.critical(warnMsg) message = "do you want to use common password suffixes? (slow!) [y/N] " test = readInput(message, default="N") if test[0] in ("y", "Y"): suffix_list += COMMON_PASSWORD_SUFFIXES infoMsg = "starting dictionary-based cracking (%s)" % __functions__[hash_regex].func_name logger.info(infoMsg) for item in attack_info: ((user, _), _) = item if user and not user.startswith(DUMMY_USER_PREFIX): kb.wordlist.append(normalizeUnicode(user)) if hash_regex in (HASH.MYSQL, HASH.MYSQL_OLD, HASH.MD5_GENERIC, HASH.SHA1_GENERIC): for suffix in suffix_list: if len(attack_info) == len(results) or processException: break if suffix: clearConsoleLine() infoMsg = "using suffix '%s'" % suffix logger.info(infoMsg) kb.wordlist.rewind() retVal = None processes = [] try: if _multiprocessing and not IS_WIN: if _multiprocessing.cpu_count() > 1: infoMsg = "starting %d processes " % _multiprocessing.cpu_count() singleTimeLogMessage(infoMsg) retVal = _multiprocessing.Queue() for i in xrange(_multiprocessing.cpu_count()): p = _multiprocessing.Process(target=__bruteProcessVariantA, args=(attack_info, hash_regex, kb.wordlist, suffix, retVal, i, _multiprocessing.cpu_count())) processes.append(p) for p in processes: p.start() for p in processes: p.join() else: warnMsg = "multiprocessing hash cracking is currently " warnMsg += "not supported on this platform" singleTimeWarnMessage(warnMsg) retVal = Queue() __bruteProcessVariantA(attack_info, hash_regex, kb.wordlist, suffix, retVal, 0, 1) except KeyboardInterrupt: print processException = True warnMsg = "user aborted during dictionary-based attack phase (Ctrl+C was pressed)" logger.warn(warnMsg) for process in processes: process.terminate() process.join() finally: if retVal: conf.hashDB.beginTransaction() while not retVal.empty(): _, hash_, word = item = retVal.get(block=False) conf.hashDB.write(hash_, word) results.append(item) conf.hashDB.endTransaction() clearConsoleLine() else: for ((user, hash_), kwargs) in attack_info: if processException: break 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) kb.wordlist.rewind() retVal = None processes = [] try: if _multiprocessing and not IS_WIN: if _multiprocessing.cpu_count() > 1: infoMsg = "starting %d processes " % _multiprocessing.cpu_count() singleTimeLogMessage(infoMsg) retVal = _multiprocessing.Queue() found_ = _multiprocessing.Value('i', False) for i in xrange(_multiprocessing.cpu_count()): p = _multiprocessing.Process(target=__bruteProcessVariantB, args=(user, hash_, kwargs, hash_regex, kb.wordlist, suffix, retVal, found_, i, _multiprocessing.cpu_count())) processes.append(p) for p in processes: p.start() for p in processes: p.join() found = found_.value != 0 else: warnMsg = "multiprocessing hash cracking is currently " warnMsg += "not supported on this platform" singleTimeWarnMessage(warnMsg) class Value(): pass retVal = Queue() found_ = Value() found_.value = False __bruteProcessVariantB(user, hash_, kwargs, hash_regex, kb.wordlist, suffix, retVal, found_, 0, 1) 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: process.terminate() process.join() finally: if retVal: conf.hashDB.beginTransaction() while not retVal.empty(): _, hash_, word = item = retVal.get(block=False) conf.hashDB.write(hash_, word) results.append(item) conf.hashDB.endTransaction() clearConsoleLine()