Class: CMSScanner::Controller::Core

Inherits:
Base
  • Object
show all
Defined in:
app/controllers/core.rb,
app/controllers/core/cli_options.rb

Overview

CLI Options for the Core Controller

Instance Method Summary collapse

Methods inherited from Base

#==, #datastore, #formatter, #output, #parsed_options, parsed_options=, #render, reset, #target, #tmp_directory, #user_interaction?

Instance Method Details

#after_scanObject



59
60
61
62
63
64
65
66
# File 'app/controllers/core.rb', line 59

def after_scan
  @stop_time     = Time.now
  @elapsed       = @stop_time - @start_time
  @used_memory   = memory_usage - @start_memory
  @requests_done = CMSScanner.total_requests

  output('finished')
end

#before_scan(output_banner = true) ⇒ Object



16
17
18
19
20
21
22
# File 'app/controllers/core.rb', line 16

def before_scan(output_banner = true)
  output('banner') if output_banner

  setup_cache

  check_target_availability
end

#check_target_availabilityVoid

Checks that the target is accessible, raises related errors otherwise

Returns:

  • (Void)


27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'app/controllers/core.rb', line 27

def check_target_availability
  res = NS::Browser.get(target.url)

  case res.code
  when 0
    fail TargetDownError, res
  when 401
    fail HTTPAuthRequiredError
  when 403
    fail AccessForbiddenError
  when 407
    fail ProxyAuthRequiredError
  end

  # Checks for redirects
  # An out of scope redirect will raise an HTTPRedirectError
  effective_url = target.homepage_res.effective_url

  return if target.in_scope?(effective_url)

  fail HTTPRedirectError, effective_url unless parsed_options[:ignore_main_redirect]

  target.homepage_res = res
end

#cli_browser_cache_optionsArray<OptParseValidator::OptBase>

Returns:

  • (Array<OptParseValidator::OptBase>)


69
70
71
72
73
74
75
76
77
78
# File 'app/controllers/core/cli_options.rb', line 69

def cli_browser_cache_options
  [
    OptInteger.new(['--cache-ttl TIME_TO_LIVE', 'The cache time to live in seconds'], default: 600),
    OptBoolean.new(['--clear-cache', 'Clear the cache before the scan']),
    OptDirectoryPath.new(['--cache-dir PATH'],
                         readable: true,
                         writable: true,
                         default: File.join(tmp_directory, 'cache'))
  ]
end

#cli_browser_cookies_optionsArray<OptParseValidator::OptBase>

Returns:

  • (Array<OptParseValidator::OptBase>)


56
57
58
59
60
61
62
63
64
65
66
# File 'app/controllers/core/cli_options.rb', line 56

def cli_browser_cookies_options
  [
    OptString.new(['--cookie-string COOKIE',
                   'Cookie string to use in requests, ' \
                   'format: cookie1=value1[; cookie2=value2]']),
    OptFilePath.new(['--cookie-jar FILE-PATH', 'File to read and write cookies'],
                    writable: true,
                    exists: false,
                    default: File.join(tmp_directory, 'cookie_jar.txt'))
  ]
end

#cli_browser_optionsArray<OptParseValidator::OptBase>

Returns:

  • (Array<OptParseValidator::OptBase>)


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'app/controllers/core/cli_options.rb', line 26

def cli_browser_options
  [
    OptString.new(['--user-agent VALUE', '--ua']),
    OptString.new(['--vhost VALUE', 'The virtual host (Host header) to use in requests']),
    OptBoolean.new(['--random-user-agent', '--rua',
                    'Use a random user-agent for each scan']),
    OptFilePath.new(['--user-agents-list FILE-PATH',
                     'List of agents to use with --random-user-agent'], exists: true),
    OptCredentials.new(['--http-auth login:password']),
    OptPositiveInteger.new(['--max-threads VALUE', '-t', 'The max threads to use'],
                           default: 5),
    OptPositiveInteger.new(['--throttle MilliSeconds', 'Milliseconds to wait before doing another web request. ' \
                            'If used, the max threads will be set to 1.']),
    OptPositiveInteger.new(['--request-timeout SECONDS', 'The request timeout in seconds'],
                           default: 60),
    OptPositiveInteger.new(['--connect-timeout SECONDS', 'The connection timeout in seconds'],
                           default: 30)
  ] + cli_browser_proxy_options + cli_browser_cookies_options + cli_browser_cache_options
end

#cli_browser_proxy_optionsArray<OptParseValidator::OptBase>

Returns:

  • (Array<OptParseValidator::OptBase>)


47
48
49
50
51
52
53
# File 'app/controllers/core/cli_options.rb', line 47

def cli_browser_proxy_options
  [
    OptProxy.new(['--proxy protocol://IP:port',
                  'Supported protocols depend on the cURL installed']),
    OptCredentials.new(['--proxy-auth login:password'])
  ]
end

#cli_optionsObject



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'app/controllers/core/cli_options.rb', line 5

def cli_options
  formats = NS::Formatter.availables

  [
    OptURL.new(['-u', '--url URL', 'The URL to scan'], required: true, default_protocol: 'http'),
    OptBoolean.new(['--ignore-main-redirect', 'Ignore the main redirect if any and scan the target url']),
    OptBoolean.new(%w(-v --verbose)),
    OptFilePath.new(['-o', '--output FILE', 'Output to FILE'], writable: true, exists: false),
    OptChoice.new(['-f', '--format FORMAT',
                   'Output results in the format supplied'], choices: formats),
    OptChoice.new(['--detection-mode MODE'],
                  choices: %w(mixed passive aggressive),
                  normalize: :to_sym,
                  default: :mixed),
    OptArray.new(['--scope DOMAINS',
                  'Comma separated (sub-)domains to consider in scope. ',
                  'Wildcard(s) allowed in the trd of valid domains, e.g: *.target.tld'])
  ] + cli_browser_options
end

#runObject



52
53
54
55
56
57
# File 'app/controllers/core.rb', line 52

def run
  @start_time   = Time.now
  @start_memory = memory_usage

  output('started', url: target.url, effective_url: target.homepage_url)
end

#setup_cacheObject



7
8
9
10
11
12
13
14
# File 'app/controllers/core.rb', line 7

def setup_cache
  return unless parsed_options[:cache_dir]

  storage_path = File.join(parsed_options[:cache_dir], Digest::MD5.hexdigest(target.url))

  Typhoeus::Config.cache = Cache::Typhoeus.new(storage_path)
  Typhoeus::Config.cache.clean if parsed_options[:clear_cache]
end