metasploit-credential 6.0.23 → 6.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4b9e7598b0e2092c89cf53906e4f4a1095d8ab1a0db16909c7b6dfdb34f36126
|
|
4
|
+
data.tar.gz: 05d85b467d16961cd74ddca8d91b9a556917796d063e9220790ebbab5a8fdebf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 29e2ef10c016b40770b87a09b91102717c8e65e47592c3774953f804ed95558020aef18abc8556218f413802afbd56798d2f5253e109b5e618de5b35cdaf0f0f
|
|
7
|
+
data.tar.gz: 9b66948b98ed071ddfe1942e73f5454ae9c9f718b352028e344aec532fa9b27f730f62024dde594174f5176d8f6dd3bb54f10649b0f90da148d13f20c8a73804
|
|
@@ -39,20 +39,43 @@ module Metasploit::Credential::Creation
|
|
|
39
39
|
old_realm_id = nil
|
|
40
40
|
|
|
41
41
|
retry_transaction do
|
|
42
|
-
private = Metasploit::Credential::Password.where(data: password).first_or_create!
|
|
43
|
-
public = Metasploit::Credential::Public.where(username: username).first_or_create!
|
|
44
42
|
old_core = Metasploit::Credential::Core.find(core_id)
|
|
45
43
|
old_realm_id = old_core.realm.id if old_core.realm
|
|
44
|
+
if username.blank? && old_core.public
|
|
45
|
+
username = old_core.public.username
|
|
46
|
+
end
|
|
47
|
+
private = Metasploit::Credential::Password.where(data: password).first_or_create!
|
|
48
|
+
public = Metasploit::Credential::Public.where(username: username).first_or_create!
|
|
46
49
|
end
|
|
47
50
|
|
|
48
51
|
core = nil
|
|
49
52
|
|
|
50
53
|
retry_transaction do
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
# Create the CrackedPassword origin for this specific originating
|
|
55
|
+
# core first, then look up a Core that is already tied to it.
|
|
56
|
+
# This prevents two different hashes that crack to the same
|
|
57
|
+
# password from collapsing into a single Core where only the
|
|
58
|
+
# first origin link is recorded.
|
|
59
|
+
origin = Metasploit::Credential::Origin::CrackedPassword.where(metasploit_credential_core_id: core_id).first_or_create!
|
|
60
|
+
|
|
61
|
+
core = Metasploit::Credential::Core.find_by(
|
|
62
|
+
origin_type: 'Metasploit::Credential::Origin::CrackedPassword',
|
|
63
|
+
origin_id: origin.id
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
unless core
|
|
67
|
+
core = Metasploit::Credential::Core.where(
|
|
68
|
+
public_id: public.id,
|
|
69
|
+
private_id: private.id,
|
|
70
|
+
realm_id: old_realm_id,
|
|
71
|
+
workspace_id: old_core.workspace_id
|
|
72
|
+
).first_or_initialize
|
|
73
|
+
|
|
74
|
+
if core.origin_id.nil?
|
|
75
|
+
core.origin = origin
|
|
76
|
+
end
|
|
55
77
|
end
|
|
78
|
+
|
|
56
79
|
if opts[:task_id]
|
|
57
80
|
core.tasks << Mdm::Task.find(opts[:task_id])
|
|
58
81
|
end
|
|
@@ -136,6 +159,17 @@ module Metasploit::Credential::Creation
|
|
|
136
159
|
end
|
|
137
160
|
|
|
138
161
|
if opts.has_key?(:username)
|
|
162
|
+
# When cracking a hash, the caller may not know the username
|
|
163
|
+
# (e.g. krb5tgs / krb5asrep). Fall back to the originating
|
|
164
|
+
# core's public so each cracked hash gets a distinct Core
|
|
165
|
+
# instead of all of them collapsing into a single BlankUsername
|
|
166
|
+
# Core where only the first origin link is recorded.
|
|
167
|
+
if opts[:username].blank? && opts[:origin_type] == :cracked_password && opts[:originating_core_id]
|
|
168
|
+
originating_core = Metasploit::Credential::Core.find_by(id: opts[:originating_core_id])
|
|
169
|
+
if originating_core&.public
|
|
170
|
+
opts = opts.merge(username: originating_core.public.username)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
139
173
|
core_opts[:public] = create_credential_public(opts)
|
|
140
174
|
end
|
|
141
175
|
|
|
@@ -256,7 +290,20 @@ module Metasploit::Credential::Creation
|
|
|
256
290
|
|
|
257
291
|
core = nil
|
|
258
292
|
retry_transaction do
|
|
259
|
-
|
|
293
|
+
# When the origin is a CrackedPassword, look up by origin first
|
|
294
|
+
# so that each originating hash gets its own cracked Core.
|
|
295
|
+
# Without this, two different hashes that crack to the same
|
|
296
|
+
# password (and share public/realm/workspace) resolve to a
|
|
297
|
+
# single Core and only the first origin link is recorded.
|
|
298
|
+
if origin.is_a?(Metasploit::Credential::Origin::CrackedPassword)
|
|
299
|
+
core = Metasploit::Credential::Core.find_by(
|
|
300
|
+
origin_type: origin.class.to_s,
|
|
301
|
+
origin_id: origin.id
|
|
302
|
+
)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
core ||= Metasploit::Credential::Core.where(private_id: private_id, public_id: public_id, realm_id: realm_id, workspace_id: workspace_id).first_or_initialize
|
|
306
|
+
|
|
260
307
|
if core.origin_id.nil?
|
|
261
308
|
core.origin = origin
|
|
262
309
|
end
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
a40adeaa65852477620cc75a2031e3330751540828be89231cc907bc82edda8d4d9f438dcf88844adc06d119dd172b75ceca305d75b355c4e8cb7532a6e7114a
|
|
@@ -209,6 +209,48 @@ RSpec.describe Metasploit::Credential::Creation do
|
|
|
209
209
|
expect( Metasploit::Credential::PostgresMD5.count ).to eq(1)
|
|
210
210
|
end
|
|
211
211
|
end
|
|
212
|
+
|
|
213
|
+
context 'when origin is cracked_password and username is blank' do
|
|
214
|
+
let(:named_public) { FactoryBot.create(:metasploit_credential_username) }
|
|
215
|
+
let(:hash_private) { FactoryBot.create(:metasploit_credential_nonreplayable_hash) }
|
|
216
|
+
let(:manual_origin) { FactoryBot.create(:metasploit_credential_origin_manual) }
|
|
217
|
+
|
|
218
|
+
let!(:originating_core) do
|
|
219
|
+
FactoryBot.create(:metasploit_credential_core,
|
|
220
|
+
public: named_public, private: hash_private,
|
|
221
|
+
workspace: workspace, origin: manual_origin)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
let(:credential_data) {{
|
|
225
|
+
workspace_id: workspace.id,
|
|
226
|
+
origin_type: :cracked_password,
|
|
227
|
+
originating_core_id: originating_core.id,
|
|
228
|
+
username: '',
|
|
229
|
+
private_data: 'cracked_pw',
|
|
230
|
+
private_type: :password
|
|
231
|
+
}}
|
|
232
|
+
|
|
233
|
+
it 'falls back to the originating core public username instead of creating a BlankUsername' do
|
|
234
|
+
core = test_object.create_credential(credential_data)
|
|
235
|
+
expect(core.public.username).to eq(named_public.username)
|
|
236
|
+
expect(core.public).not_to be_a(Metasploit::Credential::BlankUsername)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
it 'creates distinct Cores when two different hashes crack to the same password with blank usernames' do
|
|
240
|
+
hash_private2 = FactoryBot.create(:metasploit_credential_nonreplayable_hash)
|
|
241
|
+
named_public2 = FactoryBot.create(:metasploit_credential_username)
|
|
242
|
+
originating_core2 = FactoryBot.create(:metasploit_credential_core,
|
|
243
|
+
public: named_public2, private: hash_private2,
|
|
244
|
+
workspace: workspace, origin: manual_origin)
|
|
245
|
+
|
|
246
|
+
core1 = test_object.create_credential(credential_data)
|
|
247
|
+
core2 = test_object.create_credential(credential_data.merge(originating_core_id: originating_core2.id))
|
|
248
|
+
|
|
249
|
+
expect(core1.id).not_to eq(core2.id)
|
|
250
|
+
expect(core1.public.username).to eq(named_public.username)
|
|
251
|
+
expect(core2.public.username).to eq(named_public2.username)
|
|
252
|
+
end
|
|
253
|
+
end
|
|
212
254
|
end
|
|
213
255
|
|
|
214
256
|
context '#create_credential_and_login' do
|
|
@@ -463,6 +505,223 @@ RSpec.describe Metasploit::Credential::Creation do
|
|
|
463
505
|
|
|
464
506
|
end
|
|
465
507
|
|
|
508
|
+
context 'when two different hashes crack to the same password' do
|
|
509
|
+
let(:public_user1) { FactoryBot.create(:metasploit_credential_username) }
|
|
510
|
+
let(:public_user2) { FactoryBot.create(:metasploit_credential_username) }
|
|
511
|
+
let(:hash1) { FactoryBot.create(:metasploit_credential_nonreplayable_hash) }
|
|
512
|
+
let(:hash2) { FactoryBot.create(:metasploit_credential_nonreplayable_hash) }
|
|
513
|
+
let(:manual_origin) { FactoryBot.create(:metasploit_credential_origin_manual) }
|
|
514
|
+
let(:cracked_password) { 'cracked_same_password' }
|
|
515
|
+
|
|
516
|
+
let!(:hash_core1) do
|
|
517
|
+
FactoryBot.create(:metasploit_credential_core,
|
|
518
|
+
public: public_user1, private: hash1,
|
|
519
|
+
realm: realm, workspace: workspace, origin: manual_origin)
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
let!(:hash_core2) do
|
|
523
|
+
FactoryBot.create(:metasploit_credential_core,
|
|
524
|
+
public: public_user2, private: hash2,
|
|
525
|
+
realm: realm, workspace: workspace, origin: manual_origin)
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
it 'creates separate Cores for each originating hash' do
|
|
529
|
+
core1 = test_object.create_cracked_credential(
|
|
530
|
+
core_id: hash_core1.id,
|
|
531
|
+
username: public_user1.username,
|
|
532
|
+
password: cracked_password
|
|
533
|
+
)
|
|
534
|
+
core2 = test_object.create_cracked_credential(
|
|
535
|
+
core_id: hash_core2.id,
|
|
536
|
+
username: public_user2.username,
|
|
537
|
+
password: cracked_password
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
expect(core1.id).not_to eq(core2.id)
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
it 'records distinct CrackedPassword origins pointing to each originating core' do
|
|
544
|
+
core1 = test_object.create_cracked_credential(
|
|
545
|
+
core_id: hash_core1.id,
|
|
546
|
+
username: public_user1.username,
|
|
547
|
+
password: cracked_password
|
|
548
|
+
)
|
|
549
|
+
core2 = test_object.create_cracked_credential(
|
|
550
|
+
core_id: hash_core2.id,
|
|
551
|
+
username: public_user2.username,
|
|
552
|
+
password: cracked_password
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
expect(core1.origin).to be_a(Metasploit::Credential::Origin::CrackedPassword)
|
|
556
|
+
expect(core2.origin).to be_a(Metasploit::Credential::Origin::CrackedPassword)
|
|
557
|
+
expect(core1.origin.metasploit_credential_core_id).to eq(hash_core1.id)
|
|
558
|
+
expect(core2.origin.metasploit_credential_core_id).to eq(hash_core2.id)
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
context 'when both hashes share the same username and realm' do
|
|
562
|
+
let(:shared_public) { FactoryBot.create(:metasploit_credential_username) }
|
|
563
|
+
|
|
564
|
+
let!(:hash_core_a) do
|
|
565
|
+
FactoryBot.create(:metasploit_credential_core,
|
|
566
|
+
public: shared_public, private: hash1,
|
|
567
|
+
realm: realm, workspace: workspace, origin: manual_origin)
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
let!(:hash_core_b) do
|
|
571
|
+
FactoryBot.create(:metasploit_credential_core,
|
|
572
|
+
public: shared_public, private: hash2,
|
|
573
|
+
realm: realm, workspace: workspace, origin: manual_origin)
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
it 'reuses the existing Core but creates distinct CrackedPassword origins for each hash' do
|
|
577
|
+
core_a = test_object.create_cracked_credential(
|
|
578
|
+
core_id: hash_core_a.id,
|
|
579
|
+
username: shared_public.username,
|
|
580
|
+
password: cracked_password
|
|
581
|
+
)
|
|
582
|
+
core_b = test_object.create_cracked_credential(
|
|
583
|
+
core_id: hash_core_b.id,
|
|
584
|
+
username: shared_public.username,
|
|
585
|
+
password: cracked_password
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
# Both resolve to the same Core because public/private/realm/workspace match
|
|
589
|
+
expect(core_a.id).to eq(core_b.id)
|
|
590
|
+
|
|
591
|
+
# But distinct CrackedPassword origins are still recorded for each originating hash
|
|
592
|
+
origins = Metasploit::Credential::Origin::CrackedPassword.where(
|
|
593
|
+
metasploit_credential_core_id: [hash_core_a.id, hash_core_b.id]
|
|
594
|
+
)
|
|
595
|
+
expect(origins.count).to eq(2)
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
context 'when username is blank' do
|
|
601
|
+
let(:named_public) { FactoryBot.create(:metasploit_credential_username) }
|
|
602
|
+
let(:hash_private) { FactoryBot.create(:metasploit_credential_nonreplayable_hash) }
|
|
603
|
+
let(:manual_origin) { FactoryBot.create(:metasploit_credential_origin_manual) }
|
|
604
|
+
|
|
605
|
+
let!(:originating_core) do
|
|
606
|
+
FactoryBot.create(:metasploit_credential_core,
|
|
607
|
+
public: named_public, private: hash_private,
|
|
608
|
+
realm: realm, workspace: workspace, origin: manual_origin)
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
it 'falls back to the originating core public username' do
|
|
612
|
+
core = test_object.create_cracked_credential(
|
|
613
|
+
core_id: originating_core.id,
|
|
614
|
+
username: '',
|
|
615
|
+
password: password
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
expect(core.public.username).to eq(named_public.username)
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
it 'does not create a BlankUsername record for the cracked credential' do
|
|
622
|
+
blank_count_before = Metasploit::Credential::BlankUsername.count
|
|
623
|
+
test_object.create_cracked_credential(
|
|
624
|
+
core_id: originating_core.id,
|
|
625
|
+
username: '',
|
|
626
|
+
password: password
|
|
627
|
+
)
|
|
628
|
+
|
|
629
|
+
# The cracked Core should use the originating core's named username,
|
|
630
|
+
# not create a new BlankUsername
|
|
631
|
+
cracked_core = Metasploit::Credential::Core.last
|
|
632
|
+
expect(cracked_core.public).not_to be_a(Metasploit::Credential::BlankUsername)
|
|
633
|
+
expect(Metasploit::Credential::BlankUsername.count).to eq(blank_count_before)
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
context 'with two different hashes that both have named publics' do
|
|
637
|
+
let(:named_public2) { FactoryBot.create(:metasploit_credential_username) }
|
|
638
|
+
let(:hash_private2) { FactoryBot.create(:metasploit_credential_nonreplayable_hash) }
|
|
639
|
+
|
|
640
|
+
let!(:originating_core2) do
|
|
641
|
+
FactoryBot.create(:metasploit_credential_core,
|
|
642
|
+
public: named_public2, private: hash_private2,
|
|
643
|
+
realm: realm, workspace: workspace, origin: manual_origin)
|
|
644
|
+
end
|
|
645
|
+
|
|
646
|
+
it 'creates separate Cores each with the correct username from their originating core' do
|
|
647
|
+
core1 = test_object.create_cracked_credential(
|
|
648
|
+
core_id: originating_core.id,
|
|
649
|
+
username: '',
|
|
650
|
+
password: password
|
|
651
|
+
)
|
|
652
|
+
core2 = test_object.create_cracked_credential(
|
|
653
|
+
core_id: originating_core2.id,
|
|
654
|
+
username: '',
|
|
655
|
+
password: password
|
|
656
|
+
)
|
|
657
|
+
|
|
658
|
+
expect(core1.id).not_to eq(core2.id)
|
|
659
|
+
expect(core1.public.username).to eq(named_public.username)
|
|
660
|
+
expect(core2.public.username).to eq(named_public2.username)
|
|
661
|
+
end
|
|
662
|
+
end
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
context 'end-to-end: two different hash types (e.g. krb5tgs and krb5asrep) cracked to the same password' do
|
|
666
|
+
let(:krb5tgs_public) { Metasploit::Credential::Username.create!(username: 'krb5tgs') }
|
|
667
|
+
let(:krb5asrep_public) { Metasploit::Credential::Username.create!(username: 'krb5asrep') }
|
|
668
|
+
let(:krb5tgs_hash) { FactoryBot.create(:metasploit_credential_nonreplayable_hash) }
|
|
669
|
+
let(:krb5asrep_hash) { FactoryBot.create(:metasploit_credential_nonreplayable_hash) }
|
|
670
|
+
let(:manual_origin) { FactoryBot.create(:metasploit_credential_origin_manual) }
|
|
671
|
+
let(:cracked_pw) { 'hashcat' }
|
|
672
|
+
|
|
673
|
+
let!(:krb5tgs_core) do
|
|
674
|
+
FactoryBot.create(:metasploit_credential_core,
|
|
675
|
+
public: krb5tgs_public, private: krb5tgs_hash,
|
|
676
|
+
workspace: workspace, origin: manual_origin)
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
let!(:krb5asrep_core) do
|
|
680
|
+
FactoryBot.create(:metasploit_credential_core,
|
|
681
|
+
public: krb5asrep_public, private: krb5asrep_hash,
|
|
682
|
+
workspace: workspace, origin: manual_origin)
|
|
683
|
+
end
|
|
684
|
+
|
|
685
|
+
it 'creates 2 new cracked Cores in addition to the 2 originals' do
|
|
686
|
+
expect {
|
|
687
|
+
test_object.create_cracked_credential(core_id: krb5tgs_core.id, username: '', password: cracked_pw)
|
|
688
|
+
test_object.create_cracked_credential(core_id: krb5asrep_core.id, username: '', password: cracked_pw)
|
|
689
|
+
}.to change { Metasploit::Credential::Core.count }.by(2)
|
|
690
|
+
end
|
|
691
|
+
|
|
692
|
+
it 'links each cracked Core back to its originating hash via CrackedPassword origin' do
|
|
693
|
+
cracked1 = test_object.create_cracked_credential(core_id: krb5tgs_core.id, username: '', password: cracked_pw)
|
|
694
|
+
cracked2 = test_object.create_cracked_credential(core_id: krb5asrep_core.id, username: '', password: cracked_pw)
|
|
695
|
+
|
|
696
|
+
expect(cracked1.origin).to be_a(Metasploit::Credential::Origin::CrackedPassword)
|
|
697
|
+
expect(cracked2.origin).to be_a(Metasploit::Credential::Origin::CrackedPassword)
|
|
698
|
+
expect(cracked1.origin.metasploit_credential_core_id).to eq(krb5tgs_core.id)
|
|
699
|
+
expect(cracked2.origin.metasploit_credential_core_id).to eq(krb5asrep_core.id)
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
it 'uses the originating core username for each cracked Core instead of BlankUsername' do
|
|
703
|
+
cracked1 = test_object.create_cracked_credential(core_id: krb5tgs_core.id, username: '', password: cracked_pw)
|
|
704
|
+
cracked2 = test_object.create_cracked_credential(core_id: krb5asrep_core.id, username: '', password: cracked_pw)
|
|
705
|
+
|
|
706
|
+
expect(cracked1.public.username).to eq('krb5tgs')
|
|
707
|
+
expect(cracked2.public.username).to eq('krb5asrep')
|
|
708
|
+
end
|
|
709
|
+
|
|
710
|
+
it 'allows looking up the cracked password from each originating hash core' do
|
|
711
|
+
test_object.create_cracked_credential(core_id: krb5tgs_core.id, username: '', password: cracked_pw)
|
|
712
|
+
test_object.create_cracked_credential(core_id: krb5asrep_core.id, username: '', password: cracked_pw)
|
|
713
|
+
|
|
714
|
+
# Simulate the lookup that creds display does: find cracked Cores by their CrackedPassword origin
|
|
715
|
+
cracked_cores = Metasploit::Credential::Core.where(origin_type: 'Metasploit::Credential::Origin::CrackedPassword')
|
|
716
|
+
cracked_by_originating_id = cracked_cores.each_with_object({}) do |core, map|
|
|
717
|
+
map[core.origin.metasploit_credential_core_id] = core
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
expect(cracked_by_originating_id[krb5tgs_core.id].private.data).to eq(cracked_pw)
|
|
721
|
+
expect(cracked_by_originating_id[krb5asrep_core.id].private.data).to eq(cracked_pw)
|
|
722
|
+
end
|
|
723
|
+
end
|
|
724
|
+
|
|
466
725
|
end
|
|
467
726
|
|
|
468
727
|
context '#create_credential_origin_import' do
|
|
@@ -981,6 +1240,100 @@ RSpec.describe Metasploit::Credential::Creation do
|
|
|
981
1240
|
expect(core.tasks).to include(task)
|
|
982
1241
|
end
|
|
983
1242
|
|
|
1243
|
+
context 'when origin is a CrackedPassword' do
|
|
1244
|
+
let(:manual_origin) { FactoryBot.create(:metasploit_credential_origin_manual) }
|
|
1245
|
+
let(:hash1) { FactoryBot.create(:metasploit_credential_nonreplayable_hash) }
|
|
1246
|
+
let(:hash2) { FactoryBot.create(:metasploit_credential_nonreplayable_hash) }
|
|
1247
|
+
let(:cracked_pw) { FactoryBot.create(:metasploit_credential_password) }
|
|
1248
|
+
let(:pub1) { FactoryBot.create(:metasploit_credential_username) }
|
|
1249
|
+
let(:pub2) { FactoryBot.create(:metasploit_credential_username) }
|
|
1250
|
+
let(:rlm) { FactoryBot.create(:metasploit_credential_realm) }
|
|
1251
|
+
let(:ws) { FactoryBot.create(:mdm_workspace) }
|
|
1252
|
+
|
|
1253
|
+
let!(:hash_core1) do
|
|
1254
|
+
FactoryBot.create(:metasploit_credential_core,
|
|
1255
|
+
public: pub1, private: hash1,
|
|
1256
|
+
realm: rlm, workspace: ws, origin: manual_origin)
|
|
1257
|
+
end
|
|
1258
|
+
|
|
1259
|
+
let!(:hash_core2) do
|
|
1260
|
+
FactoryBot.create(:metasploit_credential_core,
|
|
1261
|
+
public: pub2, private: hash2,
|
|
1262
|
+
realm: rlm, workspace: ws, origin: manual_origin)
|
|
1263
|
+
end
|
|
1264
|
+
|
|
1265
|
+
it 'creates separate Cores when CrackedPassword origins have different publics' do
|
|
1266
|
+
origin1 = Metasploit::Credential::Origin::CrackedPassword.create!(metasploit_credential_core_id: hash_core1.id)
|
|
1267
|
+
origin2 = Metasploit::Credential::Origin::CrackedPassword.create!(metasploit_credential_core_id: hash_core2.id)
|
|
1268
|
+
|
|
1269
|
+
core1 = test_object.create_credential_core(
|
|
1270
|
+
origin: origin1,
|
|
1271
|
+
public: pub1,
|
|
1272
|
+
private: cracked_pw,
|
|
1273
|
+
realm: rlm,
|
|
1274
|
+
workspace_id: ws.id
|
|
1275
|
+
)
|
|
1276
|
+
core2 = test_object.create_credential_core(
|
|
1277
|
+
origin: origin2,
|
|
1278
|
+
public: pub2,
|
|
1279
|
+
private: cracked_pw,
|
|
1280
|
+
realm: rlm,
|
|
1281
|
+
workspace_id: ws.id
|
|
1282
|
+
)
|
|
1283
|
+
|
|
1284
|
+
expect(core1.id).not_to eq(core2.id)
|
|
1285
|
+
expect(core1.origin_id).to eq(origin1.id)
|
|
1286
|
+
expect(core2.origin_id).to eq(origin2.id)
|
|
1287
|
+
end
|
|
1288
|
+
|
|
1289
|
+
it 'returns the existing Core when called again with the same CrackedPassword origin' do
|
|
1290
|
+
origin1 = Metasploit::Credential::Origin::CrackedPassword.create!(metasploit_credential_core_id: hash_core1.id)
|
|
1291
|
+
|
|
1292
|
+
core_first = test_object.create_credential_core(
|
|
1293
|
+
origin: origin1,
|
|
1294
|
+
public: pub1,
|
|
1295
|
+
private: cracked_pw,
|
|
1296
|
+
realm: rlm,
|
|
1297
|
+
workspace_id: ws.id
|
|
1298
|
+
)
|
|
1299
|
+
core_second = test_object.create_credential_core(
|
|
1300
|
+
origin: origin1,
|
|
1301
|
+
public: pub1,
|
|
1302
|
+
private: cracked_pw,
|
|
1303
|
+
realm: rlm,
|
|
1304
|
+
workspace_id: ws.id
|
|
1305
|
+
)
|
|
1306
|
+
|
|
1307
|
+
expect(core_first.id).to eq(core_second.id)
|
|
1308
|
+
end
|
|
1309
|
+
|
|
1310
|
+
it 'looks up by origin before falling back to public/private/realm/workspace' do
|
|
1311
|
+
origin1 = Metasploit::Credential::Origin::CrackedPassword.create!(metasploit_credential_core_id: hash_core1.id)
|
|
1312
|
+
|
|
1313
|
+
core = test_object.create_credential_core(
|
|
1314
|
+
origin: origin1,
|
|
1315
|
+
public: pub1,
|
|
1316
|
+
private: cracked_pw,
|
|
1317
|
+
realm: rlm,
|
|
1318
|
+
workspace_id: ws.id
|
|
1319
|
+
)
|
|
1320
|
+
|
|
1321
|
+
# Calling again with the same origin returns the same core
|
|
1322
|
+
# even though the lookup by origin happens first
|
|
1323
|
+
core_again = test_object.create_credential_core(
|
|
1324
|
+
origin: origin1,
|
|
1325
|
+
public: pub1,
|
|
1326
|
+
private: cracked_pw,
|
|
1327
|
+
realm: rlm,
|
|
1328
|
+
workspace_id: ws.id
|
|
1329
|
+
)
|
|
1330
|
+
|
|
1331
|
+
expect(core.id).to eq(core_again.id)
|
|
1332
|
+
expect(core.origin).to be_a(Metasploit::Credential::Origin::CrackedPassword)
|
|
1333
|
+
expect(core.origin.metasploit_credential_core_id).to eq(hash_core1.id)
|
|
1334
|
+
end
|
|
1335
|
+
end
|
|
1336
|
+
|
|
984
1337
|
end
|
|
985
1338
|
|
|
986
1339
|
context '#create_credential_login' do
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: metasploit-credential
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 6.0.
|
|
4
|
+
version: 6.0.24
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Metasploit Hackers
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-05-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: metasploit-concern
|