Class: Arachni::Element::Auditable

Inherits:
Object
  • Object
show all
Includes:
Module::Utilities
Defined in:
lib/arachni/parser/auditable.rb

Direct Known Subclasses

Parser::Element::Base

Defined Under Namespace

Modules: Format

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Module::Utilities

#exception_jail, #get_path, #hash_keys_to_str, #normalize_url, #read_file, #seed, #uri_decode, #uri_encode, #uri_parse, #uri_parser, #url_sanitize

Instance Attribute Details

#alteredObject

Returns the value of attribute altered.



17
18
19
# File 'lib/arachni/parser/auditable.rb', line 17

def altered
  @altered
end

#optsObject (readonly)

Returns the value of attribute opts.



18
19
20
# File 'lib/arachni/parser/auditable.rb', line 18

def opts
  @opts
end

Class Method Details

.resetObject



13
14
15
# File 'lib/arachni/parser/auditable.rb', line 13

def self.reset
    @@audited = Set.new
end

.restrict_to_elements!(elements) ⇒ Object



331
332
333
334
335
336
337
# File 'lib/arachni/parser/auditable.rb', line 331

def self.restrict_to_elements!( elements )
    @@restrict_to_elements = Set.new
    elements.each {
        |elem|
        @@restrict_to_elements << elem
    }
end

Instance Method Details

#audit(injection_str, opts = { }, &block) ⇒ Object

Audits self

Parameters:

  • injection_str (String)

    the string to be injected

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

    options as described in Module::Auditor#OPTIONS

  • &block (Block)

    block to be passed the:

    • HTTP response

    • name of the input vector

    • updated opts

    The block will be called as soon as the
    HTTP response is received.
    


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
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/arachni/parser/auditable.rb', line 128

def audit( injection_str, opts = { }, &block )

    # respect user audit options
    audit_opt = "@audit_#{self.type}s"
    return if !Arachni::Options.instance.instance_variable_get( audit_opt )

    @@audited ||= Set.new

    opts            = Arachni::Module::Auditor::OPTIONS.merge( opts )
    opts[:element]  = self.type

    opts[:injected_orig] = injection_str

    # if we don't have any auditable elements just return
    return if auditable.empty?

    audit_id = audit_id( injection_str, opts )
    return if !opts[:redundant] && audited?( audit_id )

    results = []
    # iterate through all variation and audit each one
    injection_sets( injection_str, opts ).each {
        |elem|

        elem.auditor( get_auditor )
        opts[:altered] = elem.altered.dup

        return if skip?( elem )

        # inform the user about what we're auditing
        print_status( get_status_str( opts[:altered] ) )  if !opts[:silent]

        # submit the element with the injection values
        req = elem.submit( opts )
        return if !req

        on_complete( req, elem, &block )
        req.after_complete {
            |result|
            results << result.flatten[1] if result.flatten[1]
        }
    }

    audited( audit_id )
end

#audit_id(injection_str = '', opts = {}) ⇒ String

Returns am audit identifier string to be registered using #audited.

Parameters:

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

Returns:



318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/arachni/parser/auditable.rb', line 318

def audit_id( injection_str = '', opts = {} )
    vars = auditable.keys.sort.to_s

    str = ''
    str += !opts[:no_auditor] ? "#{@auditor.class.info[:name]}:" : ''

    str += "#{@action}:" + "#{self.type}:#{vars}"
    str += "=#{injection_str.to_s}" if !opts[:no_injection_str]
    str += ":timeout=#{opts[:timeout]}" if !opts[:no_timeout]

    return str
end

#auditor(auditor) ⇒ Object



48
49
50
# File 'lib/arachni/parser/auditable.rb', line 48

def auditor( auditor )
    @auditor = auditor
end

#debug?Boolean

Delegate output related methods to the auditor

Returns:

  • (Boolean)


68
69
70
# File 'lib/arachni/parser/auditable.rb', line 68

def debug?
    @auditor.debug? rescue false
end

#get_auditorObject



52
53
54
# File 'lib/arachni/parser/auditable.rb', line 52

def get_auditor
    @auditor
end

#get_status_str(altered) ⇒ String

Returns a status string that explaining what’s happening.

The string contains the name of the input that is being audited the url and the type of the input (form, link, cookie…)

Parameters:

  • url (String)

    the url under audit

  • input (Hash)
  • opts (Hash)

Returns:



306
307
308
# File 'lib/arachni/parser/auditable.rb', line 306

def get_status_str( altered )
    return "Auditing #{self.type} variable '" + altered + "' of " + @action
end

#http_request(url, opts) ⇒ Object

Callback invoked by #audit to submit the object via Module::HTTP.

Must be implemented by the extending class.

Parameters:

See Also:



96
97
98
# File 'lib/arachni/parser/auditable.rb', line 96

def http_request( url, opts )

end

#infoObject

impersonate the auditor to the output methods



290
291
292
# File 'lib/arachni/parser/auditable.rb', line 290

def info
    @auditor ? @auditor.class.info : { :name => '' }
end

#injection_sets(injection_str, opts = { }) ⇒ Array

Injects the injecton_str in self’s values according to formatting options and returns an array of Element permutations.

Parameters:

  • injection_str (String)

    the string to inject

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

    formatting and permutation options

    • :skip_orig => skip submission with default/original values (for Parser::Element::Form elements)

    • :format => Format

    • :param_flip => flip injection value and input name

Returns:



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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/arachni/parser/auditable.rb', line 190

def injection_sets( injection_str, opts = { } )

    opts = Arachni::Module::Auditor::OPTIONS.merge( opts )
    hash = auditable( ).dup

    var_combo = []
    if( !hash || hash.size == 0 ) then return [] end

    if( self.is_a?( Arachni::Parser::Element::Form ) && !opts[:skip_orig] )

        if !audited?( audit_id( Arachni::Parser::Element::Form::FORM_VALUES_ORIGINAL ) )
            # this is the original hash, in case the default values
            # are valid and present us with new attack vectors
            elem = self.dup
            elem.altered = Arachni::Parser::Element::Form::FORM_VALUES_ORIGINAL
            var_combo << elem
        end

        if !audited?( audit_id( Arachni::Parser::Element::Form::FORM_VALUES_SAMPLE ) )
            duphash = hash.dup
            elem = self.dup
            elem.auditable = Arachni::Module::KeyFiller.fill( duphash )
            elem.altered = Arachni::Parser::Element::Form::FORM_VALUES_SAMPLE
            var_combo << elem
        end
    end

    chash = hash.dup
    hash.keys.each {
        |k|

        # don't audit parameter flips
        next if hash[k] == seed

        chash = Arachni::Module::KeyFiller.fill( chash )
        opts[:format].each {
            |format|

            str  = format_str( injection_str, chash[k], format )

            elem = self.dup
            elem.altered = k.dup
            elem.auditable = chash.merge( { k => str } )
            var_combo << elem
        }

    }

    if opts[:param_flip] #&& !self.is_a?( Arachni::Parser::Element::Cookie )
        elem = self.dup

        # when under HPG mode element auditing is strictly regulated
        # and when we flip params we essentially create a new element
        # which won't be on the whitelist
        elem.override_instance_scope!

        elem.altered = 'Parameter flip'
        elem.auditable[injection_str] = seed
        var_combo << elem
    end

    # if there are two password type fields in the form there's a good
    # chance that it's a 'please retype your password' thing so make sure
    # that we have a variation which has identical password values
    if self.is_a?( Arachni::Parser::Element::Form )
        chash = hash.dup
        chash = Arachni::Module::KeyFiller.fill( chash )
        delem = self.dup

        add = false
        @raw['auditable'].each {
            |input|

            if input['type'] == 'password'
                delem.altered = input['name']

                opts[:format].each {
                    |format|
                    chash[input['name']] =
                        format_str( injection_str, chash[input['name']], format )
                }

                add = true
            end
        } if @raw['auditable']

        if add
            delem.auditable = chash
            var_combo << delem
        end
    end


    print_debug_injection_set( var_combo, opts )

    return var_combo
end

#override_instance_scope!Object



56
57
58
# File 'lib/arachni/parser/auditable.rb', line 56

def override_instance_scope!
    @override_instance_scope = true
end

#override_instance_scope?Boolean

Returns:

  • (Boolean)


60
61
62
# File 'lib/arachni/parser/auditable.rb', line 60

def override_instance_scope?
    @override_instance_scope ||= false
end


80
81
82
# File 'lib/arachni/parser/auditable.rb', line 80

def print_debug( str = '' )
    @auditor.print_debug( str )
end


72
73
74
# File 'lib/arachni/parser/auditable.rb', line 72

def print_error( str = '' )
    @auditor.print_error( str )
end


76
77
78
# File 'lib/arachni/parser/auditable.rb', line 76

def print_status( str = '' )
    @auditor.print_status( str )
end

#skip?(elem) ⇒ Boolean

Returns:

  • (Boolean)


174
175
176
# File 'lib/arachni/parser/auditable.rb', line 174

def skip?( elem )
    return @auditor.skip?( elem )
end

#submit(opts = {}) ⇒ Object

Submits self using #http_request.

Parameters:

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

See Also:



107
108
109
110
111
112
113
114
# File 'lib/arachni/parser/auditable.rb', line 107

def submit( opts = {} )

    opts = Arachni::Module::Auditor::OPTIONS.merge( opts )
    opts[:params]  = @auditable.dup
    @opts = opts

    return http_request( @action, opts )
end