Class: Metasploit::Framework::LoginScanner::SonicWall

Inherits:
HTTP
  • Object
show all
Defined in:
lib/metasploit/framework/login_scanner/sonicwall.rb

Overview

SonicWall Login Scanner supporting

  • User Login

  • Admin Login

Constant Summary collapse

DEFAULT_SSL_PORT =
[443, 4433]
LIKELY_PORTS =
[443, 4433]
LIKELY_SERVICE_NAMES =
[
  'SonicWall Network Security'
]
PRIVATE_TYPES =
[:password]
REALM_KEY =
nil

Constants inherited from HTTP

HTTP::AUTHORIZATION_HEADER, HTTP::DEFAULT_HTTP_NOT_AUTHED_CODES, HTTP::DEFAULT_HTTP_SUCCESS_CODES, HTTP::DEFAULT_PORT, HTTP::DEFAULT_REALM

Instance Attribute Summary

Attributes inherited from HTTP

#digest_auth_iis, #evade_header_folding, #evade_method_random_case, #evade_method_random_invalid, #evade_method_random_valid, #evade_pad_fake_headers, #evade_pad_fake_headers_count, #evade_pad_get_params, #evade_pad_get_params_count, #evade_pad_method_uri_count, #evade_pad_method_uri_type, #evade_pad_post_params, #evade_pad_post_params_count, #evade_pad_uri_version_count, #evade_pad_uri_version_type, #evade_shuffle_get_params, #evade_shuffle_post_params, #evade_uri_dir_fake_relative, #evade_uri_dir_self_reference, #evade_uri_encode_mode, #evade_uri_fake_end, #evade_uri_fake_params_start, #evade_uri_full_url, #evade_uri_use_backslashes, #evade_version_random_invalid, #evade_version_random_valid, #http_password, #http_success_codes, #http_username, #keep_connection_alive, #kerberos_authenticator_factory, #method, #ntlm_domain, #ntlm_send_lm, #ntlm_send_ntlm, #ntlm_send_spn, #ntlm_use_lm_key, #ntlm_use_ntlmv2, #ntlm_use_ntlmv2_session, #uri, #user_agent, #vhost

Instance Method Summary collapse

Methods inherited from HTTP

#authentication_required?, #send_request

Constructor Details

#initialize(scanner_config, domain) ⇒ SonicWall

Returns a new instance of SonicWall.



19
20
21
22
# File 'lib/metasploit/framework/login_scanner/sonicwall.rb', line 19

def initialize(scanner_config, domain)
  @domain = domain
  super(scanner_config)
end

Instance Method Details

#attempt_login(credential) ⇒ Object



139
140
141
142
143
144
145
146
147
148
149
# File 'lib/metasploit/framework/login_scanner/sonicwall.rb', line 139

def (credential)
  result_options = {
    credential: credential,
    host: @host,
    port: @port,
    protocol: 'tcp',
    service_name: 'sonicwall'
  }
  result_options.merge!((credential.public, credential.private, 1))
  Result.new(result_options)
end

#auth_details_reqObject



34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/metasploit/framework/login_scanner/sonicwall.rb', line 34

def auth_details_req
  params = req_params_base

  #
  # Admin and SSLVPN user login procedure differs only in usage of domain field in JSON data
  #
  params.merge!({
    'data' => JSON.pretty_generate(@domain.empty? ? {
      'override' => false,
      'snwl' => true
    } : { 'domain' => @domain, 'override' => false, 'snwl' => true })
  })
  return params
end

#auth_req(header) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/metasploit/framework/login_scanner/sonicwall.rb', line 49

def auth_req(header)
  params = req_params_base

  params.merge!({
    'headers' =>
    {
      'Authorization' => header.join(', ')
    }
  })

  params.merge!({
    'data' => JSON.pretty_generate(@domain.empty? ? {
      'override' => false,
      'snwl' => true
    } : { 'domain' => @domain, 'override' => false, 'snwl' => true })
  })

  return params
end

#check_setupObject



81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/metasploit/framework/login_scanner/sonicwall.rb', line 81

def check_setup
  request_params = {
    'method' => 'GET',
    'uri' => normalize_uri('/sonicui/7/login/')
  }
  res = send_request(request_params)
  if res&.code == 200 && res.body&.include?('SonicWall')
    return false
  end

  'Unable to locate "SonicWall" in body. (Is this really SonicWall?)'
end

#do_login(username, password, depth) ⇒ Object

The login procedure is two-step procedure for SonicWall due to HTTP Digest Authentication. In the first request, client receives data,cryptographic hashes and algorithm selection from server. It should calculate final response hash from username, password and additional data received from server. The second request contains all this information.



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/metasploit/framework/login_scanner/sonicwall.rb', line 97

def (username, password, depth)
  return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Waiting too long in lockout' } if depth >= 2

  #-- get authentication details from first request
  res = get_auth_details(username, password)

  return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Invalid response' } unless res
  return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Failed to receive a authentication details' } unless res&.headers && res.headers.key?('X-SNWL-Authenticate')

  res.headers['X-SNWL-Authenticate'] =~ /Digest (.*)/

  parameters = {}
  ::Regexp.last_match(1).split(/,[[:space:]]*/).each do |p|
    k, v = p.split('=', 2)
    parameters[k] = v.gsub('"', '')
  end
  return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Incorrect authentication header' } if parameters.empty?

  digest_auth = Rex::Proto::Http::AuthDigest.new
  auth_header = digest_auth.digest(username, password, 'POST', '/api/sonicos/auth', parameters)
  return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Could not calculate hash' } unless auth_header

  #-- send the actual request with all hashes and information

  res = (auth_header)

  return { status: ::Metasploit::Model::Login::Status::SUCCESSFUL, proof: res.to_s } if res&.code == 200


  msg_json = res.get_json_document

  return { status: ::Metasploit::Model::Login::Status::INCORRECT, proof: res.to_s } unless msg_json
  msg = get_resp_msg(msg_json)

  if msg == 'User is locked out'
    sleep(5 * 60)
    return (username, password, depth + 1)
  end

  return { status: ::Metasploit::Model::Login::Status::INCORRECT, proof: msg }
end

#get_auth_details(username, password) ⇒ Object



69
70
71
# File 'lib/metasploit/framework/login_scanner/sonicwall.rb', line 69

def get_auth_details(username, password)
  send_request(auth_details_req)
end

#get_resp_msg(msg) ⇒ Object



77
78
79
# File 'lib/metasploit/framework/login_scanner/sonicwall.rb', line 77

def get_resp_msg(msg)
  msg.dig('status', 'info', 0, 'message')
end

#req_params_baseObject



24
25
26
27
28
29
30
31
32
# File 'lib/metasploit/framework/login_scanner/sonicwall.rb', line 24

def req_params_base
  {
    'method' => 'POST',
    'uri' => normalize_uri('/api/sonicos/auth'),
    'ctype' => 'application/json',
    # Force SSL as the application uses non-standard TCP port for HTTPS - 4433
    'ssl' => true
  }
end

#try_login(header) ⇒ Object



73
74
75
# File 'lib/metasploit/framework/login_scanner/sonicwall.rb', line 73

def (header)
  send_request(auth_req(header))
end