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::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=, #url, #url=

Methods included from Utilities

#cookie_encode, #cookies_from_document, #cookies_from_file, #cookies_from_response, #exception_jail, #exclude_path?, #extract_domain, #form_decode, #form_encode, #form_parse_request_body, #forms_from_document, #forms_from_response, #get_path, #hash_keys_to_str, #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?, #remove_constants, #seed, #skip_path?, #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, #info, #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_path?, #status_string, #submit, #update

Methods included from Capabilities::Auditable::RDiff

included, #rdiff_analysis

Methods included from Capabilities::Auditable::Timeout

add_timeout_audit_block, add_timeout_candidate, #call_on_timing_blocks, call_on_timing_blocks, current_timeout_audit_operations_cnt, included, on_timing_attacks, #responsive?, running_timeout_attacks?, #timeout_analysis, timeout_analysis_phase_2, timeout_audit_blocks, timeout_audit_operations_cnt, timeout_audit_run, timeout_loaded_modules

Methods included from Capabilities::Auditable::Taint

#taint_analysis

Methods included from Capabilities::Mutable

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

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 contained the

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

    If empty, the owner URL will be treated as the actionable URL and 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 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 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.



62
63
64
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
# File 'lib/arachni/element/link.rb', line 62

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



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

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

.encode(str) ⇒ Object



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

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

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

Returns an array of links from a document.

Parameters:

  • url (String)

    request URL

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

Returns:



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# 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']
        next if skip_path?( c_link['href'] )

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

.from_response(response) ⇒ Array<Link>

Returns an array of links based on HTTP response.

Parameters:

Returns:



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

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 variables and their values from a URL query.

Parameters:

Returns:

  • (Hash)

    name=>value pairs



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

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

    query = uri_parse( url ).query
    return {} if !query || query.empty?

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

Instance Method Details

#action=(url) ⇒ Object

See Also:



199
200
201
202
203
# File 'lib/arachni/element/link.rb', line 199

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



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

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:



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

def id
    #self.action + auditable.keys.reject { |name| name.include?( seed ) }.sort.to_s
    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



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

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:



98
99
100
# File 'lib/arachni/element/link.rb', line 98

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:



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

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:



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

def type
    Arachni::Element::LINK
end