Esempio n. 1
0
def setInjection(inj):
    """
    Save information retrieved about injection place and parameter in the
    session file.
    """

    try:
        condition = ( not kb.resumedQueries
                    or ( kb.resumedQueries.has_key(conf.url) and
                    not kb.resumedQueries[conf.url].has_key("Injection data"))
                    or ( kb.resumedQueries[conf.url].has_key("Injection data")
                    and intersect(base64unpickle(kb.resumedQueries[conf.url]["Injection data"][:-1]).data.keys(),\
                        inj.data.keys()) != inj.data.keys()
                    ) )
    except AttributeError:
        warnMsg = "there were some changes in data model "
        warnMsg += "preventing normal resume of previously stored "
        warnMsg += "injection data. please use the --flush-session "
        warnMsg += "to have it fixed"
        singleTimeWarnMessage(warnMsg)

        condition = False

    if condition:
        dataToSessionFile("[%s][%s][%s][Injection data][%s]\n" % (conf.url, inj.place, safeFormatString(conf.parameters[inj.place]), base64pickle(inj)))
Esempio n. 2
0
def setDbms(dbms):
    """
    @param dbms: database management system to be set into the knowledge
    base as fingerprint.
    @type dbms: C{str}
    """

    condition = (
                  not kb.resumedQueries
                  or ( kb.resumedQueries.has_key(conf.url) and
                  not kb.resumedQueries[conf.url].has_key("DBMS") )
                )

    if condition:
        dataToSessionFile("[%s][%s][%s][DBMS][%s]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]), safeFormatString(dbms)))

    firstRegExp = "(%s|%s|%s|%s)" % ("|".join([alias for alias in MSSQL_ALIASES]),
                                     "|".join([alias for alias in MYSQL_ALIASES]),
                                     "|".join([alias for alias in PGSQL_ALIASES]),
                                     "|".join([alias for alias in ORACLE_ALIASES]))
    dbmsRegExp = re.search("^%s" % firstRegExp, dbms, re.I)

    if dbmsRegExp:
        dbms = dbmsRegExp.group(1)

    kb.dbms = dbms

    logger.info("the back-end DBMS is %s" % kb.dbms)
Esempio n. 3
0
def setDbms(dbms):
    """
    @param dbms: database management system to be set into the knowledge
    base as fingerprint.
    @type dbms: C{str}
    """
    condition = (not kb.resumedQueries
                 or (kb.resumedQueries.has_key(conf.url)
                     and not kb.resumedQueries[conf.url].has_key("DBMS")))

    if condition:
        dataToSessionFile(
            "[%s][%s][%s][DBMS][%s]\n" %
            (conf.url, kb.injection.place,
             safeFormatString(
                 conf.parameters[kb.injection.place]), safeFormatString(dbms)))

    firstRegExp = "(%s)" % ("|".join([alias for alias in SUPPORTED_DBMS]))
    dbmsRegExp = re.search("^%s" % firstRegExp, dbms, re.I)

    if dbmsRegExp:
        dbms = dbmsRegExp.group(1)

    Backend.setDbms(dbms)

    logger.info("the back-end DBMS is %s" % Backend.getDbms())
Esempio n. 4
0
    def tableExistsThread():
        while count[0] < length and kb.threadContinue:
            tbllock.acquire()
            table = safeSQLIdentificatorNaming(tables[count[0]])
            count[0] += 1
            tbllock.release()

            if conf.db and not conf.db.endswith(METADB_SUFFIX):
                fullTableName = "%s%s%s" % (conf.db, '..' if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) else '.', table)
            else:
                fullTableName = table

            result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %d FROM %s)", (randomInt(1), fullTableName)))

            iolock.acquire()

            if result and table.lower() not in items:
                retVal.append(table)

                items.add(table.lower())

                dataToSessionFile("[%s][%s][%s][TABLE_EXISTS][%s]\n" % (conf.url,\
                  kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]),\
                  safeFormatString(fullTableName)))

                if conf.verbose in (1, 2):
                    clearConsoleLine(True)
                    infoMsg = "\r[%s] [INFO] retrieved: %s\n" % (time.strftime("%X"), table)
                    dataToStdout(infoMsg, True)

            if conf.verbose in (1, 2):
                status = '%d/%d items (%d%s)' % (count[0], length, round(100.0*count[0]/length), '%')
                dataToStdout("\r[%s] [INFO] tried %s" % (time.strftime("%X"), status), True)

            iolock.release()
Esempio n. 5
0
def queryOutputLength(expression, payload):
    """
    Returns the query output length.
    """

    lengthQuery = queries[kb.dbms].length.query

    select = re.search("\ASELECT\s+", expression, re.I)
    selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I)
    selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I)
    selectFromExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I)
    selectExpr = re.search("\ASELECT\s+(.+)$", expression, re.I)
    miscExpr = re.search("\A(.+)", expression, re.I)

    if selectTopExpr or selectDistinctExpr or selectFromExpr or selectExpr:
        if selectTopExpr:
            regExpr = selectTopExpr.groups()[0]
        elif selectDistinctExpr:
            regExpr = selectDistinctExpr.groups()[0]
        elif selectFromExpr:
            regExpr = selectFromExpr.groups()[0]
        elif selectExpr:
            regExpr = selectExpr.groups()[0]
    elif miscExpr:
        regExpr = miscExpr.groups()[0]

    if (select and re.search("\A(COUNT|LTRIM)\(", regExpr, re.I)) or len(regExpr) <= 1:
        return None, None, None

    if selectDistinctExpr:
        lengthExpr = "SELECT %s FROM (%s)" % (lengthQuery % regExpr, expression)

        if kb.dbms in (DBMS.MYSQL, DBMS.POSTGRESQL):
            lengthExpr += " AS %s" % randomStr(lowercase=True)
    elif select:
        lengthExpr = expression.replace(regExpr, lengthQuery % regExpr, 1)
    else:
        lengthExpr = lengthQuery % expression

    infoMsg = "retrieving the length of query output"
    logger.info(infoMsg)

    output = resume(lengthExpr, payload)

    if output:
        return 0, output, regExpr

    dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], lengthExpr))

    start = time.time()
    lengthExprUnescaped = unescaper.unescape(lengthExpr)
    count, length = bisection(payload, lengthExprUnescaped, charsetType=2)

    debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start))
    logger.debug(debugMsg)

    if length == " ":
        length = 0

    return count, length, regExpr
Esempio n. 6
0
def goError(expression, suppressOutput=False, returnPayload=False):
    """
    Retrieve the output of a SQL query taking advantage of an error-based
    SQL injection vulnerability on the affected parameter.
    """

    result = None

    if suppressOutput:
        pushValue(conf.verbose)
        conf.verbose = 0

    if conf.direct:
        return direct(expression), None

    condition = (
                  kb.resumedQueries and conf.url in kb.resumedQueries.keys()
                  and expression in kb.resumedQueries[conf.url].keys()
                )

    if condition:
        result = resume(expression, None)

    if not result:
        result = errorUse(expression, returnPayload)

        if not returnPayload:
            dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, replaceNewlineTabs(result)))

    if suppressOutput:
        conf.verbose = popValue()

    return result
Esempio n. 7
0
def __goInference(payload,
                  expression,
                  charsetType=None,
                  firstChar=None,
                  lastChar=None,
                  dump=False):
    start = time.time()

    timeBasedCompare = (kb.technique
                        in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED))

    if (conf.eta or conf.threads > 1
        ) and Backend.getIdentifiedDbms() and not timeBasedCompare:
        _, length, _ = queryOutputLength(expression, payload)
    else:
        length = None

    dataToSessionFile("[%s][%s][%s][%s][" %
                      (conf.url, kb.injection.place,
                       conf.parameters[kb.injection.place], expression))

    count, value = bisection(payload, expression, length, charsetType,
                             firstChar, lastChar, dump)

    if not kb.bruteMode:
        debugMsg = "performed %d queries in %d seconds" % (
            count, calculateDeltaSeconds(start))
        logger.debug(debugMsg)

    return value
Esempio n. 8
0
def setXpCmdshellAvailability(available):
    condition = (
                  not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
                  not kb.resumedQueries[conf.url].has_key("xp_cmdshell availability") )
                )

    if condition:
        dataToSessionFile("[%s][%s][%s][xp_cmdshell availability][%s]\n" % (conf.url, kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]), str(available).lower()))
Esempio n. 9
0
def setRemoteTempPath():
    condition = (
                  not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
                  not kb.resumedQueries[conf.url].has_key("Remote temp path") )
                )

    if condition:
        dataToSessionFile("[%s][%s][%s][Remote temp path][%s]\n" % (conf.url, kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]), safeFormatString(conf.tmpPath)))
Esempio n. 10
0
def setError():
    condition = (
                  not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
                  not kb.resumedQueries[conf.url].has_key("Error based injection") )
                )

    if condition:
        dataToSessionFile("[%s][%s][%s][Error based injection][Yes]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace])))
Esempio n. 11
0
def setMatchRatio():
    condition = (
                  isinstance(conf.matchRatio, (int, float))
                  and ( not kb.resumedQueries
                  or ( kb.resumedQueries.has_key(conf.url) and not
                  kb.resumedQueries[conf.url].has_key("Match ratio") ) )
                )

    if condition:
        dataToSessionFile("[%s][%s][%s][Match ratio][%s]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]), conf.matchRatio))
Esempio n. 12
0
def direct(query, content=True):
    output = None
    select = True
    query = agent.payloadDirect(query)

    if Backend.isDbms(DBMS.ORACLE) and query.startswith("SELECT ") and " FROM " not in query:
        query = "%s FROM DUAL" % query

    for sqlTitle, sqlStatements in SQL_STATEMENTS.items():
        for sqlStatement in sqlStatements:
            if query.lower().startswith(sqlStatement) and sqlTitle != "SQL SELECT statement":
                select = False
                break

    if select and not query.upper().startswith("SELECT "):
        query = "SELECT " + query

    logger.log(9, query)

    if not select:
        output = timeout(func=conf.dbmsConnector.execute, args=(query,), duration=conf.timeout, default=None)
    elif conf.hostname in kb.resumedQueries and query in kb.resumedQueries[conf.hostname] and "sqlmapoutput" not in query and "sqlmapfile" not in query:
        try:
            output = base64unpickle(kb.resumedQueries[conf.hostname][query][:-1])
        except:
            output = timeout(func=conf.dbmsConnector.select, args=(query,), duration=conf.timeout, default=None)

        infoMsg = "resumed from file '%s': " % conf.sessionFile
        infoMsg += "%s..." % getUnicode(output, UNICODE_ENCODING)[:20]
        logger.info(infoMsg)
    else:
        output = timeout(func=conf.dbmsConnector.select, args=(query,), duration=conf.timeout, default=None)

    if output is None or len(output) == 0:
        return None
    elif content:
        if conf.hostname not in kb.resumedQueries or ( conf.hostname in kb.resumedQueries and query not in kb.resumedQueries[conf.hostname] ):
            dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.hostname, kb.injection.place, conf.parameters[kb.injection.place], query, base64pickle(output)))

        if len(output) == 1:
            if len(output[0]) == 1:
                out = list(output)[0][0]
                if isinstance(out, str):
                    out = utf8decode(out)
                return getUnicode(out, UNICODE_ENCODING)
            else:
                return list(output)
        else:
            return output
    else:
        for line in output:
            if line[0] in (1, -1):
                return True
            else:
                return False
Esempio n. 13
0
def setRemoteTempPath():
    condition = (not kb.resumedQueries or
                 (kb.resumedQueries.has_key(conf.url) and
                  not kb.resumedQueries[conf.url].has_key("Remote temp path")))

    if condition:
        dataToSessionFile(
            "[%s][%s][%s][Remote temp path][%s]\n" %
            (conf.url, kb.injection.place,
             safeFormatString(conf.parameters[kb.injection.place]),
             safeFormatString(conf.tmpPath)))
Esempio n. 14
0
def setStacked():
    condition = (
                  not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
                  not kb.resumedQueries[conf.url].has_key("Stacked queries") )
                )

    if not isinstance(kb.stackedTest, basestring):
        return

    if condition:
        dataToSessionFile("[%s][%s][%s][Stacked queries][%s]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]), kb.stackedTest))
Esempio n. 15
0
def setRegexp():
    """
    Save regular expression to match in session file.
    """

    condition = (
                  not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
                  not kb.resumedQueries[conf.url].has_key("Regular expression") )
                )

    if condition:
        dataToSessionFile("[%s][None][None][Regular expression][%s]\n" % (conf.url, conf.regexp))
Esempio n. 16
0
def queryOutputLength(expression, payload):
    """
    Returns the query output length.
    """

    lengthQuery = queries[kb.dbms].length

    select = re.search("\ASELECT\s+", expression, re.I)
    selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM",
                              expression, re.I)
    selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM",
                                   expression, re.I)
    selectExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I)
    miscExpr = re.search("\A(.+)", expression, re.I)

    if selectTopExpr or selectDistinctExpr or selectExpr:
        if selectTopExpr:
            regExpr = selectTopExpr.groups()[0]
        elif selectDistinctExpr:
            regExpr = selectDistinctExpr.groups()[0]
        elif selectExpr:
            regExpr = selectExpr.groups()[0]
    elif miscExpr:
        regExpr = miscExpr.groups()[0]

    if (select and re.search("\A(COUNT|LTRIM)\(", regExpr,
                             re.I)) or len(regExpr) <= 1:
        return None, None, None

    if select:
        lengthExpr = expression.replace(regExpr, lengthQuery % regExpr, 1)
    else:
        lengthExpr = lengthQuery % expression

    infoMsg = "retrieving the length of query output"
    logger.info(infoMsg)

    output = resume(lengthExpr, payload)

    if output:
        return 0, output, regExpr

    dataToSessionFile(
        "[%s][%s][%s][%s][" %
        (conf.url, kb.injPlace, conf.parameters[kb.injPlace], lengthExpr))

    lengthExprUnescaped = unescaper.unescape(lengthExpr)
    count, length = bisection(payload, lengthExprUnescaped)

    if length == " ":
        length = 0

    return count, length, regExpr
Esempio n. 17
0
def setString():
    """
    Save string to match in session file.
    """

    condition = (not kb.resumedQueries
                 or (kb.resumedQueries.has_key(conf.url)
                     and not kb.resumedQueries[conf.url].has_key("String")))

    if condition:
        dataToSessionFile("[%s][None][None][String][%s]\n" %
                          (conf.url, conf.string))
Esempio n. 18
0
def setString():
    """
    Save string to match in session file.
    """

    condition = (
                  not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
                  not kb.resumedQueries[conf.url].has_key("String") )
                )

    if condition:
        dataToSessionFile("[%s][None][None][String][%s]\n" % (conf.url, conf.string))
Esempio n. 19
0
def setRegexp():
    """
    Save regular expression to match in session file.
    """

    condition = (
        not kb.resumedQueries
        or (kb.resumedQueries.has_key(conf.url)
            and not kb.resumedQueries[conf.url].has_key("Regular expression")))

    if condition:
        dataToSessionFile("[%s][None][None][Regular expression][%s]\n" %
                          (conf.url, conf.regexp))
Esempio n. 20
0
def __setOutputResume():
    """
    Check and set the output text file and the resume functionality.
    """

    if conf.sessionFile and os.path.exists(conf.sessionFile):
        readSessionFP = open(conf.sessionFile, "r")
        lines = readSessionFP.readlines()

        for line in lines:
            if line.count("][") == 4:
                line = line.split("][")

                if len(line) != 5:
                    continue

                url, _, _, expression, value = line

                if not value:
                    continue

                if url[0] == "[":
                    url = url[1:]

                if value[-1] == "\n":
                    value = value[:-1]

                if url != conf.url:
                    continue

                if url not in kb.resumedQueries.keys():
                    kb.resumedQueries[url] = {}
                    kb.resumedQueries[url][expression] = value

                resumeConfKb(expression, url, value)

                if expression not in kb.resumedQueries[url].keys():
                    kb.resumedQueries[url][expression] = value
                elif len(value) >= len(kb.resumedQueries[url][expression]):
                    kb.resumedQueries[url][expression] = value

        readSessionFP.close()

    if conf.sessionFile:
        try:
            conf.sessionFP = open(conf.sessionFile, "a")
            dataToSessionFile("\n[%s]\n" % time.strftime("%X %x"))
        except IOError:
            errMsg = "unable to write on the session file specified"
            raise sqlmapFilePathException, errMsg
Esempio n. 21
0
def setDynamicMarkings(markings):
    """
    Save information retrieved about dynamic markings to the
    session file.
    """

    condition = (
        (not kb.resumedQueries
         or (kb.resumedQueries.has_key(conf.url)
             and not kb.resumedQueries[conf.url].has_key("Dynamic markings"))))

    if condition:
        dataToSessionFile("[%s][%s][%s][Dynamic markings][%s]\n" %
                          (conf.url, None, None, base64pickle(markings)))
Esempio n. 22
0
def setOs():
    """
    Example of kb.bannerFp dictionary:

    {
      'sp': set(['Service Pack 4']),
      'dbmsVersion': '8.00.194',
      'dbmsServicePack': '0',
      'distrib': set(['2000']),
      'dbmsRelease': '2000',
      'type': set(['Windows'])
    }
    """

    infoMsg = ""
    condition = (not kb.resumedQueries
                 or (kb.resumedQueries.has_key(conf.url)
                     and not kb.resumedQueries[conf.url].has_key("OS")))

    if not kb.bannerFp:
        return

    if "type" in kb.bannerFp:
        kb.os = Format.humanize(kb.bannerFp["type"])
        infoMsg = "the back-end DBMS operating system is %s" % kb.os

    if "distrib" in kb.bannerFp:
        kb.osVersion = Format.humanize(kb.bannerFp["distrib"])
        infoMsg += " %s" % kb.osVersion

    if "sp" in kb.bannerFp:
        kb.osSP = int(
            Format.humanize(kb.bannerFp["sp"]).replace("Service Pack ", ""))

    elif "sp" not in kb.bannerFp and kb.os == "Windows":
        kb.osSP = 0

    if kb.os and kb.osVersion and kb.osSP:
        infoMsg += " Service Pack %d" % kb.osSP

    if infoMsg:
        logger.info(infoMsg)

    if condition:
        dataToSessionFile(
            "[%s][%s][%s][OS][%s]\n" %
            (conf.url, kb.injection.place,
             safeFormatString(conf.parameters[kb.injection.place]),
             safeFormatString(kb.os)))
Esempio n. 23
0
def setDynamicMarkings(markings):
    """
    Save information retrieved about dynamic markings to the
    session file.
    """

    condition = (
                  ( not kb.resumedQueries
                  or ( kb.resumedQueries.has_key(conf.url) and
                  not kb.resumedQueries[conf.url].has_key("Dynamic markings")
                  ) )
                )

    if condition:
        dataToSessionFile("[%s][%s][%s][Dynamic markings][%s]\n" % (conf.url, None, None, base64pickle(markings)))
Esempio n. 24
0
def queryOutputLength(expression, payload):
    """
    Returns the query output length.
    """

    lengthQuery         = queries[kb.dbms].length

    select              = re.search("\ASELECT\s+", expression, re.I)
    selectTopExpr       = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I)
    selectDistinctExpr  = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I)
    selectExpr          = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I)
    miscExpr            = re.search("\A(.+)", expression, re.I)

    if selectTopExpr or selectDistinctExpr or selectExpr:
        if selectTopExpr:
            regExpr = selectTopExpr.groups()[0]
        elif selectDistinctExpr:
            regExpr = selectDistinctExpr.groups()[0]
        elif selectExpr:
            regExpr = selectExpr.groups()[0]
    elif miscExpr:
        regExpr = miscExpr.groups()[0]

    if ( select and re.search("\A(COUNT|LTRIM)\(", regExpr, re.I) ) or len(regExpr) <= 1:
        return None, None, None

    if select:
        lengthExpr = expression.replace(regExpr, lengthQuery % regExpr, 1)
    else:
        lengthExpr = lengthQuery % expression

    infoMsg = "retrieving the length of query output"
    logger.info(infoMsg)

    output = resume(lengthExpr, payload)

    if output:
        return 0, output, regExpr

    dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], lengthExpr))

    lengthExprUnescaped = unescaper.unescape(lengthExpr)
    count, length       = bisection(payload, lengthExprUnescaped)

    if length == " ":
        length = 0

    return count, length, regExpr
Esempio n. 25
0
def setParenthesis(parenthesisCount):
    """
    @param parenthesisCount: number of parenthesis to be set into the
    knowledge base as fingerprint.
    @type parenthesisCount: C{int}
    """

    condition = (
                  not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
                  not kb.resumedQueries[conf.url].has_key("Parenthesis") )
                )

    if condition:
        dataToSessionFile("[%s][%s][%s][Parenthesis][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], parenthesisCount))

    kb.parenthesis = parenthesisCount
Esempio n. 26
0
def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None):
    start = time.time()

    if ( conf.eta or conf.threads > 1 ) and kb.dbms:
        _, length, _ = queryOutputLength(expression, payload)
    else:
        length = None

    dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression))

    count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar)

    debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start))
    logger.debug(debugMsg)

    return value
Esempio n. 27
0
def setOs():
    """
    Example of kb.bannerFp dictionary:

    {
      'sp': set(['Service Pack 4']),
      'dbmsVersion': '8.00.194',
      'dbmsServicePack': '0',
      'distrib': set(['2000']),
      'dbmsRelease': '2000',
      'type': set(['Windows'])
    }
    """

    infoMsg = ""
    condition = (
                  not kb.resumedQueries
                  or ( kb.resumedQueries.has_key(conf.url) and
                  not kb.resumedQueries[conf.url].has_key("OS") )
                )

    if not kb.bannerFp:
        return

    if "type" in kb.bannerFp:
        Backend.setOs(Format.humanize(kb.bannerFp["type"]))
        infoMsg = "the back-end DBMS operating system is %s" % Backend.getOs()

    if "distrib" in kb.bannerFp:
        kb.osVersion = Format.humanize(kb.bannerFp["distrib"])
        infoMsg += " %s" % kb.osVersion

    if "sp" in kb.bannerFp:
        kb.osSP = int(Format.humanize(kb.bannerFp["sp"]).replace("Service Pack ", ""))

    elif "sp" not in kb.bannerFp and Backend.isOs(OS.WINDOWS):
        kb.osSP = 0

    if Backend.getOs() and kb.osVersion and kb.osSP:
        infoMsg += " Service Pack %d" % kb.osSP

    if infoMsg:
        logger.info(infoMsg)

    if condition:
        dataToSessionFile("[%s][%s][%s][OS][%s]\n" % (conf.url, kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]), Backend.getOs()))
Esempio n. 28
0
def setParenthesis(parenthesisCount):
    """
    @param parenthesisCount: number of parenthesis to be set into the
    knowledge base as fingerprint.
    @type parenthesisCount: C{int}
    """

    condition = (not kb.resumedQueries or
                 (kb.resumedQueries.has_key(conf.url)
                  and not kb.resumedQueries[conf.url].has_key("Parenthesis")))

    if condition:
        dataToSessionFile("[%s][%s][%s][Parenthesis][%s]\n" %
                          (conf.url, kb.injPlace, conf.parameters[kb.injPlace],
                           parenthesisCount))

    kb.parenthesis = parenthesisCount
Esempio n. 29
0
def setInjection(inj):
    """
    Save information retrieved about injection place and parameter in the
    session file.
    """

    condition = ( not kb.resumedQueries
                  or ( kb.resumedQueries.has_key(conf.url) and
                  not kb.resumedQueries[conf.url].has_key("Injection data"))
                  or ( kb.resumedQueries[conf.url].has_key("Injection data")
                  and intersect(base64unpickle(kb.resumedQueries[conf.url]["Injection data"][:-1]).data.keys(),\
                    inj.data.keys()) != inj.data.keys()
                ) )

    if condition:
        dataToSessionFile(
            "[%s][%s][%s][Injection data][%s]\n" %
            (conf.url, inj.place, safeFormatString(
                conf.parameters[inj.place]), base64pickle(inj)))
Esempio n. 30
0
def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False):
    start = time.time()

    timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED))

    if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not timeBasedCompare:
        _, length, _ = queryOutputLength(expression, payload)
    else:
        length = None

    dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injection.place, conf.parameters[kb.injection.place], expression))

    count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump)

    if not kb.bruteMode:
        debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start))
        logger.debug(debugMsg)

    return value
Esempio n. 31
0
def __goInference(payload, expression):
    start = time.time()

    if ( conf.eta or conf.threads > 1 ) and kb.dbms:
        _, length, _ = queryOutputLength(expression, payload)
    else:
        length = None

    dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression))

    count, value = bisection(payload, expression, length=length)
    duration = int(time.time() - start)

    if conf.eta and length:
        infoMsg = "retrieved: %s" % value
        logger.info(infoMsg)

    infoMsg = "performed %d queries in %d seconds" % (count, duration)
    logger.info(infoMsg)

    return value
Esempio n. 32
0
def setInjection():
    """
    Save information retrieved about injection place and parameter in the
    session file.
    """

    if kb.injPlace == "User-Agent":
        kb.injParameter = conf.agent

    condition = (
        kb.injPlace and kb.injParameter and
        (not kb.resumedQueries or
         (kb.resumedQueries.has_key(conf.url) and
          (not kb.resumedQueries[conf.url].has_key("Injection point")
           or not kb.resumedQueries[conf.url].has_key("Injection parameter")
           or not kb.resumedQueries[conf.url].has_key("Injection type")))))

    if condition:
        dataToSessionFile(
            "[%s][%s][%s][Injection point][%s]\n" %
            (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injPlace))
        dataToSessionFile("[%s][%s][%s][Injection parameter][%s]\n" %
                          (conf.url, kb.injPlace, conf.parameters[kb.injPlace],
                           kb.injParameter))
        dataToSessionFile(
            "[%s][%s][%s][Injection type][%s]\n" %
            (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injType))
Esempio n. 33
0
    def tableExistsThread():
        threadData = getCurrentThreadData()

        while kb.threadContinue:
            kb.locks.countLock.acquire()
            if threadData.shared.count < threadData.shared.limit:
                table = safeSQLIdentificatorNaming(tables[threadData.shared.count], True)
                threadData.shared.count += 1
                kb.locks.countLock.release()
            else:
                kb.locks.countLock.release()
                break

            if conf.db and METADB_SUFFIX not in conf.db:
                fullTableName = "%s%s%s" % (conf.db, '..' if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) else '.', table)
            else:
                fullTableName = table

            result = inject.checkBooleanExpression("%s" % safeStringFormat(BRUTE_TABLE_EXISTS_TEMPLATE, (randomInt(1), fullTableName)))

            kb.locks.ioLock.acquire()

            if result and table.lower() not in threadData.shared.unique:
                threadData.shared.outputs.append(table)
                threadData.shared.unique.add(table.lower())

                dataToSessionFile("[%s][%s][%s][TABLE_EXISTS][%s]\n" % (conf.url,\
                  kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]),\
                  safeFormatString(fullTableName)))

                if conf.verbose in (1, 2):
                    clearConsoleLine(True)
                    infoMsg = "[%s] [INFO] retrieved: %s\r\n" % (time.strftime("%X"), table)
                    dataToStdout(infoMsg, True)

            if conf.verbose in (1, 2):
                status = '%d/%d items (%d%s)' % (threadData.shared.count, threadData.shared.limit, round(100.0*threadData.shared.count/threadData.shared.limit), '%')
                dataToStdout("\r[%s] [INFO] tried %s" % (time.strftime("%X"), status), True)

            kb.locks.ioLock.release()
Esempio n. 34
0
def __goInference(payload, expression):
    start = time.time()

    if (conf.eta or conf.threads > 1) and kb.dbms:
        _, length, _ = queryOutputLength(expression, payload)
    else:
        length = None

    dataToSessionFile(
        "[%s][%s][%s][%s][" %
        (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression))

    count, value = bisection(payload, expression, length=length)
    duration = int(time.time() - start)

    if conf.eta and length:
        infoMsg = "retrieved: %s" % value
        logger.info(infoMsg)

    infoMsg = "performed %d queries in %d seconds" % (count, duration)
    logger.info(infoMsg)

    return value
Esempio n. 35
0
def setDbms(dbms):
    """
    @param dbms: database management system to be set into the knowledge
    base as fingerprint.
    @type dbms: C{str}
    """

    condition = (not kb.resumedQueries
                 or (kb.resumedQueries.has_key(conf.url)
                     and not kb.resumedQueries[conf.url].has_key("DBMS")))

    if condition:
        dataToSessionFile(
            "[%s][%s][%s][DBMS][%s]\n" %
            (conf.url, kb.injPlace, conf.parameters[kb.injPlace], dbms))

    firstRegExp = "(%s|%s)" % ("|".join([alias for alias in MSSQL_ALIASES]),
                               "|".join([alias for alias in MYSQL_ALIASES]))
    dbmsRegExp = re.search("^%s" % firstRegExp, dbms, re.I)

    if dbmsRegExp:
        dbms = dbmsRegExp.group(1)

    kb.dbms = dbms
Esempio n. 36
0
def setUnion(comment=None, count=None, position=None):
    """
    @param comment: union comment to save in session file
    @type comment: C{str}

    @param count: union count to save in session file
    @type count: C{str}

    @param position: union position to save in session file
    @type position: C{str}
    """

    if comment and count:
        condition = (
            not kb.resumedQueries
            or (kb.resumedQueries.has_key(conf.url) and
                (not kb.resumedQueries[conf.url].has_key("Union comment")
                 or not kb.resumedQueries[conf.url].has_key("Union count"))))

        if condition:
            dataToSessionFile(
                "[%s][%s][%s][Union comment][%s]\n" %
                (conf.url, kb.injPlace, conf.parameters[kb.injPlace], comment))
            dataToSessionFile(
                "[%s][%s][%s][Union count][%s]\n" %
                (conf.url, kb.injPlace, conf.parameters[kb.injPlace], count))

        kb.unionComment = comment
        kb.unionCount = count

    elif position:
        condition = (
            not kb.resumedQueries
            or (kb.resumedQueries.has_key(conf.url) and
                (not kb.resumedQueries[conf.url].has_key("Union position"))))

        if condition:
            dataToSessionFile("[%s][%s][%s][Union position][%s]\n" %
                              (conf.url, kb.injPlace,
                               conf.parameters[kb.injPlace], position))

        kb.unionPosition = position
Esempio n. 37
0
def setInjection():
    """
    Save information retrieved about injection place and parameter in the
    session file.
    """

    if kb.injPlace == "User-Agent":
        kb.injParameter = conf.agent

    condition = (
                  kb.injPlace and kb.injParameter and ( not kb.resumedQueries
                  or ( kb.resumedQueries.has_key(conf.url) and
                  ( not kb.resumedQueries[conf.url].has_key("Injection point") 
                  or not kb.resumedQueries[conf.url].has_key("Injection parameter")
                  or not kb.resumedQueries[conf.url].has_key("Injection type")
                  ) ) )
                )

    if condition:
        dataToSessionFile("[%s][%s][%s][Injection point][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injPlace))
        dataToSessionFile("[%s][%s][%s][Injection parameter][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injParameter))
        dataToSessionFile("[%s][%s][%s][Injection type][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injType))
Esempio n. 38
0
def setUnion(comment=None, count=None, position=None):
    """
    @param comment: union comment to save in session file
    @type comment: C{str}

    @param count: union count to save in session file
    @type count: C{str}

    @param position: union position to save in session file
    @type position: C{str}
    """

    if comment and count:
        condition = (
                      not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
                      ( not kb.resumedQueries[conf.url].has_key("Union comment") 
                      or not kb.resumedQueries[conf.url].has_key("Union count")
                      ) )
                    )

        if condition:
            dataToSessionFile("[%s][%s][%s][Union comment][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], comment))
            dataToSessionFile("[%s][%s][%s][Union count][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], count))

        kb.unionComment = comment
        kb.unionCount = count

    elif position:
        condition = (
                      not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
                      ( not kb.resumedQueries[conf.url].has_key("Union position")
                      ) )
                    )

        if condition:
            dataToSessionFile("[%s][%s][%s][Union position][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], position))

        kb.unionPosition = position
Esempio n. 39
0
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:
            return None

        condition = (
            kb.resumedQueries
            and conf.url in kb.resumedQueries.keys()
            and expression in kb.resumedQueries[conf.url].keys()
        )

        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 = re.findall("%s(.*?)%s" % (DUMP_START_MARKER, DUMP_STOP_MARKER), resumedValue, re.S)

            if logValue:
                logValue = ", ".join([value.replace(DUMP_DEL_MARKER, ", ") for value in logValue])
            else:
                logValue = resumedValue

            if "\n" in logValue:
                infoMsg += "%s..." % logValue.split("\n")[0]
            else:
                infoMsg += logValue

            logger.info(infoMsg)

            return resumedValue

        # If we called this function without providing a payload it means that
        # we have called it from lib/request/inject __goInband() function
        # in UNION query (inband) SQL injection so we return to the calling
        # function so that the query output will be retrieved taking advantage
        # of the inband SQL injection vulnerability.
        if not payload:
            return None

        if not kb.dbms:
            return None

        substringQuery = queries[kb.dbms].substring.query
        select = re.search("\ASELECT ", expression, re.I)

        _, 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.injPlace, conf.parameters[kb.injPlace], 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.injPlace, conf.parameters[kb.injPlace], 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
Esempio n. 40
0
        def downloadThread():
            try:
                while kb.threadContinue:
                    idxlock.acquire()

                    if index[0] >= length:
                        idxlock.release()

                        return

                    index[0] += 1
                    curidx = index[0]
                    idxlock.release()

                    if kb.threadContinue:
                        charStart = time.time()
                        val = getChar(curidx)
                        if val is None:
                            val = INFERENCE_UNKNOWN_CHAR
                    else:
                        break

                    valuelock.acquire()
                    value[curidx - 1] = val
                    currentValue = list(value)
                    valuelock.release()

                    if kb.threadContinue:
                        if showEta:
                            etaProgressUpdate(time.time() - charStart,
                                              index[0])
                        elif conf.verbose >= 1:
                            startCharIndex = 0
                            endCharIndex = 0

                            for i in xrange(length):
                                if currentValue[i] is not None:
                                    endCharIndex = max(endCharIndex, i)

                            output = ''

                            if endCharIndex > conf.progressWidth:
                                startCharIndex = endCharIndex - conf.progressWidth

                            count = 0

                            for i in xrange(startCharIndex, endCharIndex + 1):
                                output += '_' if currentValue[
                                    i] is None else currentValue[i]

                            for i in xrange(length):
                                count += 1 if currentValue[i] is not None else 0

                            if startCharIndex > 0:
                                output = '..' + output[2:]

                            if (endCharIndex - startCharIndex
                                    == conf.progressWidth) and (endCharIndex <
                                                                length - 1):
                                output = output[:-2] + '..'

                            if conf.verbose in (1, 2) and not showEta:
                                output += '_' * (min(
                                    length, conf.progressWidth) - len(output))
                                status = ' %d/%d (%d%s)' % (
                                    count, length, round(
                                        100.0 * count / length), '%')
                                output += status if count != length else " " * len(
                                    status)

                                iolock.acquire()
                                dataToStdout("\r[%s] [INFO] retrieved: %s" %
                                             (time.strftime("%X"),
                                              filterControlChars(output)))
                                iolock.release()

                if not kb.threadContinue:
                    if int(threading.currentThread().getName()
                           ) == numThreads - 1:
                        partialValue = unicode()
                        for v in value:
                            if v is None:
                                break
                            elif isinstance(v, basestring):
                                partialValue += v

                        if len(partialValue) > 0:
                            dataToSessionFile(replaceNewlineTabs(partialValue))

            except (sqlmapConnectionException, sqlmapValueException), errMsg:
                print
                kb.threadException = True
                logger.error("thread %d: %s" % (numThread + 1, errMsg))
Esempio n. 41
0
            if kb.injection.place is not None and kb.injection.parameter is not None:
                kb.injections.append(kb.injection)

            readSessionFP.close()
        else:
            try:
                os.remove(conf.sessionFile)
                logger.info("flushing session file")
            except OSError, msg:
                errMsg = "unable to flush the session file (%s)" % msg
                raise sqlmapFilePathException, errMsg

    try:
        conf.sessionFP = codecs.open(conf.sessionFile, "a", UNICODE_ENCODING)
        dataToSessionFile("\n[%s]\n" % time.strftime("%X %x"))
    except IOError:
        errMsg = "unable to write on the session file specified"
        raise sqlmapFilePathException, errMsg


def __createFilesDir():
    """
    Create the file directory.
    """

    if not conf.rFile:
        return

    conf.filePath = paths.SQLMAP_FILES_PATH % conf.hostname
Esempio n. 42
0
        if None in value:
            for v in value:
                if isinstance(v, str) and v != None:
                    partialValue += v

            if partialValue:
                finalValue = partialValue
                infoMsg = "\r[%s] [INFO] partially retrieved: %s" % (
                    time.strftime("%X"), finalValue)
        else:
            finalValue = "".join(value)
            infoMsg = "\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"),
                                                       finalValue)

        if isinstance(finalValue, str) and len(finalValue) > 0:
            dataToSessionFile(replaceNewlineTabs(finalValue))

        if conf.verbose in (1, 2) and not showEta and infoMsg:
            dataToStdout(infoMsg)

    else:
        index = 0

        while True:
            index += 1
            charStart = time.time()
            val = getChar(index)

            if val == None:
                break
Esempio n. 43
0
def queryOutputLength(expression, payload):
    """
    Returns the query output length.
    """

    lengthQuery = queries[Backend.getIdentifiedDbms()].length.query
    select = re.search("\ASELECT\s+", expression, re.I)
    selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM",
                              expression, re.I)
    selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM",
                                   expression, re.I)
    selectFromExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I)
    selectExpr = re.search("\ASELECT\s+(.+)$", expression, re.I)
    miscExpr = re.search("\A(.+)", expression, re.I)

    if selectTopExpr or selectDistinctExpr or selectFromExpr or selectExpr:
        if selectTopExpr:
            regExpr = selectTopExpr.groups()[0]
        elif selectDistinctExpr:
            regExpr = selectDistinctExpr.groups()[0]
        elif selectFromExpr:
            regExpr = selectFromExpr.groups()[0]
        elif selectExpr:
            regExpr = selectExpr.groups()[0]
    elif miscExpr:
        regExpr = miscExpr.groups()[0]

    if (select and re.search("\A(COUNT|LTRIM)\(", regExpr,
                             re.I)) or len(regExpr) <= 1:
        return None, None, None

    if selectDistinctExpr:
        lengthExpr = "SELECT %s FROM (%s)" % (lengthQuery % regExpr,
                                              expression)

        if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
            lengthExpr += " AS %s" % randomStr(lowercase=True)
    elif select:
        lengthExpr = expression.replace(regExpr, lengthQuery % regExpr, 1)
    else:
        lengthExpr = lengthQuery % expression

    infoMsg = "retrieving the length of query output"
    logger.info(infoMsg)

    output = resume(lengthExpr, payload)

    if output:
        return 0, output, regExpr

    dataToSessionFile("[%s][%s][%s][%s][" %
                      (conf.url, kb.injection.place,
                       conf.parameters[kb.injection.place], lengthExpr))

    start = time.time()
    lengthExprUnescaped = unescaper.unescape(lengthExpr)
    count, length = bisection(payload, lengthExprUnescaped, charsetType=2)

    debugMsg = "performed %d queries in %d seconds" % (
        count, calculateDeltaSeconds(start))
    logger.debug(debugMsg)

    if length == " ":
        length = 0

    return count, length, regExpr
Esempio n. 44
0
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.keys()
                     and expression in kb.resumedQueries[conf.url].keys())

        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 = re.findall(
                "%s(.*?)%s" % (DUMP_START_MARKER, DUMP_STOP_MARKER),
                resumedValue, re.S)

            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

            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 = re.search("\ASELECT ", expression, re.I)

        _, 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
Esempio n. 45
0
def bisection(payload, expression, length=None, charsetType=None, firstChar=None, lastChar=None, dump=False):
    """
    Bisection algorithm that can be used to perform blind SQL injection
    on an affected host
    """

    partialValue = ""
    finalValue = ""
    asciiTbl = getCharset(charsetType)
    timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED))

    # Set kb.partRun in case "common prediction" feature (a.k.a. "good
    # samaritan") is used
    kb.partRun = getPartRun() if conf.predictOutput else None

    if "LENGTH(" in expression or "LEN(" in expression:
        firstChar = 0
    elif dump and conf.firstChar is not None and ( isinstance(conf.firstChar, int) or ( isinstance(conf.firstChar, basestring) and conf.firstChar.isdigit() ) ):
        firstChar = int(conf.firstChar) - 1
    elif firstChar is None:
        firstChar = 0
    elif ( isinstance(firstChar, basestring) and firstChar.isdigit() ) or isinstance(firstChar, int):
        firstChar = int(firstChar) - 1

    if "LENGTH(" in expression or "LEN(" in expression:
        lastChar = 0
    elif dump and conf.lastChar is not None and ( isinstance(conf.lastChar, int) or ( isinstance(conf.lastChar, basestring) and conf.lastChar.isdigit() ) ):
        lastChar = int(conf.lastChar)
    elif lastChar in ( None, "0" ):
        lastChar = 0
    elif ( isinstance(lastChar, basestring) and lastChar.isdigit() ) or isinstance(lastChar, int):
        lastChar = int(lastChar)

    if Backend.getDbms():
        _, _, _, _, _, _, fieldToCastStr, _ = agent.getFields(expression)
        nulledCastedField = agent.nullAndCastField(fieldToCastStr)
        expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1)
        expressionUnescaped = unescaper.unescape(expressionReplaced)
    else:
        expressionUnescaped = unescaper.unescape(expression)

    if length and not isinstance(length, int) and length.isdigit():
        length = int(length)

    if length == 0:
        return 0, ""

    if lastChar > 0 and length > ( lastChar - firstChar ):
        length = ( lastChar - firstChar )

    showEta = conf.eta and isinstance(length, int)
    numThreads = min(conf.threads, length)
    threads = []

    if showEta:
        progress = ProgressBar(maxValue=length)
        progressTime = []

    if timeBasedCompare and conf.threads > 1:
        warnMsg = "multi-threading is considered unsafe in time-based data retrieval. Going to switch it off automatically"
        singleTimeWarnMessage(warnMsg)

    if numThreads > 1:
        if not timeBasedCompare:
            debugMsg = "starting %d thread%s" % (numThreads, ("s" if numThreads > 1 else ""))
            logger.debug(debugMsg)
        else:
            numThreads = 1

    if conf.threads == 1 and not timeBasedCompare:
        warnMsg = "running in a single-thread mode. Please consider "
        warnMsg += "usage of --threads switch for faster data retrieval"
        singleTimeWarnMessage(warnMsg)

    if conf.verbose in (1, 2) and not showEta:
        if isinstance(length, int) and conf.threads > 1:
            dataToStdout("[%s] [INFO] retrieved: %s" % (time.strftime("%X"), "_" * min(length, conf.progressWidth)))
            dataToStdout("\r[%s] [INFO] retrieved: " % time.strftime("%X"))
        else:
            dataToStdout("[%s] [INFO] retrieved: " % time.strftime("%X"))

    queriesCount = [0] # As list to deal with nested scoping rules
    hintlock = threading.Lock()

    def tryHint(idx):
        hintlock.acquire()
        hintValue = kb.hintValue
        hintlock.release()

        if hintValue is not None and len(hintValue) >= idx:
            if Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.MAXDB, DBMS.DB2):
                posValue = hintValue[idx-1]
            else:
                posValue = ord(hintValue[idx-1])

            forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, posValue))
            queriesCount[0] += 1
            result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)

            if result:
                return hintValue[idx-1]

        hintlock.acquire()
        kb.hintValue = None
        hintlock.release()

        return None

    def validateChar(idx, value):
        """
        Used in time-based inference (in case that original and retrieved
        value are not equal there will be a deliberate delay).
        """

        forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_NOT_EQUALS_CHAR), (expressionUnescaped, idx, value))
        queriesCount[0] += 1
        result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)

        return not result

    def getChar(idx, charTbl=asciiTbl, continuousOrder=True, expand=charsetType is None):
        """
        continuousOrder means that distance between each two neighbour's
        numerical values is exactly 1
        """

        result = tryHint(idx)

        if result:
            return result

        originalTbl = list(charTbl)

        if continuousOrder:
            # Used for gradual expanding into unicode charspace
            shiftTable = [5, 4]

        if CHAR_INFERENCE_MARK in payload and ord('\n') in charTbl:
            charTbl.remove(ord('\n'))

        if len(charTbl) == 1:
            forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, charTbl[0]))
            queriesCount[0] += 1
            result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)

            if result:
                return decodeIntToUnicode(charTbl[0])
            else:
                return None

        maxChar = maxValue = charTbl[-1]
        minChar = minValue = charTbl[0]

        while len(charTbl) != 1:
            position = (len(charTbl) >> 1)
            posValue = charTbl[position]

            if CHAR_INFERENCE_MARK not in payload:
                forgedPayload = safeStringFormat(payload, (expressionUnescaped, idx, posValue))
            else:
                # e.g.: ... > '%c' -> ... > ORD(..)
                markingValue = "'%s'" % CHAR_INFERENCE_MARK
                unescapedCharValue = unescaper.unescape(markingValue % decodeIntToUnicode(posValue))
                forgedPayload = safeStringFormat(payload, (expressionUnescaped, idx)).replace(markingValue, unescapedCharValue)

            queriesCount[0] += 1
            result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)

            if result:
                minValue = posValue

                if type(charTbl) != xrange:
                    charTbl = charTbl[position:]
                else:
                    # xrange() - extended virtual charset used for memory/space optimization
                    charTbl = xrange(charTbl[position], charTbl[-1] + 1)
            else:
                maxValue = posValue

                if type(charTbl) != xrange:
                    charTbl = charTbl[:position]
                else:
                    charTbl = xrange(charTbl[0], charTbl[position])

            if len(charTbl) == 1:
                if continuousOrder:
                    if maxValue == 1:
                        return None

                    # Going beyond the original charset
                    elif minValue == maxChar:
                        # If the original charTbl was [0,..,127] new one
                        # will be [128,..,128*16-1] or from 128 to 2047
                        # and instead of making a HUGE list with all the
                        # elements we use a xrange, which is a virtual
                        # list
                        if expand and shiftTable:
                            charTbl = xrange(maxChar + 1, (maxChar + 1) << shiftTable.pop())
                            originalTbl = list(charTbl)
                            maxChar = maxValue = charTbl[-1]
                            minChar = minValue = charTbl[0]
                        else:
                            return None
                    else:
                        retVal = minValue + 1

                        if retVal in originalTbl or (retVal == ord('\n') and CHAR_INFERENCE_MARK in payload):
                            if timeBasedCompare and not validateChar(idx, retVal):
                                errMsg = "invalid character detected. retrying.."
                                logger.error(errMsg)

                                if not kb.originalTimeDelay:
                                    kb.originalTimeDelay = conf.timeSec

                                conf.timeSec += 1
                                if (conf.timeSec - kb.originalTimeDelay) <= MAX_TIME_REVALIDATION_STEPS:
                                    warnMsg = "increasing time delay to %d second%s " % (conf.timeSec, 's' if conf.timeSec > 1 else '')
                                    warnMsg += "(due to invalid char)"
                                    logger.warn(warnMsg)

                                    if kb.adjustTimeDelay:
                                        dbgMsg = "turning off auto-adjustment mechanism"
                                        logger.debug(dbgMsg)
                                        kb.adjustTimeDelay = False
                                    return getChar(idx, originalTbl, continuousOrder, expand)
                                else:
                                    errMsg = "unable to properly validate character value. using last known value ('%s').." % decodeIntToUnicode(retVal)
                                    logger.error(errMsg)
                                    conf.timeSec = kb.originalTimeDelay
                                    return decodeIntToUnicode(retVal)
                            else:
                                return decodeIntToUnicode(retVal)
                        else:
                            return None
                else:
                    if minValue == maxChar or maxValue == minChar:
                        return None

                    # If we are working with non-continuous elements, set
                    # both minValue and character afterwards are possible
                    # candidates
                    for retVal in (originalTbl[originalTbl.index(minValue)], originalTbl[originalTbl.index(minValue) + 1]):
                        forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, retVal))
                        queriesCount[0] += 1
                        result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)

                        if result:
                            return decodeIntToUnicode(retVal)

                    return None

    def etaProgressUpdate(charTime, index):
        if len(progressTime) <= ( (length * 3) / 100 ):
            eta = 0
        else:
            midTime = sum(progressTime) / len(progressTime)
            midTimeWithLatest = (midTime + charTime) / 2
            eta = midTimeWithLatest * (length - index) / conf.threads

        progressTime.append(charTime)
        progress.update(index)
        progress.draw(eta)

    # Go multi-threading (--threads > 1)
    if conf.threads > 1 and isinstance(length, int) and length > 1:
        value = []
        threadData = getCurrentThreadData()

        threadData.shared.value = [ None ] * length
        threadData.shared.index = [ firstChar ]    # As list for python nested function scoping

        lockNames = ('iolock', 'idxlock', 'valuelock')
        for lock in lockNames:
            kb.locks[lock] = threading.Lock()

        try:
            def blindThread():
                threadData = getCurrentThreadData()

                while kb.threadContinue:
                    kb.locks.idxlock.acquire()

                    if threadData.shared.index[0] >= length:
                        kb.locks.idxlock.release()

                        return

                    threadData.shared.index[0] += 1
                    curidx = threadData.shared.index[0]
                    kb.locks.idxlock.release()

                    if kb.threadContinue:
                        charStart = time.time()
                        val = getChar(curidx)
                        if val is None:
                            val = INFERENCE_UNKNOWN_CHAR
                    else:
                        break

                    kb.locks.valuelock.acquire()
                    threadData.shared.value[curidx-1] = val
                    currentValue = list(threadData.shared.value)
                    kb.locks.valuelock.release()

                    if kb.threadContinue:
                        if showEta:
                            etaProgressUpdate(time.time() - charStart, threadData.shared.index[0])
                        elif conf.verbose >= 1:
                            startCharIndex = 0
                            endCharIndex = 0

                            for i in xrange(length):
                                if currentValue[i] is not None:
                                    endCharIndex = max(endCharIndex, i)

                            output = ''

                            if endCharIndex > conf.progressWidth:
                                startCharIndex = endCharIndex - conf.progressWidth

                            count = 0

                            for i in xrange(startCharIndex, endCharIndex + 1):
                                output += '_' if currentValue[i] is None else currentValue[i]

                            for i in xrange(length):
                                count += 1 if currentValue[i] is not None else 0

                            if startCharIndex > 0:
                                output = '..' + output[2:]

                            if (endCharIndex - startCharIndex == conf.progressWidth) and (endCharIndex < length-1):
                                output = output[:-2] + '..'

                            if conf.verbose in (1, 2) and not showEta:
                                output += '_' * (min(length, conf.progressWidth) - len(output))
                                status = ' %d/%d (%d%s)' % (count, length, round(100.0*count/length), '%')
                                output += status if count != length else " "*len(status)

                                kb.locks.iolock.acquire()
                                dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(output)))
                                kb.locks.iolock.release()

                if not kb.threadContinue:
                    if int(threading.currentThread().getName()) == numThreads - 1:
                        partialValue = unicode()
                        for v in threadData.shared.value:
                            if v is None:
                                break
                            elif isinstance(v, basestring):
                                partialValue += v

                        if len(partialValue) > 0:
                            dataToSessionFile(replaceNewlineTabs(partialValue))

            runThreads(numThreads, blindThread, startThreadMsg=False)

        except KeyboardInterrupt:
            raise

        finally:
            value = threadData.shared.value
            
        infoMsg = None

        # If we have got one single character not correctly fetched it
        # can mean that the connection to the target url was lost
        if None in value:
            for v in value:
                if isinstance(v, basestring) and v is not None:
                    partialValue += v

            if partialValue:
                finalValue = partialValue
                infoMsg = "\r[%s] [INFO] partially retrieved: %s" % (time.strftime("%X"), filterControlChars(finalValue))
        else:
            finalValue = "".join(value)
            infoMsg = "\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(finalValue))

        if isinstance(finalValue, basestring) and len(finalValue) > 0:
            dataToSessionFile(replaceNewlineTabs(finalValue))

        if conf.verbose in (1, 2) and not showEta and infoMsg:
            dataToStdout(infoMsg)

    # No multi-threading (--threads = 1)
    else:
        index = firstChar

        while True:
            index += 1
            charStart = time.time()

            # Common prediction feature (a.k.a. "good samaritan")
            # NOTE: to be used only when multi-threading is not set for
            # the moment
            if conf.predictOutput and len(finalValue) > 0 and kb.partRun is not None:
                val = None
                commonValue, commonPattern, commonCharset, otherCharset = goGoodSamaritan(finalValue, asciiTbl)

                # If there is one single output in common-outputs, check
                # it via equal against the query output
                if commonValue is not None:
                    # One-shot query containing equals commonValue
                    testValue = unescaper.unescape("'%s'" % commonValue) if "'" not in commonValue else unescaper.unescape("%s" % commonValue, quote=False)
                    query = agent.prefixQuery(safeStringFormat("AND (%s) = %s", (expressionUnescaped, testValue)))
                    query = agent.suffixQuery(query)
                    queriesCount[0] += 1
                    result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False)

                    # Did we have luck?
                    if result:
                        dataToSessionFile(replaceNewlineTabs(commonValue[index-1:]))

                        if showEta:
                            etaProgressUpdate(time.time() - charStart, len(commonValue))
                        elif conf.verbose in (1, 2):
                            dataToStdout(commonValue[index-1:])

                        finalValue = commonValue

                        break

                # If there is a common pattern starting with finalValue,
                # check it via equal against the substring-query output
                if commonPattern is not None:
                    # Substring-query containing equals commonPattern
                    subquery = queries[Backend.getIdentifiedDbms()].substring.query % (expressionUnescaped, 1, len(commonPattern))
                    testValue = unescaper.unescape("'%s'" % commonPattern) if "'" not in commonPattern else unescaper.unescape("%s" % commonPattern, quote=False)
                    query = agent.prefixQuery(safeStringFormat("AND (%s) = %s", (subquery, testValue)))
                    query = agent.suffixQuery(query)
                    queriesCount[0] += 1
                    result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False)

                    # Did we have luck?
                    if result:
                        val = commonPattern[index-1:]
                        index += len(val)-1

                # Otherwise if there is no commonValue (single match from
                # txt/common-outputs.txt) and no commonPattern
                # (common pattern) use the returned common charset only
                # to retrieve the query output
                if not val and commonCharset:
                    val = getChar(index, commonCharset, False)

                # If we had no luck with commonValue and common charset,
                # use the returned other charset
                if not val:
                    val = getChar(index, otherCharset, otherCharset == asciiTbl)
            else:
                val = getChar(index, asciiTbl)

            if val is None or ( lastChar > 0 and index > lastChar ):
                break

            if kb.data.processChar:
                val = kb.data.processChar(val)

            finalValue += val
            dataToSessionFile(replaceNewlineTabs(val))

            if showEta:
                etaProgressUpdate(time.time() - charStart, index)
            elif conf.verbose in (1, 2):
                dataToStdout(val)

            if len(finalValue) > INFERENCE_BLANK_BREAK and finalValue[-INFERENCE_BLANK_BREAK:].isspace():
                break

    if conf.verbose in (1, 2) or showEta:
        dataToStdout("\n")

    if ( conf.verbose in ( 1, 2 ) and showEta ) or conf.verbose >= 3:
        infoMsg = "retrieved: %s" % filterControlChars(finalValue)
        logger.info(infoMsg)

    if not partialValue:
        dataToSessionFile("]\n")

    if kb.threadException:
        raise sqlmapThreadException, "something unexpected happened inside the threads"

    return queriesCount[0], safecharencode(finalValue) if kb.safeCharEncode else finalValue
Esempio n. 46
0
            def blindThread():
                threadData = getCurrentThreadData()

                while kb.threadContinue:
                    kb.locks.idxlock.acquire()

                    if threadData.shared.index[0] >= length:
                        kb.locks.idxlock.release()

                        return

                    threadData.shared.index[0] += 1
                    curidx = threadData.shared.index[0]
                    kb.locks.idxlock.release()

                    if kb.threadContinue:
                        charStart = time.time()
                        val = getChar(curidx)
                        if val is None:
                            val = INFERENCE_UNKNOWN_CHAR
                    else:
                        break

                    kb.locks.valuelock.acquire()
                    threadData.shared.value[curidx-1] = val
                    currentValue = list(threadData.shared.value)
                    kb.locks.valuelock.release()

                    if kb.threadContinue:
                        if showEta:
                            etaProgressUpdate(time.time() - charStart, threadData.shared.index[0])
                        elif conf.verbose >= 1:
                            startCharIndex = 0
                            endCharIndex = 0

                            for i in xrange(length):
                                if currentValue[i] is not None:
                                    endCharIndex = max(endCharIndex, i)

                            output = ''

                            if endCharIndex > conf.progressWidth:
                                startCharIndex = endCharIndex - conf.progressWidth

                            count = 0

                            for i in xrange(startCharIndex, endCharIndex + 1):
                                output += '_' if currentValue[i] is None else currentValue[i]

                            for i in xrange(length):
                                count += 1 if currentValue[i] is not None else 0

                            if startCharIndex > 0:
                                output = '..' + output[2:]

                            if (endCharIndex - startCharIndex == conf.progressWidth) and (endCharIndex < length-1):
                                output = output[:-2] + '..'

                            if conf.verbose in (1, 2) and not showEta:
                                output += '_' * (min(length, conf.progressWidth) - len(output))
                                status = ' %d/%d (%d%s)' % (count, length, round(100.0*count/length), '%')
                                output += status if count != length else " "*len(status)

                                kb.locks.iolock.acquire()
                                dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(output)))
                                kb.locks.iolock.release()

                if not kb.threadContinue:
                    if int(threading.currentThread().getName()) == numThreads - 1:
                        partialValue = unicode()
                        for v in threadData.shared.value:
                            if v is None:
                                break
                            elif isinstance(v, basestring):
                                partialValue += v

                        if len(partialValue) > 0:
                            dataToSessionFile(replaceNewlineTabs(partialValue))
Esempio n. 47
0
def __oneShotErrorUse(expression, field):
    global reqCount

    threadData = getCurrentThreadData()

    retVal = None
    offset = 1

    while True:
        check = "%s(?P<result>.*?)%s" % (kb.misc.start, kb.misc.stop)
        nulledCastedField = agent.nullAndCastField(field)

        if Backend.getIdentifiedDbms() == DBMS.MYSQL:
            nulledCastedField = queries[DBMS.MYSQL].substring.query % (
                nulledCastedField, offset, MYSQL_ERROR_CHUNK_LENGTH)

        # Forge the error-based SQL injection request
        vector = kb.injection.data[PAYLOAD.TECHNIQUE.ERROR].vector
        query = agent.prefixQuery(vector)
        query = agent.suffixQuery(query)
        injExpression = expression.replace(field, nulledCastedField, 1)
        injExpression = unescaper.unescape(injExpression)
        injExpression = query.replace("[QUERY]", injExpression)
        payload = agent.payload(newValue=injExpression)

        # Perform the request
        page, headers = Request.queryPage(payload, content=True)

        reqCount += 1

        # Parse the returned page to get the exact error-based
        # sql injection output
        output = extractRegexResult(check, page, re.DOTALL | re.IGNORECASE) \
                or extractRegexResult(check, listToStrValue(headers.headers \
                if headers else None), re.DOTALL | re.IGNORECASE) \
                or extractRegexResult(check, threadData.lastRedirectMsg[1] \
                if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == \
                threadData.lastRequestUID else None, re.DOTALL | re.IGNORECASE)

        if output:
            output = getUnicode(output, kb.pageEncoding)

        if isinstance(output, basestring):
            output = htmlunescape(output).replace("<br>", "\n")

        if Backend.getIdentifiedDbms() == DBMS.MYSQL:
            if offset == 1:
                retVal = output
            else:
                retVal += output if output else ''

            if not (output and len(output) == MYSQL_ERROR_CHUNK_LENGTH):
                break
            else:
                offset += MYSQL_ERROR_CHUNK_LENGTH
        else:
            retVal = output
            break

    retVal = __errorReplaceChars(retVal)

    dataToSessionFile(
        "[%s][%s][%s][%s][%s]\n" %
        (conf.url, kb.injection.place, conf.parameters[kb.injection.place],
         expression, replaceNewlineTabs(retVal)))

    return retVal
Esempio n. 48
0
def columnExists(columnFile, regex=None):
    if not conf.tbl:
        errMsg = "missing table parameter"
        raise sqlmapMissingMandatoryOptionException, errMsg

    columns = getFileItems(columnFile, unique=True)
    columns = filterListValue(columns, regex)

    if conf.db and not conf.db.endswith(METADB_SUFFIX):
        table = "%s%s%s" % (conf.db, '..' if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) else '.', conf.tbl)
    else:
        table = conf.tbl
    table = safeSQLIdentificatorNaming(table)

    retVal = []
    infoMsg = "checking column existence using items from '%s'" % columnFile
    logger.info(infoMsg)

    count = [0]
    length = len(columns)
    threads = []
    collock = threading.Lock()
    iolock = threading.Lock()
    kb.threadContinue = True
    kb.bruteMode = True

    def columnExistsThread():
        while count[0] < length and kb.threadContinue:
            collock.acquire()
            column = safeSQLIdentificatorNaming(columns[count[0]])
            count[0] += 1
            collock.release()

            result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s)", (column, table)))

            iolock.acquire()

            if result:
                retVal.append(column)

                if conf.verbose in (1, 2):
                    clearConsoleLine(True)
                    infoMsg = "\r[%s] [INFO] retrieved: %s\n" % (time.strftime("%X"), column)
                    dataToStdout(infoMsg, True)

            if conf.verbose in (1, 2):
                status = '%d/%d items (%d%s)' % (count[0], length, round(100.0*count[0]/length), '%')
                dataToStdout("\r[%s] [INFO] tried %s" % (time.strftime("%X"), status), True)

            iolock.release()

    if conf.threads > 1:
        infoMsg = "starting %d threads" % conf.threads
        logger.info(infoMsg)
    else:
        message = "please enter number of threads? [Enter for %d (current)] " % conf.threads
        choice = readInput(message, default=str(conf.threads))
        if choice and choice.isdigit():
            conf.threads = int(choice)
        
    if conf.threads == 1:
        warnMsg = "running in a single-thread mode. This could take a while."
        logger.warn(warnMsg)

    # Start the threads
    for numThread in range(conf.threads):
        thread = threading.Thread(target=columnExistsThread, name=str(numThread))
        thread.start()
        threads.append(thread)

    # And wait for them to all finish
    try:
        alive = True

        while alive:
            alive = False

            for thread in threads:
                if thread.isAlive():
                    alive = True
                    thread.join(5)
    except KeyboardInterrupt:
        kb.threadContinue = False
        kb.threadException = True

        print
        logger.debug("waiting for threads to finish")

        warnMsg = "user aborted during common column existence check. "
        warnMsg += "sqlmap will display some columns only"
        logger.warn(warnMsg)

        try:
            while (threading.activeCount() > 1):
                pass

        except KeyboardInterrupt:
            raise sqlmapThreadException, "user aborted"
    finally:
        kb.bruteMode = False
        kb.threadContinue = True
        kb.threadException = False

    clearConsoleLine(True)
    dataToStdout("\n")

    if not retVal:
        warnMsg = "no column found"
        logger.warn(warnMsg)
    else:
        columns = {}

        for column in retVal:
            result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE ROUND(%s)=ROUND(%s))", (column, table, column, column)))

            if result:
                columns[column] = 'numeric'
            else:
                columns[column] = 'non-numeric'

            dataToSessionFile("[%s][%s][%s][COLUMN_EXISTS][%s|%s %s]\n" % (conf.url, kb.injection.place,\
              safeFormatString(conf.parameters[kb.injection.place]), safeFormatString(table),\
              safeFormatString(column), safeFormatString(columns[column])))

        kb.data.cachedColumns[conf.db] = {conf.tbl: columns}

    return kb.data.cachedColumns
Esempio n. 49
0
            if kb.injection.place is not None and kb.injection.parameter is not None:
                kb.injections.append(kb.injection)

            readSessionFP.close()
        else:
            try:
                os.remove(conf.sessionFile)
                logger.info("flushing session file")
            except OSError, msg:
                errMsg = "unable to flush the session file (%s)" % msg
                raise sqlmapFilePathException, errMsg

    try:
        conf.sessionFP = codecs.open(conf.sessionFile, "a", UNICODE_ENCODING)
        dataToSessionFile("\n[%s]\n" % time.strftime("%X %x"))
    except IOError:
        errMsg = "unable to write on the session file specified"
        raise sqlmapFilePathException, errMsg

def __createFilesDir():
    """
    Create the file directory.
    """

    if not conf.rFile:
        return

    conf.filePath = paths.SQLMAP_FILES_PATH % conf.hostname

    if not os.path.isdir(conf.filePath):
Esempio n. 50
0
def resume(expression, payload):
    """
    This function can be called to resume part or entire output of a
    SQL injection query output.
    """

    condition = (kb.resumedQueries and conf.url in kb.resumedQueries.keys()
                 and expression in kb.resumedQueries[conf.url].keys())

    if not condition:
        return None

    resumedValue = kb.resumedQueries[conf.url][expression]

    if not resumedValue:
        return None

    if resumedValue[-1] == "]":
        resumedValue = resumedValue[:-1]

        infoMsg = "read from file '%s': " % conf.sessionFile
        logValue = re.findall("__START__(.*?)__STOP__", resumedValue, re.S)

        if logValue:
            logValue = ", ".join(
                [value.replace("__DEL__", ", ") for value in logValue])
        else:
            logValue = resumedValue

        if "\n" in logValue:
            infoMsg += "%s..." % logValue.split("\n")[0]
        else:
            infoMsg += logValue

        logger.info(infoMsg)

        return resumedValue

    # If we called this function without providing a payload it means that
    # we have called it from lib/request/inject __goInband() function
    # in UNION query (inband) SQL injection so we return to the calling
    # function so that the query output will be retrieved taking advantage
    # of the inband SQL injection vulnerability.
    if not payload:
        return None

    expressionUnescaped = unescaper.unescape(expression)
    substringQuery = queries[kb.dbms].substring
    select = re.search("\ASELECT ", expression, re.I)

    _, 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.injPlace, conf.parameters[kb.injPlace],
                           expression, 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.injPlace, conf.parameters[kb.injPlace],
                           expression, resumedValue))

        if select:
            newExpr = expressionUnescaped.replace(
                regExpr,
                substringQuery % (regExpr, len(resumedValue) + 1, int(length)),
                1)
        else:
            newExpr = substringQuery % (expressionUnescaped,
                                        len(resumedValue) + 1, int(length))

        missingCharsLength = int(length) - len(resumedValue)

        infoMsg = "retrieving pending %d query " % missingCharsLength
        infoMsg += "output characters"
        logger.info(infoMsg)

        _, finalValue = bisection(payload, newExpr, length=missingCharsLength)

        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
Esempio n. 51
0
        # If we have got one single character not correctly fetched it
        # can mean that the connection to the target url was lost
        if None in value:
            for v in value:
                if isinstance(v, str) and v is not None:
                    partialValue += v

            if partialValue:
                finalValue = partialValue
                infoMsg = "\r[%s] [INFO] partially retrieved: %s" % (time.strftime("%X"), finalValue)
        else:
            finalValue = "".join(value)
            infoMsg = "\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), finalValue)

        if isinstance(finalValue, str) and len(finalValue) > 0:
            dataToSessionFile(replaceNewlineTabs(finalValue))

        if conf.verbose >= 1 and not showEta and infoMsg:
            dataToStdout(infoMsg)

        conf.seqLock = None
    else:
        index = firstChar

        while True:
            index    += 1
            charStart = time.time()
            val       = getChar(index, asciiTbl)

            if val is None or ( lastChar > 0 and index > lastChar ):
                break
Esempio n. 52
0
        if None in value:
            for v in value:
                if isinstance(v, basestring) and v is not None:
                    partialValue += v

            if partialValue:
                finalValue = partialValue
                infoMsg = "\r[%s] [INFO] partially retrieved: %s" % (
                    time.strftime("%X"), filterControlChars(finalValue))
        else:
            finalValue = "".join(value)
            infoMsg = "\r[%s] [INFO] retrieved: %s" % (
                time.strftime("%X"), filterControlChars(finalValue))

        if isinstance(finalValue, basestring) and len(finalValue) > 0:
            dataToSessionFile(replaceNewlineTabs(finalValue))

        if conf.verbose in (1, 2) and not showEta and infoMsg:
            dataToStdout(infoMsg)

    # No multi-threading (--threads = 1)
    else:
        index = firstChar

        while True:
            index += 1
            charStart = time.time()

            # Common prediction feature (a.k.a. "good samaritan")
            # NOTE: to be used only when multi-threading is not set for
            # the moment
Esempio n. 53
0
def setUnion(comment=None, count=None, position=None, negative=False, falseCond=False, payload=None):
    """
    @param comment: union comment to save in session file
    @type comment: C{str}

    @param count: union count to save in session file
    @type count: C{str}

    @param position: union position to save in session file
    @type position: C{str}
    """

    if comment:
        condition = (
                      not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
                      not kb.resumedQueries[conf.url].has_key("Union comment") )
                    )

        if condition:
            dataToSessionFile("[%s][%s][%s][Union comment][%s]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]), safeFormatString(comment)))

        kb.unionComment = comment

    if count:
        condition = (
                      not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
                      not kb.resumedQueries[conf.url].has_key("Union count") )
                    )

        if condition:
            dataToSessionFile("[%s][%s][%s][Union count][%d]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]), count))

        kb.unionCount = count

    if position is not None:
        condition = (
                      not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
                      not kb.resumedQueries[conf.url].has_key("Union position") )
                    )

        if condition:
            dataToSessionFile("[%s][%s][%s][Union position][%s]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]), position))

        kb.unionPosition = position

    if negative:
        condition = (
                      not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
                      ( not kb.resumedQueries[conf.url].has_key("Union negative")
                      ) )
                    )

        if condition:
            dataToSessionFile("[%s][%s][%s][Union negative][Yes]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace])))

        kb.unionNegative = True

    if falseCond:
        condition = (
                      not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
                      ( not kb.resumedQueries[conf.url].has_key("Union false condition")
                      ) )
                    )

        if condition:
            dataToSessionFile("[%s][%s][%s][Union false condition][Yes]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace])))

        kb.unionFalseCond = True

    if payload:
        condition = (
                      not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
                      ( not kb.resumedQueries[conf.url].has_key("Union payload")
                      ) )
                    )

        if condition:
            dataToSessionFile("[%s][%s][%s][Union payload][%s]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]), payload))

        kb.unionTest = payload