Module: Arachni::Element::Capabilities::Analyzable::Differential

Included in:
Arachni::Element::Capabilities::Analyzable
Defined in:
lib/arachni/element/capabilities/analyzable/differential.rb

Overview

Performs boolean injection and behavioral analysis (using differential analysis techniques based on Support::Signature comparisons) in order to determine whether the web application is responding to the injected data and how.

If the behavior can be manipulated by the injected data in ways that it’s not supposed to (like when evaluating injected code) then the element is deemed vulnerable.

Author:

Constant Summary collapse

DIFFERENTIAL_OPTIONS =
{
    # Append our seeds to the default values.
    format:         [Mutable::Format::STRAIGHT],

    # Amount of refinement operations to remove context-irrelevant dynamic
    # content -- like banners etc.
    precision:      2,

    # Override global fuzzing settings and only use the default method of the
    # element under audit.
    respect_method: true,

    # Disable {Arachni::Options#audit_cookies_extensively}, there's little
    # to be gained in this case and just causes interference.
    extensively:    false,

    # Don't generate or submit any mutations with default or sample inputs.
    skip_original:  true,

    # Allow redundant audits, we need multiple ones for noise-reduction.
    redundant:      true,

    # Don't let #audit print output, we'll handle that ourselves.
    silent:         true,

    # Default value for a forceful 'false' response.
    false:          '-1'
}

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.resetObject



25
26
27
# File 'lib/arachni/element/capabilities/analyzable/differential.rb', line 25

def reset
    # In case we want to reset state or something...
end

Instance Method Details

#differential_analysis(opts = {}) ⇒ Bool

Performs differential analysis and logs an issue should there be one.

opts = {
    false: 'false resource id',
    pairs: [
          { 'true expression' => 'false expression' }
    ]
}

element.differential_analysis( opts )

Here’s how it goes:

  • let ‘control` be the response of the injection of ’false resource id’

  • let ‘true_response` be the response of the injection of ’true expression’

  • let ‘false_response` be the response of the injection of ’false expression’

  • let ‘control_verification` be a fresh control

A vulnerability is logged if:

control == control_verification && control == false_response AND
  true_response.code == 200 AND false_response != true_response

The ‘bool` response is also checked in order to determine if it’s a custom 404, if it is then it’ll be skipped.

If a block has been provided analysis and logging will be delegated to it.

Parameters:

  • opts (Hash) (defaults to: {})

Options Hash (opts):

  • :format (Integer)

    As seen in Mutable::Format.

  • :precision (Integer)

    Amount of refinement iterations to perform for the signatures.

  • :pairs (Array<Hash>)

    Pair of strings that should yield different results when interpreted. Keys should be the ‘true` expressions.

  • :false (String)

    A string which would illicit a ‘false’ response but without any code.

Returns:

  • (Bool)

    ‘true` if the audit was scheduled successfully, `false` otherwise (like if the resource is out of scope or already audited).



101
102
103
104
105
106
107
108
109
110
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
152
153
154
# File 'lib/arachni/element/capabilities/analyzable/differential.rb', line 101

def differential_analysis( opts = {} )
    return if self.inputs.empty?

    return false if audited? audit_id
    audited audit_id

    if scope.out?
        print_debug 'Differential analysis: Element is out of scope,' <<
                        " skipping: #{audit_id}"
        return false
    end

    opts = self.class::MUTATION_OPTIONS.merge( DIFFERENTIAL_OPTIONS.merge( opts ) )

    mutations_size = 0
    each_mutation( opts[:false], opts ) { mutations_size += 1 }
    mutations_size *= opts[:precision]

    @data_gathering = {
        mutations_size:     mutations_size,
        expected_responses: mutations_size + (mutations_size * opts[:pairs].size * 2),
        received_responses: 0,
        done:               false,
        controls:           {}
    }

    # Holds all the data from the probes.
    signatures = {
        # Control baseline per input.
        controls:              {},

        # Verification control baseline per input.
        controls_verification: {},

        # Corrupted baselines per input.
        corrupted:             {},

        # Rest of the data are dynamically populated using input pairs
        # as keys.
    }

    # Populate the baseline/control forced-false signatures.
    populate_control_signatures( opts, signatures )

    http.after_run do
        # Populate the 'true' signatures.
        populate_signatures( :true, opts, signatures )

        # Populate the 'false' signatures.
        populate_signatures( :false, opts, signatures )
    end

    true
end