metasploit-credential 6.0.4 → 6.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97884e997f5fe9428e4fc79f0b4a9e4a4e51a06363b372a2fa1affa0dffba6d5
4
- data.tar.gz: 37e4b1a543e249e7facb0c6570efd104d4bf347922636b561aecb78bab0602a8
3
+ metadata.gz: 6f75b5f1ebaf8c77550aaa570f436d0b47fe7e56737d04fda0e37ea2e2bbb7db
4
+ data.tar.gz: afba4ff649a4108b47f278b9eda28a17d395d3855b2af3df88f408b3b4221596
5
5
  SHA512:
6
- metadata.gz: 23da300c2d52cd12a8aeb398010b21d2542ab4f88f59946fabde21efbb3554c30f36b32839961abef13c43528324ddacc807d68872cc9df3bbf2e47d31c66905
7
- data.tar.gz: 90f93c7bd036e2f6b328dca97707d5e85bd40a257cb6f7dba928d0d6fd983cd295e38b3052cb6aae271c37bd730e4b5c36e71feed1e1dc561bb0b163c207d098
6
+ metadata.gz: 7802c585f17887c93b52387c46db9d3ac478493972f5b232f3bc4ec66926de8c5691c69062fbcc7fcbfcde83e6ae15e1516d15fa8de988a07d632c544c221798
7
+ data.tar.gz: 1142a52a0a8bd41b727a1eb0a211254d041d677c86b2badd26d28d232e61f5fb8008a99bc9f958178383a83864e227cd09df640c2ffcc4002d927cabc2d9dd6b
checksums.yaml.gz.sig CHANGED
Binary file
@@ -73,7 +73,8 @@ class Metasploit::Credential::KrbEncKey < Metasploit::Credential::PasswordHash
73
73
  # Callbacks
74
74
  #
75
75
 
76
- before_validation :normalize_data
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
- # Callbacks
58
+ # Serializers
59
59
  #
60
60
 
61
- before_validation :normalize_data
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
@@ -13,7 +13,8 @@ class Metasploit::Credential::PostgresMD5 < Metasploit::Credential::ReplayableHa
13
13
  # Callbacks
14
14
  #
15
15
 
16
- before_validation :normalize_data
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')
@@ -0,0 +1,9 @@
1
+ class Metasploit::Credential::CaseInsensitiveSerializer
2
+ def self.load(value)
3
+ value
4
+ end
5
+
6
+ def self.dump(value)
7
+ value.downcase
8
+ end
9
+ end
@@ -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: row['private_data']).first_or_create
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
@@ -3,7 +3,7 @@
3
3
  module Metasploit
4
4
  module Credential
5
5
  # VERSION is managed by GemRelease
6
- VERSION = '6.0.4'
6
+ VERSION = '6.0.6'
7
7
 
8
8
  # @return [String]
9
9
  #
@@ -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
@@ -178,6 +178,37 @@ RSpec.describe Metasploit::Credential::Creation do
178
178
  end
179
179
  end
180
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
181
212
  end
182
213
 
183
214
  context '#create_credential_and_login' 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
@@ -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
4
+ version: 6.0.6
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-04-11 00:00:00.000000000 Z
96
+ date: 2023-10-04 00:00:00.000000000 Z
97
97
  dependencies:
98
98
  - !ruby/object:Gem::Dependency
99
99
  name: metasploit-concern
@@ -291,6 +291,7 @@ files:
291
291
  - db/migrate/20161107203710_create_index_on_private_data_and_type_for_ssh_key.rb
292
292
  - db/migrate/20221209005658_create_index_on_private_data_and_type_for_pkcs12.rb
293
293
  - lib/metasploit/credential.rb
294
+ - lib/metasploit/credential/case_insensitive_serializer.rb
294
295
  - lib/metasploit/credential/core_validations.rb
295
296
  - lib/metasploit/credential/creation.rb
296
297
  - lib/metasploit/credential/engine.rb
metadata.gz.sig CHANGED
Binary file