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
32979 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
self.kerberos_clock_skew = clock_skew if clock_skew
31
res = send_request_tgt(
32
server_name: server_name,
33
client_name: credential.public,
34
password: credential.private,
35
realm: credential.realm
36
)
37
unless res.preauth_required
38
# Pre-auth not required - let's get an RC4-HMAC ticket, since it's more easily crackable
39
begin
40
res = send_request_tgt(
41
server_name: server_name,
42
client_name: credential.public,
43
password: credential.private,
44
realm: credential.realm,
45
offered_etypes: [Rex::Proto::Kerberos::Crypto::Encryption::RC4_HMAC]
46
)
47
rescue Rex::Proto::Kerberos::Model::Error::KerberosEncryptionNotSupported => e
48
# RC4 likely disabled - let's just use the initial response
49
end
50
end
51
52
result_options = result_options.merge(
53
{
54
status: Metasploit::Model::Login::Status::SUCCESSFUL,
55
proof: res
56
}
57
)
58
return Metasploit::Framework::LoginScanner::Result.new(result_options)
59
rescue ::EOFError => e
60
result_options = result_options.merge({ status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e })
61
return Metasploit::Framework::LoginScanner::Result.new(result_options)
62
rescue Rex::Proto::Kerberos::Model::Error::KerberosError => e
63
status = self.class.login_status_for_kerberos_error(e)
64
result_options = result_options.merge({ status: status, proof: e })
65
return Metasploit::Framework::LoginScanner::Result.new(result_options)
66
end
67
end
68
69
attr_accessor :server_name
70
attr_accessor :clock_skew
71
72
# Override the kerberos client's methods with the login scanner implementations
73
alias rhost host
74
alias rport port
75
alias timeout connection_timeout
76
77
# @param [Rex::Proto::Kerberos::Model::Error::KerberosError] krb_err The kerberos error
78
def self.login_status_for_kerberos_error(krb_err)
79
error_code = krb_err.error_code
80
case error_code
81
when Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_KEY_EXPIRED, Rex::Proto::Kerberos::Model::Error::ErrorCodes::KRB_AP_ERR_SKEW
82
# Correct password, but either password needs resetting or clock is skewed
83
begin
84
pa_data_entry = krb_err.res.e_data_as_pa_data.find do |pa_data|
85
pa_data.type == Rex::Proto::Kerberos::Model::PreAuthType::PA_PW_SALT
86
end
87
88
if pa_data_entry
89
pw_salt = pa_data_entry.decoded_value
90
if pw_salt.nt_status
91
case pw_salt.nt_status.value
92
when ::WindowsError::NTStatus::STATUS_PASSWORD_EXPIRED
93
# Windows Server 2019 Build 17763 (possibly others) replies with STATUS_PASSWORD_EXPIRED even when the password is incorrect
94
Metasploit::Model::Login::Status::INCORRECT
95
else
96
Metasploit::Model::Login::Status::SUCCESSFUL
97
end
98
else
99
Metasploit::Model::Login::Status::SUCCESSFUL
100
end
101
else
102
Metasploit::Model::Login::Status::SUCCESSFUL
103
end
104
rescue Rex::Proto::Kerberos::Model::Error::KerberosDecodingError
105
Metasploit::Model::Login::Status::SUCCESSFUL
106
end
107
when Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_C_PRINCIPAL_UNKNOWN
108
# The username doesn't exist
109
Metasploit::Model::Login::Status::INVALID_PUBLIC_PART
110
when Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_CLIENT_REVOKED
111
# Locked out, disabled or expired
112
# It doesn't appear to be documented anywhere, but Microsoft gives us a bit
113
# of extra information in the e-data section
114
begin
115
pa_data_entry = krb_err.res.e_data_as_pa_data.find do |pa_data|
116
pa_data.type == Rex::Proto::Kerberos::Model::PreAuthType::PA_PW_SALT
117
end
118
119
if pa_data_entry
120
pw_salt = pa_data_entry.decoded_value
121
if pw_salt.nt_status
122
case pw_salt.nt_status.value
123
when ::WindowsError::NTStatus::STATUS_ACCOUNT_LOCKED_OUT
124
Metasploit::Model::Login::Status::LOCKED_OUT
125
when ::WindowsError::NTStatus::STATUS_ACCOUNT_DISABLED
126
Metasploit::Model::Login::Status::DISABLED
127
when ::WindowsError::NTStatus::STATUS_ACCOUNT_EXPIRED
128
# Actually expired, which is effectively Disabled
129
Metasploit::Model::Login::Status::DISABLED
130
else
131
# Unknown - maintain existing behaviour
132
Metasploit::Model::Login::Status::DISABLED
133
end
134
else
135
Metasploit::Model::Login::Status::DISABLED
136
end
137
else
138
Metasploit::Model::Login::Status::DISABLED
139
end
140
rescue Rex::Proto::Kerberos::Model::Error::KerberosDecodingError
141
# Could be a non-MS implementation?
142
Metasploit::Model::Login::Status::DISABLED
143
end
144
else
145
Metasploit::Model::Login::Status::INCORRECT
146
end
147
end
148
149
private
150
151
def set_sane_defaults
152
self.connection_timeout = 10 if self.connection_timeout.nil?
153
self.port = DEFAULT_PORT unless self.port
154
end
155
156
def print_status(*args)
157
framework_module.print_status(*args) if framework_module
158
end
159
160
def print_good(*args)
161
framework_module.print_good(*args) if framework_module
162
end
163
164
def vprint_status(*args)
165
framework_module.vprint_status(*args) if framework_module
166
end
167
end
168
end
169
end
170
end
171
172