Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/metasploit/framework/login_scanner/kerberos.rb
28052 views
1
require 'metasploit/framework/login_scanner/base'
2
3
module Metasploit
4
module Framework
5
module LoginScanner
6
7
# Kerberos User scanner
8
class Kerberos
9
include Metasploit::Framework::LoginScanner::Base
10
include Msf::Exploit::Remote::Kerberos::Client
11
12
DEFAULT_PORT = 88
13
REALM_KEY = Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN
14
DEFAULT_REALM = nil
15
LIKELY_PORTS = [ DEFAULT_PORT ].freeze
16
LIKELY_SERVICE_NAMES = [ 'kerberos', 'kerberos5', 'krb5', 'kerberos-sec' ].freeze
17
PRIVATE_TYPES = %i[ password ].freeze
18
CAN_GET_SESSION = true
19
20
def attempt_login(credential)
21
result_options = {
22
credential: credential,
23
host: host,
24
port: port,
25
protocol: 'tcp',
26
service_name: 'kerberos'
27
}
28
29
begin
30
res = send_request_tgt(
31
server_name: server_name,
32
client_name: credential.public,
33
password: credential.private,
34
realm: credential.realm
35
)
36
unless res.preauth_required
37
# Pre-auth not required - let's get an RC4-HMAC ticket, since it's more easily crackable
38
begin
39
res = send_request_tgt(
40
server_name: server_name,
41
client_name: credential.public,
42
password: credential.private,
43
realm: credential.realm,
44
offered_etypes: [Rex::Proto::Kerberos::Crypto::Encryption::RC4_HMAC]
45
)
46
rescue Rex::Proto::Kerberos::Model::Error::KerberosEncryptionNotSupported => e
47
# RC4 likely disabled - let's just use the initial response
48
end
49
end
50
51
result_options = result_options.merge(
52
{
53
status: Metasploit::Model::Login::Status::SUCCESSFUL,
54
proof: res
55
}
56
)
57
return Metasploit::Framework::LoginScanner::Result.new(result_options)
58
rescue ::EOFError => e
59
result_options = result_options.merge({ status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e })
60
return Metasploit::Framework::LoginScanner::Result.new(result_options)
61
rescue Rex::Proto::Kerberos::Model::Error::KerberosError => e
62
status = self.class.login_status_for_kerberos_error(e)
63
result_options = result_options.merge({ status: status, proof: e })
64
return Metasploit::Framework::LoginScanner::Result.new(result_options)
65
end
66
end
67
68
attr_accessor :server_name
69
70
# Override the kerberos client's methods with the login scanner implementations
71
alias rhost host
72
alias rport port
73
alias timeout connection_timeout
74
75
# @param [Rex::Proto::Kerberos::Model::Error::KerberosError] krb_err The kerberos error
76
def self.login_status_for_kerberos_error(krb_err)
77
error_code = krb_err.error_code
78
case error_code
79
when Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_KEY_EXPIRED, Rex::Proto::Kerberos::Model::Error::ErrorCodes::KRB_AP_ERR_SKEW
80
# Correct password, but either password needs resetting or clock is skewed
81
begin
82
pa_data_entry = krb_err.res.e_data_as_pa_data.find do |pa_data|
83
pa_data.type == Rex::Proto::Kerberos::Model::PreAuthType::PA_PW_SALT
84
end
85
86
if pa_data_entry
87
pw_salt = pa_data_entry.decoded_value
88
if pw_salt.nt_status
89
case pw_salt.nt_status.value
90
when ::WindowsError::NTStatus::STATUS_PASSWORD_EXPIRED
91
# Windows Server 2019 Build 17763 (possibly others) replies with STATUS_PASSWORD_EXPIRED even when the password is incorrect
92
Metasploit::Model::Login::Status::INCORRECT
93
else
94
Metasploit::Model::Login::Status::SUCCESSFUL
95
end
96
else
97
Metasploit::Model::Login::Status::SUCCESSFUL
98
end
99
else
100
Metasploit::Model::Login::Status::SUCCESSFUL
101
end
102
rescue Rex::Proto::Kerberos::Model::Error::KerberosDecodingError
103
Metasploit::Model::Login::Status::SUCCESSFUL
104
end
105
when Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_C_PRINCIPAL_UNKNOWN
106
# The username doesn't exist
107
Metasploit::Model::Login::Status::INVALID_PUBLIC_PART
108
when Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_CLIENT_REVOKED
109
# Locked out, disabled or expired
110
# It doesn't appear to be documented anywhere, but Microsoft gives us a bit
111
# of extra information in the e-data section
112
begin
113
pa_data_entry = krb_err.res.e_data_as_pa_data.find do |pa_data|
114
pa_data.type == Rex::Proto::Kerberos::Model::PreAuthType::PA_PW_SALT
115
end
116
117
if pa_data_entry
118
pw_salt = pa_data_entry.decoded_value
119
if pw_salt.nt_status
120
case pw_salt.nt_status.value
121
when ::WindowsError::NTStatus::STATUS_ACCOUNT_LOCKED_OUT
122
Metasploit::Model::Login::Status::LOCKED_OUT
123
when ::WindowsError::NTStatus::STATUS_ACCOUNT_DISABLED
124
Metasploit::Model::Login::Status::DISABLED
125
when ::WindowsError::NTStatus::STATUS_ACCOUNT_EXPIRED
126
# Actually expired, which is effectively Disabled
127
Metasploit::Model::Login::Status::DISABLED
128
else
129
# Unknown - maintain existing behaviour
130
Metasploit::Model::Login::Status::DISABLED
131
end
132
else
133
Metasploit::Model::Login::Status::DISABLED
134
end
135
else
136
Metasploit::Model::Login::Status::DISABLED
137
end
138
rescue Rex::Proto::Kerberos::Model::Error::KerberosDecodingError
139
# Could be a non-MS implementation?
140
Metasploit::Model::Login::Status::DISABLED
141
end
142
else
143
Metasploit::Model::Login::Status::INCORRECT
144
end
145
end
146
147
private
148
149
def set_sane_defaults
150
self.connection_timeout = 10 if self.connection_timeout.nil?
151
self.port = DEFAULT_PORT unless self.port
152
end
153
154
def print_status(*args)
155
framework_module.print_status(*args) if framework_module
156
end
157
158
def print_good(*args)
159
framework_module.print_good(*args) if framework_module
160
end
161
162
def vprint_status(*args)
163
framework_module.vprint_status(*args) if framework_module
164
end
165
end
166
end
167
end
168
end
169
170