Module: Arachni::Element::Capabilities::Auditable

Includes:
Inputtable, Mutable, Submittable, WithAuditor, Utilities
Included in:
Analyzable, DOM
Defined in:
lib/arachni/element/capabilities/auditable.rb,
lib/arachni/element/capabilities/auditable/dom.rb

Overview

Provides inputs, HTTP submission and audit functionality to Mutable elements.

Author:

Defined Under Namespace

Modules: DOM

Constant Summary collapse

OPTIONS =

Default audit options.

{
    # Optionally enable skipping of already audited inputs, disabled by default.
    redundant:     false,

    # Block to be passed each mutation right before being submitted.
    # Allows for last minute changes.
    each_mutation: nil,

    # Block to be passed each mutation to determine if it should be skipped.
    skip_like:     nil
}

Constants included from Mutable

Mutable::MUTATION_OPTIONS

Instance Attribute Summary collapse

Attributes included from WithAuditor

#auditor

Attributes included from Mutable

#affected_input_name, #format, #seed

Attributes included from Inputtable

#default_inputs, #inputs

Class Method Summary collapse

Instance Method Summary collapse

Methods included from WithAuditor

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

Methods included from Mutable

#affected_input_value, #affected_input_value=, #each_mutation, #immutables, #mutation?, #mutations, #switch_method, #to_h

Methods included from Submittable

#action, #action=, #http, #http_request, #id, #method, #method=, #platforms, #submit, #to_h

Methods included from Inputtable

#[], #[]=, #changes, #has_inputs?, #inputtable_id, #to_h, #try_input, #update, #valid_input_data?, #valid_input_name?, #valid_input_name_data?, #valid_input_value?, #valid_input_value_data?

Methods included from Utilities

#available_port, #caller_name, #caller_path, #cookie_decode, #cookie_encode, #cookies_from_document, #cookies_from_file, #cookies_from_response, #exception_jail, #exclude_path?, #follow_protocol?, #form_decode, #form_encode, #forms_from_document, #forms_from_response, #generate_token, #get_path, #hms_to_seconds, #html_decode, #html_encode, #include_path?, #links_from_document, #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?, #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

Instance Attribute Details

#audit_optionsHash

Returns Audit and general options for convenience’s sake.

Returns:

  • (Hash)

    Audit and general options for convenience’s sake.



33
34
35
# File 'lib/arachni/element/capabilities/auditable.rb', line 33

def audit_options
  @audit_options
end

Class Method Details

.resetObject

Empties the de-duplication/uniqueness look-up table.

Unless you’re sure you need this, set the :redundant flag to true when calling audit methods to bypass it.



52
53
54
55
# File 'lib/arachni/element/capabilities/auditable.rb', line 52

def Auditable.reset
    State.audit.clear
    @@skip_like_blocks = []
end

.skip_like(&block) ⇒ Auditable

Returns ‘self`.

Parameters:

  • block (Block)

    Block to decide whether an element should be skipped or not.

Returns:



62
63
64
65
66
# File 'lib/arachni/element/capabilities/auditable.rb', line 62

def self.skip_like( &block )
    fail 'Missing block.' if !block_given?
    skip_like_blocks << block
    self
end

Instance Method Details

#audit(payloads, opts = {}, &block) ⇒ Boolean?

Note:

Requires an WithAuditor#auditor.

Submits mutations of ‘self` and calls the `block` to handle the results.

Parameters:

  • payloads (String, Array<String>, Hash{Symbol => <String, Array<String>>})

    Payloads to inject, if given:

    • String – Will inject the single payload.

    • Array – Will iterate over all payloads and inject them.

    • Hash – Expects platform names (as ‘Symbol`s ) for keys and

      {Array} of `payloads` for values. The applicable `payloads` will be
      {Platform::Manager#pick picked} from the hash based on
      {#platforms applicable platforms} for the {#action resource} to be
      audited.
      
  • opts (Hash) (defaults to: {})

    Options as described in OPTIONS.

  • block (Block)

    Block to be used for analysis of responses, will be passed each response and mutation.

Returns:

  • (Boolean, nil)
    • ‘true` when the audit was successful.

    • ‘false` when:

      * There are no {#inputs} inputs.
      * The element is {WithScope::Scope#out? out} of {WithScope::Scope}.
      * The element has already been audited and the `:redundant` option
         is `false` -- the default.
      * The element matches a {.skip_like} block.
      
    • ‘nil` when:

      * An empty array/hash of `payloads` was given.
      * There are no `payloads` applicable to the element's platforms.
      

Raises:

  • ArgumentError On missing ‘block` or unsupported `payloads` type.

See Also:



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/arachni/element/capabilities/auditable.rb', line 117

def audit( payloads, opts = {}, &block )
    fail ArgumentError, 'Missing block.' if !block_given?

    return false if self.inputs.empty?

    if scope.out?
        print_debug_level_2 "#{__method__}: Element is out of scope, " <<
                                "skipping: #{audit_id}"
        return false
    end

    case payloads
        when String
            audit_single( payloads, opts, &block )

        when Array
            return if payloads.empty?

            payloads.each do |payload|
                audit_single( payload, opts, &block )
            end

        when Hash
            platform_payloads = platforms.any? ?
                platforms.pick( payloads ) : payloads

            return if platform_payloads.empty?

            payload_platforms = Set.new( payloads.keys )
            platform_payloads.each do |platform, payloads_for_platform|
                audit( [payloads_for_platform].flatten.compact,
                       opts.merge(
                           platform: platform,
                           payload_platforms: payload_platforms
                       ),
                       &block )
            end

        else
            raise ArgumentError,
                  "Unsupported payload type '#{payloads.class}'. " <<
                      'Expected one of: String, Array, Hash'
    end
end

#audit_id(payload = nil) ⇒ String

Returns ID string used to identify the #audit of ‘self` by its WithAuditor#auditor.

Parameters:

  • payload (String) (defaults to: nil)

    Payload about to be used for the #audit.

Returns:



206
207
208
# File 'lib/arachni/element/capabilities/auditable.rb', line 206

def audit_id( payload = nil )
    "#{auditor.class.name}:#{coverage_id}:#{payload}"
end

#audit_status_messageString

Returns Status message explaining what input vector is being audited, containing its name, Base#type and Submittable#action.

Returns:



176
177
178
179
# File 'lib/arachni/element/capabilities/auditable.rb', line 176

def audit_status_message
    "Auditing #{self.type} input '#{affected_input_name}'" <<
        " pointing to: '#{audit_status_message_action}'"
end

#audit_status_message_actionObject

This method is abstract.

Action URL to be used in #audit_status_message instead of Submittable#action.



185
186
187
# File 'lib/arachni/element/capabilities/auditable.rb', line 185

def audit_status_message_action
    self.action
end

#audit_verbose_messageString

Returns Verbose message including the payload used to audit the current vector.

Returns:

  • (String)

    Verbose message including the payload used to audit the current vector.



191
192
193
194
195
196
197
198
199
# File 'lib/arachni/element/capabilities/auditable.rb', line 191

def audit_verbose_message
    s = "With: #{seed.inspect}"

    if seed != affected_input_value
        s << " -> #{affected_input_value.inspect}"
    end

    s
end

#coverage_hashInteger

Returns Digest of #coverage_id.

Returns:



220
221
222
# File 'lib/arachni/element/capabilities/auditable.rb', line 220

def coverage_hash
    coverage_id.persistent_hash
end

#coverage_idString

Note:

Differences in input values will not be taken into consideration.

Returns String identifying self’s coverage of the web application’s input surface.

Returns:

  • (String)

    String identifying self’s coverage of the web application’s input surface.



214
215
216
# File 'lib/arachni/element/capabilities/auditable.rb', line 214

def coverage_id
    "#{action}:#{type}:#{inputs.keys.sort}"
end

#dupObject



233
234
235
# File 'lib/arachni/element/capabilities/auditable.rb', line 233

def dup
    copy_auditable( super )
end

#initialize(options) ⇒ Object



68
69
70
71
# File 'lib/arachni/element/capabilities/auditable.rb', line 68

def initialize( options )
    super
    @audit_options = {}
end

#matches_skip_like_blocks?Boolean

Returns ‘true` if the element matches one or more skip_like_blocks, `false` otherwise.

Returns:

  • (Boolean)

    ‘true` if the element matches one or more skip_like_blocks, `false` otherwise.

See Also:

  • skip_like_blocks


229
230
231
# File 'lib/arachni/element/capabilities/auditable.rb', line 229

def matches_skip_like_blocks?
    Auditable.matches_skip_like_blocks? self
end

#resetObject

Resets the audit options to their original values.



74
75
76
77
78
# File 'lib/arachni/element/capabilities/auditable.rb', line 74

def reset
    super if defined?( super )
    @audit_options = {}
    self
end

#skip?(elem) ⇒ Boolean

This method is abstract.
Note:

To be overridden by inputs element implementations for more fine-grained audit control.

Returns ‘true` if `self` should be audited, `false` otherwise.

Returns:

  • (Boolean)

    ‘true` if `self` should be audited, `false` otherwise.



169
170
171
# File 'lib/arachni/element/capabilities/auditable.rb', line 169

def skip?( elem )
    false
end