metasploit-credential 6.0.3 → 6.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +2 -2
- data/app/models/metasploit/credential/krb_enc_key.rb +2 -10
- data/app/models/metasploit/credential/ntlm_hash.rb +5 -11
- data/app/models/metasploit/credential/pkcs12.rb +84 -0
- data/app/models/metasploit/credential/postgres_md5.rb +2 -10
- data/app/models/metasploit/credential/private.rb +1 -0
- data/config/locales/en.yml +6 -1
- data/db/migrate/20221209005658_create_index_on_private_data_and_type_for_pkcs12.rb +32 -0
- data/lib/metasploit/credential/case_insensitive_serializer.rb +9 -0
- data/lib/metasploit/credential/creation.rb +2 -0
- data/lib/metasploit/credential/importer/core.rb +1 -2
- data/lib/metasploit/credential/version.rb +1 -1
- data/lib/metasploit/credential.rb +2 -0
- data/spec/dummy/config/database.yml +2 -2
- data/spec/factories/metasploit/credential/pkcs12.rb +37 -0
- data/spec/lib/metasploit/credential/creation_spec.rb +53 -2
- data/spec/models/metasploit/credential/krb_enc_key_spec.rb +26 -0
- data/spec/models/metasploit/credential/ntlm_hash_spec.rb +24 -0
- data/spec/models/metasploit/credential/pkcs12_spec.rb +116 -0
- data/spec/models/metasploit/credential/postgres_md5_spec.rb +26 -0
- data/spec/models/metasploit/credential/private_spec.rb +1 -0
- data.tar.gz.sig +0 -0
- metadata +9 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c890cd98fc73ff6cbd909ded7207646f534477a4308f60f1e7dc09231cd29d88
|
4
|
+
data.tar.gz: 62fd27bcb61c852fb705cb89a0848771f6c4ae64b6a3c76202228ea6d2037969
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06bf39bbda84fc40c4f25085a39e4f27211a50246879fbe3b50f034c502a9b6fcf7cebbe9292912a4bfc42f8804837a45e8cbc332253b5f3fc5b122983f6b23e
|
7
|
+
data.tar.gz: d361ca8222849ab597accea494fef812339b971537bcd9cdbc3259eb19271a57f31cd1773c8338282211bf43569ee507888eb09f7326799b9ec6d66140bc50cd
|
checksums.yaml.gz.sig
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
w
|
2
|
-
|
1
|
+
�,-�Ds����4'w��nB�rI�}m��c�z.�?�{?D�ls�BG�� >ה)�N�:����u��#[3�[�������ޚ{��0aƺ%�|����#�P~?��P�'F��#,N;��$��.�U���<�8:�w��t��{-
|
2
|
+
�r4A��o�z��<��Q�0g��}�_�� �����K����L���GrS!O�� �2��l��wb�j�v�Z}n�2Z�+����O[�h�?���.���O�X.�
|
@@ -73,7 +73,8 @@ class Metasploit::Credential::KrbEncKey < Metasploit::Credential::PasswordHash
|
|
73
73
|
# Callbacks
|
74
74
|
#
|
75
75
|
|
76
|
-
|
76
|
+
serialize :data, Metasploit::Credential::CaseInsensitiveSerializer
|
77
|
+
validates_uniqueness_of :data, :case_sensitive => false
|
77
78
|
|
78
79
|
#
|
79
80
|
# Validations
|
@@ -162,15 +163,6 @@ class Metasploit::Credential::KrbEncKey < Metasploit::Credential::PasswordHash
|
|
162
163
|
}
|
163
164
|
end
|
164
165
|
|
165
|
-
# Normalizes {#data} by making it all lowercase so that the unique validation and index on
|
166
|
-
# ({Metasploit::Credential::Private#type}, {#data}) catches collision in a case-insensitive manner without the need
|
167
|
-
# to use case-insensitive comparisons.
|
168
|
-
def normalize_data
|
169
|
-
if data
|
170
|
-
self.data = data.downcase
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
166
|
# Validates that {#data} is in the expected data format
|
175
167
|
def data_format
|
176
168
|
unless DATA_REGEXP.match(data)
|
@@ -55,15 +55,18 @@ class Metasploit::Credential::NTLMHash < Metasploit::Credential::ReplayableHash
|
|
55
55
|
# @return [String] `'<LAN Manager hex digest>:<NT LAN Manager hex digest>'`
|
56
56
|
|
57
57
|
#
|
58
|
-
#
|
58
|
+
# Serializers
|
59
59
|
#
|
60
60
|
|
61
|
-
|
61
|
+
# Hash results are always downcased when stored in the database
|
62
|
+
# This serializer allows for ORM to search in a case-insensitive
|
63
|
+
serialize :data, Metasploit::Credential::CaseInsensitiveSerializer
|
62
64
|
|
63
65
|
#
|
64
66
|
# Validations
|
65
67
|
#
|
66
68
|
|
69
|
+
validates_uniqueness_of :data, :case_sensitive => false
|
67
70
|
validate :data_format
|
68
71
|
|
69
72
|
#
|
@@ -130,15 +133,6 @@ class Metasploit::Credential::NTLMHash < Metasploit::Credential::ReplayableHash
|
|
130
133
|
|
131
134
|
private
|
132
135
|
|
133
|
-
# Normalizes {#data} by making it all lowercase so that the unique validation and index on
|
134
|
-
# ({Metasploit::Credential::Private#type}, {#data}) catches collision in a case-insensitive manner without the need
|
135
|
-
# to use case-insensitive comparisons.
|
136
|
-
def normalize_data
|
137
|
-
if data
|
138
|
-
self.data = data.downcase
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
136
|
# Validates that {#data} is in the NTLM data format of <LAN Manager hex digest>:<NT LAN Manager hex digest>. Both hex
|
143
137
|
# digests are 32 lowercase hexadecimal characters.
|
144
138
|
def data_format
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
# A private Pkcs12 file.
|
5
|
+
class Metasploit::Credential::Pkcs12 < Metasploit::Credential::Private
|
6
|
+
#
|
7
|
+
# Attributes
|
8
|
+
#
|
9
|
+
|
10
|
+
# @!attribute data
|
11
|
+
# A private pkcs12 file, base64 encoded - i.e. starting with 'MIIMhgIBAzCCDFAGCSqGSIb3DQEHAaCC....'
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
|
15
|
+
#
|
16
|
+
#
|
17
|
+
# Validations
|
18
|
+
#
|
19
|
+
#
|
20
|
+
|
21
|
+
#
|
22
|
+
# Attribute Validations
|
23
|
+
#
|
24
|
+
|
25
|
+
validates :data,
|
26
|
+
presence: true
|
27
|
+
#
|
28
|
+
# Method Validations
|
29
|
+
#
|
30
|
+
|
31
|
+
validate :readable
|
32
|
+
|
33
|
+
#
|
34
|
+
# Instance Methods
|
35
|
+
#
|
36
|
+
|
37
|
+
# Converts the private pkcs12 data in {#data} to an `OpenSSL::PKCS12` instance.
|
38
|
+
#
|
39
|
+
# @return [OpenSSL::PKCS12]
|
40
|
+
# @raise [ArgumentError] if {#data} cannot be loaded
|
41
|
+
def openssl_pkcs12
|
42
|
+
if data
|
43
|
+
begin
|
44
|
+
password = ''
|
45
|
+
OpenSSL::PKCS12.new(Base64.strict_decode64(data), password)
|
46
|
+
rescue OpenSSL::PKCS12::PKCS12Error => error
|
47
|
+
raise ArgumentError.new(error)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# The {#data key data}'s fingerprint, suitable for displaying to the
|
53
|
+
# user.
|
54
|
+
#
|
55
|
+
# @return [String]
|
56
|
+
def to_s
|
57
|
+
return '' unless data
|
58
|
+
|
59
|
+
cert = openssl_pkcs12.certificate
|
60
|
+
result = []
|
61
|
+
result << "subject:#{cert.subject.to_s}"
|
62
|
+
result << "issuer:#{cert.issuer.to_s}"
|
63
|
+
result.join(',')
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
#
|
69
|
+
# Validates that {#data} can be read by OpenSSL and a `OpenSSL::PKCS12` can be created from {#data}. Any exception
|
70
|
+
# raised will be reported as a validation error.
|
71
|
+
#
|
72
|
+
# @return [void]
|
73
|
+
def readable
|
74
|
+
if data
|
75
|
+
begin
|
76
|
+
openssl_pkcs12
|
77
|
+
rescue => error
|
78
|
+
errors.add(:data, "#{error.class} #{error}")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
Metasploit::Concern.run(self)
|
84
|
+
end
|
@@ -13,7 +13,8 @@ class Metasploit::Credential::PostgresMD5 < Metasploit::Credential::ReplayableHa
|
|
13
13
|
# Callbacks
|
14
14
|
#
|
15
15
|
|
16
|
-
|
16
|
+
serialize :data, Metasploit::Credential::CaseInsensitiveSerializer
|
17
|
+
validates_uniqueness_of :data, :case_sensitive => false
|
17
18
|
|
18
19
|
#
|
19
20
|
# Validations
|
@@ -23,15 +24,6 @@ class Metasploit::Credential::PostgresMD5 < Metasploit::Credential::ReplayableHa
|
|
23
24
|
|
24
25
|
private
|
25
26
|
|
26
|
-
# Normalizes {#data} by making it all lowercase so that the unique validation and index on
|
27
|
-
# ({Metasploit::Credential::Private#type}, {#data}) catches collision in a case-insensitive manner without the need
|
28
|
-
# to use case-insensitive comparisons.
|
29
|
-
def normalize_data
|
30
|
-
if data
|
31
|
-
self.data = data.downcase
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
27
|
def data_format
|
36
28
|
unless DATA_REGEXP.match(data)
|
37
29
|
errors.add(:data, 'is not in Postgres MD5 Hash format')
|
data/config/locales/en.yml
CHANGED
@@ -57,6 +57,7 @@ en:
|
|
57
57
|
metasploit/credential/ntlm_hash: "NTLM hash"
|
58
58
|
metasploit/credential/ssh_key: "SSH key"
|
59
59
|
metasploit/credential/krb_enc_key: 'Krb enc key'
|
60
|
+
metasploit/credential/pkcs12: 'Pkcs12 (pfx)'
|
60
61
|
errors:
|
61
62
|
models:
|
62
63
|
metasploit/credential/core:
|
@@ -83,10 +84,14 @@ en:
|
|
83
84
|
attributes:
|
84
85
|
data:
|
85
86
|
format: "is not in the KrbEncKey data format of 'msf_krbenckey:<ENCTYPE>:<KEY>:<SALT>', where the key and salt are in hexadecimal characters"
|
87
|
+
metasploit/credential/pkcs12:
|
88
|
+
attributes:
|
89
|
+
data:
|
90
|
+
format: "is not a Base64 encoded pkcs12 file without a password"
|
86
91
|
metasploit/credential/ssh_key:
|
87
92
|
attributes:
|
88
93
|
data:
|
89
|
-
encrypted: "is encrypted, but Metasploit::Credential::SSHKey only supports
|
94
|
+
encrypted: "is encrypted, but Metasploit::Credential::SSHKey only supports unencrypted private keys."
|
90
95
|
not_private: "is not a private key."
|
91
96
|
errors:
|
92
97
|
messages:
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class CreateIndexOnPrivateDataAndTypeForPkcs12 < ActiveRecord::Migration[6.1]
|
2
|
+
def up
|
3
|
+
# Drop the existing index created by 20161107153145_recreate_index_on_private_data_and_type.rb, and recreate it
|
4
|
+
# with Metasploit::Credential::Pkcs12 ignored
|
5
|
+
remove_index :metasploit_credential_privates, [:type, :data], if_exists: true
|
6
|
+
change_table :metasploit_credential_privates do |t|
|
7
|
+
t.index [:type, :data],
|
8
|
+
unique: true,
|
9
|
+
where: "NOT (type = 'Metasploit::Credential::SSHKey' or type = 'Metasploit::Credential::Pkcs12')"
|
10
|
+
end
|
11
|
+
|
12
|
+
# Create a new index similar to 20161107203710_create_index_on_private_data_and_type_for_ssh_key.rb
|
13
|
+
sql = <<~EOF
|
14
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "index_metasploit_credential_privates_on_type_and_data_pkcs12" ON
|
15
|
+
"metasploit_credential_privates" ("type", decode(md5(data), 'hex'))
|
16
|
+
WHERE type in ('Metasploit::Credential::Pkcs12')
|
17
|
+
EOF
|
18
|
+
execute(sql)
|
19
|
+
end
|
20
|
+
|
21
|
+
def down
|
22
|
+
# Restore the original metasploit_credential_privates index from /Users/adfoster/Documents/code/metasploit-credential/db/migrate/20161107153145_recreate_index_on_private_data_and_type.rb
|
23
|
+
# XXX: this would crash if there are any Pkcs12 entries present, so for the simplicity of avoiding a data migration we keep the pkcs12 type ommitted from the index
|
24
|
+
remove_index :metasploit_credential_privates, [:type, :data], if_exists: true
|
25
|
+
change_table :metasploit_credential_privates do |t|
|
26
|
+
t.index [:type, :data],
|
27
|
+
unique: true,
|
28
|
+
where: "NOT (type = 'Metasploit::Credential::SSHKey' or type = 'Metasploit::Credential::Pkcs12')"
|
29
|
+
end
|
30
|
+
remove_index :metasploit_credential_privates, name: :index_metasploit_credential_privates_on_type_and_data_pkcs12, if_exists: true
|
31
|
+
end
|
32
|
+
end
|
@@ -479,6 +479,8 @@ module Metasploit::Credential::Creation
|
|
479
479
|
private_object = Metasploit::Credential::Password.where(data: private_data).first_or_create
|
480
480
|
when :ssh_key
|
481
481
|
private_object = Metasploit::Credential::SSHKey.where(data: private_data).first_or_create
|
482
|
+
when :pkcs12
|
483
|
+
private_object = Metasploit::Credential::Pkcs12.where(data: private_data).first_or_create
|
482
484
|
when :krb_enc_key
|
483
485
|
private_object = Metasploit::Credential::KrbEncKey.where(data: private_data).first_or_create
|
484
486
|
when :ntlm_hash
|
@@ -116,7 +116,6 @@ class Metasploit::Credential::Importer::Core
|
|
116
116
|
private_class = row['private_type'].present? ? row['private_type'].constantize : ''
|
117
117
|
private_data = row['private_data'].present? ? row['private_data'] : ''
|
118
118
|
|
119
|
-
|
120
119
|
if realms[realm_value].nil?
|
121
120
|
realms[realm_value] = Metasploit::Credential::Realm.where(key: realm_key, value: realm_value).first_or_create
|
122
121
|
end
|
@@ -210,7 +209,7 @@ class Metasploit::Credential::Importer::Core
|
|
210
209
|
if private_data.strip == BLANK_TOKEN
|
211
210
|
private_object_for_row = Metasploit::Credential::BlankPassword.first_or_create
|
212
211
|
else
|
213
|
-
private_object_for_row = @private_credential_type.constantize.where(data:
|
212
|
+
private_object_for_row = @private_credential_type.constantize.where(data: private_data).first_or_create
|
214
213
|
end
|
215
214
|
|
216
215
|
# need to check private_object_for_row.valid? to raise a user facing message if any cred had invalid private
|
@@ -28,6 +28,7 @@ module Metasploit
|
|
28
28
|
|
29
29
|
autoload :BlankPassword
|
30
30
|
autoload :BlankUsername
|
31
|
+
autoload :CaseInsensitiveSerializer
|
31
32
|
autoload :Core
|
32
33
|
autoload :CoreValidations
|
33
34
|
autoload :Creation
|
@@ -43,6 +44,7 @@ module Metasploit
|
|
43
44
|
autoload :Origin
|
44
45
|
autoload :Password
|
45
46
|
autoload :PasswordHash
|
47
|
+
autoload :Pkcs12
|
46
48
|
autoload :PostgresMD5
|
47
49
|
autoload :Private
|
48
50
|
autoload :Public
|
@@ -1,6 +1,6 @@
|
|
1
1
|
development: &pgsql
|
2
2
|
adapter: postgresql
|
3
|
-
database: metasploit-
|
3
|
+
database: metasploit-credential_development2
|
4
4
|
username: msf
|
5
5
|
password: pass123
|
6
6
|
host: localhost
|
@@ -10,4 +10,4 @@ development: &pgsql
|
|
10
10
|
min_messages: warning
|
11
11
|
test:
|
12
12
|
<<: *pgsql
|
13
|
-
database: metasploit-
|
13
|
+
database: metasploit-credential_test2
|
@@ -0,0 +1,37 @@
|
|
1
|
+
FactoryBot.define do
|
2
|
+
factory :metasploit_credential_pkcs12,
|
3
|
+
class: Metasploit::Credential::Pkcs12 do
|
4
|
+
transient do
|
5
|
+
# key size tuned for speed. DO NOT use for production, it is below current recommended key size of 2048
|
6
|
+
key_size { 1024 }
|
7
|
+
# signing algorithm for the pkcs12 cert
|
8
|
+
signing_algorithm { 'SHA256' }
|
9
|
+
# the cert subject
|
10
|
+
subject { '/C=BE/O=Test/OU=Test/CN=Test' }
|
11
|
+
# the cert issuer
|
12
|
+
issuer { '/C=BE/O=Test/OU=Test/CN=Test' }
|
13
|
+
end
|
14
|
+
|
15
|
+
data {
|
16
|
+
password = ''
|
17
|
+
pkcs12_name = ''
|
18
|
+
|
19
|
+
private_key = OpenSSL::PKey::RSA.new(key_size)
|
20
|
+
public_key = private_key.public_key
|
21
|
+
|
22
|
+
cert = OpenSSL::X509::Certificate.new
|
23
|
+
cert.subject = OpenSSL::X509::Name.parse(subject)
|
24
|
+
cert.issuer = OpenSSL::X509::Name.parse(issuer)
|
25
|
+
cert.not_before = Time.now
|
26
|
+
cert.not_after = Time.now + 365 * 24 * 60 * 60
|
27
|
+
cert.public_key = public_key
|
28
|
+
cert.serial = 0x0
|
29
|
+
cert.version = 2
|
30
|
+
cert.sign(private_key, OpenSSL::Digest.new(signing_algorithm))
|
31
|
+
|
32
|
+
pkcs12 = OpenSSL::PKCS12.create(password, pkcs12_name, private_key, cert)
|
33
|
+
pkcs12_base64 = Base64.strict_encode64(pkcs12.to_der)
|
34
|
+
pkcs12_base64
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
@@ -134,20 +134,30 @@ RSpec.describe Metasploit::Credential::Creation do
|
|
134
134
|
nonreplayable_hash: "Metasploit::Credential::NonreplayableHash",
|
135
135
|
ntlm_hash: "Metasploit::Credential::NTLMHash",
|
136
136
|
postgres_md5: "Metasploit::Credential::PostgresMD5",
|
137
|
-
ssh_key: "Metasploit::Credential::SSHKey"
|
137
|
+
ssh_key: "Metasploit::Credential::SSHKey",
|
138
|
+
krb_enc_key: "Metasploit::Credential::KrbEncKey",
|
139
|
+
pkcs12: "Metasploit::Credential::Pkcs12"
|
138
140
|
}.each_pair do |private_type, public_class|
|
139
141
|
context "Origin[manual], Public[Username], Private[#{private_type}]" do
|
140
142
|
let(:ssh_key) {
|
141
143
|
key_class = OpenSSL::PKey.const_get(:RSA)
|
142
144
|
key_class.generate(512).to_s
|
143
145
|
}
|
146
|
+
let(:krb_enc_key) {
|
147
|
+
FactoryBot.build(:metasploit_credential_krb_enc_key).data
|
148
|
+
}
|
149
|
+
let(:pkcs12) {
|
150
|
+
FactoryBot.build(:metasploit_credential_pkcs12).data
|
151
|
+
}
|
144
152
|
let(:private_data) { {
|
145
153
|
password: 'password',
|
146
154
|
blank_password: '',
|
147
155
|
nonreplayable_hash: '435ba65d2e46d35bc656086694868d1ab2c0f9fd',
|
148
156
|
ntlm_hash: 'aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0',
|
149
157
|
postgres_md5: 'md5ac4bbe016b808c3c0b816981f240dcae',
|
150
|
-
ssh_key: ssh_key
|
158
|
+
ssh_key: ssh_key,
|
159
|
+
krb_enc_key: krb_enc_key,
|
160
|
+
pkcs12: pkcs12
|
151
161
|
}}
|
152
162
|
let(:credential_data) {{
|
153
163
|
workspace_id: workspace.id,
|
@@ -168,6 +178,37 @@ RSpec.describe Metasploit::Credential::Creation do
|
|
168
178
|
end
|
169
179
|
end
|
170
180
|
end
|
181
|
+
context 'deletion and creation' do
|
182
|
+
let(:private_data) { 'md5ac4bbe016b808c3c0b816981f240dcae' }
|
183
|
+
let(:private_data_upcase) { private_data.upcase }
|
184
|
+
let(:credential_data) {{
|
185
|
+
workspace_id: workspace.id,
|
186
|
+
user_id: user.id,
|
187
|
+
origin_type: :manual,
|
188
|
+
username: 'admin',
|
189
|
+
private_data: private_data,
|
190
|
+
private_type: :postgres_md5
|
191
|
+
}}
|
192
|
+
it 'creates a private cred' do
|
193
|
+
expect{ test_object.create_credential(credential_data) }.to change{ Metasploit::Credential::PostgresMD5.count }.by(1)
|
194
|
+
end
|
195
|
+
let(:credential_data_upcase) {{
|
196
|
+
workspace_id: workspace.id,
|
197
|
+
user_id: user.id,
|
198
|
+
origin_type: :manual,
|
199
|
+
username: 'admin',
|
200
|
+
private_data: private_data_upcase,
|
201
|
+
private_type: :postgres_md5
|
202
|
+
}}
|
203
|
+
it 'allows for the recreation of core with case insensitive private credentials set to different case' do
|
204
|
+
expect{ test_object.create_credential(credential_data) }.to change{ Metasploit::Credential::PostgresMD5.count }.by(1)
|
205
|
+
expect{ Metasploit::Credential::Core.first.destroy }.to change{ Metasploit::Credential::Core.count }.by(-1)
|
206
|
+
expect( Metasploit::Credential::PostgresMD5.count ).to eq(1)
|
207
|
+
expect( Metasploit::Credential::Core.count ).to eq(0)
|
208
|
+
expect{ test_object.create_credential(credential_data_upcase) }.to change{ Metasploit::Credential::Core.count }.by(1)
|
209
|
+
expect( Metasploit::Credential::PostgresMD5.count ).to eq(1)
|
210
|
+
end
|
211
|
+
end
|
171
212
|
end
|
172
213
|
|
173
214
|
context '#create_credential_and_login' do
|
@@ -821,6 +862,16 @@ RSpec.describe Metasploit::Credential::Creation do
|
|
821
862
|
expect{ test_object.create_credential_private(opts) }.to change{ Metasploit::Credential::KrbEncKey.count }.by(1)
|
822
863
|
end
|
823
864
|
end
|
865
|
+
|
866
|
+
context 'when :private_type is pkcs12' do
|
867
|
+
it 'creates a Metasploit::Credential::Pkcs12' do
|
868
|
+
opts = {
|
869
|
+
private_data: FactoryBot.build(:metasploit_credential_pkcs12).data,
|
870
|
+
private_type: :pkcs12
|
871
|
+
}
|
872
|
+
expect{ test_object.create_credential_private(opts) }.to change{ Metasploit::Credential::Pkcs12.count }.by(1)
|
873
|
+
end
|
874
|
+
end
|
824
875
|
end
|
825
876
|
|
826
877
|
context '#create_credential_core' do
|
@@ -148,4 +148,30 @@ RSpec.describe Metasploit::Credential::KrbEncKey, type: :model do
|
|
148
148
|
end
|
149
149
|
end
|
150
150
|
end
|
151
|
+
|
152
|
+
context 'serialization' do
|
153
|
+
context '#first_or_create' do
|
154
|
+
let(:data) { 'msf_krbenckey:23:e22e04519aa757d12f1219c4f31252f4:' }
|
155
|
+
let(:upcase_data) {data.upcase}
|
156
|
+
|
157
|
+
context 'creates a new instance that stores case-insensitive value' do
|
158
|
+
it 'creates case insensitive data' do
|
159
|
+
expect{ Metasploit::Credential::KrbEncKey.where(data: data).first_or_create }.to change{Metasploit::Credential::KrbEncKey.count}.by(1)
|
160
|
+
expect{ Metasploit::Credential::KrbEncKey.where(data: upcase_data).first_or_create }.not_to change{Metasploit::Credential::KrbEncKey.count}
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
context 'finds an existing case insensitive match' do
|
165
|
+
let(:krb_enc_key) do
|
166
|
+
FactoryBot.build(
|
167
|
+
:metasploit_credential_krb_enc_key,
|
168
|
+
data: upcase_data
|
169
|
+
)
|
170
|
+
end
|
171
|
+
it 'successfully looks up credential in case insensitive way' do
|
172
|
+
expect( krb_enc_key.data ).to eq(data)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
151
177
|
end
|
@@ -397,5 +397,29 @@ RSpec.describe Metasploit::Credential::NTLMHash, type: :model do
|
|
397
397
|
end
|
398
398
|
end
|
399
399
|
|
400
|
+
context 'serialization' do
|
401
|
+
context '#first_or_create' do
|
402
|
+
let(:data) { 'aad3b435b51404eeaad3b435b51404ee:4dc0249ad90ab626362050195893c788' }
|
403
|
+
let(:upcase_data) {data.upcase}
|
404
|
+
|
405
|
+
context 'creates a new instance that stores case-insensitive value' do
|
406
|
+
it 'creates case insensitive data' do
|
407
|
+
expect{ Metasploit::Credential::NTLMHash.where(data: data).first_or_create }.to change{Metasploit::Credential::NTLMHash.count}.by(1)
|
408
|
+
expect{ Metasploit::Credential::NTLMHash.where(data: upcase_data).first_or_create }.not_to change{Metasploit::Credential::NTLMHash.count}
|
409
|
+
end
|
410
|
+
end
|
400
411
|
|
412
|
+
context 'finds an existing case insensitive match' do
|
413
|
+
let(:ntlm_hash) do
|
414
|
+
FactoryBot.build(
|
415
|
+
:metasploit_credential_ntlm_hash,
|
416
|
+
data: upcase_data
|
417
|
+
)
|
418
|
+
end
|
419
|
+
it 'successfully looks up credential in case insensitive way' do
|
420
|
+
expect( ntlm_hash.data ).to eq(data)
|
421
|
+
end
|
422
|
+
end
|
423
|
+
end
|
424
|
+
end
|
401
425
|
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
RSpec.describe Metasploit::Credential::Pkcs12, type: :model do
|
2
|
+
it_should_behave_like 'Metasploit::Concern.run'
|
3
|
+
|
4
|
+
context 'factories' do
|
5
|
+
context 'metasploit_credential_pkcs12' do
|
6
|
+
subject(:metasploit_credential_pkcs12) do
|
7
|
+
FactoryBot.build(:metasploit_credential_pkcs12)
|
8
|
+
end
|
9
|
+
|
10
|
+
it { is_expected.to be_valid }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'validations' do
|
15
|
+
it { is_expected.to validate_presence_of :data }
|
16
|
+
|
17
|
+
context 'on #data' do
|
18
|
+
subject(:data_errors) do
|
19
|
+
pkcs12.errors[:data]
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:pkcs12) do
|
23
|
+
FactoryBot.build(:metasploit_credential_pkcs12)
|
24
|
+
end
|
25
|
+
|
26
|
+
context '#readable' do
|
27
|
+
context 'with #data' do
|
28
|
+
context 'with error' do
|
29
|
+
#
|
30
|
+
# Shared Examples
|
31
|
+
#
|
32
|
+
|
33
|
+
shared_examples_for 'exception' do
|
34
|
+
it 'includes error class' do
|
35
|
+
exception_class_name = exception.class.to_s
|
36
|
+
expect(
|
37
|
+
data_errors.any? { |error|
|
38
|
+
error.include? exception_class_name
|
39
|
+
}
|
40
|
+
).to be true
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'includes error message' do
|
44
|
+
exception_message = exception.to_s
|
45
|
+
|
46
|
+
expect(
|
47
|
+
data_errors.any? { |error|
|
48
|
+
error.include? exception_message
|
49
|
+
}
|
50
|
+
).to be true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Callbacks
|
56
|
+
#
|
57
|
+
|
58
|
+
before(:example) do
|
59
|
+
expect(pkcs12).to receive(:openssl_pkcs12).and_raise(exception)
|
60
|
+
|
61
|
+
pkcs12.valid?
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'with ArgumentError' do
|
65
|
+
let(:exception) do
|
66
|
+
ArgumentError.new("Bad Argument")
|
67
|
+
end
|
68
|
+
|
69
|
+
it_should_behave_like 'exception'
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'with OpenSSL::PKCS12::PKCS12Error' do
|
73
|
+
let(:exception) do
|
74
|
+
OpenSSL::PKCS12::PKCS12Error.new('mac verify failure')
|
75
|
+
end
|
76
|
+
|
77
|
+
it_should_behave_like 'exception'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'without error' do
|
82
|
+
before(:example) do
|
83
|
+
pkcs12.valid?
|
84
|
+
end
|
85
|
+
|
86
|
+
it { is_expected.to be_empty }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'without #data' do
|
91
|
+
let(:error) do
|
92
|
+
I18n.translate!('errors.messages.blank')
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# Callbacks
|
97
|
+
#
|
98
|
+
|
99
|
+
before(:example) do
|
100
|
+
pkcs12.data = nil
|
101
|
+
|
102
|
+
pkcs12.valid?
|
103
|
+
end
|
104
|
+
|
105
|
+
it { is_expected.to include(error) }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'human name' do
|
112
|
+
it 'properly determines the model\'s human name' do
|
113
|
+
expect(described_class.model_name.human).to eq('Pkcs12 (pfx)')
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -119,4 +119,30 @@ RSpec.describe Metasploit::Credential::PostgresMD5, type: :model do
|
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
|
+
context 'serialization' do
|
123
|
+
context '#first_or_create' do
|
124
|
+
let(:data) { "md5#{SecureRandom.hex(16)}" }
|
125
|
+
let(:upcase_data) {data.upcase}
|
126
|
+
|
127
|
+
context 'creates a new instance that stores case-insensitive value' do
|
128
|
+
it 'creates case insensitive data' do
|
129
|
+
expect{ Metasploit::Credential::PostgresMD5.where(data: data).first_or_create }.to change{Metasploit::Credential::PostgresMD5.count}.by(1)
|
130
|
+
expect{ Metasploit::Credential::PostgresMD5.where(data: upcase_data).first_or_create }.not_to change{Metasploit::Credential::PostgresMD5.count}
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context 'finds an existing case insensitive match' do
|
135
|
+
let(:postgres_md5) do
|
136
|
+
FactoryBot.build(
|
137
|
+
:metasploit_credential_postgres_md5,
|
138
|
+
data: upcase_data
|
139
|
+
)
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'successfully looks up credential in case insensitive way' do
|
143
|
+
expect( postgres_md5.data ).to eq(data)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
122
148
|
end
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
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.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Metasploit Hackers
|
@@ -93,7 +93,7 @@ cert_chain:
|
|
93
93
|
EknWpNgVhohbot1lfVAMmIhdtOVaRVcQQixWPwprDj/ydB8ryDMDosIMcw+fkoXU
|
94
94
|
9GJsSaSRRYQ9UUkVL27b64okU8D48m8=
|
95
95
|
-----END CERTIFICATE-----
|
96
|
-
date: 2023-
|
96
|
+
date: 2023-05-19 00:00:00.000000000 Z
|
97
97
|
dependencies:
|
98
98
|
- !ruby/object:Gem::Dependency
|
99
99
|
name: metasploit-concern
|
@@ -255,6 +255,7 @@ files:
|
|
255
255
|
- app/models/metasploit/credential/origin/session.rb
|
256
256
|
- app/models/metasploit/credential/password.rb
|
257
257
|
- app/models/metasploit/credential/password_hash.rb
|
258
|
+
- app/models/metasploit/credential/pkcs12.rb
|
258
259
|
- app/models/metasploit/credential/postgres_md5.rb
|
259
260
|
- app/models/metasploit/credential/private.rb
|
260
261
|
- app/models/metasploit/credential/public.rb
|
@@ -288,7 +289,9 @@ files:
|
|
288
289
|
- db/migrate/20150106201450_old_creds_to_new_creds2.rb
|
289
290
|
- db/migrate/20161107153145_recreate_index_on_private_data_and_type.rb
|
290
291
|
- db/migrate/20161107203710_create_index_on_private_data_and_type_for_ssh_key.rb
|
292
|
+
- db/migrate/20221209005658_create_index_on_private_data_and_type_for_pkcs12.rb
|
291
293
|
- lib/metasploit/credential.rb
|
294
|
+
- lib/metasploit/credential/case_insensitive_serializer.rb
|
292
295
|
- lib/metasploit/credential/core_validations.rb
|
293
296
|
- lib/metasploit/credential/creation.rb
|
294
297
|
- lib/metasploit/credential/engine.rb
|
@@ -366,6 +369,7 @@ files:
|
|
366
369
|
- spec/factories/metasploit/credential/origin/sessions.rb
|
367
370
|
- spec/factories/metasploit/credential/password_hashes.rb
|
368
371
|
- spec/factories/metasploit/credential/passwords.rb
|
372
|
+
- spec/factories/metasploit/credential/pkcs12.rb
|
369
373
|
- spec/factories/metasploit/credential/postgres_md5.rb
|
370
374
|
- spec/factories/metasploit/credential/privates.rb
|
371
375
|
- spec/factories/metasploit/credential/publics.rb
|
@@ -401,6 +405,7 @@ files:
|
|
401
405
|
- spec/models/metasploit/credential/origin/session_spec.rb
|
402
406
|
- spec/models/metasploit/credential/password_hash_spec.rb
|
403
407
|
- spec/models/metasploit/credential/password_spec.rb
|
408
|
+
- spec/models/metasploit/credential/pkcs12_spec.rb
|
404
409
|
- spec/models/metasploit/credential/postgres_md5_spec.rb
|
405
410
|
- spec/models/metasploit/credential/private_spec.rb
|
406
411
|
- spec/models/metasploit/credential/public_spec.rb
|
@@ -497,6 +502,7 @@ test_files:
|
|
497
502
|
- spec/factories/metasploit/credential/origin/sessions.rb
|
498
503
|
- spec/factories/metasploit/credential/password_hashes.rb
|
499
504
|
- spec/factories/metasploit/credential/passwords.rb
|
505
|
+
- spec/factories/metasploit/credential/pkcs12.rb
|
500
506
|
- spec/factories/metasploit/credential/postgres_md5.rb
|
501
507
|
- spec/factories/metasploit/credential/privates.rb
|
502
508
|
- spec/factories/metasploit/credential/publics.rb
|
@@ -532,6 +538,7 @@ test_files:
|
|
532
538
|
- spec/models/metasploit/credential/origin/session_spec.rb
|
533
539
|
- spec/models/metasploit/credential/password_hash_spec.rb
|
534
540
|
- spec/models/metasploit/credential/password_spec.rb
|
541
|
+
- spec/models/metasploit/credential/pkcs12_spec.rb
|
535
542
|
- spec/models/metasploit/credential/postgres_md5_spec.rb
|
536
543
|
- spec/models/metasploit/credential/private_spec.rb
|
537
544
|
- spec/models/metasploit/credential/public_spec.rb
|
metadata.gz.sig
CHANGED
Binary file
|