Module: Arachni::Utilities

Overview

Includes some useful methods for the system.

Author:

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

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.available_port_mutexObject



358
359
360
# File 'lib/arachni/utilities.rb', line 358

def self.available_port_mutex
    @available_port_mutex ||= Mutex.new
end

Instance Method Details

#available_portFixnum

Returns Random available port number.

Returns:

  • (Fixnum)

    Random available port number.



343
344
345
346
347
348
349
350
351
352
353
354
355
356
# File 'lib/arachni/utilities.rb', line 343

def available_port
    available_port_mutex.synchronize do
        @used_ports ||= Set.new

        loop do
            port = self.rand_port

            if port_available?( port ) && !@used_ports.include?( port )
                @used_ports << port
                return port
            end
        end
    end
end

#bytes_to_kilobytes(bytes) ⇒ Object



415
416
417
# File 'lib/arachni/utilities.rb', line 415

def bytes_to_kilobytes( bytes )
    (bytes / 1024.0 ).round( 3 )
end

#bytes_to_megabytes(bytes) ⇒ Object



411
412
413
# File 'lib/arachni/utilities.rb', line 411

def bytes_to_megabytes( bytes )
    (bytes / 1024.0 / 1024.0).round( 3 )
end

#caller_nameString

Returns Filename (without extension) of the caller.

Returns:

  • (String)

    Filename (without extension) of the caller.



22
23
24
# File 'lib/arachni/utilities.rb', line 22

def caller_name
    File.basename( caller_path( 3 ), '.rb' )
end

#caller_path(offset = 2) ⇒ String

Returns Filepath of the caller.

Returns:

  • (String)

    Filepath of the caller.



28
29
30
# File 'lib/arachni/utilities.rb', line 28

def caller_path( offset = 2 )
    ::Kernel.caller[offset].split( /:(\d+):in/ ).first
end


98
99
100
# File 'lib/arachni/utilities.rb', line 98

def cookie_decode( *args )
    Cookie.decode( *args )
end


93
94
95
# File 'lib/arachni/utilities.rb', line 93

def cookie_encode( *args )
    Cookie.encode( *args )
end

#cookies_from_file(*args) ⇒ Object



88
89
90
# File 'lib/arachni/utilities.rb', line 88

def cookies_from_file( *args )
    Cookie.from_file( *args )
end

#cookies_from_parser(*args) ⇒ Object



78
79
80
# File 'lib/arachni/utilities.rb', line 78

def cookies_from_parser( *args )
    Cookie.from_parser(*args )
end

#cookies_from_response(*args) ⇒ Object



73
74
75
# File 'lib/arachni/utilities.rb', line 73

def cookies_from_response( *args )
    Cookie.from_response( *args )
end

#exception_jail(raise_exception = true, &block) ⇒ Object

Wraps the `block` in exception handling code and runs it.

Parameters:

  • raise_exception (Bool) (defaults to: true)

    Re-raise exception?

  • block (Block)


424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
# File 'lib/arachni/utilities.rb', line 424

def exception_jail( raise_exception = true, &block )
    block.call
rescue => e
    if respond_to?( :print_error ) && respond_to?( :print_exception )
        print_exception e
        print_error
        print_error 'Parent:'
        print_error  self.class.to_s
        print_error
        print_error 'Block:'
        print_error block.to_s
        print_error
        print_error 'Caller:'
        ::Kernel.caller.each { |l| print_error l }
        print_error '-' * 80
    end

    raise e if raise_exception

    nil
end

#exclude_path?(url) ⇒ Bool

Decides whether the given `url` matches any framework exclusion rules.

Parameters:

Returns:

  • (Bool)

See Also:



208
209
210
# File 'lib/arachni/utilities.rb', line 208

def exclude_path?( url )
    uri_parse( url ).scope.exclude?
end

#follow_protocol?(url, reference = Options.url) ⇒ Bool

Decides whether the given `url` has an acceptable protocol.

Parameters:

  • url (String)
  • reference (String) (defaults to: Options.url)

    Reference URL.

Returns:

  • (Bool)

See Also:



250
251
252
# File 'lib/arachni/utilities.rb', line 250

def follow_protocol?( url, reference = Options.url )
    uri_parse( url ).scope.follow_protocol?( reference )
end

#form_decode(*args) ⇒ Object



53
54
55
# File 'lib/arachni/utilities.rb', line 53

def form_decode( *args )
    Form.decode( *args )
end

#form_encode(*args) ⇒ Object



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

def form_encode( *args )
    Form.encode( *args )
end

#forms_from_parser(*args) ⇒ Object



43
44
45
# File 'lib/arachni/utilities.rb', line 43

def forms_from_parser( *args )
    Form.from_parser(*args )
end

#forms_from_response(*args) ⇒ Object



38
39
40
# File 'lib/arachni/utilities.rb', line 38

def forms_from_response( *args )
    Form.from_response( *args )
end

#full_and_absolute_url?(url) ⇒ Boolean

Returns:

  • (Boolean)

See Also:



162
163
164
# File 'lib/arachni/utilities.rb', line 162

def full_and_absolute_url?( url )
    Arachni::URI.full_and_absolute?( url.to_s )
end

#generate_tokenObject



374
375
376
# File 'lib/arachni/utilities.rb', line 374

def generate_token
    SecureRandom.hex
end

#get_path(url) ⇒ String

Returns path Full URL up to the path component (no resource, query etc.).

Parameters:

Returns:

  • (String)

    path Full URL up to the path component (no resource, query etc.).

See Also:



172
173
174
# File 'lib/arachni/utilities.rb', line 172

def get_path( url )
    uri_parse( url ).up_to_path
end

#hms_to_seconds(time) ⇒ Object



404
405
406
407
408
409
# File 'lib/arachni/utilities.rb', line 404

def hms_to_seconds( time )
    a = [1, 60, 3600] * 2
    time.split( /[:\.]/ ).map { |t| t.to_i * a.pop }.inject(&:+)
rescue
    0
end

#html_decode(str) ⇒ Object Also known as: html_unescape



112
113
114
# File 'lib/arachni/utilities.rb', line 112

def html_decode( str )
    ::CGI.unescapeHTML( str.to_s )
end

#html_encode(str) ⇒ Object Also known as: html_escape



117
118
119
# File 'lib/arachni/utilities.rb', line 117

def html_encode( str )
    ::CGI.escapeHTML( str.to_s )
end

#include_path?(url) ⇒ Bool

Decides whether the given `url` matches any framework inclusion rules.

Parameters:

Returns:

  • (Bool)

See Also:

  • URI.include?
  • Options#include


220
221
222
# File 'lib/arachni/utilities.rb', line 220

def include_path?( url )
    uri_parse( url ).scope.include?
end


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

def links_from_parser( *args )
    Link.from_parser(*args )
end


63
64
65
# File 'lib/arachni/utilities.rb', line 63

def links_from_response( *args )
    Link.from_response( *args )
end

#normalize_url(url) ⇒ Object



157
158
159
# File 'lib/arachni/utilities.rb', line 157

def normalize_url( url )
    URI.normalize( url )
end

#page_from_response(*args) ⇒ Object

See Also:



103
104
105
# File 'lib/arachni/utilities.rb', line 103

def page_from_response( *args )
    Page.from_response( *args )
end

#page_from_url(*args, &block) ⇒ Object

See Also:



108
109
110
# File 'lib/arachni/utilities.rb', line 108

def page_from_url( *args, &block )
    Page.from_url( *args, &block )
end


83
84
85
# File 'lib/arachni/utilities.rb', line 83

def parse_set_cookie( *args )
    Cookie.parse_set_cookie( *args )
end

#path_in_domain?(url, reference = Options.url) ⇒ Bool

Compares 2 urls in order to decide whether or not they belong to the same domain.

Parameters:

  • url (String)
  • reference (String) (defaults to: Options.url)

Returns:

  • (Bool)

    `true` if self is in the same domain as the `reference` URL, false otherwise.

See Also:



196
197
198
# File 'lib/arachni/utilities.rb', line 196

def path_in_domain?( url, reference = Options.url )
    uri_parse( url ).scope.in_domain?( reference )
end

#path_too_deep?(url) ⇒ Bool

Returns `true` is the path exceeds the framework limit, `false` otherwise.

Parameters:

Returns:

  • (Bool)

    `true` is the path exceeds the framework limit, `false` otherwise.

See Also:



182
183
184
# File 'lib/arachni/utilities.rb', line 182

def path_too_deep?( url )
    uri_parse( url ).scope.too_deep?
end

#port_available?(port) ⇒ Bool

Checks whether the port number is available.

Parameters:

  • port (Fixnum)

Returns:

  • (Bool)


383
384
385
386
387
388
389
390
391
392
# File 'lib/arachni/utilities.rb', line 383

def port_available?( port )
    begin
        socket = ::Socket.new( :INET, :STREAM, 0 )
        socket.bind( ::Socket.sockaddr_in( port, '127.0.0.1' ) )
        socket.close
        true
    rescue Errno::EADDRINUSE, Errno::EACCES
        false
    end
end

#rand_portInteger

Returns Random port within the user specified range.

Returns:

  • (Integer)

    Random port within the user specified range.

See Also:



367
368
369
370
371
372
# File 'lib/arachni/utilities.rb', line 367

def rand_port
    first, last = Options.dispatcher.instance_port_range
    range = (first..last).to_a

    range[ rand( range.last - range.first ) ]
end

#random_seedString

Returns random HEX (SHA2) string.

Returns:

  • (String)

    random HEX (SHA2) string



33
34
35
# File 'lib/arachni/utilities.rb', line 33

def random_seed
    @@random_seed ||= generate_token
end

#redundant_path?(url, update_counters = false) ⇒ Bool

Checks if the provided URL matches a redundant filter and decreases its counter if so.

If a filter's counter has reached 0 the method returns true.

Parameters:

Returns:

  • (Bool)

    `true` if the `url` is redundant, `false` otherwise.

See Also:

  • OptionGroups::Scope#redundant_path_patterns?


235
236
237
# File 'lib/arachni/utilities.rb', line 235

def redundant_path?( url, update_counters = false )
    uri_parse( url ).scope.redundant?( update_counters )
end

#regexp_array_match(regexps, str) ⇒ Object



446
447
448
449
450
451
452
453
454
# File 'lib/arachni/utilities.rb', line 446

def regexp_array_match( regexps, str )
    regexps = [regexps].flatten.compact.
        map { |s| s.is_a?( Regexp ) ? s : Regexp.new( s.to_s ) }
    return true if regexps.empty?

    cnt = 0
    regexps.each { |filter| cnt += 1 if str =~ filter }
    cnt == regexps.size
end

#remove_constants(mod, skip = []) ⇒ Object



456
457
458
459
460
461
462
463
464
465
466
467
468
# File 'lib/arachni/utilities.rb', line 456

def remove_constants( mod, skip = [] )
    return if skip.include?( mod )
    return if !(mod.is_a?( Class ) || mod.is_a?( Module )) ||
        !mod.to_s.start_with?( 'Arachni' )

    parent = Object
    mod.to_s.split( '::' )[0..-2].each do |ancestor|
        parent = parent.const_get( ancestor.to_sym )
    end

    mod.constants.each { |m| mod.send( :remove_const, m ) }
    nil
end

#request_parse_body(*args) ⇒ Object



58
59
60
# File 'lib/arachni/utilities.rb', line 58

def request_parse_body( *args )
    HTTP::Request.parse_body( *args )
end

#seconds_to_hms(seconds) ⇒ String

Returns Time in `00:00:00` (`hours:minutes:seconds`) format.

Parameters:

  • seconds (String, Float, Integer)

Returns:

  • (String)

    Time in `00:00:00` (`hours:minutes:seconds`) format.



398
399
400
401
402
# File 'lib/arachni/utilities.rb', line 398

def seconds_to_hms( seconds )
    seconds = seconds.to_i
    [seconds / 3600, seconds / 60 % 60, seconds % 60].
        map { |t| t.to_s.rjust( 2, '0' ) }.join( ':' )
end

#skip_page?(page) ⇒ Bool

Determines whether or not the given Page.

Parameters:

Returns:

See Also:



304
305
306
# File 'lib/arachni/utilities.rb', line 304

def skip_page?( page )
    page.scope.out?
end

#skip_path?(path) ⇒ Bool

Note:

Does *not* call #redundant_path?.

Decides whether or not the provided `path` should be skipped based on:

Parameters:

Returns:

  • (Bool)


266
267
268
269
270
271
272
273
# File 'lib/arachni/utilities.rb', line 266

def skip_path?( path )
    return true if !path

    parsed = uri_parse( path.to_s )
    return true if !parsed

    parsed.scope.out?
end

#skip_resource?(resource) ⇒ Bool

Determines whether or not the given `resource` should be ignored depending on its type and content.

Parameters:

  • resource (Page, Arachni::HTTP::Response, String)

    If given a:

    * {Page}: both its URL and body will be examined.
    * {Arachni::HTTP::Response}: both its effective URL and body will be examined.
    * {String}: if multi-line it will be treated as a response body,
        otherwise as a path.
    

Returns:

  • (Bool)

    `true` if the resource should be ignore,`false` otherwise.

See Also:

  • #skip_path?
  • ignore_page?
  • ignore_response?
  • Options#ignore?


328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/arachni/utilities.rb', line 328

def skip_resource?( resource )
    case resource
        when Page
            skip_page?( resource )

        when Arachni::HTTP::Response
            skip_response?( resource )

        else
            skip_path? resource.to_s
    end
end

#skip_response?(response) ⇒ Bool

Determines whether or not the given HTTP::Response should be ignored.

Parameters:

Returns:

  • (Bool)

    `true` if the `#body` of the given object matches any of the exclusion patterns, `false` otherwise.

See Also:



287
288
289
# File 'lib/arachni/utilities.rb', line 287

def skip_response?( response )
    response.scope.out?
end

#to_absolute(relative_url, reference_url = Options.instance.url.to_s) ⇒ Object



152
153
154
# File 'lib/arachni/utilities.rb', line 152

def to_absolute( relative_url, reference_url = Options.instance.url.to_s )
    URI.to_absolute( relative_url, reference_url )
end

#uri_decode(url) ⇒ Object



138
139
140
# File 'lib/arachni/utilities.rb', line 138

def uri_decode( url )
    URI.decode( url )
end

#uri_encode(*args) ⇒ Object



133
134
135
# File 'lib/arachni/utilities.rb', line 133

def uri_encode( *args )
    URI.encode( *args )
end

#uri_parse(url) ⇒ Object

See Also:



128
129
130
# File 'lib/arachni/utilities.rb', line 128

def uri_parse( url )
    URI.parse( url )
end

#uri_parse_query(url) ⇒ Object



147
148
149
# File 'lib/arachni/utilities.rb', line 147

def uri_parse_query( url )
    URI.parse_query( url )
end

#uri_parserURI::Parser

Returns cached URI parser.

Returns:

  • (URI::Parser)

    cached URI parser



123
124
125
# File 'lib/arachni/utilities.rb', line 123

def uri_parser
    URI.parser
end

#uri_rewrite(*args) ⇒ Object



142
143
144
# File 'lib/arachni/utilities.rb', line 142

def uri_rewrite( *args )
    URI.rewrite( *args )
end