Class: Arachni::Element::Link

Inherits:
Base show all
Includes:
Capabilities::Refreshable
Defined in:
lib/arachni/element/link.rb

Constant Summary

Constants included from Capabilities::Auditable

Capabilities::Auditable::OPTIONS

Constants included from Capabilities::Auditable::RDiff

Capabilities::Auditable::RDiff::RDIFF_OPTIONS

Constants included from Capabilities::Auditable::Taint

Capabilities::Auditable::Taint::REMARK, Capabilities::Auditable::Taint::TAINT_OPTIONS

Constants included from Capabilities::Mutable

Capabilities::Mutable::MUTATION_OPTIONS

Instance Attribute Summary

Attributes inherited from Base

#raw

Attributes included from Capabilities::Auditable

#auditor, #opts, #orig

Attributes included from Capabilities::Mutable

#altered

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Capabilities::Refreshable

#refresh

Methods inherited from Base

#action, #dup, #method, #method=, #platforms, #url, #url=

Methods included from Utilities

#available_port, #cookie_encode, #cookies_from_document, #cookies_from_file, #cookies_from_response, #exception_jail, #exclude_path?, #extract_domain, #follow_protocol?, #form_decode, #form_encode, #form_parse_request_body, #forms_from_document, #forms_from_response, #generate_token, #get_path, #html_decode, #html_encode, #include_path?, #links_from_document, #links_from_response, #normalize_url, #page_from_response, #page_from_url, #parse_query, #parse_set_cookie, #parse_url_vars, #path_in_domain?, #path_too_deep?, #port_available?, #rand_port, #redundant_path?, #remove_constants, #seed, #skip_page?, #skip_path?, #skip_resource?, #to_absolute, #uri_decode, #uri_encode, #uri_parse, #uri_parser, #url_sanitize

Methods included from Capabilities::Auditable

#==, #[], #[]=, #audit, #auditable, #auditable=, #changes, #debug?, #has_inputs?, #hash, #http, #matches_skip_like_blocks?, #orphan?, #override_instance_scope, #override_instance_scope?, #print_bad, #print_debug, #print_debug_backtrace, #print_error, #print_error_backtrace, #print_info, #print_line, #print_ok, #print_status, #provisioned_issue_id, #remove_auditor, #reset, reset, reset_instance_scope, #reset_scope_override, restrict_to_elements, #scope_audit_id, #skip?, skip_like, #status_string, #submit, #update, #use_anonymous_auditor

Methods included from Capabilities::Auditable::RDiff

#rdiff_analysis

Methods included from Capabilities::Auditable::Timeout

add_timeout_candidate, add_timeout_phase3_candidate, #call_on_timing_blocks, call_on_timing_blocks, current_timeout_audit_operations_cnt, deduplicate?, #deduplicate?, #disable_deduplication, disable_deduplication, enable_deduplication, #enable_deduplication, included, on_timing_attacks, reset, #responsive?, running_timeout_attacks?, #timeout_analysis, timeout_analysis_phase_2, timeout_analysis_phase_3, timeout_audit_operations_cnt, timeout_audit_run, timeout_candidates, timeout_loaded_modules

Methods included from Capabilities::Auditable::Taint

#taint_analysis

Methods included from Capabilities::Mutable

#altered_value, #altered_value=, #each_mutation, #immutables, #mutated?, #mutations, #mutations_for, #original?, #permutations, #permutations_for, #switch_method

Constructor Details

#initialize(url, raw = {}) ⇒ Link

Creates a new Link element from a URL or more complex data.

Parameters:

  • url (String)

    Owner URL – URL of the page which contains the link.

  • raw (String, Hash) (defaults to: {})

    If empty, the owner URL will be treated as the actionable URL and Capabilities::Auditable#auditable inputs will be extracted from its query component.

    If a String is passed, it will be treated as the actionable URL and auditable inputs will be extracted from its query component.

    If a ‘Hash` is passed, it will look for an actionable URL `String` in the following keys:

    • ‘’href’‘

    • ‘:href`

    • ‘’action’‘

    • ‘:action`

    and for an Capabilities::Auditable#auditable inputs ‘Hash` in:

    • ‘’vars’‘

    • ‘:vars`

    • ‘’inputs’‘

    • ‘:inputs`

    these should contain inputs in ‘name => value` pairs.

    If the ‘Hash` doesn’t contain any of the following keys, its contents will be used as Capabilities::Auditable#auditable inputs instead and ‘url` will be used as the actionable URL.

    If no inputs have been provided it will try to extract some from the actionable URL, if empty inputs (empty ‘Hash`) have been provided the URL will not be parsed and the Link will instead be configured without any auditable inputs/vectors.



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/arachni/element/link.rb', line 65

def initialize( url, raw = {} )
    super( url, raw )

    if !@raw || @raw.empty?
        self.action = self.url
    elsif raw.is_a?( String )
        self.action = @raw
    elsif raw.is_a?( Hash )
        keys = raw.keys
        has_input_hash  = (keys & ['vars', :vars, 'inputs', :inputs]).any?
        has_action_hash = (keys & ['href', :href, 'action', :action]).any?

        if !has_input_hash && !has_action_hash
            self.auditable = @raw
        else
            self.auditable = @raw['vars'] || @raw[:vars] || @raw['inputs'] || @raw[:inputs]
        end
        self.action = @raw['href'] || @raw[:href] || @raw['action'] || @raw[:action]
    end

    self.auditable = self.class.parse_query_vars( self.action ) if !self.auditable || self.auditable.empty?

    if @raw.is_a?( String )
        @raw = {
            action: self.action,
            inputs: self.auditable
        }
    end

    self.method = 'get'

    @orig = self.auditable.dup
    @orig.freeze
end

Class Method Details

.decode(str) ⇒ Object



135
136
137
# File 'lib/arachni/element/link.rb', line 135

def self.decode( str )
    URI.decode( str )
end

.encode(str) ⇒ Object



131
132
133
# File 'lib/arachni/element/link.rb', line 131

def self.encode( str )
    URI.encode( str )
end

.from_document(url, document) ⇒ Array<Link>

Extracts links from a document.

Parameters:

  • url (String)

    URL of the document – used for path normalization purposes.

  • document (String, Nokogiri::HTML::Document)

Returns:



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/arachni/element/link.rb', line 160

def self.from_document( url, document )
    document = Nokogiri::HTML( document.to_s ) if !document.is_a?( Nokogiri::HTML::Document )
    base_url =  begin
        document.search( '//base[@href]' )[0]['href']
    rescue
        url
    end

    document.search( '//a' ).map do |link|
        c_link = {}
        c_link['href'] = to_absolute( link['href'], base_url )
        next if !c_link['href']

        new( url, c_link['href'] )
    end.compact
end

.from_response(response) ⇒ Array<Link>

Extracts links from an HTTP response.

Parameters:

Returns:



146
147
148
149
# File 'lib/arachni/element/link.rb', line 146

def self.from_response( response )
    url = response.effective_url
    [new( url, parse_query_vars( url ) )] | from_document( url, response.body )
end

.parse_query_vars(url) ⇒ Hash

Extracts inputs from a URL query.

Parameters:

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/arachni/element/link.rb', line 184

def self.parse_query_vars( url )
    return {} if !url

    parsed = uri_parse( url )
    return {} if !parsed

    query = parsed.query
    return {} if !query || query.empty?

    query.to_s.split( '&' ).inject( {} ) do |h, pair|
        name, value = pair.split( '=', 2 )
        h[name.to_s] = value.to_s
        h
    end
end

Instance Method Details

#action=(url) ⇒ Object

See Also:



201
202
203
204
205
# File 'lib/arachni/element/link.rb', line 201

def action=( url )
    v = super( url )
    @audit_id_url = self.action.split( '?' ).first.to_s.split( ';' ).first
    v
end

#audit_id(injection_str = '', opts = {}) ⇒ Object



207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/arachni/element/link.rb', line 207

def audit_id( injection_str = '', opts = {} )
    vars = auditable.keys.compact.sort.to_s

    str = ''
    str << "#{@auditor.fancy_name}:" if !opts[:no_auditor] && !orphan?

    str << "#{@audit_id_url}:" + "#{self.type}:#{vars}"
    str << "=#{injection_str.to_s}" if !opts[:no_injection_str]
    str << ":timeout=#{opts[:timeout]}" if !opts[:no_timeout]

    str
end

#idString

Returns Unique link ID.

Returns:

  • (String)

    Unique link ID.



107
108
109
110
# File 'lib/arachni/element/link.rb', line 107

def id
    query_vars = self.class.parse_query_vars( self.action )
    "#{@audit_id_url}::#{self.method}::#{query_vars.merge( self.auditable ).keys.compact.sort.to_s}"
end

#id_from(type = :auditable) ⇒ Object



112
113
114
115
# File 'lib/arachni/element/link.rb', line 112

def id_from( type = :auditable )
    query_vars = self.class.parse_query_vars( self.action )
    "#{@audit_id_url}::#{self.method}::#{query_vars.merge( self.send( type ) ).keys.compact.sort.to_s}"
end

#simpleHash

Returns Simple representation of self in the form of ‘{ Base#action => Capabilities::Auditable#auditable }`.

Returns:



102
103
104
# File 'lib/arachni/element/link.rb', line 102

def simple
    { self.action => self.auditable }
end

#to_sString

Returns Absolute URL with a merged version of Base#action and Capabilities::Auditable#auditable as a query.

Returns:



119
120
121
122
123
124
# File 'lib/arachni/element/link.rb', line 119

def to_s
    query_vars = self.class.parse_query_vars( self.action )
    uri = uri_parse( self.action )
    uri.query = query_vars.merge( self.auditable ).map { |k, v| "#{k}=#{v}" }.join( '&' )
    uri.to_s
end

#typeString

Returns ‘link’.

Returns:



127
128
129
# File 'lib/arachni/element/link.rb', line 127

def type
    Arachni::Element::LINK
end