metasploit-credential 6.0.13 → 6.0.14
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 +4 -4
- data/README.md +1 -1
- data/app/models/metasploit/credential/pkcs12.rb +51 -2
- data/app/models/metasploit/credential/private.rb +8 -0
- data/config/locales/en.yml +1 -1
- data/db/migrate/20250204172657_add_metadata_to_metasploit_credential_privates.rb +5 -0
- data/lib/metasploit/credential/creation.rb +1 -1
- data/lib/metasploit/credential/version.rb +1 -1
- data/spec/dummy/db/structure.sql +4 -1
- data/spec/factories/metasploit/credential/pkcs12.rb +66 -6
- data/spec/lib/metasploit/credential/creation_spec.rb +25 -2
- data/spec/models/metasploit/credential/pkcs12_spec.rb +238 -0
- data/spec/models/metasploit/credential/private_spec.rb +9 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b08c247237833c0a93eee32f6d14a678a2f320d46827eec1553d999e2601447
|
4
|
+
data.tar.gz: 8c446fa6be10d1040cb8bbcdee59fc6be9cc167bcc569d4e608ac80aafbc4b01
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5922d220d8a3614d21b3a6a4639527b0d0486dac4edf6d7832f9e0354274b5b3903d6ab6049722ff3ec66f5ec7bd2aedb09155980f49582307c54f08f9efe5d0
|
7
|
+
data.tar.gz: 40dbe1b8f9ebf70be13840c791ffc05149759e44347a08946291b4c0e76b3450a4fc718910b20d7585509731d8d4432a52dbaa5067726fefd68cd475dc118bcf
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Metasploit::Credential [](https://github.com/rapid7/metasploit-credential/actions/workflows/verify.yml)[](https://github.com/rapid7/metasploit-credential/actions/workflows/verify.yml)[](https://gemnasium.com/rapid7/metasploit-credential)[](http://badge.fury.io/rb/metasploit-credential)[](http://inch-ci.org/github/rapid7/metasploit-credential)
|
2
2
|
|
3
3
|
## Versioning
|
4
4
|
|
@@ -3,6 +3,7 @@ require 'base64'
|
|
3
3
|
|
4
4
|
# A private Pkcs12 file.
|
5
5
|
class Metasploit::Credential::Pkcs12 < Metasploit::Credential::Private
|
6
|
+
|
6
7
|
#
|
7
8
|
# Attributes
|
8
9
|
#
|
@@ -12,6 +13,14 @@ class Metasploit::Credential::Pkcs12 < Metasploit::Credential::Private
|
|
12
13
|
#
|
13
14
|
# @return [String]
|
14
15
|
|
16
|
+
# @!attribute metadata
|
17
|
+
# Metadata for this Pkcs12:
|
18
|
+
# adcs_ca: The Certificate Authority that issued the certificate
|
19
|
+
# adcs_template: The certificate template used to issue the certificate
|
20
|
+
# pkcs12_password: The password to decrypt the Pkcs12
|
21
|
+
#
|
22
|
+
# @return [JSONB]
|
23
|
+
|
15
24
|
#
|
16
25
|
#
|
17
26
|
# Validations
|
@@ -24,15 +33,49 @@ class Metasploit::Credential::Pkcs12 < Metasploit::Credential::Private
|
|
24
33
|
|
25
34
|
validates :data,
|
26
35
|
presence: true
|
36
|
+
|
27
37
|
#
|
28
38
|
# Method Validations
|
29
39
|
#
|
30
40
|
|
31
41
|
validate :readable
|
32
42
|
|
43
|
+
#
|
44
|
+
# Class methods
|
45
|
+
#
|
46
|
+
|
33
47
|
#
|
34
48
|
# Instance Methods
|
35
49
|
#
|
50
|
+
#
|
51
|
+
|
52
|
+
# The CA that issued the certificate
|
53
|
+
#
|
54
|
+
# @return [String]
|
55
|
+
def adcs_ca
|
56
|
+
metadata['adcs_ca']
|
57
|
+
end
|
58
|
+
|
59
|
+
# The certificate template used to issue the certificate
|
60
|
+
#
|
61
|
+
# @return [String]
|
62
|
+
def adcs_template
|
63
|
+
metadata['adcs_template']
|
64
|
+
end
|
65
|
+
|
66
|
+
# The password to decrypt the Pkcs12
|
67
|
+
#
|
68
|
+
# @return [String]
|
69
|
+
def pkcs12_password
|
70
|
+
metadata['pkcs12_password']
|
71
|
+
end
|
72
|
+
|
73
|
+
# The status if the certificate (active or inactive)
|
74
|
+
#
|
75
|
+
# @return [String]
|
76
|
+
def status
|
77
|
+
metadata['status']
|
78
|
+
end
|
36
79
|
|
37
80
|
# Converts the private pkcs12 data in {#data} to an `OpenSSL::PKCS12` instance.
|
38
81
|
#
|
@@ -41,7 +84,7 @@ class Metasploit::Credential::Pkcs12 < Metasploit::Credential::Private
|
|
41
84
|
def openssl_pkcs12
|
42
85
|
if data
|
43
86
|
begin
|
44
|
-
password = ''
|
87
|
+
password = metadata.fetch('pkcs12_password', '')
|
45
88
|
OpenSSL::PKCS12.new(Base64.strict_decode64(data), password)
|
46
89
|
rescue OpenSSL::PKCS12::PKCS12Error => error
|
47
90
|
raise ArgumentError.new(error)
|
@@ -50,7 +93,7 @@ class Metasploit::Credential::Pkcs12 < Metasploit::Credential::Private
|
|
50
93
|
end
|
51
94
|
|
52
95
|
# The {#data key data}'s fingerprint, suitable for displaying to the
|
53
|
-
# user.
|
96
|
+
# user. The Pkcs12 password is voluntarily not included.
|
54
97
|
#
|
55
98
|
# @return [String]
|
56
99
|
def to_s
|
@@ -60,9 +103,12 @@ class Metasploit::Credential::Pkcs12 < Metasploit::Credential::Private
|
|
60
103
|
result = []
|
61
104
|
result << "subject:#{cert.subject.to_s}"
|
62
105
|
result << "issuer:#{cert.issuer.to_s}"
|
106
|
+
result << "ADCS CA:#{metadata['adcs_ca']}" if metadata['adcs_ca']
|
107
|
+
result << "ADCS template:#{metadata['adcs_template']}" if metadata['adcs_template']
|
63
108
|
result.join(',')
|
64
109
|
end
|
65
110
|
|
111
|
+
|
66
112
|
private
|
67
113
|
|
68
114
|
#
|
@@ -80,5 +126,8 @@ class Metasploit::Credential::Pkcs12 < Metasploit::Credential::Private
|
|
80
126
|
end
|
81
127
|
end
|
82
128
|
|
129
|
+
|
130
|
+
public
|
131
|
+
|
83
132
|
Metasploit::Concern.run(self)
|
84
133
|
end
|
@@ -50,6 +50,11 @@ class Metasploit::Credential::Private < ApplicationRecord
|
|
50
50
|
#
|
51
51
|
# @return [DateTime]
|
52
52
|
|
53
|
+
# @!attribute metadata
|
54
|
+
# Metadata related to the private data. The data contained in this JSONB structure varies based on the subclass.
|
55
|
+
#
|
56
|
+
# @return [JSONB]
|
57
|
+
|
53
58
|
#
|
54
59
|
#
|
55
60
|
# Search
|
@@ -63,6 +68,9 @@ class Metasploit::Credential::Private < ApplicationRecord
|
|
63
68
|
search_attribute :data,
|
64
69
|
type: :string
|
65
70
|
|
71
|
+
search_attribute :metadata,
|
72
|
+
type: :jsonb
|
73
|
+
|
66
74
|
#
|
67
75
|
# Search Withs
|
68
76
|
#
|
data/config/locales/en.yml
CHANGED
@@ -87,7 +87,7 @@ en:
|
|
87
87
|
metasploit/credential/pkcs12:
|
88
88
|
attributes:
|
89
89
|
data:
|
90
|
-
format: "is not a Base64 encoded pkcs12 file without a password"
|
90
|
+
format: "is not a serialized data containing Base64 encoded pkcs12 file without a password and metadata"
|
91
91
|
metasploit/credential/ssh_key:
|
92
92
|
attributes:
|
93
93
|
data:
|
@@ -480,7 +480,7 @@ module Metasploit::Credential::Creation
|
|
480
480
|
when :ssh_key
|
481
481
|
private_object = Metasploit::Credential::SSHKey.where(data: private_data).first_or_create
|
482
482
|
when :pkcs12
|
483
|
-
private_object = Metasploit::Credential::Pkcs12.where(data: private_data).first_or_create
|
483
|
+
private_object = Metasploit::Credential::Pkcs12.where(data: private_data, metadata: opts.fetch(:private_metadata, {})).first_or_create
|
484
484
|
when :krb_enc_key
|
485
485
|
private_object = Metasploit::Credential::KrbEncKey.where(data: private_data).first_or_create
|
486
486
|
when :ntlm_hash
|
data/spec/dummy/db/structure.sql
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
SET statement_timeout = 0;
|
2
2
|
SET lock_timeout = 0;
|
3
3
|
SET idle_in_transaction_session_timeout = 0;
|
4
|
+
SET transaction_timeout = 0;
|
4
5
|
SET client_encoding = 'UTF8';
|
5
6
|
SET standard_conforming_strings = on;
|
6
7
|
SELECT pg_catalog.set_config('search_path', '', false);
|
@@ -929,7 +930,8 @@ CREATE TABLE public.metasploit_credential_privates (
|
|
929
930
|
data text NOT NULL,
|
930
931
|
created_at timestamp without time zone NOT NULL,
|
931
932
|
updated_at timestamp without time zone NOT NULL,
|
932
|
-
jtr_format character varying
|
933
|
+
jtr_format character varying,
|
934
|
+
metadata jsonb DEFAULT '{}'::jsonb NOT NULL
|
933
935
|
);
|
934
936
|
|
935
937
|
|
@@ -4147,6 +4149,7 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|
4147
4149
|
('20190308134512'),
|
4148
4150
|
('20190507120211'),
|
4149
4151
|
('20221209005658'),
|
4152
|
+
('20250204172657'),
|
4150
4153
|
('21'),
|
4151
4154
|
('22'),
|
4152
4155
|
('23'),
|
@@ -10,10 +10,15 @@ FactoryBot.define do
|
|
10
10
|
subject { '/C=BE/O=Test/OU=Test/CN=Test' }
|
11
11
|
# the cert issuer
|
12
12
|
issuer { '/C=BE/O=Test/OU=Test/CN=Test' }
|
13
|
+
# the pkcs12 password
|
14
|
+
pkcs12_password { '' }
|
15
|
+
# the cert not_before date
|
16
|
+
not_before { Time.now }
|
17
|
+
# the cert not_after date
|
18
|
+
not_after { Time.now + 365 * 24 * 60 * 60 }
|
13
19
|
end
|
14
20
|
|
15
21
|
data {
|
16
|
-
password = ''
|
17
22
|
pkcs12_name = ''
|
18
23
|
|
19
24
|
private_key = OpenSSL::PKey::RSA.new(key_size)
|
@@ -22,16 +27,71 @@ FactoryBot.define do
|
|
22
27
|
cert = OpenSSL::X509::Certificate.new
|
23
28
|
cert.subject = OpenSSL::X509::Name.parse(subject)
|
24
29
|
cert.issuer = OpenSSL::X509::Name.parse(issuer)
|
25
|
-
cert.not_before =
|
26
|
-
cert.not_after =
|
30
|
+
cert.not_before = not_before
|
31
|
+
cert.not_after = not_after
|
27
32
|
cert.public_key = public_key
|
28
33
|
cert.serial = 0x0
|
29
34
|
cert.version = 2
|
30
35
|
cert.sign(private_key, OpenSSL::Digest.new(signing_algorithm))
|
31
36
|
|
32
|
-
pkcs12 = OpenSSL::PKCS12.create(
|
33
|
-
|
34
|
-
pkcs12_base64
|
37
|
+
pkcs12 = OpenSSL::PKCS12.create(pkcs12_password, pkcs12_name, private_key, cert)
|
38
|
+
Base64.strict_encode64(pkcs12.to_der)
|
35
39
|
}
|
36
40
|
end
|
41
|
+
|
42
|
+
factory :metasploit_credential_pkcs12_with_ca, parent: :metasploit_credential_pkcs12 do
|
43
|
+
transient do
|
44
|
+
# The CA that issued the certificate
|
45
|
+
adcs_ca { 'test-ca' }
|
46
|
+
end
|
47
|
+
|
48
|
+
metadata { { adcs_ca: adcs_ca } }
|
49
|
+
end
|
50
|
+
|
51
|
+
factory :metasploit_credential_pkcs12_with_adcs_template, parent: :metasploit_credential_pkcs12 do
|
52
|
+
transient do
|
53
|
+
# The certificate template used to issue the certificate
|
54
|
+
adcs_template { 'User' }
|
55
|
+
end
|
56
|
+
|
57
|
+
metadata { { adcs_template: adcs_template} }
|
58
|
+
end
|
59
|
+
|
60
|
+
factory :metasploit_credential_pkcs12_with_pkcs12_password, parent: :metasploit_credential_pkcs12 do
|
61
|
+
transient do
|
62
|
+
# The password to decrypt the pkcs12
|
63
|
+
pkcs12_password { 'Password!' }
|
64
|
+
end
|
65
|
+
|
66
|
+
metadata { { pkcs12_password: pkcs12_password } }
|
67
|
+
end
|
68
|
+
|
69
|
+
factory :metasploit_credential_pkcs12_with_status, parent: :metasploit_credential_pkcs12 do
|
70
|
+
transient do
|
71
|
+
# The CA that issued the certificate
|
72
|
+
status { 'active' }
|
73
|
+
end
|
74
|
+
|
75
|
+
metadata { { status: status } }
|
76
|
+
end
|
77
|
+
|
78
|
+
factory :metasploit_credential_pkcs12_with_ca_and_adcs_template, parent: :metasploit_credential_pkcs12 do
|
79
|
+
transient do
|
80
|
+
adcs_ca { 'test-ca' }
|
81
|
+
adcs_template { 'User' }
|
82
|
+
end
|
83
|
+
|
84
|
+
metadata { { adcs_ca: adcs_ca, adcs_template: adcs_template } }
|
85
|
+
end
|
86
|
+
|
87
|
+
factory :metasploit_credential_pkcs12_with_ca_and_adcs_template_and_pkcs12_password, parent: :metasploit_credential_pkcs12 do
|
88
|
+
transient do
|
89
|
+
adcs_ca { 'test-ca' }
|
90
|
+
adcs_template { 'User' }
|
91
|
+
pkcs12_password { 'Password!' }
|
92
|
+
end
|
93
|
+
|
94
|
+
metadata { { adcs_ca: adcs_ca, adcs_template: adcs_template, pkcs12_password: pkcs12_password } }
|
95
|
+
end
|
96
|
+
|
37
97
|
end
|
@@ -864,13 +864,36 @@ RSpec.describe Metasploit::Credential::Creation do
|
|
864
864
|
end
|
865
865
|
|
866
866
|
context 'when :private_type is pkcs12' do
|
867
|
-
|
868
|
-
|
867
|
+
let(:opts) {
|
868
|
+
{
|
869
869
|
private_data: FactoryBot.build(:metasploit_credential_pkcs12).data,
|
870
870
|
private_type: :pkcs12
|
871
871
|
}
|
872
|
+
}
|
873
|
+
it 'creates a Metasploit::Credential::Pkcs12' do
|
872
874
|
expect{ test_object.create_credential_private(opts) }.to change{ Metasploit::Credential::Pkcs12.count }.by(1)
|
873
875
|
end
|
876
|
+
|
877
|
+
context 'with metadata' do
|
878
|
+
it 'creates a Metasploit::Credential::Pkcs12 with the expected metadata' do
|
879
|
+
adcs_ca = 'test_ca'
|
880
|
+
adcs_template = 'test_template'
|
881
|
+
opts[:private_metadata] = { adcs_ca: adcs_ca, adcs_template: adcs_template }
|
882
|
+
pkcs12 = test_object.create_credential_private(opts)
|
883
|
+
expect(pkcs12.adcs_ca).to eq(adcs_ca)
|
884
|
+
expect(pkcs12.adcs_template).to eq(adcs_template)
|
885
|
+
end
|
886
|
+
end
|
887
|
+
|
888
|
+
context 'and the Pkcs12 has a password' do
|
889
|
+
it 'creates a valid Metasploit::Credential::Pkcs12' do
|
890
|
+
pkcs12_password = 'test_password'
|
891
|
+
opts[:private_data] = FactoryBot.build(:metasploit_credential_pkcs12, pkcs12_password: pkcs12_password ).data
|
892
|
+
opts[:private_metadata] = { pkcs12_password: pkcs12_password }
|
893
|
+
pkcs12 = test_object.create_credential_private(opts)
|
894
|
+
expect(pkcs12).to be_valid
|
895
|
+
end
|
896
|
+
end
|
874
897
|
end
|
875
898
|
end
|
876
899
|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
RSpec.describe Metasploit::Credential::Pkcs12, type: :model do
|
2
2
|
it_should_behave_like 'Metasploit::Concern.run'
|
3
3
|
|
4
|
+
it { is_expected.to be_a Metasploit::Credential::Private }
|
5
|
+
|
4
6
|
context 'factories' do
|
5
7
|
context 'metasploit_credential_pkcs12' do
|
6
8
|
subject(:metasploit_credential_pkcs12) do
|
@@ -9,6 +11,54 @@ RSpec.describe Metasploit::Credential::Pkcs12, type: :model do
|
|
9
11
|
|
10
12
|
it { is_expected.to be_valid }
|
11
13
|
end
|
14
|
+
|
15
|
+
context 'metasploit_credential_pkcs12_with_ca' do
|
16
|
+
subject(:metasploit_credential_pkcs12_with_ca) do
|
17
|
+
FactoryBot.build(:metasploit_credential_pkcs12_with_ca)
|
18
|
+
end
|
19
|
+
|
20
|
+
it { is_expected.to be_valid }
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'metasploit_credential_pkcs12_with_adcs_template' do
|
24
|
+
subject(:metasploit_credential_pkcs12_with_adcs_template) do
|
25
|
+
FactoryBot.build(:metasploit_credential_pkcs12_with_adcs_template)
|
26
|
+
end
|
27
|
+
|
28
|
+
it { is_expected.to be_valid }
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'metasploit_credential_pkcs12_with_pkcs12_password' do
|
32
|
+
subject(:metasploit_credential_pkcs12_with_pkcs12_password) do
|
33
|
+
FactoryBot.build(:metasploit_credential_pkcs12_with_pkcs12_password)
|
34
|
+
end
|
35
|
+
|
36
|
+
it { is_expected.to be_valid }
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'metasploit_credential_pkcs12_with_status' do
|
40
|
+
subject(:metasploit_credential_pkcs12_with_status) do
|
41
|
+
FactoryBot.build(:metasploit_credential_pkcs12_with_status)
|
42
|
+
end
|
43
|
+
|
44
|
+
it { is_expected.to be_valid }
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'metasploit_credential_pkcs12_with_ca_and_adcs_template' do
|
48
|
+
subject(:metasploit_credential_pkcs12_with_ca_and_adcs_template) do
|
49
|
+
FactoryBot.build(:metasploit_credential_pkcs12_with_ca_and_adcs_template)
|
50
|
+
end
|
51
|
+
|
52
|
+
it { is_expected.to be_valid }
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'metasploit_credential_pkcs12_with_ca_and_adcs_template_and_pkcs12_password' do
|
56
|
+
subject(:metasploit_credential_pkcs12_with_ca_and_adcs_template_and_pkcs12_password) do
|
57
|
+
FactoryBot.build(:metasploit_credential_pkcs12_with_ca_and_adcs_template_and_pkcs12_password)
|
58
|
+
end
|
59
|
+
|
60
|
+
it { is_expected.to be_valid }
|
61
|
+
end
|
12
62
|
end
|
13
63
|
|
14
64
|
context 'validations' do
|
@@ -105,6 +155,194 @@ RSpec.describe Metasploit::Credential::Pkcs12, type: :model do
|
|
105
155
|
it { is_expected.to include(error) }
|
106
156
|
end
|
107
157
|
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context '#data' do
|
163
|
+
it 'returns the base64 encoded pkcs12' do
|
164
|
+
cert = 'mycert'
|
165
|
+
data = Base64.strict_encode64(cert)
|
166
|
+
pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data)
|
167
|
+
expect(pkcs12.data).to eq(data)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context '#metadata' do
|
172
|
+
let(:cert) { 'mycert' }
|
173
|
+
let(:data) { Base64.strict_encode64(cert) }
|
174
|
+
|
175
|
+
context 'with the CA' do
|
176
|
+
it 'returns the CA in the metadata' do
|
177
|
+
adcs_ca = 'myca'
|
178
|
+
pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data, metadata: { adcs_ca: adcs_ca })
|
179
|
+
expect(pkcs12.metadata).to eq( { 'adcs_ca' => adcs_ca } )
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context 'with the Certififate Template' do
|
184
|
+
it 'returns the certificate template in the metadata' do
|
185
|
+
adcs_template = 'mytemplate'
|
186
|
+
pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data, metadata: { adcs_template: adcs_template })
|
187
|
+
expect(pkcs12.metadata).to eq( { 'adcs_template' => adcs_template } )
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context 'with both the CA and the Certififate Template' do
|
192
|
+
it 'returns the CA and the certificate template in the metadata' do
|
193
|
+
adcs_ca = 'myca'
|
194
|
+
adcs_template = 'mytemplate'
|
195
|
+
pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data, metadata: { adcs_ca: adcs_ca, adcs_template: adcs_template })
|
196
|
+
expect(pkcs12.metadata).to eq( { 'adcs_ca' => adcs_ca, 'adcs_template' => adcs_template } )
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
context 'with both the CA, the Certififate Template and the cert password' do
|
201
|
+
it 'returns the CA and the certificate template in the metadata' do
|
202
|
+
adcs_ca = 'myca'
|
203
|
+
adcs_template = 'mytemplate'
|
204
|
+
pkcs12_password = 'mypassword'
|
205
|
+
pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data, metadata: { adcs_ca: adcs_ca, adcs_template: adcs_template, pkcs12_password: pkcs12_password })
|
206
|
+
expect(pkcs12.metadata).to eq( { 'adcs_ca' => adcs_ca, 'adcs_template' => adcs_template, 'pkcs12_password' => pkcs12_password } )
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
context '#adcs_ca' do
|
212
|
+
it 'returns the CA' do
|
213
|
+
cert = 'mycert'
|
214
|
+
data = Base64.strict_encode64(cert)
|
215
|
+
adcs_ca = 'myca'
|
216
|
+
pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data, metadata: { adcs_ca: adcs_ca })
|
217
|
+
expect(pkcs12.adcs_ca).to eq(adcs_ca)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context '#adcs_template' do
|
222
|
+
it 'returns the certificate template' do
|
223
|
+
cert = 'mycert'
|
224
|
+
data = Base64.strict_encode64(cert)
|
225
|
+
adcs_template = 'mytemplate'
|
226
|
+
pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data, metadata: { adcs_template: adcs_template })
|
227
|
+
expect(pkcs12.adcs_template).to eq(adcs_template)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context '#pkcs12_password' do
|
232
|
+
it 'returns the Pkcs12 password' do
|
233
|
+
cert = 'mycert'
|
234
|
+
data = Base64.strict_encode64(cert)
|
235
|
+
pkcs12_password = 'mypassword'
|
236
|
+
pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: data, metadata: { pkcs12_password: pkcs12_password })
|
237
|
+
expect(pkcs12.pkcs12_password).to eq(pkcs12_password)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
context '#openssl_pkcs12' do
|
242
|
+
subject { FactoryBot.build(:metasploit_credential_pkcs12).openssl_pkcs12 }
|
243
|
+
|
244
|
+
it { is_expected.to be_a OpenSSL::PKCS12 }
|
245
|
+
|
246
|
+
it 'raises an exception if data is not a base64-encoded certificate' do
|
247
|
+
expect {
|
248
|
+
FactoryBot.build(:metasploit_credential_pkcs12, data: 'wrong_cert').openssl_pkcs12
|
249
|
+
}.to raise_error(ArgumentError)
|
250
|
+
end
|
251
|
+
|
252
|
+
it 'returns the expected OpenSSL::PKCS12' do
|
253
|
+
subject = '/C=FR/O=Yeah/OU=Yeah/CN=Yeah'
|
254
|
+
issuer = '/C=FR/O=Issuer1/OU=Issuer1/CN=Issuer1'
|
255
|
+
pkcs12 = FactoryBot.build(
|
256
|
+
:metasploit_credential_pkcs12,
|
257
|
+
signing_algorithm: 'SHA512',
|
258
|
+
subject: subject,
|
259
|
+
issuer: issuer
|
260
|
+
)
|
261
|
+
openssl_pkcs12 = pkcs12.openssl_pkcs12
|
262
|
+
expect(openssl_pkcs12.certificate.signature_algorithm).to eq("sha512WithRSAEncryption")
|
263
|
+
expect(openssl_pkcs12.certificate.subject.to_s).to eq(subject)
|
264
|
+
expect(openssl_pkcs12.certificate.issuer.to_s).to eq(issuer)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
context '#to_s' do
|
269
|
+
let(:subject) { '/C=FR/O=Yeah/OU=Yeah/CN=Yeah' }
|
270
|
+
let(:issuer) { '/C=FR/O=Issuer1/OU=Issuer1/CN=Issuer1' }
|
271
|
+
let(:adcs_ca) { 'myca' }
|
272
|
+
let(:adcs_template) { 'mytemplate' }
|
273
|
+
let(:pkcs12_password) { 'mypassword' }
|
274
|
+
|
275
|
+
context 'with the pkcs21 only' do
|
276
|
+
it 'returns the expected string' do
|
277
|
+
pkcs12 = FactoryBot.build(
|
278
|
+
:metasploit_credential_pkcs12,
|
279
|
+
subject: subject,
|
280
|
+
issuer: issuer
|
281
|
+
)
|
282
|
+
expect(pkcs12.to_s).to eq("subject:#{subject},issuer:#{issuer}")
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
context 'with the pkcs21 and the CA' do
|
287
|
+
it 'returns the expected string' do
|
288
|
+
pkcs12 = FactoryBot.build(
|
289
|
+
:metasploit_credential_pkcs12_with_ca,
|
290
|
+
subject: subject,
|
291
|
+
issuer: issuer,
|
292
|
+
metadata: { adcs_ca: adcs_ca }
|
293
|
+
)
|
294
|
+
expect(pkcs12.to_s).to eq("subject:#{subject},issuer:#{issuer},ADCS CA:#{adcs_ca}")
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
context 'with the pkcs21 and the ADCS template' do
|
299
|
+
it 'returns the expected string' do
|
300
|
+
pkcs12 = FactoryBot.build(
|
301
|
+
:metasploit_credential_pkcs12_with_adcs_template,
|
302
|
+
subject: subject,
|
303
|
+
issuer: issuer,
|
304
|
+
metadata: { adcs_template: adcs_template }
|
305
|
+
)
|
306
|
+
expect(pkcs12.to_s).to eq("subject:#{subject},issuer:#{issuer},ADCS template:#{adcs_template}")
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
context 'with the pkcs21, the CA and the ADCS template' do
|
311
|
+
it 'returns the expected string' do
|
312
|
+
subject = '/C=FR/O=Yeah/OU=Yeah/CN=Yeah'
|
313
|
+
issuer = '/C=FR/O=Issuer1/OU=Issuer1/CN=Issuer1'
|
314
|
+
pkcs12 = FactoryBot.build(
|
315
|
+
:metasploit_credential_pkcs12_with_ca_and_adcs_template,
|
316
|
+
subject: subject,
|
317
|
+
issuer: issuer,
|
318
|
+
metadata: { adcs_ca: adcs_ca, adcs_template: adcs_template }
|
319
|
+
)
|
320
|
+
expect(pkcs12.to_s).to eq("subject:#{subject},issuer:#{issuer},ADCS CA:#{adcs_ca},ADCS template:#{adcs_template}")
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
context 'with the pkcs21, the CA, the ADCS template and the pkcs12 password' do
|
325
|
+
it 'returns the expected string' do
|
326
|
+
subject = '/C=FR/O=Yeah/OU=Yeah/CN=Yeah'
|
327
|
+
issuer = '/C=FR/O=Issuer1/OU=Issuer1/CN=Issuer1'
|
328
|
+
pkcs12_password = 'mypassword'
|
329
|
+
pkcs12 = FactoryBot.build(
|
330
|
+
:metasploit_credential_pkcs12_with_ca_and_adcs_template_and_pkcs12_password,
|
331
|
+
subject: subject,
|
332
|
+
issuer: issuer,
|
333
|
+
pkcs12_password: pkcs12_password,
|
334
|
+
metadata: { adcs_ca: adcs_ca, adcs_template: adcs_template, pkcs12_password: pkcs12_password }
|
335
|
+
)
|
336
|
+
# The Pkcs12 password is voluntarily not included
|
337
|
+
expect(pkcs12.to_s).to eq("subject:#{subject},issuer:#{issuer},ADCS CA:#{adcs_ca},ADCS template:#{adcs_template}")
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
context 'with no data' do
|
342
|
+
it 'returns an empty string' do
|
343
|
+
pkcs12 = FactoryBot.build(:metasploit_credential_pkcs12, data: nil)
|
344
|
+
expect(pkcs12.to_s).to eq('')
|
345
|
+
end
|
108
346
|
end
|
109
347
|
end
|
110
348
|
|
@@ -126,6 +126,15 @@ RSpec.describe Metasploit::Credential::Private, type: :model do
|
|
126
126
|
:type,
|
127
127
|
type: :string
|
128
128
|
|
129
|
+
it_should_behave_like 'search_attribute',
|
130
|
+
:data,
|
131
|
+
type: :string
|
132
|
+
|
133
|
+
it_should_behave_like 'search_attribute',
|
134
|
+
:metadata,
|
135
|
+
type: :jsonb
|
136
|
+
|
137
|
+
|
129
138
|
it_should_behave_like 'search_with',
|
130
139
|
Metasploit::Credential::Search::Operator::Type,
|
131
140
|
name: :type,
|
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.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Metasploit Hackers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-04-
|
11
|
+
date: 2025-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: metasploit-concern
|
@@ -205,6 +205,7 @@ files:
|
|
205
205
|
- db/migrate/20161107153145_recreate_index_on_private_data_and_type.rb
|
206
206
|
- db/migrate/20161107203710_create_index_on_private_data_and_type_for_ssh_key.rb
|
207
207
|
- db/migrate/20221209005658_create_index_on_private_data_and_type_for_pkcs12.rb
|
208
|
+
- db/migrate/20250204172657_add_metadata_to_metasploit_credential_privates.rb
|
208
209
|
- lib/metasploit/credential.rb
|
209
210
|
- lib/metasploit/credential/case_insensitive_serializer.rb
|
210
211
|
- lib/metasploit/credential/core_validations.rb
|