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

Returns a new instance of 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.

Parameters:

  • url (String)

    Resource to check.

  • silent (Bool) (defaults to: false)

    If false, a message will be printed to stdout containing the status of the operation.

  • block (Proc)

    Called if the file exists, just before logging the issue, and is passed the HTTP response.

Returns:

  • (Object)
    • false if an invalid URL was provided.
    • true if everything went fine.

See Also:


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.

Parameters:

  • url (String)

    Resource to check.

  • block (Block)

    Block to be passed true if the resource exists or false otherwise and the response for the resource check.

Returns:

  • (Object)
    • false if an invalid URL was provided.
    • true if everything went fine.

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