コード例 #1
0
def get_fingerprinting_wordlist(wordlist):
    """
    Load the wordlist of fingerprints and prepare the info in a dict.

    It using as a keys the name of the server family and, as value, an
    iterable with the keywords related with this web server.

    :return: The results of load of webservers keywords info and related webservers.
    :rtype: tuple(WEBSERVER_KEYWORDS, RELATED_SERVES) <=>  (dict(SERVERNAME: set(str(KEYWORDS))), dict(SERVER_NAME, set(str(RELATED_SERVERS)))
    """

    # Load the wordlist
    m_w = WordListLoader.get_advanced_wordlist_as_dict(wordlist,
                                                       separator=";",
                                                       smart_load=True)

    # Load references.
    #
    #   References in the wordlist are specified by # prefix.
    #
    already_parsed = set()
    related = defaultdict(set)
    m_webservers_keys = extend_items(m_w, already_parsed, related)

    return (m_webservers_keys, related)
コード例 #2
0
ファイル: fingerprint_os.py プロジェクト: damarsan/golismero
    def ttl_platform_detection(self, main_url):
        """
        This function tries to recognize the remote platform doing a ping and analyzing the
        TTL of IP header response.

        :param main_url: Base url to test.
        :type main_url: str

        :return: Possible platforms.
        :rtype: list(tuple(OS, version))
        """

        # Do a ping
        try:
            m_ttl = do_ping_and_receive_ttl(ParsedURL(main_url).hostname, 2)

            # Load words for the wordlist
            l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
                Config.plugin_extra_config["Wordlist_ttl"]["ttl"])
            # Looking for matches
            l_matches = l_wordlist_instance.matches_by_value(m_ttl)

            if l_matches:
                m_ret = {}
                for v in l_matches:
                    sp = v.split("|")
                    k = sp[0].strip()
                    v = sp[1].strip()
                    m_ret[k] = v

                return [(k, v) for k, v in m_ret.iteritems()]
            else:
                return {}
        except EnvironmentError:
            Logger.log_error(
                "[!] You can't run the platform detection plugin if you're not root."
            )
            return {}
        except Exception, e:
            Logger.log_error("[!] Platform detection failed, reason: %s" % e)
            return {}
コード例 #3
0
ファイル: fingerprint_os.py プロジェクト: atimorin/golismero
    def ttl_platform_detection(self, main_url):
        """
        This function tries to recognize the remote platform doing a ping and analyzing the
        TTL of IP header response.

        :param main_url: Base url to test.
        :type main_url: str

        :return: Possible platforms.
        :rtype: list(tuple(OS, version))
        """

        # Do a ping
        try:
            m_ttl               = do_ping_and_receive_ttl(ParsedURL(main_url).hostname, 2)

            # Load words for the wordlist
            l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config["Wordlist_ttl"]["ttl"])
            # Looking for matches
            l_matches           = l_wordlist_instance.matches_by_value(m_ttl)

            if l_matches:
                m_ret = {}
                for v in l_matches:
                    sp = v.split("|")
                    k = sp[0].strip()
                    v = sp[1].strip()
                    m_ret[k] = v

                return [(k,v) for k,v in m_ret.iteritems()]
            else:
                return {}
        except EnvironmentError:
            Logger.log_error("[!] You can't run the platform detection plugin if you're not root.")
            return {}
        except Exception, e:
            Logger.log_error("[!] Platform detection failed, reason: %s" % e)
            return {}
コード例 #4
0
def get_fingerprinting_wordlist(wordlist):
    """
    Load the wordlist of fingerprints and prepare the info in a dict.

    It using as a keys the name of the server family and, as value, an
    iterable with the keywords related with this web server.

    :return: The results of load of webservers keywords info and related webservers.
    :rtype: tuple(WEBSERVER_KEYWORDS, RELATED_SERVES) <=>  (dict(SERVERNAME: set(str(KEYWORDS))), dict(SERVER_NAME, set(str(RELATED_SERVERS)))
    """

    # Load the wordlist
    m_w = WordListLoader.get_advanced_wordlist_as_dict(wordlist, separator=";", smart_load=True)

    # Load references.
    #
    #   References in the wordlist are specified by # prefix.
    #
    already_parsed    = set()
    related           = defaultdict(set)
    m_webservers_keys = extend_items(m_w, already_parsed, related)

    return (m_webservers_keys, related)
コード例 #5
0
def http_analyzers(main_url, update_status_func, number_of_entries=4):
    """
    Analyze HTTP headers for detect the web server. Return a list with most possible web servers.

    :param main_url: Base url to test.
    :type main_url: str

    :param update_status_func: function used to update the status of the process
    :type update_status_func: function

    :param number_of_entries: number of resutls tu return for most probable web servers detected.
    :type number_of_entries: int

    :return: Web server family, Web server version, Web server complete description, related web servers (as a dict('SERVER_RELATED' : set(RELATED_NAMES))), others web server with their probabilities as a dict(CONCRETE_WEB_SERVER, PROBABILITY)
    """

    # Load wordlist directly related with a HTTP fields.
    # { HTTP_HEADER_FIELD : [wordlists] }
    m_wordlists_HTTP_fields = {
        "Accept-Ranges"              : "accept-range",
        "Server"                     : "banner",
        "Cache-Control"              : "cache-control",
        "Connection"                 : "connection",
        "Content-Type"               : "content-type",
        "WWW-Authenticate"           : "htaccess-realm",
        "Pragma"                     : "pragma",
        "X-Powered-By"               : "x-powered-by"
    }

    m_actions = {
        'GET'        : { 'wordlist' : 'Wordlist_get'            , 'weight' : 1 , 'protocol' : 'HTTP/1.1', 'method' : 'GET'      , 'payload': '/' },
        'LONG_GET'   : { 'wordlist' : 'Wordlist_get_long'       , 'weight' : 1 , 'protocol' : 'HTTP/1.1', 'method' : 'GET'      , 'payload': '/%s' % ('a' * 200) },
        'NOT_FOUND'  : { 'wordlist' : 'Wordlist_get_notfound'   , 'weight' : 2 , 'protocol' : 'HTTP/1.1', 'method' : 'GET'      , 'payload': '/404_NOFOUND__X02KAS' },
        'HEAD'       : { 'wordlist' : 'Wordlist_head'           , 'weight' : 3 , 'protocol' : 'HTTP/1.1', 'method' : 'HEAD'     , 'payload': '/' },
        'OPTIONS'    : { 'wordlist' : 'Wordlist_options'        , 'weight' : 2 , 'protocol' : 'HTTP/1.1', 'method' : 'OPTIONS'  , 'payload': '/' },
        'DELETE'     : { 'wordlist' : 'Wordlist_delete'         , 'weight' : 5 , 'protocol' : 'HTTP/1.1', 'method' : 'DELETE'   , 'payload': '/' },
        'TEST'       : { 'wordlist' : 'Wordlist_attack'         , 'weight' : 5 , 'protocol' : 'HTTP/1.1', 'method' : 'TEST'     , 'payload': '/' },
        'INVALID'    : { 'wordlist' : 'Wordlist_wrong_method'   , 'weight' : 5 , 'protocol' : 'HTTP/9.8', 'method' : 'GET'      , 'payload': '/' },
        'ATTACK'     : { 'wordlist' : 'Wordlist_wrong_version'  , 'weight' : 2 , 'protocol' : 'HTTP/1.1', 'method' : 'GET'      , 'payload': "/etc/passwd?format=%%%%&xss=\x22><script>alert('xss');</script>&traversal=../../&sql='%20OR%201;"}
    }


    # Store results for others HTTP params
    m_d                   = ParsedURL(main_url)
    m_hostname            = m_d.hostname
    m_port                = m_d.port
    m_debug               = False # Only for develop

    # Counter of banners. Used when others methods fails.
    m_banners_counter     = Counter()

    # Score counter
    m_counters = HTTPAnalyzer(debug=m_debug)

    # Var used to update the status
    m_data_len = len(m_actions)
    i          = 1 # element in process


    for l_action, v in m_actions.iteritems():
        if m_debug:
            print "###########"
        l_method      = v["method"]
        l_payload     = v["payload"]
        l_proto       = v["protocol"]
        l_wordlist    = v["wordlist"]

        # Each type of probe hast different weight.
        #
        # Weights go from 0 - 5
        #
        l_weight      = v["weight"]

        # Make the URL
        l_url         = urljoin(main_url, l_payload)

        # Make the raw request
        #l_raw_request = "%(method)s %(payload)s %(protocol)s\r\nHost: %(host)s:%(port)s\r\nConnection: Close\r\n\r\n" % (
        l_raw_request = "%(method)s %(payload)s %(protocol)s\r\nHost: %(host)s\r\n\r\n" % (
            {
                "method"     : l_method,
                "payload"    : l_payload,
                "protocol"   : l_proto,
                "host"       : m_hostname,
                "port"       : m_port
            }
        )
        if m_debug:
            print "REQUEST"
            print l_raw_request

        # Do the connection
        l_response = None
        try:
            m_raw_request = HTTP_Raw_Request(l_raw_request)
            discard_data(m_raw_request)
            l_response = HTTP.make_raw_request(
                host        = m_hostname,
                port        = m_port,
                raw_request = m_raw_request,
                callback    = check_raw_response)
            if l_response:
                discard_data(l_response)
        except NetworkException,e:
            Logger.log_error_more_verbose("Server-Fingerprint plugin: No response for URL (%s) '%s'. Message: %s" % (l_method, l_url, str(e)))
            continue

        if not l_response:
            Logger.log_error_more_verbose("No response for URL '%s'." % l_url)
            continue

        if m_debug:
            print "RESPONSE"
            print l_response.raw_headers


        # Update the status
        update_status_func((float(i) * 100.0) / float(m_data_len))
        Logger.log_more_verbose("Making '%s' test." % (l_wordlist))
        i += 1

        # Analyze for each wordlist
        #
        # Store the server banner
        try:
            m_banners_counter[l_response.headers["Server"]] += l_weight
        except KeyError:
            pass

        #
        # =====================
        # HTTP directly related
        # =====================
        #
        #
        for l_http_header_name, l_header_wordlist in m_wordlists_HTTP_fields.iteritems():

            # Check if HTTP header field is in response
            if l_http_header_name not in l_response.headers:
                continue

            l_curr_header_value = l_response.headers[l_http_header_name]

            # Generate concrete wordlist name
            l_wordlist_path     = Config.plugin_extra_config[l_wordlist][l_header_wordlist]

            # Load words for the wordlist
            l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(l_wordlist_path)
            # Looking for matches
            l_matches           = l_wordlist_instance.matches_by_value(l_curr_header_value)

            m_counters.inc(l_matches, l_action, l_weight, l_http_header_name, message="HTTP field: " + l_curr_header_value)

        #
        # =======================
        # HTTP INdirectly related
        # =======================
        #
        #

        #
        # Status code
        # ===========
        #
        l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["statuscode"])
        # Looking for matches
        l_matches           = l_wordlist_instance.matches_by_value(l_response.status)

        m_counters.inc(l_matches, l_action, l_weight, "statuscode", message="Status code: " + l_response.status)


        #
        # Status text
        # ===========
        #
        l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["statustext"])
        # Looking for matches
        l_matches           = l_wordlist_instance.matches_by_value(l_response.reason)

        m_counters.inc(l_matches, l_action, l_weight, "statustext", message="Status text: " + l_response.reason)


        #
        # Header space
        # ============
        #
        # Count the number of spaces between HTTP field name and their value, for example:
        # -> Server: Apache 1
        # The number of spaces are: 1
        #
        # -> Server:Apache 1
        # The number of spaces are: 0
        #
        l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["header-space"])
        # Looking for matches
        try:
            l_http_value        = l_response.headers[0] # get the value of first HTTP field
            l_spaces_num        = str(abs(len(l_http_value) - len(l_http_value.lstrip())))
            l_matches           = l_wordlist_instance.matches_by_value(l_spaces_num)

            m_counters.inc(l_matches, l_action, l_weight, "header-space", message="Header space: " + l_spaces_num)

        except IndexError:
            print "index error header space"
            pass


        #
        # Header capitalafterdash
        # =======================
        #
        # Look for non capitalized first letter of field name, for example:
        # -> Content-type: ....
        # Instead of:
        # -> Content-Type: ....
        #
        l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["header-capitalafterdash"])
        # Looking for matches
        l_valid_fields     = [x for x in l_response.headers.iterkeys() if "-" in x]

        if l_valid_fields:

            l_h = l_valid_fields[0]

            l_value = l_h.split("-")[1] # Get the second value: Content-type => type
            l_dush  = None

            if l_value[0].isupper(): # Check first letter is lower
                l_dush = 1
            else:
                l_dush = 0

            l_matches           = l_wordlist_instance.matches_by_value(l_dush)
            m_counters.inc(l_matches, l_action, l_weight, "header-capitalizedafterdush", message="Capital after dash: %s" % str(l_dush))

        #
        # Header order
        # ============
        #
        l_header_order  = ','.join(l_response.headers.iterkeys())

        l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["header-order"])
        l_matches           = l_wordlist_instance.matches_by_value(l_header_order)

        m_counters.inc(l_matches, l_action, l_weight, "header-order", message="Header order: " + l_header_order)


        #
        # Protocol name
        # ============
        #
        # For a response like:
        # -> HTTP/1.0 200 OK
        #    ....
        #
        # Get the 'HTTP' value.
        #
        try:
            l_proto             = l_response.protocol # Get the 'HTTP' text from response, if available
            if l_proto:
                l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["protocol-name"])
                l_matches           = l_wordlist_instance.matches_by_value(l_proto)

                m_counters.inc(l_matches, l_action, l_weight, "proto-name", message="Proto name: " + l_proto)

        except IndexError:
            print "index error protocol name"
            pass


        #
        # Protocol version
        # ================
        #
        # For a response like:
        # -> HTTP/1.0 200 OK
        #    ....
        #
        # Get the '1.0' value.
        #
        try:
            l_version           = l_response.version # Get the '1.0' text from response, if available
            if l_version:
                l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["protocol-version"])
                l_matches           = l_wordlist_instance.matches_by_value(l_version)

                m_counters.inc(l_matches, l_action, l_weight, "proto-version", message="Proto version: " + l_version)

        except IndexError:
            print "index error protocol version"
            pass



        if "ETag" in l_response.headers:
            l_etag_header       = l_response.headers["ETag"]
            #
            # ETag length
            # ================
            #
            l_etag_len          = len(l_etag_header)
            l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["etag-legth"])
            l_matches           = l_wordlist_instance.matches_by_value(l_etag_len)

            m_counters.inc(l_matches, l_action, l_weight, "etag-length", message="ETag length: " + str(l_etag_len))


            #
            # ETag Quotes
            # ================
            #
            l_etag_striped          = l_etag_header.strip()
            if l_etag_striped.startswith("\"") or l_etag_striped.startswith("'"):
                l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["etag-quotes"])
                l_matches           = l_wordlist_instance.matches_by_value(l_etag_striped[0])

                m_counters.inc(l_matches, l_action, l_weight, "etag-quotes", message="Etag quotes: " + l_etag_striped[0])

        if "Vary" in l_response.headers:
            l_vary_header       = l_response.headers["Vary"]
            #
            # Vary delimiter
            # ================
            #
            # Checks if Vary header delimiter is something like this:
            # -> Vary: Accept-Encoding,User-Agent
            # Or this:
            # -> Vary: Accept-Encoding, User-Agent
            #
            l_var_delimiter     = ", " if l_vary_header.find(", ") else ","
            l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["vary-delimiter"])
            l_matches           = l_wordlist_instance.matches_by_value(l_var_delimiter)

            m_counters.inc(l_matches, l_action, l_weight, "vary-delimiter", message="Vary delimiter: " + l_var_delimiter)

            #
            # Vary capitalizer
            # ================
            #
            # Checks if Vary header delimiter is something like this:
            # -> Vary: Accept-Encoding,user-Agent
            # Or this:
            # -> Vary: accept-encoding,user-agent
            #
            l_vary_capitalizer  = str(0 if l_vary_header == l_vary_header.lower() else 1)
            l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["vary-capitalize"])
            l_matches           = l_wordlist_instance.matches_by_value(l_vary_capitalizer)

            m_counters.inc(l_matches, l_action, l_weight, "vary-capitalize", message="Vary capitalizer: " + l_vary_capitalizer)


            #
            # Vary order
            # ================
            #
            # Checks order between vary values:
            # -> Vary: Accept-Encoding,user-Agent
            # Or this:
            # -> Vary: User-Agent,Accept-Encoding
            #
            l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["vary-order"])
            l_matches           = l_wordlist_instance.matches_by_value(l_vary_header)

            m_counters.inc(l_matches, l_action, l_weight, "vary-order", message="Vary order: " + l_vary_header)


        #
        # =====================
        # HTTP specific options
        # =====================
        #
        #
        if l_action == "HEAD":
            #
            # HEAD Options
            # ============
            #
            l_option            = l_response.headers.get("Allow")
            if l_option:
                l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["options-public"])
                # Looking for matches
                l_matches           = l_wordlist_instance.matches_by_value(l_option)

                m_counters.inc(l_matches, l_action, l_weight, "options-allow", message="HEAD option: " + l_option)


        if l_action == "OPTIONS" or l_action == "INVALID" or l_action == "DELETE":
            if "Allow" in l_response.headers:
                #
                # Options allow
                # =============
                #
                l_option            = l_response.headers.get("Allow")
                if l_option:
                    l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["options-public"])
                    # Looking for matches
                    l_matches           = l_wordlist_instance.matches_by_value(l_option)

                    m_counters.inc(l_matches, l_action, l_weight, "options-allow", message="OPTIONS allow: "  + l_action + " # " + l_option)


                #
                # Allow delimiter
                # ===============
                #
                l_option            = l_response.headers.get("Allow")
                if l_option:
                    l_var_delimiter     = ", " if l_option.find(", ") else ","
                    l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["options-delimited"])
                    # Looking for matches
                    l_matches           = l_wordlist_instance.matches_by_value(l_var_delimiter)

                    m_counters.inc(l_matches, l_action, l_weight, "options-delimiter", message="OPTION allow delimiter " + l_action + " # " + l_option)


            if "Public" in l_response.headers:
                #
                # Public response
                # ===============
                #
                l_option            = l_response.headers.get("Public")
                if l_option:
                    l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(Config.plugin_extra_config[l_wordlist]["options-public"])
                    # Looking for matches
                    l_matches           = l_wordlist_instance.matches_by_value(l_option)

                    m_counters.inc(l_matches, l_action, l_weight, "options-public", message="Public response: " + l_action + " # " + l_option)
コード例 #6
0
def http_analyzers(main_url, update_status_func, number_of_entries=4):
    """
    Analyze HTTP headers for detect the web server. Return a list with most possible web servers.

    :param main_url: Base url to test.
    :type main_url: str

    :param update_status_func: function used to update the status of the process
    :type update_status_func: function

    :param number_of_entries: number of resutls tu return for most probable web servers detected.
    :type number_of_entries: int

    :return: Web server family, Web server version, Web server complete description, related web servers (as a dict('SERVER_RELATED' : set(RELATED_NAMES))), others web server with their probabilities as a dict(CONCRETE_WEB_SERVER, PROBABILITY)
    """

    # Load wordlist directly related with a HTTP fields.
    # { HTTP_HEADER_FIELD : [wordlists] }
    m_wordlists_HTTP_fields = {
        "Accept-Ranges": "accept-range",
        "Server": "banner",
        "Cache-Control": "cache-control",
        "Connection": "connection",
        "Content-Type": "content-type",
        "WWW-Authenticate": "htaccess-realm",
        "Pragma": "pragma",
        "X-Powered-By": "x-powered-by"
    }

    m_actions = {
        'GET': {
            'wordlist': 'Wordlist_get',
            'weight': 1,
            'protocol': 'HTTP/1.1',
            'method': 'GET',
            'payload': '/'
        },
        'LONG_GET': {
            'wordlist': 'Wordlist_get_long',
            'weight': 1,
            'protocol': 'HTTP/1.1',
            'method': 'GET',
            'payload': '/%s' % ('a' * 200)
        },
        'NOT_FOUND': {
            'wordlist': 'Wordlist_get_notfound',
            'weight': 2,
            'protocol': 'HTTP/1.1',
            'method': 'GET',
            'payload': '/404_NOFOUND__X02KAS'
        },
        'HEAD': {
            'wordlist': 'Wordlist_head',
            'weight': 3,
            'protocol': 'HTTP/1.1',
            'method': 'HEAD',
            'payload': '/'
        },
        'OPTIONS': {
            'wordlist': 'Wordlist_options',
            'weight': 2,
            'protocol': 'HTTP/1.1',
            'method': 'OPTIONS',
            'payload': '/'
        },
        'DELETE': {
            'wordlist': 'Wordlist_delete',
            'weight': 5,
            'protocol': 'HTTP/1.1',
            'method': 'DELETE',
            'payload': '/'
        },
        'TEST': {
            'wordlist': 'Wordlist_attack',
            'weight': 5,
            'protocol': 'HTTP/1.1',
            'method': 'TEST',
            'payload': '/'
        },
        'INVALID': {
            'wordlist': 'Wordlist_wrong_method',
            'weight': 5,
            'protocol': 'HTTP/9.8',
            'method': 'GET',
            'payload': '/'
        },
        'ATTACK': {
            'wordlist':
            'Wordlist_wrong_version',
            'weight':
            2,
            'protocol':
            'HTTP/1.1',
            'method':
            'GET',
            'payload':
            "/etc/passwd?format=%%%%&xss=\x22><script>alert('xss');</script>&traversal=../../&sql='%20OR%201;"
        }
    }

    # Store results for others HTTP params
    m_d = ParsedURL(main_url)
    m_hostname = m_d.hostname
    m_port = m_d.port
    m_debug = False  # Only for develop

    # Counter of banners. Used when others methods fails.
    m_banners_counter = Counter()

    # Score counter
    m_counters = HTTPAnalyzer(debug=m_debug)

    # Var used to update the status
    m_data_len = len(m_actions)
    i = 1  # element in process

    for l_action, v in m_actions.iteritems():
        if m_debug:
            print "###########"
        l_method = v["method"]
        l_payload = v["payload"]
        l_proto = v["protocol"]
        l_wordlist = v["wordlist"]

        # Each type of probe hast different weight.
        #
        # Weights go from 0 - 5
        #
        l_weight = v["weight"]

        # Make the URL
        l_url = urljoin(main_url, l_payload)

        # Make the raw request
        #l_raw_request = "%(method)s %(payload)s %(protocol)s\r\nHost: %(host)s:%(port)s\r\nConnection: Close\r\n\r\n" % (
        l_raw_request = "%(method)s %(payload)s %(protocol)s\r\nHost: %(host)s\r\n\r\n" % (
            {
                "method": l_method,
                "payload": l_payload,
                "protocol": l_proto,
                "host": m_hostname,
                "port": m_port
            })
        if m_debug:
            print "REQUEST"
            print l_raw_request

        # Do the connection
        l_response = None
        try:
            m_raw_request = HTTP_Raw_Request(l_raw_request)
            discard_data(m_raw_request)
            l_response = HTTP.make_raw_request(host=m_hostname,
                                               port=m_port,
                                               raw_request=m_raw_request,
                                               callback=check_raw_response)
            if l_response:
                discard_data(l_response)
        except NetworkException, e:
            Logger.log_error_more_verbose(
                "Server-Fingerprint plugin: No response for URL (%s) '%s'. Message: %s"
                % (l_method, l_url, str(e)))
            continue

        if not l_response:
            Logger.log_error_more_verbose("No response for URL '%s'." % l_url)
            continue

        if m_debug:
            print "RESPONSE"
            print l_response.raw_headers

        # Update the status
        update_status_func((float(i) * 100.0) / float(m_data_len))
        Logger.log_more_verbose("Making '%s' test." % (l_wordlist))
        i += 1

        # Analyze for each wordlist
        #

        # Store the server banner
        try:
            m_banners_counter[l_response.headers["Server"]] += l_weight
        except KeyError:
            pass

        #
        # =====================
        # HTTP directly related
        # =====================
        #
        #
        for l_http_header_name, l_header_wordlist in m_wordlists_HTTP_fields.iteritems(
        ):

            # Check if HTTP header field is in response
            if l_http_header_name not in l_response.headers:
                continue

            l_curr_header_value = l_response.headers[l_http_header_name]

            # Generate concrete wordlist name
            l_wordlist_path = Config.plugin_extra_config[l_wordlist][
                l_header_wordlist]

            # Load words for the wordlist
            l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
                l_wordlist_path)
            # Looking for matches
            l_matches = l_wordlist_instance.matches_by_value(
                l_curr_header_value)

            m_counters.inc(l_matches,
                           l_action,
                           l_weight,
                           l_http_header_name,
                           message="HTTP field: " + l_curr_header_value)

        #
        # =======================
        # HTTP INdirectly related
        # =======================
        #
        #

        #
        # Status code
        # ===========
        #
        l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
            Config.plugin_extra_config[l_wordlist]["statuscode"])
        # Looking for matches
        l_matches = l_wordlist_instance.matches_by_value(l_response.status)

        m_counters.inc(l_matches,
                       l_action,
                       l_weight,
                       "statuscode",
                       message="Status code: " + l_response.status)

        #
        # Status text
        # ===========
        #
        l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
            Config.plugin_extra_config[l_wordlist]["statustext"])
        # Looking for matches
        l_matches = l_wordlist_instance.matches_by_value(l_response.reason)

        m_counters.inc(l_matches,
                       l_action,
                       l_weight,
                       "statustext",
                       message="Status text: " + l_response.reason)

        #
        # Header space
        # ============
        #
        # Count the number of spaces between HTTP field name and their value, for example:
        # -> Server: Apache 1
        # The number of spaces are: 1
        #
        # -> Server:Apache 1
        # The number of spaces are: 0
        #
        l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
            Config.plugin_extra_config[l_wordlist]["header-space"])
        # Looking for matches
        try:
            l_http_value = l_response.headers[
                0]  # get the value of first HTTP field
            l_spaces_num = str(
                abs(len(l_http_value) - len(l_http_value.lstrip())))
            l_matches = l_wordlist_instance.matches_by_value(l_spaces_num)

            m_counters.inc(l_matches,
                           l_action,
                           l_weight,
                           "header-space",
                           message="Header space: " + l_spaces_num)

        except IndexError:
            print "index error header space"
            pass

        #
        # Header capitalafterdash
        # =======================
        #
        # Look for non capitalized first letter of field name, for example:
        # -> Content-type: ....
        # Instead of:
        # -> Content-Type: ....
        #
        l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
            Config.plugin_extra_config[l_wordlist]["header-capitalafterdash"])
        # Looking for matches
        l_valid_fields = [x for x in l_response.headers.iterkeys() if "-" in x]

        if l_valid_fields:

            l_h = l_valid_fields[0]

            l_value = l_h.split("-")[
                1]  # Get the second value: Content-type => type
            l_dush = None

            if l_value[0].isupper():  # Check first letter is lower
                l_dush = 1
            else:
                l_dush = 0

            l_matches = l_wordlist_instance.matches_by_value(l_dush)
            m_counters.inc(l_matches,
                           l_action,
                           l_weight,
                           "header-capitalizedafterdush",
                           message="Capital after dash: %s" % str(l_dush))

        #
        # Header order
        # ============
        #
        l_header_order = ','.join(l_response.headers.iterkeys())

        l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
            Config.plugin_extra_config[l_wordlist]["header-order"])
        l_matches = l_wordlist_instance.matches_by_value(l_header_order)

        m_counters.inc(l_matches,
                       l_action,
                       l_weight,
                       "header-order",
                       message="Header order: " + l_header_order)

        #
        # Protocol name
        # ============
        #
        # For a response like:
        # -> HTTP/1.0 200 OK
        #    ....
        #
        # Get the 'HTTP' value.
        #
        try:
            l_proto = l_response.protocol  # Get the 'HTTP' text from response, if available
            if l_proto:
                l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
                    Config.plugin_extra_config[l_wordlist]["protocol-name"])
                l_matches = l_wordlist_instance.matches_by_value(l_proto)

                m_counters.inc(l_matches,
                               l_action,
                               l_weight,
                               "proto-name",
                               message="Proto name: " + l_proto)

        except IndexError:
            print "index error protocol name"
            pass

        #
        # Protocol version
        # ================
        #
        # For a response like:
        # -> HTTP/1.0 200 OK
        #    ....
        #
        # Get the '1.0' value.
        #
        try:
            l_version = l_response.version  # Get the '1.0' text from response, if available
            if l_version:
                l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
                    Config.plugin_extra_config[l_wordlist]["protocol-version"])
                l_matches = l_wordlist_instance.matches_by_value(l_version)

                m_counters.inc(l_matches,
                               l_action,
                               l_weight,
                               "proto-version",
                               message="Proto version: " + l_version)

        except IndexError:
            print "index error protocol version"
            pass

        if "ETag" in l_response.headers:
            l_etag_header = l_response.headers["ETag"]
            #
            # ETag length
            # ================
            #
            l_etag_len = len(l_etag_header)
            l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
                Config.plugin_extra_config[l_wordlist]["etag-legth"])
            l_matches = l_wordlist_instance.matches_by_value(l_etag_len)

            m_counters.inc(l_matches,
                           l_action,
                           l_weight,
                           "etag-length",
                           message="ETag length: " + str(l_etag_len))

            #
            # ETag Quotes
            # ================
            #
            l_etag_striped = l_etag_header.strip()
            if l_etag_striped.startswith("\"") or l_etag_striped.startswith(
                    "'"):
                l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
                    Config.plugin_extra_config[l_wordlist]["etag-quotes"])
                l_matches = l_wordlist_instance.matches_by_value(
                    l_etag_striped[0])

                m_counters.inc(l_matches,
                               l_action,
                               l_weight,
                               "etag-quotes",
                               message="Etag quotes: " + l_etag_striped[0])

        if "Vary" in l_response.headers:
            l_vary_header = l_response.headers["Vary"]
            #
            # Vary delimiter
            # ================
            #
            # Checks if Vary header delimiter is something like this:
            # -> Vary: Accept-Encoding,User-Agent
            # Or this:
            # -> Vary: Accept-Encoding, User-Agent
            #
            l_var_delimiter = ", " if l_vary_header.find(", ") else ","
            l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
                Config.plugin_extra_config[l_wordlist]["vary-delimiter"])
            l_matches = l_wordlist_instance.matches_by_value(l_var_delimiter)

            m_counters.inc(l_matches,
                           l_action,
                           l_weight,
                           "vary-delimiter",
                           message="Vary delimiter: " + l_var_delimiter)

            #
            # Vary capitalizer
            # ================
            #
            # Checks if Vary header delimiter is something like this:
            # -> Vary: Accept-Encoding,user-Agent
            # Or this:
            # -> Vary: accept-encoding,user-agent
            #
            l_vary_capitalizer = str(0 if l_vary_header ==
                                     l_vary_header.lower() else 1)
            l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
                Config.plugin_extra_config[l_wordlist]["vary-capitalize"])
            l_matches = l_wordlist_instance.matches_by_value(
                l_vary_capitalizer)

            m_counters.inc(l_matches,
                           l_action,
                           l_weight,
                           "vary-capitalize",
                           message="Vary capitalizer: " + l_vary_capitalizer)

            #
            # Vary order
            # ================
            #
            # Checks order between vary values:
            # -> Vary: Accept-Encoding,user-Agent
            # Or this:
            # -> Vary: User-Agent,Accept-Encoding
            #
            l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
                Config.plugin_extra_config[l_wordlist]["vary-order"])
            l_matches = l_wordlist_instance.matches_by_value(l_vary_header)

            m_counters.inc(l_matches,
                           l_action,
                           l_weight,
                           "vary-order",
                           message="Vary order: " + l_vary_header)

        #
        # =====================
        # HTTP specific options
        # =====================
        #
        #
        if l_action == "HEAD":
            #
            # HEAD Options
            # ============
            #
            l_option = l_response.headers.get("Allow")
            if l_option:
                l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
                    Config.plugin_extra_config[l_wordlist]["options-public"])
                # Looking for matches
                l_matches = l_wordlist_instance.matches_by_value(l_option)

                m_counters.inc(l_matches,
                               l_action,
                               l_weight,
                               "options-allow",
                               message="HEAD option: " + l_option)

        if l_action == "OPTIONS" or l_action == "INVALID" or l_action == "DELETE":
            if "Allow" in l_response.headers:
                #
                # Options allow
                # =============
                #
                l_option = l_response.headers.get("Allow")
                if l_option:
                    l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
                        Config.plugin_extra_config[l_wordlist]
                        ["options-public"])
                    # Looking for matches
                    l_matches = l_wordlist_instance.matches_by_value(l_option)

                    m_counters.inc(l_matches,
                                   l_action,
                                   l_weight,
                                   "options-allow",
                                   message="OPTIONS allow: " + l_action +
                                   " # " + l_option)

                #
                # Allow delimiter
                # ===============
                #
                l_option = l_response.headers.get("Allow")
                if l_option:
                    l_var_delimiter = ", " if l_option.find(", ") else ","
                    l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
                        Config.plugin_extra_config[l_wordlist]
                        ["options-delimited"])
                    # Looking for matches
                    l_matches = l_wordlist_instance.matches_by_value(
                        l_var_delimiter)

                    m_counters.inc(l_matches,
                                   l_action,
                                   l_weight,
                                   "options-delimiter",
                                   message="OPTION allow delimiter " +
                                   l_action + " # " + l_option)

            if "Public" in l_response.headers:
                #
                # Public response
                # ===============
                #
                l_option = l_response.headers.get("Public")
                if l_option:
                    l_wordlist_instance = WordListLoader.get_advanced_wordlist_as_dict(
                        Config.plugin_extra_config[l_wordlist]
                        ["options-public"])
                    # Looking for matches
                    l_matches = l_wordlist_instance.matches_by_value(l_option)

                    m_counters.inc(l_matches,
                                   l_action,
                                   l_weight,
                                   "options-public",
                                   message="Public response: " + l_action +
                                   " # " + l_option)