Class: Arachni::Element::Server

Inherits:
Base show all
Includes:
Capabilities::WithAuditor
Defined in:
lib/arachni/element/server.rb

Overview

Represents a remote server, mainly for checking for and logging remote resources.

Author:

Constant Summary collapse

SIMILARITY_TOLERANCE =

Valid responses to discovery checks should vary wildly, especially when considering the types of directories and files that these checks look for.

On the other hand, custom-404 or such responses will have many things in common which makes it possible to spot them without much bother.

Ideally, custom-404s will be identified properly by the HTTP::Client::Dynamic404Handler but this is here to save our ass in case there's a bug or an unforeseen edge-case or something.

Also, identified resources should be analyzed by the Trainer but there can be cases where unreliable custom-404 signatures lead to FPs and feeding FPs to the system can create an infinite loop.

0.25
REMARK =

Remark in case of an untrusted issue.

'This issue was logged by a discovery check but ' +
'the response for the resource it identified is very similar to responses ' +
'for other resources of similar type. This is a strong indication that ' +
'the logged issue is a false positive.'

Constants inherited from Base

Base::MAX_SIZE

Instance Attribute Summary

Attributes included from Capabilities::WithAuditor

#auditor

Attributes inherited from Base

#initialization_options, #page

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Capabilities::WithAuditor

#dup, #marshal_dump, #orphan?, #prepare_for_report, #remove_auditor

Methods inherited from Base

#==, #action, #dup, from_rpc_data, #hash, #id, #marshal_dump, #marshal_load, #persistent_hash, #prepare_for_report, #reset, #to_h, #to_hash, #to_rpc_data, too_big?, type, #type, #url, #url=

Methods included from Utilities

#available_port, available_port_mutex, #bytes_to_kilobytes, #bytes_to_megabytes, #caller_name, #caller_path, #cookie_decode, #cookie_encode, #cookies_from_file, #cookies_from_parser, #cookies_from_response, #exception_jail, #exclude_path?, #follow_protocol?, #form_decode, #form_encode, #forms_from_parser, #forms_from_response, #full_and_absolute_url?, #generate_token, #get_path, #hms_to_seconds, #html_decode, #html_encode, #include_path?, #links_from_parser, #links_from_response, #normalize_url, #page_from_response, #page_from_url, #parse_set_cookie, #path_in_domain?, #path_too_deep?, #port_available?, #rand_port, #random_seed, #redundant_path?, #regexp_array_match, #remove_constants, #request_parse_body, #seconds_to_hms, #skip_page?, #skip_path?, #skip_resource?, #skip_response?, #to_absolute, #uri_decode, #uri_encode, #uri_parse, #uri_parse_query, #uri_parser, #uri_rewrite

Methods included from Capabilities::WithScope

#scope

Constructor Details

#initialize(url) ⇒ Server



40
41
42
43
44
45
46
47
48
49
50
# File 'lib/arachni/element/server.rb', line 40

def initialize( url )
    super url: url
    @initialization_options = url

    # Holds possible issue responses, they'll be logged after #analyze
    # goes over them.
    @candidates = []

    # Process responses that may point to issues.
    http.after_run( &method(:analyze) )
end

Class Method Details

.flag_issues_as_untrusted(issue_digests) ⇒ Object



140
141
142
143
144
145
146
147
# File 'lib/arachni/element/server.rb', line 140

def self.flag_issues_as_untrusted( issue_digests )
    issue_digests.uniq.each do |digest|
        next if !(issue = Arachni::Data.issues[digest])

        issue.add_remark :meta_analysis, REMARK
        issue.trusted = false
    end
end

.flag_issues_if_untrusted(similarity, issue_digests) ⇒ Object



149
150
151
152
153
# File 'lib/arachni/element/server.rb', line 149

def self.flag_issues_if_untrusted( similarity, issue_digests )
    return if similarity < SIMILARITY_TOLERANCE

    flag_issues_as_untrusted( issue_digests )
end

Instance Method Details

#httpObject



125
126
127
# File 'lib/arachni/element/server.rb', line 125

def http
    Arachni::HTTP::Client
end

#inspectObject



129
130
131
132
133
134
135
136
137
138
# File 'lib/arachni/element/server.rb', line 129

def inspect
    s = "#<#{self.class} "

    if !orphan?
        s << "auditor=#{auditor.class} "
    end

    s << "url=#{url.inspect}"
    s << '>'
end

#log_remote_file_if_exists(url, silent = false, options = {}, &block) ⇒ Object Also known as: log_remote_directory_if_exists

Note:

Ignores custom 404 responses.

Logs a remote file or directory if it exists.



70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/arachni/element/server.rb', line 70

def log_remote_file_if_exists( url, silent = false, options = {}, &block )
    # Make sure the URL is valid.
    return false if !(url.start_with?( 'http://' ) || url.start_with?( 'https://' ))

    auditor.print_status( "Checking for #{url}" ) if !silent
    remote_file_exist?( url ) do |bool, response|
        auditor.print_status( "Analyzing response for: #{url}" ) if !silent
        next if !bool

        @candidates << [response, block, options]
    end
end

#remote_file_exist?(url, &block) ⇒ Object Also known as: remote_file_exists?

Note:

Ignores custom 404 responses.

Checks whether or not a remote resource exists.



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/arachni/element/server.rb', line 97

def remote_file_exist?( url, &block )
    # Make sure the URL is valid.
    return false if !(url.start_with?( 'http://' ) || url.start_with?( 'https://' ))

    if http.dynamic_404_handler.needs_check?( url )

        # Don't enable fingerprinting if there's a dynamic handler, we don't
        # want to keep analyzing non existent resources.
        #
        # If a resource does exist though it will be fingerprinted down the
        # line.
        http.get( url, performer: self, fingerprint: false, follow_location: true ) do |r|
            if r.code == 200
                http.dynamic_404_handler._404?( r ) { |bool| block.call( !bool, r ) }
            else
                block.call( false, r )
            end
        end
    else
        http.request( url, method: :head, performer: self, follow_location: true ) do |response|
            block.call( response.code == 200, response )
        end
    end

    true
end