Module: Arachni::Module::Auditor

Included in:
Base
Defined in:
lib/module/auditor.rb

Overview

Auditor module

Included by Base.
Includes audit methods used to attack a web page.

@author: Anastasios “Zapotek” Laskos

                                     <tasos.laskos@gmail.com>
                                     <zapotek@segfault.gr>

@version: 0.1-pre

Instance Method Summary (collapse)

Instance Method Details

- (Object) audit_cookies(injection_str, id_regex = nil, id = nil, &block)

Audits cookies injecting the injection_str as value for the cookies and then matching the response body against the id_regex.

If the id argument has been provided the matched data of the id_regex will be ==’ed against it.

Parameters:

  • (String) injection_str
  • (String) id_regex (defaults to: nil)

    regular expression string

  • (String) id (defaults to: nil)

    string to double check the id_regex matched data

  • (Block) block

    to be executed right after the request has been made. It will be passed the currently audited variable, the response and the url.

  • (Array<Hash<String, String>>) the

    positive results of the audit, if no block has been given



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/module/auditor.rb', line 278

def audit_cookies( injection_str, id_regex = nil, id = nil, &block )
    
    results = []
    
    # iterate through each cookie
    work_on_cookies {
        |orig_cookie|
    inject_each_var( get_cookie_simple( orig_cookie ), injection_str ).each {
        |cookie|

        next if Options.instance.exclude_cookies.include?( cookie['altered'] )
        
        audit_id = "#{self.class.info['Name']}:" +
            "#{@page.url}:#{Vulnerability::Element::COOKIE}:" +
            "#{cookie['altered'].to_s}=#{cookie['hash'].to_s}"
        
        next if @@audited.include?( audit_id )

        # tell the user what we're auditing
        print_status( self.class.info['Name']  + 
            " is auditing:\tcookie '" +
            cookie['altered'] + "' of " + @page.url )

        # make a get request with our cookies
        res = @http.cookie( @page.url, cookie['hash'], nil )
            
        @@audited << audit_id

        # check for a response
        if !res then next end
        
        if block_given?
            block.call( @page.url, res, cookie['altered'] )
            next
        end
        
        if !res.body then next end
            
        # get possible matches
        result = get_matches( Vulnerability::Element::COOKIE,
            cookie['altered'], res, injection_str, id_regex, id, @page.url )
        # and append them
        results << result if result
    }
    }

    results
end

- (Object) audit_forms(injection_str, id_regex = nil, id = nil, &block)

Audits forms injecting the injection_str as value for the variables and then matching the response body against the id_regex.

If the id argument has been provided the matched data of the id_regex will be ==’ed against it.

Parameters:

  • (String) injection_str
  • (String) id_regex (defaults to: nil)

    regular expression string

  • (String) id (defaults to: nil)

    string to double check the id_regex matched data

  • (Block) block

    to be executed right after the request has been made. It will be passed the currently audited variable, the response and the url.

  • (Array<Hash<String, String>>) the

    positive results of the audit, if no block has been given



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
# File 'lib/module/auditor.rb', line 198

def audit_forms( injection_str, id_regex = nil, id = nil, &block )
    
    results = []
    
    work_on_forms {
        |orig_form|
        form = get_form_simple( orig_form )

        next if !form
        
        url    = form['attrs']['action']
        method = form['attrs']['method']
            
        # iterate through each auditable element
        inject_each_var( form['auditable'], injection_str ).each {
            |input|

            audit_id = "#{self.class.info['Name']}:" +
                "#{url}:" +
                "#{Vulnerability::Element::FORM}:" + 
                "#{input['altered'].to_s}=#{input['hash'].to_s}"
            
            next if @@audited.include?( audit_id )
            
            # inform the user what we're auditing
            print_status( self.class.info['Name']  + 
                " is auditing:\tform input '" +
                input['altered'] + "' with action " + url )

            if( method != 'get' )
                res = @http.post( url, input['hash'] )
            else
                res = @http.get( url, input['hash'] )
            end
            
            @@audited << audit_id
            
            # make sure that we have a response before continuing
            if !res then next end
            
            # call the block, if there's one
            if block_given?
                block.call( url, res, input['altered'] )
                next
            end

            if !res.body then next end
        
            # get matches
            result = get_matches( Vulnerability::Element::FORM,
                input['altered'], res, injection_str, id_regex, id, url )
            
            # and append them to the results array
            results << result if result
        }
    }
    results
end

- (Object) audit_headers(injection_str, id_regex = nil, id = nil, &block)

Audits HTTP request headers injecting the injection_str as values and then matching the response body against the id_regex.

If the id argument has been provided the matched data of the id_regex will be ==’ed against it.

Parameters:

  • (String) injection_str
  • (String) id_regex (defaults to: nil)

    regular expression string

  • (String) id (defaults to: nil)

    string to double check the id_regex matched data

  • (Block) block

    to be executed right after the request has been made. It will be passed the currently audited variable, the response and the url.

  • (Array<Hash<String, String>>) the

    positive results of the audit, if no block has been given



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/module/auditor.rb', line 54

def audit_headers( injection_str, id_regex = nil, id = nil, &block )

    results = []
    
    # iterate through header fields and audit each one
    inject_each_var( get_request_headers( true ), injection_str ).each {
        |vars|

        audit_id = "#{self.class.info['Name']}:" +
            "#{@page.url}:#{Vulnerability::Element::HEADER}:" +
            "#{vars['altered'].to_s}=#{vars['hash'].to_s}"
        
        next if @@audited.include?( audit_id )

        # tell the user what we're doing
        print_status( self.class.info['Name']  + 
            " is auditing:\theader field '" +
            vars['altered'] + "' of " + @page.url )
        
        # audit the url vars
        res = @http.header( @page.url, vars['hash'] )
        @@audited << audit_id

        # something might have gone bad,
        # make sure it doesn't ruin the rest of the show...
        if !res then next end
        
        # call the passed block
        if block_given?
            block.call( @page.url, res, vars['altered'] )
            next
        end
        
        if !res.body then next end
        
        # get matches
        result = get_matches( Vulnerability::Element::HEADER,
            vars['altered'], res, injection_str, id_regex, id, @page.url )
        
        # and append them to the results array
        results << result if result
    }

    results
end

Audits links injecting the injection_str as value for the variables and then matching the response body against the id_regex.

If the id argument has been provided the matched data of the id_regex will be ==’ed against it.

Parameters:

  • (String) injection_str
  • (String) id_regex (defaults to: nil)

    regular expression string

  • (String) id (defaults to: nil)

    string to double check the id_regex matched data

  • (Block) block

    to be executed right after the request has been made. It will be passed the currently audited variable, the response and the url.

  • (Array<Hash<String, String>>) the

    positive results of the audit, if no block has been given



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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/module/auditor.rb', line 121

def audit_links( injection_str, id_regex = nil, id = nil, &block )

    results = []
    
    work_on_links {
        |link|
        
        url       = link['href']
        link_vars = link['vars']
            
        # if we don't have any auditable elements just return
        if !link_vars then next end

        # iterate through all url vars and audit each one
        inject_each_var( link_vars, injection_str ).each {
            |vars|

            audit_id = "#{self.class.info['Name']}:" +
                "#{url}:#{Vulnerability::Element::LINK}:" +
                "#{vars['altered'].to_s}=#{vars['hash'].to_s}"
            
            next if @@audited.include?( audit_id )

            # tell the user what we're doing
            print_status( self.class.info['Name']  + 
                " is auditing:\tlink var '" +
                vars['altered'] + "' of " + url )
            
            # audit the url vars
            res = @http.get( url, vars['hash'] )
            @@audited << audit_id
            
            # something might have gone bad,
            # make sure it doesn't ruin the rest of the show...
            if !res then next end
            
            # call the passed block
            if block_given?
                block.call( url, res, vars['altered'] )
                next
            end
            
            if !res.body then next end
            
            # get matches
            result = get_matches( Vulnerability::Element::LINK,
                vars['altered'], res, injection_str, id_regex, id, url )
            
            # and append them to the results array
            results << result if result
        }
    }    

    results
end

- (Object) get_matches(where, var, res, injection_str, id_regex, id, url)



327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
# File 'lib/module/auditor.rb', line 327

def get_matches( where, var, res, injection_str, id_regex, id, url )
    
    # fairly obscure condition...pardon me...
    if ( id && res.body.scan( id_regex )[0] == id ) ||
       ( !id && res.body.scan( id_regex )[0].size > 0 )
    
        print_ok( self.class.info['Name'] + " in: #{where} var #{var}" +
        '::' + url )
        
        print_verbose( "Injected str:\t" + injection_str )    
        print_verbose( "ID str:\t\t" + id )
        print_verbose( "Matched regex:\t" + id_regex.to_s )
        print_verbose( '---------' ) if only_positives?

        return {
            'var'          => var,
            'url'          => url,
            'injected'     => injection_str,
            'id'           => id,
            'regexp'       => id_regex.to_s,
            'regexp_match' => res.body.scan( id_regex ),
            'response'     => res.body,
            'elem'         => where,
            'headers'      => {
                'request'    => get_request_headers( ),
                'response'   => get_response_headers( res ),    
            }
        }
    end
end

- (Array) inject_each_var(hash, to_inj)

Iterates through a hash setting each value to to_inj and returns an array of new hashes

Parameters:

  • (Hash) hash

    name=>value pairs

  • (String) to_inj

    the string to inject

Returns:

  • (Array)


367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
# File 'lib/module/auditor.rb', line 367

def inject_each_var( hash, to_inj )
    
    var_combo = []
    if( !hash || hash.size == 0 ) then return [] end
    
    # this is the original hash, in case the default values
    # are valid and present us with new attack vectors
    as_is = Hash.new( )
    as_is['altered'] = '__orig'
    chash = as_is['hash']    = hash.clone
        
    as_is['hash'].keys.each {
        |k|
        if( !as_is['hash'][k] ) then as_is['hash'][k] = '' end
    }
    var_combo << as_is
    
    # these are audit inputs, if a value is empty or null
    # we put a sample e-mail address in its place
    hash.keys.each {
        |k|
        
        hash = KeyFiller.fill( hash )
        
        var_combo << { 
            'altered' => k,
            'hash'    => hash.merge( { k => to_inj } )
        }
    }
    
    var_combo
end