Exemple #1
0
def test_url_parser():
    print "Testing URL parsing for all properties..."
    for case in simple:
        url = case['url']
        d = ParsedURL(url)
        for key, value in case.iteritems():
            try:
                assert getattr(d, key) == value
            except AssertionError:
                print "-" * 79
                print "Failed test case: %r" % url
                print "Attribute name: %r" % key
                print "Expected value: %r" % value
                print "Got instead:    %r" % getattr(d, key)
                print "-" * 79
                raise
Exemple #2
0
    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 {}
Exemple #3
0
def test_url_parser_custom():
    print "Testing URL modification and reparsing..."

    # Relative URLs.
    assert ParsedURL("/index.html", base_url="http://www.example.com"
                     ).url == "http://www.example.com/index.html"
    assert ParsedURL("index.html", base_url="http://www.example.com/folder/"
                     ).url == "http://www.example.com/folder/index.html"
    assert ParsedURL("index.html", base_url="http://www.example.com/folder"
                     ).url == "http://www.example.com/index.html"

    # Setters.
    d = ParsedURL("http://www.example.com")
    assert d.path == "/"
    d.path = "/index.html"
    assert d.url == "http://www.example.com/index.html"
    assert d.path == "/index.html"
    assert d.port == 80
    d.scheme = "https"
    assert d.url == "https://www.example.com/index.html"
    assert d.port == 443
    d.port = 8080
    assert d.port == 8080
    assert d.url == "https://www.example.com:8080/index.html"
    d.scheme = "http://"
    assert d.port == 8080
    assert d.url == "http://www.example.com:8080/index.html"
    d.port = None
    assert d.port == 80
    assert d.url == "http://www.example.com/index.html"
    d.path = "index.html"
    assert d.path == "/index.html"
    assert d.url == "http://www.example.com/index.html"
    d.host = "www.site.com"
    assert d.url == "http://www.site.com/index.html"
    d.netloc = "user:[email protected]"
    assert d.url == "http://*****:*****@www.site.com/index.html"
    assert d.username == "user"
    assert d.password == "pass"
    d.username = "******"
    assert d.url == "http://*****:*****@www.site.com/index.html"
    assert d.netloc == "someone:[email protected]"
    d.password = "******"
    assert d.url == "http://*****:*****@www.site.com/index.html"
    assert d.netloc == "someone:[email protected]"
    assert d.auth == "someone:secret"
    d.password = None
    assert d.url == "http://[email protected]/index.html"
    assert d.netloc == "*****@*****.**"
    assert d.auth == "someone"
    d.password = "******"
    assert d.url == "http://*****:*****@www.site.com/index.html"
    assert d.netloc == "someone:[email protected]"
    assert d.auth == "someone:secret"
    d.username = None
    assert d.url == "http://:[email protected]/index.html"
    assert d.netloc == ":[email protected]"
    assert d.auth == ":secret"
    d.auth = "test:key"
    assert d.url == "http://*****:*****@www.site.com/index.html"
    assert d.netloc == "test:[email protected]"
    assert d.username == "test"
    assert d.password == "key"
    d.auth = None
    assert d.url == "http://www.site.com/index.html"
    assert d.netloc == "www.site.com"
    assert d.username == ""
    assert d.password == ""
    d.fragment = "fragment"
    assert d.url == "http://www.site.com/index.html#fragment"
    assert d.fragment == "fragment"
    d.fragment = None
    assert d.url == "http://www.site.com/index.html"
    assert d.fragment == ""
    d.query = "key=value&param=data"
    assert d.url == "http://www.site.com/index.html?key=value&param=data"
    assert d.query_char == "?"
    assert d.query == "key=value&param=data"
    assert d.query_params == {"key": "value", "param": "data"}
    d.query_params["test"] = "me"
    assert d.url == "http://www.site.com/index.html?key=value&param=data&test=me"
    assert d.query == "key=value&param=data&test=me"
    assert d.query_params == {"key": "value", "param": "data", "test": "me"}
    d.query_params = {"some": "thing"}
    assert d.url == "http://www.site.com/index.html?some=thing"
    assert d.query == "some=thing"
    assert d.query_params == {"some": "thing"}
    d.query = "a=b&c"
    assert d.url == "http://www.site.com/index.html?a=b&c="
    assert d.query == "a=b&c="
    assert d.query_params == {"a": "b", "c": ""}
    d.query = "teststring".encode("rot13")
    assert d.url == "http://www.site.com/index.html?" + "teststring".encode(
        "rot13")
    assert d.query == "teststring".encode("rot13")
    assert d.query_params == {}
    d.query = "test string".encode("base64")[:-1]
    assert d.url == "http://www.site.com/index.html?" + "test string".encode(
        "base64")[:-1]
    assert d.query == "test string".encode("base64")[:-1]
    assert d.query_params == {}
    d.query = "test string".encode("base64")
    assert d.url == "http://www.site.com/index.html?" + "test string".encode(
        "base64")[:-1] + "%0A"
    assert d.query == "test string".encode("base64")[:-1] + "%0A"
    assert d.query_params == {"test string".encode("base64")[:-2]: "\n"}
    d.query = "test=me"
    d.query_char = "/"
    assert d.url == "http://www.site.com/index.html/test=me"
    assert d.query_char == "/"
    assert d.query == "test=me"
    assert d.query_params == {"test": "me"}
    d.fragment = "frag"
    assert d.url == "http://www.site.com/index.html/test=me#frag"

    # Methods.
    d.hostname = "this.is.a.subdomain.of.example.co.uk"
    assert ".".join(d.split_hostname()) == d.host
    assert d.split_hostname() == ("this.is.a.subdomain.of", "example", "co.uk")
    d.path = "/folder.with.extensions/file.pdf.exe"
    assert d.get_all_extensions(directory_allowed=False,
                                double_allowed=True) == [".pdf", ".exe"]
    assert d.get_all_extensions(
        directory_allowed=True,
        double_allowed=True) == [".with", ".extensions", ".pdf", ".exe"]
    assert d.get_all_extensions(directory_allowed=False,
                                double_allowed=False) == [".exe"]
    assert d.get_all_extensions(
        directory_allowed=True,
        double_allowed=False) == [".extensions", ".exe"]
    assert d.get_all_extensions(directory_allowed=False) == [".pdf", ".exe"]
    assert d.get_all_extensions(double_allowed=False) == [
        ".extensions", ".exe"
    ]
    assert d.get_all_extensions() == [".with", ".extensions", ".pdf", ".exe"]

    # Exceptions.
    last_url = d.url
    try:
        d.query_char = "*"
        assert False
    except ValueError:
        pass
    try:
        d.scheme = "fake://"
        assert False
    except ValueError:
        pass
    try:
        d.port = "fake"
        assert False
    except ValueError:
        pass
    try:
        d.port = -1
        assert False
    except ValueError:
        pass
    try:
        d.port = 80000
        assert False
    except ValueError:
        pass
    assert d.url == last_url

    # Warnings.
    with catch_warnings(record=True) as w:
        d.fragment = "#test"
        d.query = "?test=me"
    assert len(w) == 2
Exemple #4
0
def test_url_parser_custom():
    print "Testing URL modification and reparsing..."

    # Relative URLs.
    assert ParsedURL("/index.html", base_url="http://www.example.com").url == "http://www.example.com/index.html"
    assert ParsedURL("index.html", base_url="http://www.example.com/folder/").url == "http://www.example.com/folder/index.html"
    assert ParsedURL("index.html", base_url="http://www.example.com/folder").url == "http://www.example.com/index.html"

    # Setters.
    d = ParsedURL("http://www.example.com")
    assert d.path == "/"
    d.path = "/index.html"
    assert d.url == "http://www.example.com/index.html"
    assert d.path == "/index.html"
    assert d.port == 80
    d.scheme = "https"
    assert d.url == "https://www.example.com/index.html"
    assert d.port == 443
    d.port = 8080
    assert d.port == 8080
    assert d.url == "https://www.example.com:8080/index.html"
    d.scheme = "http://"
    assert d.port == 8080
    assert d.url == "http://www.example.com:8080/index.html"
    d.port = None
    assert d.port == 80
    assert d.url == "http://www.example.com/index.html"
    d.path = "index.html"
    assert d.path == "/index.html"
    assert d.url == "http://www.example.com/index.html"
    d.host = "www.site.com"
    assert d.url == "http://www.site.com/index.html"
    d.netloc = "user:[email protected]"
    assert d.url == "http://*****:*****@www.site.com/index.html"
    assert d.username == "user"
    assert d.password == "pass"
    d.username = "******"
    assert d.url == "http://*****:*****@www.site.com/index.html"
    assert d.netloc == "someone:[email protected]"
    d.password = "******"
    assert d.url == "http://*****:*****@www.site.com/index.html"
    assert d.netloc == "someone:[email protected]"
    assert d.auth == "someone:secret"
    d.password = None
    assert d.url == "http://[email protected]/index.html"
    assert d.netloc == "*****@*****.**"
    assert d.auth == "someone"
    d.password = "******"
    assert d.url == "http://*****:*****@www.site.com/index.html"
    assert d.netloc == "someone:[email protected]"
    assert d.auth == "someone:secret"
    d.username = None
    assert d.url == "http://:[email protected]/index.html"
    assert d.netloc == ":[email protected]"
    assert d.auth == ":secret"
    d.auth = "test:key"
    assert d.url == "http://*****:*****@www.site.com/index.html"
    assert d.netloc == "test:[email protected]"
    assert d.username == "test"
    assert d.password == "key"
    d.auth = None
    assert d.url == "http://www.site.com/index.html"
    assert d.netloc == "www.site.com"
    assert d.username == ""
    assert d.password == ""
    d.fragment = "fragment"
    assert d.url == "http://www.site.com/index.html#fragment"
    assert d.fragment == "fragment"
    d.fragment = None
    assert d.url == "http://www.site.com/index.html"
    assert d.fragment == ""
    d.query = "key=value&param=data"
    assert d.url == "http://www.site.com/index.html?key=value&param=data"
    assert d.query_char == "?"
    assert d.query == "key=value&param=data"
    assert d.query_params == { "key": "value", "param": "data" }
    d.query_params["test"] = "me"
    assert d.url == "http://www.site.com/index.html?key=value&param=data&test=me"
    assert d.query == "key=value&param=data&test=me"
    assert d.query_params == { "key": "value", "param": "data", "test": "me" }
    d.query_params = { "some": "thing" }
    assert d.url == "http://www.site.com/index.html?some=thing"
    assert d.query == "some=thing"
    assert d.query_params == { "some": "thing" }
    d.query = "a=b&c"
    assert d.url == "http://www.site.com/index.html?a=b&c="
    assert d.query == "a=b&c="
    assert d.query_params == { "a": "b", "c": "" }
    d.query = "teststring".encode("rot13")
    assert d.url == "http://www.site.com/index.html?" + "teststring".encode("rot13")
    assert d.query == "teststring".encode("rot13")
    assert d.query_params == {}
    d.query = "test string".encode("base64")[:-1]
    assert d.url == "http://www.site.com/index.html?" + "test string".encode("base64")[:-1]
    assert d.query == "test string".encode("base64")[:-1]
    assert d.query_params == {}
    d.query = "test string".encode("base64")
    assert d.url == "http://www.site.com/index.html?" + "test string".encode("base64")[:-1] + "%0A"
    assert d.query == "test string".encode("base64")[:-1] + "%0A"
    assert d.query_params == {"test string".encode("base64")[:-2]: "\n"}
    d.query = "test=me"
    d.query_char = "/"
    assert d.url == "http://www.site.com/index.html/test=me"
    assert d.query_char == "/"
    assert d.query == "test=me"
    assert d.query_params == { "test": "me" }
    d.fragment = "frag"
    assert d.url == "http://www.site.com/index.html/test=me#frag"

    # Methods.
    d.hostname = "this.is.a.subdomain.of.example.co.uk"
    assert ".".join(d.split_hostname()) == d.host
    assert d.split_hostname() == ("this.is.a.subdomain.of", "example", "co.uk")
    d.path = "/folder.with.extensions/file.pdf.exe"
    assert d.get_all_extensions(directory_allowed = False, double_allowed = True)  == [".pdf", ".exe"]
    assert d.get_all_extensions(directory_allowed = True,  double_allowed = True)  == [".with", ".extensions", ".pdf", ".exe"]
    assert d.get_all_extensions(directory_allowed = False, double_allowed = False) == [".exe"]
    assert d.get_all_extensions(directory_allowed = True,  double_allowed = False) == [".extensions", ".exe"]
    assert d.get_all_extensions(directory_allowed = False                        ) == [".pdf", ".exe"]
    assert d.get_all_extensions(                           double_allowed = False) == [".extensions", ".exe"]
    assert d.get_all_extensions(                                                 ) == [".with", ".extensions", ".pdf", ".exe"]

    # Exceptions.
    last_url = d.url
    try:
        d.query_char = "*"
        assert False
    except ValueError:
        pass
    try:
        d.scheme = "fake://"
        assert False
    except ValueError:
        pass
    try:
        d.port = "fake"
        assert False
    except ValueError:
        pass
    try:
        d.port = -1
        assert False
    except ValueError:
        pass
    try:
        d.port = 80000
        assert False
    except ValueError:
        pass
    assert d.url == last_url

    # Warnings.
    with catch_warnings(record=True) as w:
        d.fragment = "#test"
        d.query = "?test=me"
    assert len(w) == 2
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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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)
def http_simple_analyzer(main_url, update_status_func, number_of_entries=4):
    """Simple method to get fingerprint server info

    :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: a typle as format: 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)
    """

    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;"}
    }

    m_d                   = ParsedURL(main_url)
    m_hostname            = m_d.hostname
    m_port                = m_d.port
    m_scheme              = m_d.scheme
    m_debug               = False # Only for develop
    i                     = 0
    m_counters            = HTTPAnalyzer()
    m_data_len            = len(m_actions) # Var used to update the status
    m_banners_counter     = Counter()

    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 raw request
        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,
                proto       = m_scheme,
                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 host '%s:%d' with method '%s'. Message: %s" % (m_hostname, m_port, l_method, str(e)))
            continue

        if not l_response:
            Logger.log_error_more_verbose("No response for host '%s:%d' with method '%s'." % (m_hostname, m_port, l_method))
            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_method)
        i += 1

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

        l_server_name = None
        try:
            l_server_name = l_response.headers["Server"]
        except KeyError:
            continue

        m_counters.simple_inc(l_server_name, l_method, l_weight)