CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/metasploit/framework/credential_collection.rb
Views: 1904
1
require 'metasploit/framework/credential'
2
3
module Metasploit::Framework
4
5
class PrivateCredentialCollection
6
# @!attribute additional_privates
7
# Additional private values that should be tried
8
# @return [Array<String>]
9
attr_accessor :additional_privates
10
11
# @!attribute blank_passwords
12
# Whether each username should be tried with a blank password
13
# @return [Boolean]
14
attr_accessor :blank_passwords
15
16
# @!attribute nil_passwords
17
# Whether each username should be tried with a nil password
18
# @return [Boolean]
19
attr_accessor :nil_passwords
20
21
# @!attribute pass_file
22
# Path to a file containing passwords, one per line
23
# @return [String]
24
attr_accessor :pass_file
25
26
# @!attribute password
27
# The password that should be tried
28
# @return [String]
29
attr_accessor :password
30
31
# @!attribute prepended_creds
32
# List of credentials to be tried before any others
33
#
34
# @see #prepend_cred
35
# @return [Array<Credential>]
36
attr_accessor :prepended_creds
37
38
# @!attribute realm
39
# The authentication realm associated with this password
40
# @return [String]
41
attr_accessor :realm
42
43
# @!attribute filter
44
# A block that can be used to filter credential objects
45
attr_accessor :filter
46
47
# @option opts [Boolean] :nil_passwords See {#nil_passwords}
48
# @option opts [Boolean] :blank_passwords See {#blank_passwords}
49
# @option opts [String] :pass_file See {#pass_file}
50
# @option opts [String] :password See {#password}
51
# @option opts [Array<Credential>] :prepended_creds ([]) See {#prepended_creds}
52
# @option opts [Boolean] :user_as_pass See {#user_as_pass}
53
# @option opts [String] :user_file See {#user_file}
54
# @option opts [String] :username See {#username}
55
# @option opts [String] :userpass_file See {#userpass_file}
56
# @option opts [String] :usernames_only See {#usernames_only}
57
def initialize(opts = {})
58
opts.each do |attribute, value|
59
public_send("#{attribute}=", value)
60
end
61
self.prepended_creds ||= []
62
self.additional_privates ||= []
63
self.filter = nil
64
end
65
66
# Adds a string as an additional private credential
67
# to be combined in the collection.
68
#
69
# @param [String] private_str The string to use as a private credential
70
# @return [void]
71
def add_private(private_str='')
72
additional_privates << private_str
73
end
74
75
# Add {Credential credentials} that will be yielded by {#each}
76
#
77
# @see prepended_creds
78
# @param [Credential] cred
79
# @return [self]
80
def prepend_cred(cred)
81
prepended_creds.unshift cred
82
self
83
end
84
85
# Combines all the provided credential sources into a stream of {Credential}
86
# objects, yielding them one at a time
87
#
88
# @yieldparam credential [Metasploit::Framework::Credential]
89
# @return [void]
90
def each_filtered
91
each_unfiltered do |credential|
92
next unless self.filter.nil? || self.filter.call(credential)
93
94
yield credential
95
end
96
end
97
98
# Combines all the provided credential sources into a stream of {Credential}
99
# objects, yielding them one at a time
100
#
101
# @yieldparam credential [Metasploit::Framework::Credential]
102
# @return [void]
103
def each_unfiltered
104
if pass_file.present?
105
pass_fd = File.open(pass_file, 'r:binary')
106
end
107
108
prepended_creds.each { |c| yield c }
109
110
if password.present?
111
yield Metasploit::Framework::Credential.new(private: password, realm: realm, private_type: private_type(password))
112
end
113
if blank_passwords
114
yield Metasploit::Framework::Credential.new(private: "", realm: realm, private_type: :password)
115
end
116
if nil_passwords
117
yield Metasploit::Framework::Credential.new(private: nil, realm: realm, private_type: :password)
118
end
119
if pass_fd
120
pass_fd.each_line do |pass_from_file|
121
pass_from_file.chomp!
122
yield Metasploit::Framework::Credential.new(private: pass_from_file, realm: realm, private_type: private_type(pass_from_file))
123
end
124
pass_fd.seek(0)
125
end
126
additional_privates.each do |add_private|
127
yield Metasploit::Framework::Credential.new(private: add_private, realm: realm, private_type: private_type(add_private))
128
end
129
130
ensure
131
pass_fd.close if pass_fd && !pass_fd.closed?
132
end
133
134
# Returns true when #each will have no results to iterate
135
#
136
# @return [Boolean]
137
def empty?
138
prepended_creds.empty? && !has_privates?
139
end
140
141
# Returns true when a filter is defined
142
#
143
# @return [Boolean]
144
def filtered?
145
!self.filter.nil?
146
end
147
148
# Returns true when there are any private values set
149
#
150
# @return [Boolean]
151
def has_privates?
152
password.present? || pass_file.present? || !additional_privates.empty? || blank_passwords || nil_passwords
153
end
154
155
alias each each_filtered
156
157
protected
158
159
# Analyze a private value to determine its type by checking it against a known list of regular expressions
160
#
161
# @param [String] private The string to analyze
162
# @return [Symbol]
163
def private_type(private)
164
if private =~ /[0-9a-f]{32}:[0-9a-f]{32}/
165
:ntlm_hash
166
elsif private =~ /^md5([a-f0-9]{32})$/
167
:postgres_md5
168
else
169
:password
170
end
171
end
172
end
173
174
class CredentialCollection < PrivateCredentialCollection
175
# @!attribute password_spray
176
# Whether password spray is enabled. When true, each password is tried against each username first.
177
# Otherwise the default bruteforce logic will attempt all passwords against the first user, before
178
# continuing to the next user
179
#
180
# @return [Boolean]
181
attr_accessor :password_spray
182
183
# @!attribute additional_publics
184
# Additional public values that should be tried
185
#
186
# @return [Array<String>]
187
attr_accessor :additional_publics
188
189
# @!attribute user_as_pass
190
# Whether each username should be tried as a password for that user
191
# @return [Boolean]
192
attr_accessor :user_as_pass
193
194
# @!attribute user_file
195
# Path to a file containing usernames, one per line
196
# @return [String]
197
attr_accessor :user_file
198
199
# @!attribute username
200
# The username that should be tried
201
# @return [String]
202
attr_accessor :username
203
204
# @!attribute userpass_file
205
# Path to a file containing usernames and passwords separated by a space,
206
# one pair per line
207
# @return [String]
208
attr_accessor :userpass_file
209
210
# @!attribute anonymous_login
211
# Whether to attempt an anonymous login (blank user/pass)
212
# @return [Boolean]
213
attr_accessor :anonymous_login
214
215
# @option opts [Boolean] :blank_passwords See {#blank_passwords}
216
# @option opts [String] :pass_file See {#pass_file}
217
# @option opts [String] :password See {#password}
218
# @option opts [Array<Credential>] :prepended_creds ([]) See {#prepended_creds}
219
# @option opts [Boolean] :user_as_pass See {#user_as_pass}
220
# @option opts [String] :user_file See {#user_file}
221
# @option opts [String] :username See {#username}
222
# @option opts [String] :userpass_file See {#userpass_file}
223
def initialize(opts = {})
224
super
225
self.additional_publics ||= []
226
end
227
228
# Adds a string as an additional public credential
229
# to be combined in the collection.
230
#
231
# @param [String] public_str The string to use as a public credential
232
# @return [void]
233
def add_public(public_str='')
234
additional_publics << public_str
235
end
236
237
# Combines all the provided credential sources into a stream of {Credential}
238
# objects, yielding them one at a time
239
#
240
# @yieldparam credential [Metasploit::Framework::Credential]
241
# @return [void]
242
def each_filtered
243
if password_spray
244
each_unfiltered_password_first do |credential|
245
next unless self.filter.nil? || self.filter.call(credential)
246
247
yield credential
248
end
249
else
250
each_unfiltered_username_first do |credential|
251
next unless self.filter.nil? || self.filter.call(credential)
252
253
yield credential
254
end
255
end
256
end
257
258
alias each each_filtered
259
260
# When password spraying is enabled, do first passwords then usernames
261
# i.e.
262
# username1:password1
263
# username2:password1
264
# username3:password1
265
# ...
266
# username1:password2
267
# username2:password2
268
# username3:password2
269
# ...
270
# @yieldparam credential [Metasploit::Framework::Credential]
271
# @return [void]
272
def each_unfiltered_password_first
273
if user_file.present?
274
user_fd = File.open(user_file, 'r:binary')
275
end
276
277
prepended_creds.each { |c| yield c }
278
279
if anonymous_login
280
yield Metasploit::Framework::Credential.new(public: '', private: '', realm: realm, private_type: :password)
281
end
282
283
if password.present?
284
if nil_passwords
285
yield Metasploit::Framework::Credential.new(public: username, private: nil, realm: realm, private_type: :password)
286
end
287
if username.present?
288
yield Metasploit::Framework::Credential.new(public: username, private: password, realm: realm, private_type: private_type(password))
289
end
290
if user_as_pass
291
yield Metasploit::Framework::Credential.new(public: username, private: username, realm: realm, private_type: :password)
292
end
293
if blank_passwords
294
yield Metasploit::Framework::Credential.new(public: username, private: "", realm: realm, private_type: :password)
295
end
296
if user_fd
297
user_fd.each_line do |user_from_file|
298
user_from_file.chomp!
299
yield Metasploit::Framework::Credential.new(public: user_from_file, private: password, realm: realm, private_type: private_type(password))
300
end
301
user_fd.seek(0)
302
end
303
end
304
305
if pass_file.present?
306
File.open(pass_file, 'r:binary') do |pass_fd|
307
pass_fd.each_line do |pass_from_file|
308
pass_from_file.chomp!
309
if username.present?
310
yield Metasploit::Framework::Credential.new(public: username, private: pass_from_file, realm: realm, private_type: :password)
311
end
312
if user_as_pass
313
yield Metasploit::Framework::Credential.new(public: pass_from_file, private: pass_from_file, realm: realm, private_type: :password)
314
end
315
next unless user_fd
316
317
user_fd.each_line do |user_from_file|
318
user_from_file.chomp!
319
yield Metasploit::Framework::Credential.new(public: user_from_file, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file))
320
end
321
user_fd.seek(0)
322
end
323
end
324
end
325
326
if userpass_file.present?
327
File.open(userpass_file, 'r:binary') do |userpass_fd|
328
userpass_fd.each_line do |line|
329
user, pass = line.split(" ", 2)
330
if pass.blank?
331
pass = ''
332
else
333
pass.chomp!
334
end
335
yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm)
336
end
337
end
338
end
339
340
additional_privates.each do |add_private|
341
if username.present?
342
yield Metasploit::Framework::Credential.new(public: username, private: add_private, realm: realm, private_type: private_type(add_private))
343
end
344
user_fd.each_line do |user_from_file|
345
user_from_file.chomp!
346
yield Metasploit::Framework::Credential.new(public: user_from_file, private: add_private, realm: realm, private_type: private_type(add_private))
347
end
348
user_fd.seek(0)
349
end
350
351
additional_publics.each do |add_public|
352
if password.present?
353
yield Metasploit::Framework::Credential.new(public: add_public, private: password, realm: realm, private_type: private_type(password) )
354
end
355
if user_as_pass
356
yield Metasploit::Framework::Credential.new(public: add_public, private: user_from_file, realm: realm, private_type: :password)
357
end
358
if blank_passwords
359
yield Metasploit::Framework::Credential.new(public: add_public, private: "", realm: realm, private_type: :password)
360
end
361
if nil_passwords
362
yield Metasploit::Framework::Credential.new(public: add_public, private: nil, realm: realm, private_type: :password)
363
end
364
if user_fd
365
user_fd.each_line do |user_from_file|
366
user_from_file.chomp!
367
yield Metasploit::Framework::Credential.new(public: add_public, private: user_from_file, realm: realm, private_type: private_type(user_from_file))
368
end
369
user_fd.seek(0)
370
end
371
additional_privates.each do |add_private|
372
yield Metasploit::Framework::Credential.new(public: add_public, private: add_private, realm: realm, private_type: private_type(add_private))
373
end
374
end
375
ensure
376
user_fd.close if user_fd && !user_fd.closed?
377
end
378
379
# When password spraying is not enabled, do first usernames then passwords
380
# i.e.
381
# username1:password1
382
# username1:password2
383
# username1:password3
384
# ...
385
# username2:password1
386
# username2:password2
387
# username2:password3
388
# @yieldparam credential [Metasploit::Framework::Credential]
389
# @return [void]
390
def each_unfiltered_username_first
391
if pass_file.present?
392
pass_fd = File.open(pass_file, 'r:binary')
393
end
394
395
prepended_creds.each { |c| yield c }
396
397
if anonymous_login
398
yield Metasploit::Framework::Credential.new(public: '', private: '', realm: realm, private_type: :password)
399
end
400
401
if username.present?
402
if nil_passwords
403
yield Metasploit::Framework::Credential.new(public: username, private: nil, realm: realm, private_type: :password)
404
end
405
if password.present?
406
yield Metasploit::Framework::Credential.new(public: username, private: password, realm: realm, private_type: private_type(password))
407
end
408
if user_as_pass
409
yield Metasploit::Framework::Credential.new(public: username, private: username, realm: realm, private_type: :password)
410
end
411
if blank_passwords
412
yield Metasploit::Framework::Credential.new(public: username, private: "", realm: realm, private_type: :password)
413
end
414
if pass_fd
415
pass_fd.each_line do |pass_from_file|
416
pass_from_file.chomp!
417
yield Metasploit::Framework::Credential.new(public: username, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file))
418
end
419
pass_fd.seek(0)
420
end
421
additional_privates.each do |add_private|
422
yield Metasploit::Framework::Credential.new(public: username, private: add_private, realm: realm, private_type: private_type(add_private))
423
end
424
end
425
426
if user_file.present?
427
File.open(user_file, 'r:binary') do |user_fd|
428
user_fd.each_line do |user_from_file|
429
user_from_file.chomp!
430
if nil_passwords
431
yield Metasploit::Framework::Credential.new(public: user_from_file, private: nil, realm: realm, private_type: :password)
432
end
433
if password.present?
434
yield Metasploit::Framework::Credential.new(public: user_from_file, private: password, realm: realm, private_type: private_type(password) )
435
end
436
if user_as_pass
437
yield Metasploit::Framework::Credential.new(public: user_from_file, private: user_from_file, realm: realm, private_type: :password)
438
end
439
if blank_passwords
440
yield Metasploit::Framework::Credential.new(public: user_from_file, private: "", realm: realm, private_type: :password)
441
end
442
if pass_fd
443
pass_fd.each_line do |pass_from_file|
444
pass_from_file.chomp!
445
yield Metasploit::Framework::Credential.new(public: user_from_file, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file))
446
end
447
pass_fd.seek(0)
448
end
449
additional_privates.each do |add_private|
450
yield Metasploit::Framework::Credential.new(public: user_from_file, private: add_private, realm: realm, private_type: private_type(add_private))
451
end
452
end
453
end
454
end
455
456
if userpass_file.present?
457
File.open(userpass_file, 'r:binary') do |userpass_fd|
458
userpass_fd.each_line do |line|
459
user, pass = line.split(" ", 2)
460
if pass.blank?
461
pass = ''
462
else
463
pass.chomp!
464
end
465
yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm)
466
end
467
end
468
end
469
470
additional_publics.each do |add_public|
471
if password.present?
472
yield Metasploit::Framework::Credential.new(public: add_public, private: password, realm: realm, private_type: private_type(password) )
473
end
474
if user_as_pass
475
yield Metasploit::Framework::Credential.new(public: add_public, private: user_from_file, realm: realm, private_type: :password)
476
end
477
if blank_passwords
478
yield Metasploit::Framework::Credential.new(public: add_public, private: "", realm: realm, private_type: :password)
479
end
480
if pass_fd
481
pass_fd.each_line do |pass_from_file|
482
pass_from_file.chomp!
483
yield Metasploit::Framework::Credential.new(public: add_public, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file))
484
end
485
pass_fd.seek(0)
486
end
487
additional_privates.each do |add_private|
488
yield Metasploit::Framework::Credential.new(public: add_public, private: add_private, realm: realm, private_type: private_type(add_private))
489
end
490
end
491
ensure
492
pass_fd.close if pass_fd && !pass_fd.closed?
493
end
494
495
# Returns true when #each will have no results to iterate
496
#
497
# @return [Boolean]
498
def empty?
499
prepended_creds.empty? && !has_users? && !anonymous_login || (has_users? && !has_privates?)
500
end
501
502
# Returns true when there are any user values set
503
#
504
# @return [Boolean]
505
def has_users?
506
username.present? || user_file.present? || userpass_file.present? || !additional_publics.empty?
507
end
508
509
# Returns true when there are any private values set
510
#
511
# @return [Boolean]
512
def has_privates?
513
super || userpass_file.present? || user_as_pass
514
end
515
516
end
517
end
518
519