Module: Arachni::Element::Capabilities::Mutable

Overview

Author:

Defined Under Namespace

Modules: Format

Constant Summary collapse

MUTATION_OPTIONS =

Default formatting and mutation options.

{

    # Formatting of the injection strings.
    #
    # A new set of audit inputs will be generated for each value in the array.
    #
    # Values can be OR'ed bitfields of all available constants of {Format}.
    format:                 [
                                Format::STRAIGHT, Format::APPEND,
                                Format::NULL, Format::APPEND | Format::NULL
                            ],

    # Inject the payload into parameter values.
    #
    # * `nil`: Use system settings (`!Options.audit.parameter_values`).
    # * `true`
    # * `false`
    parameter_values:       nil,

    # Place the payload as an input name.
    #
    # * `nil`: Use system settings (`!Options.audit.parameter_names`).
    # * `true`
    # * `false`
    parameter_names:        nil,

    # Add the payload to an extra parameter.
    #
    # * `nil`: Use system settings (`!Options.audit.with_extra_parameter`).
    # * `true`
    # * `false`
    with_extra_parameter:   nil,

    # `nil`:   Use system settings (`!Options.audit.with_both_http_methods`).
    # `true`:  Don't create mutations with other methods (GET/POST).
    # `false`: Create mutations with other methods (GET/POST).
    with_both_http_methods: nil,

    # Array of parameter names remain untouched.
    skip:                   []
}
EXTRA_NAME =
'extra_arachni_input'
FUZZ_NAME =
'Parameter name fuzzing'
FUZZ_NAME_VALUE =
'arachni_name_fuzz'

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#affected_input_nameString

Returns Name of the mutated parameter.

Returns:

  • (String)

    Name of the mutated parameter.



17
18
19
# File 'lib/arachni/element/capabilities/mutable.rb', line 17

def affected_input_name
  @affected_input_name
end

#formatObject

Returns the value of attribute format.



23
24
25
# File 'lib/arachni/element/capabilities/mutable.rb', line 23

def format
  @format
end

#seedString

Returns Original seed used for the #mutations.

Returns:



21
22
23
# File 'lib/arachni/element/capabilities/mutable.rb', line 21

def seed
  @seed
end

Instance Method Details

#affected_input_valuenil, String

Returns ‘nil` if no input has been fuzzed, the `String` value of the fuzzed input.

Returns:

  • (nil, String)

    ‘nil` if no input has been fuzzed, the `String` value of the fuzzed input.



103
104
105
106
# File 'lib/arachni/element/capabilities/mutable.rb', line 103

def affected_input_value
    return if !affected_input_name
    self[affected_input_name].to_s
end

#affected_input_value=(value) ⇒ Object

Parameters:

  • value (String)

    Sets the value for the fuzzed input.



110
111
112
# File 'lib/arachni/element/capabilities/mutable.rb', line 110

def affected_input_value=( value )
    self[affected_input_name] = value
end

#dupObject



289
290
291
# File 'lib/arachni/element/capabilities/mutable.rb', line 289

def dup
    copy_mutable( super )
end

#each_mutation(payload, options = {}) {|mutation| ... } ⇒ Object

Note:

Vector names in #immutables will be excluded.

Injects the ‘payload` in self’s values according to formatting options and returns an array of mutations of self.

Parameters:

Yields:

  • (mutation)

    Each generated mutation.

Yield Parameters:

See Also:



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/arachni/element/capabilities/mutable.rb', line 153

def each_mutation( payload, options = {}, &block )
    return if self.inputs.empty?

    if !valid_input_data?( payload )
        print_debug_level_2 "Payload not supported by #{self}: #{payload.inspect}"
        return
    end

    print_debug_trainer( options )
    print_debug_formatting( options )

    options          = prepare_mutation_options( options )
    generated        = Support::LookUp::HashSet.new( hasher: :mutable_id )
    filled_in_inputs = Options.input.fill( @inputs )

    if options[:parameter_values]
        @inputs.keys.each do |name|
            # Don't let parameter name pollution from an old audit of an
            # input name trick us into doing the same for elements without
            # that option.
            next if name == EXTRA_NAME
            next if immutables.include?( name )

            each_formatted_payload(
                payload, options[:format], filled_in_inputs[name]
            ) do |format, formatted_payload|

                elem = create_and_yield_if_unique(
                    generated, filled_in_inputs, payload, name,
                    formatted_payload, format, &block
                )

                next if !elem || !options[:with_both_http_methods]
                yield_if_unique( elem.switch_method, generated, &block )
            end
        end
    end

    if options[:with_extra_parameter]
        if valid_input_name?( EXTRA_NAME )
            each_formatted_payload( payload, options[:format] ) do |format, formatted_payload|

                elem = create_and_yield_if_unique(
                    generated, filled_in_inputs.merge( EXTRA_NAME => '' ), payload, EXTRA_NAME,
                    formatted_payload, format, &block
                )

                next if !elem || !options[:with_both_http_methods]
                yield_if_unique( elem.switch_method, generated, &block )
            end
        else
            print_debug_level_2 'Extra name not supported as input name by' <<
                                    " #{audit_id}: #{payload.inspect}"
        end
    end

    if options[:parameter_names]
        if valid_input_name_data?( payload )
            elem                     = self.dup.update( filled_in_inputs )
            elem.affected_input_name = FUZZ_NAME
            elem[payload]            = FUZZ_NAME_VALUE
            elem.seed                = payload

            yield_if_unique( elem, generated, &block )
        else
            print_debug_level_2 'Payload not supported as input name by' <<
                                    " #{audit_id}: #{payload.inspect}"
        end
    end

    nil
end

#immutablesSet

Returns Names of input vectors to be excluded from #mutations.

Returns:

  • (Set)

    Names of input vectors to be excluded from #mutations.



134
135
136
# File 'lib/arachni/element/capabilities/mutable.rb', line 134

def immutables
    @immutables ||= Set.new
end

#inspectObject



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/arachni/element/capabilities/mutable.rb', line 261

def inspect
    s = "#<#{self.class} (#{http_method}) "

    if !orphan?
        s << "auditor=#{auditor.class} "
    end

    s << "url=#{url.inspect} "
    s << "action=#{action.inspect} "

    s << "default-inputs=#{default_inputs.inspect} "
    s << "inputs=#{inputs.inspect} "

    if mutation?
        s << "seed=#{seed.inspect} "
        s << "affected-input-name=#{affected_input_name.inspect} "
        s << "affected-input-value=#{affected_input_value.inspect}"
    end

    s << '>'
end

#mutation?Bool

Returns ‘true` if the element has been mutated, `false` otherwise.

Returns:

  • (Bool)

    ‘true` if the element has been mutated, `false` otherwise.



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

def mutation?
    !!self.affected_input_name
end

#mutations(payload, opts = {}) ⇒ Array

Injects the ‘payload` in self’s values according to formatting options and returns an array of mutations of self.

Vector names in #immutables will be excluded.

Parameters:

Returns:

See Also:



243
244
245
246
247
# File 'lib/arachni/element/capabilities/mutable.rb', line 243

def mutations( payload, opts = {} )
    combo = []
    each_mutation( payload, opts ) { |m| combo << m }
    combo
end

#resetObject

Resets the inputs to their original format/values.



93
94
95
96
97
98
# File 'lib/arachni/element/capabilities/mutable.rb', line 93

def reset
    super
    @affected_input_name = nil
    @seed                = nil
    self
end

#switch_methodObject



226
227
228
# File 'lib/arachni/element/capabilities/mutable.rb', line 226

def switch_method
    self.dup.tap { |c| c.method = (c.method == :get ? :post : :get) }
end

#to_hObject



249
250
251
252
253
254
255
256
257
258
259
# File 'lib/arachni/element/capabilities/mutable.rb', line 249

def to_h
    h = super

    if mutation?
        h[:affected_input_name]  = self.affected_input_name
        h[:affected_input_value] = self.affected_input_value
        h[:seed]                 = self.seed
    end

    h
end

#to_rpc_dataObject



283
284
285
286
287
# File 'lib/arachni/element/capabilities/mutable.rb', line 283

def to_rpc_data
    d = super
    d.delete 'immutables'
    d
end