def checkDbmsOs(self, detailed=False):
        if kb.os:
            return

        infoMsg = "fingerprinting the back-end DBMS operating system"
        logger.info(infoMsg)

        self.createSupportTbl(self.fileTblName, self.tblField, "character(10000)")
        inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "VERSION()"))

        # Windows executables should always have ' Visual C++' or ' mingw'
        # patterns within the banner
        osWindows = ( " Visual C++", "mingw" )

        for osPattern in osWindows:
            query  = "(SELECT LENGTH(%s) FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField)
            query += "LIKE '%" + osPattern + "%')>0"
            query  = agent.forgeCaseStatement(query)

            if inject.getValue(query, charsetType=1, suppressOutput=True) == "1":
                kb.os = "Windows"

                break

        if kb.os is None:
            kb.os = "Linux"

        infoMsg = "the back-end DBMS operating system is %s" % kb.os
        logger.info(infoMsg)

        self.cleanup(onlyFileTbl=True)
Beispiel #2
0
    def _checkExistUdf(self, udf):
        logger.info("checking if UDF '%s' already exist" % udf)

        query = agent.forgeCaseStatement(
            queries[Backend.getIdentifiedDbms()].check_udf.query % (udf, udf))
        return inject.getValue(query,
                               resumeValue=False,
                               expected=EXPECTED.BOOL,
                               charsetType=CHARSET_TYPE.BINARY)
Beispiel #3
0
    def __checkExistUdf(self, udf):
        logger.info("checking if UDF '%s' already exist" % udf)

        query  = agent.forgeCaseStatement(queries[kb.dbms].checkUdf % (udf, udf))
        exists = inject.getValue(query, resumeValue=False, unpack=False, charsetType=2)

        if exists == "1":
            return True
        else:
            return False
Beispiel #4
0
    def __checkExistUdf(self, udf):
        logger.info("checking if UDF '%s' already exist" % udf)

        query = agent.forgeCaseStatement(queries[Backend.getIdentifiedDbms()].check_udf.query % (udf, udf))
        exists = inject.getValue(query, resumeValue=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)

        if exists == "1":
            return True
        else:
            return False
Beispiel #5
0
    def __checkExistUdf(self, udf):
        logger.info("checking if UDF '%s' already exist" % udf)

        query = agent.forgeCaseStatement(queries[Backend.getIdentifiedDbms()].check_udf.query % (udf, udf))
        exists = inject.getValue(query, resumeValue=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)

        if exists == "1":
            return True
        else:
            return False
Beispiel #6
0
    def isDba(self, user=None):
        infoMsg = "testing if current user is DBA"
        logger.info(infoMsg)

        if Backend.isDbms(DBMS.MYSQL):
            self.getCurrentUser()
            query = queries[Backend.getIdentifiedDbms()].is_dba.query % (kb.data.currentUser.split("@")[0] if kb.data.currentUser else None)
        elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and user is not None:
            query = queries[Backend.getIdentifiedDbms()].is_dba.query2 % user
        else:
            query = queries[Backend.getIdentifiedDbms()].is_dba.query

        query = agent.forgeCaseStatement(query)
        kb.data.isDba = inject.checkBooleanExpression(query) or False

        return kb.data.isDba
Beispiel #7
0
    def isDba(self, user=None):
        infoMsg = "testing if current user is DBA"
        logger.info(infoMsg)

        if Backend.isDbms(DBMS.MYSQL):
            self.getCurrentUser()
            query = queries[Backend.getIdentifiedDbms()].is_dba.query % (kb.data.currentUser.split("@")[0] if kb.data.currentUser else None)
        elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and user is not None:
            query = queries[Backend.getIdentifiedDbms()].is_dba.query2 % user
        else:
            query = queries[Backend.getIdentifiedDbms()].is_dba.query

        query = agent.forgeCaseStatement(query)
        kb.data.isDba = unArrayizeValue(inject.getValue(query, expected=EXPECTED.BOOL, charsetType=CHARSET_TYPE.BINARY))

        return kb.data.isDba == "1"
Beispiel #8
0
def getValue(expression,
             blind=True,
             union=True,
             error=True,
             time=True,
             fromUser=False,
             expected=None,
             batch=False,
             unpack=True,
             resumeValue=True,
             charsetType=None,
             firstChar=None,
             lastChar=None,
             dump=False,
             suppressOutput=None,
             expectingNone=False,
             safeCharEncode=True):
    """
    Called each time sqlmap inject a SQL query on the SQL injection
    affected parameter.
    """

    if conf.hexConvert:
        charsetType = CHARSET_TYPE.HEXADECIMAL

    kb.safeCharEncode = safeCharEncode
    kb.resumeValues = resumeValue

    if suppressOutput is not None:
        pushValue(getCurrentThreadData().disableStdOut)
        getCurrentThreadData().disableStdOut = suppressOutput

    try:
        if expected == EXPECTED.BOOL:
            forgeCaseExpression = booleanExpression = expression

            if expression.upper().startswith("SELECT "):
                booleanExpression = expression[len("SELECT "):]
                if re.search(r"(?i)\(.+\)\Z", booleanExpression):
                    booleanExpression = "%s=%s" % (
                        booleanExpression,
                        "'1'" if "'1'" in booleanExpression else '1')
            else:
                forgeCaseExpression = agent.forgeCaseStatement(expression)

        if conf.direct:
            value = direct(forgeCaseExpression if expected ==
                           EXPECTED.BOOL else expression)

        elif any(
                map(isTechniqueAvailable,
                    getPublicTypeMembers(PAYLOAD.TECHNIQUE, onlyValues=True))):
            query = cleanQuery(expression)
            query = expandAsteriskForColumns(query)
            value = None
            found = False
            count = 0

            if query and not 'COUNT(*)' in query:
                query = query.replace("DISTINCT ", "")

            if not conf.forceDns:
                if union and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION):
                    kb.technique = PAYLOAD.TECHNIQUE.UNION
                    value = __goUnion(
                        forgeCaseExpression
                        if expected == EXPECTED.BOOL else query, unpack, dump)
                    count += 1
                    found = (value is not None) or (
                        value is None
                        and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE

                if error and isTechniqueAvailable(
                        PAYLOAD.TECHNIQUE.ERROR) and not found:
                    kb.technique = PAYLOAD.TECHNIQUE.ERROR
                    value = errorUse(
                        forgeCaseExpression
                        if expected == EXPECTED.BOOL else query, dump)
                    count += 1
                    found = (value is not None) or (
                        value is None
                        and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE

                if found and conf.dnsName:
                    _ = "".join(
                        filter(None,
                               (key if isTechniqueAvailable(value) else None
                                for key, value in {
                                    "E": PAYLOAD.TECHNIQUE.ERROR,
                                    "U": PAYLOAD.TECHNIQUE.UNION
                                }.items())))
                    warnMsg = "option '--dns-domain' will be ignored "
                    warnMsg += "as faster techniques are usable "
                    warnMsg += "(%s) " % _
                    singleTimeWarnMessage(warnMsg)

            if blind and isTechniqueAvailable(
                    PAYLOAD.TECHNIQUE.BOOLEAN) and not found:
                kb.technique = PAYLOAD.TECHNIQUE.BOOLEAN

                if expected == EXPECTED.BOOL:
                    value = __goBooleanProxy(booleanExpression)
                else:
                    value = __goInferenceProxy(query, fromUser, batch, unpack,
                                               charsetType, firstChar,
                                               lastChar, dump)

                count += 1
                found = (value is not None) or (
                    value is None
                    and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE

            if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME)
                         or isTechniqueAvailable(
                             PAYLOAD.TECHNIQUE.STACKED)) and not found:
                if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME):
                    kb.technique = PAYLOAD.TECHNIQUE.TIME
                else:
                    kb.technique = PAYLOAD.TECHNIQUE.STACKED

                if expected == EXPECTED.BOOL:
                    value = __goBooleanProxy(booleanExpression)
                else:
                    value = __goInferenceProxy(query, fromUser, batch, unpack,
                                               charsetType, firstChar,
                                               lastChar, dump)

            if value and isinstance(value, basestring):
                value = value.strip() if value.strip() else value[:1]
        else:
            errMsg = "none of the injection types identified can be "
            errMsg += "leveraged to retrieve queries output"
            raise sqlmapNotVulnerableException, errMsg

    finally:
        kb.resumeValues = True

        if suppressOutput is not None:
            getCurrentThreadData().disableStdOut = popValue()

    kb.safeCharEncode = False

    if not kb.testMode and value is None and Backend.getDbms(
    ) and conf.dbmsHandler:
        warnMsg = "in case of continuous data retrieval problems you are advised to try "
        warnMsg += "a switch '--no-cast' and/or switch '--hex'"
        singleTimeWarnMessage(warnMsg)

    return extractExpectedValue(value, expected)
Beispiel #9
0
def getValue(expression,
             blind=True,
             union=True,
             error=True,
             time=True,
             fromUser=False,
             expected=None,
             batch=False,
             unpack=True,
             resumeValue=True,
             charsetType=None,
             firstChar=None,
             lastChar=None,
             dump=False,
             suppressOutput=None,
             expectingNone=False,
             safeCharEncode=True):
    """
    Called each time sqlmap inject a SQL query on the SQL injection
    affected parameter.
    """

    if conf.hexConvert and expected != EXPECTED.BOOL and Backend.getIdentifiedDbms(
    ):
        if not hasattr(queries[Backend.getIdentifiedDbms()], "hex"):
            warnMsg = "switch '--hex' is currently not supported on DBMS %s" % Backend.getIdentifiedDbms(
            )
            singleTimeWarnMessage(warnMsg)
            conf.hexConvert = False
        else:
            charsetType = CHARSET_TYPE.HEXADECIMAL

    kb.safeCharEncode = safeCharEncode
    kb.resumeValues = resumeValue

    for keyword in GET_VALUE_UPPERCASE_KEYWORDS:
        expression = re.sub(r"(?i)(\A|\(|\)|\s)%s(\Z|\(|\)|\s)" % keyword,
                            r"\g<1>%s\g<2>" % keyword, expression)

    if suppressOutput is not None:
        pushValue(getCurrentThreadData().disableStdOut)
        getCurrentThreadData().disableStdOut = suppressOutput

    try:
        pushValue(conf.db)
        pushValue(conf.tbl)

        if expected == EXPECTED.BOOL:
            forgeCaseExpression = booleanExpression = expression

            if expression.startswith("SELECT "):
                booleanExpression = "(%s)=%s" % (booleanExpression,
                                                 "'1'" if "'1'"
                                                 in booleanExpression else "1")
            else:
                forgeCaseExpression = agent.forgeCaseStatement(expression)

        if conf.direct:
            value = direct(forgeCaseExpression if expected ==
                           EXPECTED.BOOL else expression)

        elif any(
                isTechniqueAvailable(_)
                for _ in getPublicTypeMembers(PAYLOAD.TECHNIQUE,
                                              onlyValues=True)):
            query = cleanQuery(expression)
            query = expandAsteriskForColumns(query)
            value = None
            found = False
            count = 0

            if query and not re.search(r"COUNT.*FROM.*\(.*DISTINCT", query,
                                       re.I):
                query = query.replace("DISTINCT ", "")

            if not conf.forceDns:
                if union and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION):
                    setTechnique(PAYLOAD.TECHNIQUE.UNION)
                    kb.forcePartialUnion = kb.injection.data[
                        PAYLOAD.TECHNIQUE.UNION].vector[8]
                    fallback = not expected and kb.injection.data[
                        PAYLOAD.TECHNIQUE.
                        UNION].where == PAYLOAD.WHERE.ORIGINAL and not kb.forcePartialUnion

                    try:
                        value = _goUnion(
                            forgeCaseExpression if expected == EXPECTED.BOOL
                            else query, unpack, dump)
                    except SqlmapConnectionException:
                        if not fallback:
                            raise

                    count += 1
                    found = (value is not None) or (
                        value is None
                        and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE

                    if not found and fallback:
                        warnMsg = "something went wrong with full UNION "
                        warnMsg += "technique (could be because of "
                        warnMsg += "limitation on retrieved number of entries)"
                        if " FROM " in query.upper():
                            warnMsg += ". Falling back to partial UNION technique"
                            singleTimeWarnMessage(warnMsg)

                            try:
                                pushValue(kb.forcePartialUnion)
                                kb.forcePartialUnion = True
                                value = _goUnion(query, unpack, dump)
                                found = (value
                                         is not None) or (value is None
                                                          and expectingNone)
                            finally:
                                kb.forcePartialUnion = popValue()
                        else:
                            singleTimeWarnMessage(warnMsg)

                if error and any(
                        isTechniqueAvailable(_)
                        for _ in (PAYLOAD.TECHNIQUE.ERROR,
                                  PAYLOAD.TECHNIQUE.QUERY)) and not found:
                    setTechnique(PAYLOAD.TECHNIQUE.ERROR if
                                 isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR)
                                 else PAYLOAD.TECHNIQUE.QUERY)
                    value = errorUse(
                        forgeCaseExpression
                        if expected == EXPECTED.BOOL else query, dump)
                    count += 1
                    found = (value is not None) or (
                        value is None
                        and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE

                if found and conf.dnsDomain:
                    _ = "".join(
                        filterNone(
                            key if isTechniqueAvailable(value) else None
                            for key, value in {
                                'E': PAYLOAD.TECHNIQUE.ERROR,
                                'Q': PAYLOAD.TECHNIQUE.QUERY,
                                'U': PAYLOAD.TECHNIQUE.UNION
                            }.items()))
                    warnMsg = "option '--dns-domain' will be ignored "
                    warnMsg += "as faster techniques are usable "
                    warnMsg += "(%s) " % _
                    singleTimeWarnMessage(warnMsg)

            if blind and isTechniqueAvailable(
                    PAYLOAD.TECHNIQUE.BOOLEAN) and not found:
                setTechnique(PAYLOAD.TECHNIQUE.BOOLEAN)

                if expected == EXPECTED.BOOL:
                    value = _goBooleanProxy(booleanExpression)
                else:
                    value = _goInferenceProxy(query, fromUser, batch, unpack,
                                              charsetType, firstChar, lastChar,
                                              dump)

                count += 1
                found = (value is not None) or (
                    value is None
                    and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE

            if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME)
                         or isTechniqueAvailable(
                             PAYLOAD.TECHNIQUE.STACKED)) and not found:
                match = re.search(r"\bFROM\b ([^ ]+).+ORDER BY ([^ ]+)",
                                  expression)
                kb.responseTimeMode = "%s|%s" % (
                    match.group(1), match.group(2)) if match else None

                if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME):
                    setTechnique(PAYLOAD.TECHNIQUE.TIME)
                else:
                    setTechnique(PAYLOAD.TECHNIQUE.STACKED)

                if expected == EXPECTED.BOOL:
                    value = _goBooleanProxy(booleanExpression)
                else:
                    value = _goInferenceProxy(query, fromUser, batch, unpack,
                                              charsetType, firstChar, lastChar,
                                              dump)
        else:
            errMsg = "none of the injection types identified can be "
            errMsg += "leveraged to retrieve queries output"
            raise SqlmapNotVulnerableException(errMsg)

    finally:
        kb.resumeValues = True
        kb.responseTimeMode = None

        conf.tbl = popValue()
        conf.db = popValue()

        if suppressOutput is not None:
            getCurrentThreadData().disableStdOut = popValue()

    kb.safeCharEncode = False

    if not any(
        (kb.testMode, conf.dummy,
         conf.offline)) and value is None and Backend.getDbms(
         ) and conf.dbmsHandler and not conf.noCast and not conf.hexConvert:
        warnMsg = "in case of continuous data retrieval problems you are advised to try "
        warnMsg += "a switch '--no-cast' "
        warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (
            DBMS.ACCESS, DBMS.FIREBIRD) else ""
        singleTimeWarnMessage(warnMsg)

    # Dirty patch (safe-encoded unicode characters)
    if isinstance(value, six.text_type) and "\\x" in value:
        try:
            candidate = eval(
                repr(value).replace("\\\\x", "\\x").replace(
                    "u'", "'", 1)).decode(conf.encoding or UNICODE_ENCODING)
            if "\\x" not in candidate:
                value = candidate
        except:
            pass

    return extractExpectedValue(value, expected)
Beispiel #10
0
def getValue(expression,
             blind=True,
             inband=True,
             error=True,
             time=True,
             fromUser=False,
             expected=None,
             batch=False,
             unpack=True,
             sort=True,
             resumeValue=True,
             charsetType=None,
             firstChar=None,
             lastChar=None,
             dump=False,
             suppressOutput=None,
             expectingNone=False,
             safeHexEncode=True):
    """
    Called each time sqlmap inject a SQL query on the SQL injection
    affected parameter. It can call a function to retrieve the output
    through inband SQL injection (if selected) and/or blind SQL injection
    (if selected).
    """

    if suppressOutput is not None:
        pushValue(getCurrentThreadData().disableStdOut)
        getCurrentThreadData().disableStdOut = suppressOutput

    try:
        if conf.direct:
            value = direct(expression)

        elif any(
                map(isTechniqueAvailable,
                    getPublicTypeMembers(PAYLOAD.TECHNIQUE, onlyValues=True))):
            query = cleanQuery(expression)
            query = expandAsteriskForColumns(query)
            value = None
            found = False

            if query and not 'COUNT(*)' in query:
                query = query.replace("DISTINCT ", "")

            count = 0

            if expected == EXPECTED.BOOL:
                forgeCaseExpression = booleanExpression = expression

                if expression.upper().startswith("SELECT "):
                    booleanExpression = expression[len("SELECT "):]
                else:
                    forgeCaseExpression = agent.forgeCaseStatement(expression)

            if inband and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION):
                kb.technique = PAYLOAD.TECHNIQUE.UNION

                if expected == EXPECTED.BOOL:
                    value = __goInband(forgeCaseExpression, expected, sort,
                                       resumeValue, unpack, dump)
                else:
                    value = __goInband(query, expected, sort, resumeValue,
                                       unpack, dump)

                count += 1
                found = (value is not None) or (
                    value is None
                    and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE

            if error and isTechniqueAvailable(
                    PAYLOAD.TECHNIQUE.ERROR) and not found:
                kb.technique = PAYLOAD.TECHNIQUE.ERROR

                if expected == EXPECTED.BOOL:
                    value = __goError(forgeCaseExpression, expected,
                                      resumeValue, dump)
                else:
                    value = __goError(query, expected, resumeValue, dump)

                count += 1
                found = (value is not None) or (
                    value is None
                    and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE

            if blind and isTechniqueAvailable(
                    PAYLOAD.TECHNIQUE.BOOLEAN) and not found:
                kb.technique = PAYLOAD.TECHNIQUE.BOOLEAN

                if expected == EXPECTED.BOOL:
                    value = __goBooleanProxy(booleanExpression, resumeValue)
                else:
                    value = __goInferenceProxy(query, fromUser, expected,
                                               batch, resumeValue, unpack,
                                               charsetType, firstChar,
                                               lastChar, dump)

                count += 1
                found = (value is not None) or (
                    value is None
                    and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE

            if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME)
                         or isTechniqueAvailable(
                             PAYLOAD.TECHNIQUE.STACKED)) and not found:
                if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME):
                    kb.technique = PAYLOAD.TECHNIQUE.TIME
                else:
                    kb.technique = PAYLOAD.TECHNIQUE.STACKED

                if expected == EXPECTED.BOOL:
                    value = __goBooleanProxy(booleanExpression, resumeValue)
                else:
                    value = __goInferenceProxy(query, fromUser, expected,
                                               batch, resumeValue, unpack,
                                               charsetType, firstChar,
                                               lastChar, dump)

            if value and isinstance(value, basestring):
                value = value.strip()
        else:
            errMsg = "none of the injection types identified can be "
            errMsg += "leveraged to retrieve queries output"
            raise sqlmapNotVulnerableException, errMsg

    finally:
        if suppressOutput is not None:
            getCurrentThreadData().disableStdOut = popValue()

    if value and expected == EXPECTED.BOOL:
        if isinstance(value, basestring):
            value = value.strip().lower()
            if value in ("true", "false"):
                value = bool(value)
            elif value in ("1", "-1"):
                value = True
            elif value == "0":
                value = False
            else:
                value = None
        elif isinstance(value, int):
            value = bool(value)
        elif value == [None]:
            value = None

    if safeHexEncode:
        value = safehexencode(value)

    return value
Beispiel #11
0
def getValue(expression,
             blind=True,
             union=True,
             error=True,
             time=True,
             fromUser=False,
             expected=None,
             batch=False,
             unpack=True,
             resumeValue=True,
             charsetType=None,
             firstChar=None,
             lastChar=None,
             dump=False,
             suppressOutput=None,
             expectingNone=False,
             safeCharEncode=True):
    """
    Called each time sqlmap inject a SQL query on the SQL injection
    affected parameter.
    """

    if conf.hexConvert:
        charsetType = CHARSET_TYPE.HEXADECIMAL

    kb.safeCharEncode = safeCharEncode
    kb.resumeValues = resumeValue

    if suppressOutput is not None:
        pushValue(getCurrentThreadData().disableStdOut)
        getCurrentThreadData().disableStdOut = suppressOutput

    try:
        pushValue(conf.db)
        pushValue(conf.tbl)

        if expected == EXPECTED.BOOL:
            forgeCaseExpression = booleanExpression = expression

            if expression.upper().startswith("SELECT "):
                booleanExpression = "(%s)=%s" % (booleanExpression,
                                                 "'1'" if "'1'"
                                                 in booleanExpression else "1")
            else:
                forgeCaseExpression = agent.forgeCaseStatement(expression)

        if conf.direct:
            value = direct(forgeCaseExpression if expected ==
                           EXPECTED.BOOL else expression)

        elif any(
                map(isTechniqueAvailable,
                    getPublicTypeMembers(PAYLOAD.TECHNIQUE, onlyValues=True))):
            query = cleanQuery(expression)
            query = expandAsteriskForColumns(query)
            value = None
            found = False
            count = 0

            if query and not re.search(r"COUNT.*FROM.*\(.*DISTINCT", query,
                                       re.I):
                query = query.replace("DISTINCT ", "")

            if not conf.forceDns:
                if union and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION):
                    kb.technique = PAYLOAD.TECHNIQUE.UNION
                    kb.forcePartialUnion = kb.injection.data[
                        PAYLOAD.TECHNIQUE.UNION].vector[8]
                    fallback = not expected and kb.injection.data[
                        PAYLOAD.TECHNIQUE.
                        UNION].where == PAYLOAD.WHERE.ORIGINAL and not kb.forcePartialUnion

                    try:
                        value = _goUnion(
                            forgeCaseExpression if expected == EXPECTED.BOOL
                            else query, unpack, dump)
                    except SqlmapConnectionException:
                        if not fallback:
                            raise

                    count += 1
                    found = (value is not None) or (
                        value is None
                        and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE

                    if not found and fallback:
                        warnMsg = "something went wrong with full UNION "
                        warnMsg += "technique (could be because of "
                        warnMsg += "limitation on retrieved number of entries)"
                        if " FROM " in query.upper():
                            warnMsg += ". Falling back to partial UNION technique"
                            singleTimeWarnMessage(warnMsg)

                            try:
                                pushValue(kb.forcePartialUnion)
                                kb.forcePartialUnion = True
                                value = _goUnion(query, unpack, dump)
                                found = (value
                                         is not None) or (value is None
                                                          and expectingNone)
                            finally:
                                kb.forcePartialUnion = popValue()
                        else:
                            singleTimeWarnMessage(warnMsg)

                if error and any(
                        isTechniqueAvailable(_)
                        for _ in (PAYLOAD.TECHNIQUE.ERROR,
                                  PAYLOAD.TECHNIQUE.QUERY)) and not found:
                    kb.technique = PAYLOAD.TECHNIQUE.ERROR if isTechniqueAvailable(
                        PAYLOAD.TECHNIQUE.ERROR) else PAYLOAD.TECHNIQUE.QUERY
                    value = errorUse(
                        forgeCaseExpression
                        if expected == EXPECTED.BOOL else query, dump)
                    count += 1
                    found = (value is not None) or (
                        value is None
                        and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE

                if found and conf.dnsName:
                    _ = "".join(
                        filter(None,
                               (key if isTechniqueAvailable(value) else None
                                for key, value in {
                                    "E": PAYLOAD.TECHNIQUE.ERROR,
                                    "Q": PAYLOAD.TECHNIQUE.QUERY,
                                    "U": PAYLOAD.TECHNIQUE.UNION
                                }.items())))
                    warnMsg = "option '--dns-domain' will be ignored "
                    warnMsg += "as faster techniques are usable "
                    warnMsg += "(%s) " % _
                    singleTimeWarnMessage(warnMsg)

            if blind and isTechniqueAvailable(
                    PAYLOAD.TECHNIQUE.BOOLEAN) and not found:
                kb.technique = PAYLOAD.TECHNIQUE.BOOLEAN

                if expected == EXPECTED.BOOL:
                    value = _goBooleanProxy(booleanExpression)
                else:
                    value = _goInferenceProxy(query, fromUser, batch, unpack,
                                              charsetType, firstChar, lastChar,
                                              dump)

                count += 1
                found = (value is not None) or (
                    value is None
                    and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE

            if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME)
                         or isTechniqueAvailable(
                             PAYLOAD.TECHNIQUE.STACKED)) and not found:
                if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME):
                    kb.technique = PAYLOAD.TECHNIQUE.TIME
                else:
                    kb.technique = PAYLOAD.TECHNIQUE.STACKED

                if expected == EXPECTED.BOOL:
                    value = _goBooleanProxy(booleanExpression)
                else:
                    value = _goInferenceProxy(query, fromUser, batch, unpack,
                                              charsetType, firstChar, lastChar,
                                              dump)

        else:
            errMsg = "none of the injection types identified can be "
            errMsg += "leveraged to retrieve queries output"
            raise SqlmapNotVulnerableException(errMsg)

    finally:
        kb.resumeValues = True

        conf.tbl = popValue()
        conf.db = popValue()

        if suppressOutput is not None:
            getCurrentThreadData().disableStdOut = popValue()

    kb.safeCharEncode = False

    if not any(
        (kb.testMode, conf.dummy,
         conf.offline)) and value is None and Backend.getDbms(
         ) and conf.dbmsHandler and not conf.noCast and not conf.hexConvert:
        warnMsg = "in case of continuous data retrieval problems you are advised to try "
        warnMsg += "a switch '--no-cast' "
        warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (
            DBMS.ACCESS, DBMS.FIREBIRD) else ""
        singleTimeWarnMessage(warnMsg)

    return extractExpectedValue(value, expected)
Beispiel #12
0
def getValue(expression,
             blind=True,
             union=True,
             error=True,
             time=True,
             fromUser=False,
             expected=None,
             batch=False,
             unpack=True,
             resumeValue=True,
             charsetType=None,
             firstChar=None,
             lastChar=None,
             dump=False,
             suppressOutput=None,
             expectingNone=False,
             safeCharEncode=True):
    """
    sqlmap每次在受影响的参数上注入SQL查询时调用。
    """
    # 转为十六进制
    if conf.hexConvert:
        charsetType = CHARSET_TYPE.HEXADECIMAL

    kb.safeCharEncode = safeCharEncode
    kb.resumeValues = resumeValue

    # keyword中是否存在("SELECT", "FROM", "WHERE", "DISTINCT", "COUNT")关键字
    for keyword in GET_VALUE_UPPERCASE_KEYWORDS:
        expression = re.sub("(?i)(\A|\(|\)|\s)%s(\Z|\(|\)|\s)" % keyword,
                            r"\g<1>%s\g<2>" % keyword, expression)

    if suppressOutput is not None:
        pushValue(getCurrentThreadData().disableStdOut)
        getCurrentThreadData().disableStdOut = suppressOutput

    try:
        pushValue(conf.db)
        pushValue(conf.tbl)

        if expected == EXPECTED.BOOL:
            forgeCaseExpression = booleanExpression = expression

            if expression.startswith("SELECT "):
                booleanExpression = "(%s)=%s" % (booleanExpression,
                                                 "'1'" if "'1'"
                                                 in booleanExpression else "1")
            else:
                forgeCaseExpression = agent.forgeCaseStatement(expression)

        if conf.direct:
            value = direct(forgeCaseExpression if expected ==
                           EXPECTED.BOOL else expression)

        elif any(
                isTechniqueAvailable(_)
                for _ in getPublicTypeMembers(PAYLOAD.TECHNIQUE,
                                              onlyValues=True)):
            query = cleanQuery(expression)
            query = expandAsteriskForColumns(query)
            value = None
            found = False
            count = 0

            if query and not re.search(r"COUNT.*FROM.*\(.*DISTINCT", query,
                                       re.I):
                query = query.replace("DISTINCT ", "")

            if not conf.forceDns:
                if union and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION):
                    kb.technique = PAYLOAD.TECHNIQUE.UNION
                    kb.forcePartialUnion = kb.injection.data[
                        PAYLOAD.TECHNIQUE.UNION].vector[8]
                    fallback = not expected and kb.injection.data[
                        PAYLOAD.TECHNIQUE.
                        UNION].where == PAYLOAD.WHERE.ORIGINAL and not kb.forcePartialUnion

                    try:
                        value = _goUnion(
                            forgeCaseExpression if expected == EXPECTED.BOOL
                            else query, unpack, dump)
                    except SqlmapConnectionException:
                        if not fallback:
                            raise

                    count += 1
                    found = (value is not None) or (
                        value is None
                        and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE

                    if not found and fallback:
                        warnMsg = "something went wrong with full UNION "
                        warnMsg += "technique (could be because of "
                        warnMsg += "limitation on retrieved number of entries)"
                        if " FROM " in query.upper():
                            warnMsg += ". Falling back to partial UNION technique"
                            singleTimeWarnMessage(warnMsg)

                            try:
                                pushValue(kb.forcePartialUnion)
                                kb.forcePartialUnion = True
                                value = _goUnion(query, unpack, dump)
                                found = (value
                                         is not None) or (value is None
                                                          and expectingNone)
                            finally:
                                kb.forcePartialUnion = popValue()
                        else:
                            singleTimeWarnMessage(warnMsg)

                if error and any(
                        isTechniqueAvailable(_)
                        for _ in (PAYLOAD.TECHNIQUE.ERROR,
                                  PAYLOAD.TECHNIQUE.QUERY)) and not found:
                    kb.technique = PAYLOAD.TECHNIQUE.ERROR if isTechniqueAvailable(
                        PAYLOAD.TECHNIQUE.ERROR) else PAYLOAD.TECHNIQUE.QUERY
                    value = errorUse(
                        forgeCaseExpression
                        if expected == EXPECTED.BOOL else query, dump)
                    count += 1
                    found = (value is not None) or (
                        value is None
                        and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE

                if found and conf.dnsDomain:
                    _ = "".join(
                        filter(None,
                               (key if isTechniqueAvailable(value) else None
                                for key, value in {
                                    'E': PAYLOAD.TECHNIQUE.ERROR,
                                    'Q': PAYLOAD.TECHNIQUE.QUERY,
                                    'U': PAYLOAD.TECHNIQUE.UNION
                                }.items())))
                    warnMsg = "option '--dns-domain' will be ignored "
                    warnMsg += "as faster techniques are usable "
                    warnMsg += "(%s) " % _
                    singleTimeWarnMessage(warnMsg)

            if blind and isTechniqueAvailable(
                    PAYLOAD.TECHNIQUE.BOOLEAN) and not found:
                kb.technique = PAYLOAD.TECHNIQUE.BOOLEAN

                if expected == EXPECTED.BOOL:
                    value = _goBooleanProxy(booleanExpression)
                else:
                    value = _goInferenceProxy(query, fromUser, batch, unpack,
                                              charsetType, firstChar, lastChar,
                                              dump)

                count += 1
                found = (value is not None) or (
                    value is None
                    and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE

            if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME)
                         or isTechniqueAvailable(
                             PAYLOAD.TECHNIQUE.STACKED)) and not found:
                kb.responseTimeMode = re.sub(
                    r"(?i)[^a-z]", "",
                    re.sub(r"'[^']+'", "",
                           re.sub(r"(?i)(\w+)\(.+\)", r"\g<1>",
                                  expression))) if re.search(
                                      r"(?i)SELECT.+FROM",
                                      expression) else None

                if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME):
                    kb.technique = PAYLOAD.TECHNIQUE.TIME
                else:
                    kb.technique = PAYLOAD.TECHNIQUE.STACKED

                if expected == EXPECTED.BOOL:
                    value = _goBooleanProxy(booleanExpression)
                else:
                    value = _goInferenceProxy(query, fromUser, batch, unpack,
                                              charsetType, firstChar, lastChar,
                                              dump)
        else:
            errMsg = "none of the injection types identified can be "
            errMsg += "leveraged to retrieve queries output"
            raise SqlmapNotVulnerableException(errMsg)

    finally:
        kb.resumeValues = True
        kb.responseTimeMode = None

        conf.tbl = popValue()
        conf.db = popValue()

        if suppressOutput is not None:
            getCurrentThreadData().disableStdOut = popValue()

    kb.safeCharEncode = False

    if not any(
        (kb.testMode, conf.dummy,
         conf.offline)) and value is None and Backend.getDbms(
         ) and conf.dbmsHandler and not conf.noCast and not conf.hexConvert:
        warnMsg = u"在对连续的数据进行检索的情况下,建议您尝试一个选项'--no-cast'或'--hex'"
        warnMsg += u"或'--hex'" if Backend.getIdentifiedDbms() not in (
            DBMS.ACCESS, DBMS.FIREBIRD) else ""
        singleTimeWarnMessage(warnMsg)

    return extractExpectedValue(value, expected)