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

Includes:
WithAuditor, Utilities
Included in:
Arachni::Element::Cookie, DOM::Capabilities::Auditable, Form, Form::Capabilities::Auditable, Header, JSON, Link, Link::Capabilities::Auditable, LinkTemplate, LinkTemplate::Capabilities::Auditable, NestedCookie, XML
Defined in:
lib/arachni/element/capabilities/auditable.rb,
lib/arachni/element/capabilities/auditable/buffered.rb,
lib/arachni/element/capabilities/auditable/line_buffered.rb

Overview

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

Author:

  • Tasos “Zapotek” Laskos <tasos.laskos@arachni-scanner.com>

Defined Under Namespace

Modules: Buffered, LineBuffered

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
}

Instance Attribute Summary collapse

Attributes included from WithAuditor

#auditor

Class Method Summary collapse

Instance Method Summary collapse

Methods included from WithAuditor

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

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

Instance Attribute Details

#audit_optionsHash

Returns Audit and general options for convenience's sake.

Returns:

  • (Hash)

    Audit and general options for convenience's sake.



27
28
29
# File 'lib/arachni/element/capabilities/auditable.rb', line 27

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.



46
47
48
49
# File 'lib/arachni/element/capabilities/auditable.rb', line 46

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:



56
57
58
59
60
# File 'lib/arachni/element/capabilities/auditable.rb', line 56

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 unsupported `payloads` type.

See Also:

  • #submit


111
112
113
114
115
116
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
# File 'lib/arachni/element/capabilities/auditable.rb', line 111

def audit( payloads, opts = {}, &block )
    return false if self.inputs.empty?

    if scope.out?
        print_debug_level_2 "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:



197
198
199
# File 'lib/arachni/element/capabilities/auditable.rb', line 197

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 #action.

Returns:

  • (String)

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



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

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.



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

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.



182
183
184
185
186
187
188
189
190
# File 'lib/arachni/element/capabilities/auditable.rb', line 182

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:



211
212
213
# File 'lib/arachni/element/capabilities/auditable.rb', line 211

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.



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

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

#dupObject



224
225
226
# File 'lib/arachni/element/capabilities/auditable.rb', line 224

def dup
    copy_auditable( super )
end

#initialize(options) ⇒ Object



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

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


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

def matches_skip_like_blocks?
    Auditable.matches_skip_like_blocks? self
end

#resetObject

Resets the audit options to their original values.



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

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.



160
161
162
# File 'lib/arachni/element/capabilities/auditable.rb', line 160

def skip?( elem )
    false
end