metasploit-credential 6.0.2 → 6.0.4
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
- checksums.yaml.gz.sig +0 -0
- data/app/models/metasploit/credential/pkcs12.rb +84 -0
- 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/creation.rb +2 -0
- data/lib/metasploit/credential/version.rb +1 -1
- data/lib/metasploit/credential.rb +1 -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 +22 -2
- data/spec/models/metasploit/credential/pkcs12_spec.rb +116 -0
- data/spec/models/metasploit/credential/private_spec.rb +1 -0
- data.tar.gz.sig +0 -0
- metadata +8 -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: 97884e997f5fe9428e4fc79f0b4a9e4a4e51a06363b372a2fa1affa0dffba6d5
|
4
|
+
data.tar.gz: 37e4b1a543e249e7facb0c6570efd104d4bf347922636b561aecb78bab0602a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 23da300c2d52cd12a8aeb398010b21d2542ab4f88f59946fabde21efbb3554c30f36b32839961abef13c43528324ddacc807d68872cc9df3bbf2e47d31c66905
|
7
|
+
data.tar.gz: 90f93c7bd036e2f6b328dca97707d5e85bd40a257cb6f7dba928d0d6fd983cd295e38b3052cb6aae271c37bd730e4b5c36e71feed1e1dc561bb0b163c207d098
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -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
|
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
|
@@ -1,6 +1,6 @@
|
|
1
1
|
development: &pgsql
|
2
2
|
adapter: postgresql
|
3
|
-
database: metasploit-
|
3
|
+
database: metasploit-credential_development3
|
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_test3
|
@@ -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,
|
@@ -821,6 +831,16 @@ RSpec.describe Metasploit::Credential::Creation do
|
|
821
831
|
expect{ test_object.create_credential_private(opts) }.to change{ Metasploit::Credential::KrbEncKey.count }.by(1)
|
822
832
|
end
|
823
833
|
end
|
834
|
+
|
835
|
+
context 'when :private_type is pkcs12' do
|
836
|
+
it 'creates a Metasploit::Credential::Pkcs12' do
|
837
|
+
opts = {
|
838
|
+
private_data: FactoryBot.build(:metasploit_credential_pkcs12).data,
|
839
|
+
private_type: :pkcs12
|
840
|
+
}
|
841
|
+
expect{ test_object.create_credential_private(opts) }.to change{ Metasploit::Credential::Pkcs12.count }.by(1)
|
842
|
+
end
|
843
|
+
end
|
824
844
|
end
|
825
845
|
|
826
846
|
context '#create_credential_core' do
|
@@ -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
|
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.4
|
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-04-11 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,6 +289,7 @@ 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
|
292
294
|
- lib/metasploit/credential/core_validations.rb
|
293
295
|
- lib/metasploit/credential/creation.rb
|
@@ -366,6 +368,7 @@ files:
|
|
366
368
|
- spec/factories/metasploit/credential/origin/sessions.rb
|
367
369
|
- spec/factories/metasploit/credential/password_hashes.rb
|
368
370
|
- spec/factories/metasploit/credential/passwords.rb
|
371
|
+
- spec/factories/metasploit/credential/pkcs12.rb
|
369
372
|
- spec/factories/metasploit/credential/postgres_md5.rb
|
370
373
|
- spec/factories/metasploit/credential/privates.rb
|
371
374
|
- spec/factories/metasploit/credential/publics.rb
|
@@ -401,6 +404,7 @@ files:
|
|
401
404
|
- spec/models/metasploit/credential/origin/session_spec.rb
|
402
405
|
- spec/models/metasploit/credential/password_hash_spec.rb
|
403
406
|
- spec/models/metasploit/credential/password_spec.rb
|
407
|
+
- spec/models/metasploit/credential/pkcs12_spec.rb
|
404
408
|
- spec/models/metasploit/credential/postgres_md5_spec.rb
|
405
409
|
- spec/models/metasploit/credential/private_spec.rb
|
406
410
|
- spec/models/metasploit/credential/public_spec.rb
|
@@ -497,6 +501,7 @@ test_files:
|
|
497
501
|
- spec/factories/metasploit/credential/origin/sessions.rb
|
498
502
|
- spec/factories/metasploit/credential/password_hashes.rb
|
499
503
|
- spec/factories/metasploit/credential/passwords.rb
|
504
|
+
- spec/factories/metasploit/credential/pkcs12.rb
|
500
505
|
- spec/factories/metasploit/credential/postgres_md5.rb
|
501
506
|
- spec/factories/metasploit/credential/privates.rb
|
502
507
|
- spec/factories/metasploit/credential/publics.rb
|
@@ -532,6 +537,7 @@ test_files:
|
|
532
537
|
- spec/models/metasploit/credential/origin/session_spec.rb
|
533
538
|
- spec/models/metasploit/credential/password_hash_spec.rb
|
534
539
|
- spec/models/metasploit/credential/password_spec.rb
|
540
|
+
- spec/models/metasploit/credential/pkcs12_spec.rb
|
535
541
|
- spec/models/metasploit/credential/postgres_md5_spec.rb
|
536
542
|
- spec/models/metasploit/credential/private_spec.rb
|
537
543
|
- spec/models/metasploit/credential/public_spec.rb
|
metadata.gz.sig
CHANGED
Binary file
|