Esempio n. 1
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. 2
0
def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False, field=None):
    start = time.time()
    value = None
    count = 0

    value = _goDns(payload, expression)

    if value:
        return value

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

    if not (timeBasedCompare and kb.dnsTest):
        if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search("(COUNT|LTRIM)\(", expression, re.I) and not timeBasedCompare:
            if field and conf.hexConvert:
                nulledCastedField = agent.nullAndCastField(field)
                injExpression = expression.replace(field, nulledCastedField, 1)
            else:
                injExpression = expression
            length = queryOutputLength(injExpression, payload)
        else:
            length = None

        kb.inferenceMode = True
        count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump)
        kb.inferenceMode = False

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

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

    value = __goDns(payload, expression)

    if value is None:
        timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED))

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

            kb.inferenceMode = True
            count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump)
            kb.inferenceMode = False

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

    return value
Esempio n. 4
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. 5
0
def _goInference(payload,
                 expression,
                 charsetType=None,
                 firstChar=None,
                 lastChar=None,
                 dump=False,
                 field=None):
    start = time.time()
    value = None
    count = 0

    value = _goDns(payload, expression)

    if payload is None:
        return None

    if value is not None:
        return value

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

    if not (timeBasedCompare and kb.dnsTest):
        if (conf.eta or conf.threads > 1
            ) and Backend.getIdentifiedDbms() and not re.search(
                r"(COUNT|LTRIM)\(", expression,
                re.I) and not (timeBasedCompare and not conf.forceThreads):

            if field and re.search(r"\ASELECT\s+DISTINCT\((.+?)\)\s+FROM",
                                   expression, re.I):
                expression = "SELECT %s FROM (%s)" % (field, expression)

                if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                    expression += " AS %s" % randomStr(lowercase=True,
                                                       seed=hash(expression))

            if field and conf.hexConvert or conf.binaryFields and field in conf.binaryFields.split(
                    ','):
                nulledCastedField = agent.nullAndCastField(field)
                injExpression = expression.replace(field, nulledCastedField, 1)
            else:
                injExpression = expression
            length = queryOutputLength(injExpression, payload)
        else:
            length = None

        kb.inferenceMode = True
        count, value = bisection(payload, expression, length, charsetType,
                                 firstChar, lastChar, dump)
        kb.inferenceMode = False

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

    return value
Esempio n. 6
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. 7
0
def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False, field=None):
    start = time.time()
    value = None
    count = 0

    value = _goDns(payload, expression)

    if payload is None:
        return None

    if value is not None:
        return value

    timeBasedCompare = (getTechnique() in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED))

    if timeBasedCompare and conf.threads > 1 and kb.forceThreads is None:
        msg = "multi-threading is considered unsafe in "
        msg += "time-based data retrieval. Are you sure "
        msg += "of your choice (breaking warranty) [y/N] "

        kb.forceThreads = readInput(msg, default='N', boolean=True)

    if not (timeBasedCompare and kb.dnsTest):
        if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search(r"(COUNT|LTRIM)\(", expression, re.I) and not (timeBasedCompare and not kb.forceThreads):

            if field and re.search(r"\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I):
                if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB, DBMS.CUBRID):
                    alias = randomStr(lowercase=True, seed=hash(expression))
                    expression = "SELECT %s FROM (%s)" % (field if '.' not in field else re.sub(r".+\.", "%s." % alias, field), expression)  # Note: MonetDB as a prime example
                    expression += " AS %s" % alias
                else:
                    expression = "SELECT %s FROM (%s)" % (field, expression)

            if field and conf.hexConvert or conf.binaryFields and field in conf.binaryFields:
                nulledCastedField = agent.nullAndCastField(field)
                injExpression = expression.replace(field, nulledCastedField, 1)
            else:
                injExpression = expression
            length = queryOutputLength(injExpression, payload)
        else:
            length = None

        kb.inferenceMode = True
        count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump)
        kb.inferenceMode = False

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

    return value
Esempio n. 8
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. 9
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. 10
0
def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False, field=None):
    start = time.time()
    value = None
    count = 0

    value = _goDns(payload, expression)

    if value:
        return value

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

    if not (timeBasedCompare and kb.dnsTest):
        if (
            (conf.eta or conf.threads > 1)
            and Backend.getIdentifiedDbms()
            and not re.search("(COUNT|LTRIM)\(", expression, re.I)
            and not timeBasedCompare
        ):

            if field and re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I):
                expression = "SELECT %s FROM (%s)" % (field, expression)

                if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                    expression += " AS %s" % randomStr(lowercase=True)

            if field and conf.hexConvert or conf.binaryFields and field in conf.binaryFields.split(","):
                nulledCastedField = agent.nullAndCastField(field)
                injExpression = expression.replace(field, nulledCastedField, 1)
            else:
                injExpression = expression
            length = queryOutputLength(injExpression, payload)
        else:
            length = None

        kb.inferenceMode = True
        count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump)
        kb.inferenceMode = False

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

    return value
Esempio n. 11
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. 12
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. 13
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. 14
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. 15
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. 16
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. 17
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. 18
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