From 8f7a32a37c6ea05918e5a45a4c346a6fd349664e Mon Sep 17 00:00:00 2001 From: Christophe De La Fuente Date: Mon, 16 Dec 2024 12:18:40 +0100 Subject: [PATCH 1/4] Update Pkcs12-related code to report CA and ADCS Template to the database - Update the `creds` command to add Pkcs12 private credentials with metadata. - Update `ms_icpr` module to store metadata. --- lib/msf/core/exploit/remote/ms_icpr.rb | 8 +- .../ui/console/command_dispatcher/creds.rb | 34 +++-- .../console/command_dispatcher/creds_spec.rb | 124 ++++++++++++++---- 3 files changed, 125 insertions(+), 41 deletions(-) diff --git a/lib/msf/core/exploit/remote/ms_icpr.rb b/lib/msf/core/exploit/remote/ms_icpr.rb index 4f405cde6083..f3fd1b21eebe 100644 --- a/lib/msf/core/exploit/remote/ms_icpr.rb +++ b/lib/msf/core/exploit/remote/ms_icpr.rb @@ -239,8 +239,12 @@ def do_request_cert(icpr, opts) workspace_id: myworkspace_id, username: upn || datastore['SMBUser'], private_type: :pkcs12, - # pkcs12 is a binary format, but for persisting we Base64 encode it - private_data: Base64.strict_encode64(pkcs12.to_der), + private_data: Metasploit::Credential::Pkcs12.build_data( + # pkcs12 is a binary format, but for persisting we Base64 encode it + pkcs12: Base64.strict_encode64(pkcs12.to_der), + ca: datastore['CA'], + adcs_template: cert_template + ), origin_type: :service, module_fullname: fullname } diff --git a/lib/msf/ui/console/command_dispatcher/creds.rb b/lib/msf/ui/console/command_dispatcher/creds.rb index 220365a4c70f..2a165e621c5c 100644 --- a/lib/msf/ui/console/command_dispatcher/creds.rb +++ b/lib/msf/ui/console/command_dispatcher/creds.rb @@ -100,16 +100,18 @@ def cmd_creds_help print_line "Usage - Adding credentials:" print_line " creds add uses the following named parameters." { - user: 'Public, usually a username', - password: 'Private, private_type Password.', - ntlm: 'Private, private_type NTLM Hash.', - postgres: 'Private, private_type postgres MD5', - pkcs12: 'Private, private_type pkcs12 archive file, must be a file path.', - 'ssh-key' => 'Private, private_type SSH key, must be a file path.', - hash: 'Private, private_type Nonreplayable hash', - jtr: 'Private, private_type John the Ripper hash type.', - realm: 'Realm, ', - 'realm-type'=>"Realm, realm_type (#{Metasploit::Model::Realm::Key::SHORT_NAMES.keys.join(' ')}), defaults to domain." + user: 'Public, usually a username', + password: 'Private, private_type Password.', + ntlm: 'Private, private_type NTLM Hash.', + postgres: 'Private, private_type postgres MD5', + pkcs12: 'Private, private_type pkcs12 archive file, must be a file path.', + 'ssh-key' => 'Private, private_type SSH key, must be a file path.', + hash: 'Private, private_type Nonreplayable hash', + jtr: 'Private, private_type John the Ripper hash type.', + realm: 'Realm, ', + 'realm-type' => "Realm, realm_type (#{Metasploit::Model::Realm::Key::SHORT_NAMES.keys.join(' ')}), defaults to domain.", + ca: 'CA, Certificate Authority that issued the pkcs12 certificate', + 'adcs-template' => 'ADCS Template, template used to issue the pkcs12 certificate' }.each_pair do |keyword, description| print_line " #{keyword.to_s.ljust 10}: #{description}" end @@ -206,7 +208,7 @@ def creds_add(*args) end begin - params.assert_valid_keys('user','password','realm','realm-type','ntlm','ssh-key','hash','address','port','protocol', 'service-name', 'jtr', 'pkcs12', 'postgres') + params.assert_valid_keys('user','password','realm','realm-type','ntlm','ssh-key','hash','address','port','protocol', 'service-name', 'jtr', 'pkcs12', 'postgres', 'ca', 'adcs-template') rescue ArgumentError => e print_error(e.message) end @@ -275,7 +277,11 @@ def creds_add(*args) print_error("Failed to add pkcs12 archive: #{e}") end data[:private_type] = :pkcs12 - data[:private_data] = pkcs12_data + data[:private_data] = Metasploit::Credential::Pkcs12.build_data( + pkcs12: pkcs12_data, + ca: params['ca'], + adcs_template: params['adcs-template'] + ) end if params.key? 'hash' @@ -414,11 +420,13 @@ def creds_search(*args) when 'password' Metasploit::Credential::Password when 'hash' - Metasploit::Credential::PasswordHash + Metasploit::Credential::NonreplayableHash when 'ntlm' Metasploit::Credential::NTLMHash when 'KrbEncKey'.downcase Metasploit::Credential::KrbEncKey + when 'pkcs12' + Metasploit::Credential::Pkcs12 when *Metasploit::Credential::NonreplayableHash::VALID_JTR_FORMATS opts[:jtr_format] = ptype Metasploit::Credential::NonreplayableHash diff --git a/spec/lib/msf/ui/console/command_dispatcher/creds_spec.rb b/spec/lib/msf/ui/console/command_dispatcher/creds_spec.rb index 7e08644e83bf..67dcef8d3faf 100644 --- a/spec/lib/msf/ui/console/command_dispatcher/creds_spec.rb +++ b/spec/lib/msf/ui/console/command_dispatcher/creds_spec.rb @@ -212,32 +212,48 @@ realm: nil, workspace: framework.db.workspace) end + let!(:pkcs12_subject) { '/C=FR/O=MyOrg/OU=MyUnit/CN=SubjectTestName' } + let!(:pkcs12_issuer) { '/C=US/O=MyIssuer/OU=MyIssuerUnit/CN=IssuerTestName' } + let!(:pkcs12_ca) { 'testCA' } + let!(:pkcs12_adcs_template) { 'TestTemplate' } + let!(:pkcs12_core) do + priv = FactoryBot.create(:metasploit_credential_pkcs12_with_ca_and_adcs_template, + subject: pkcs12_subject, + issuer: pkcs12_issuer, + ca: pkcs12_ca, + adcs_template: pkcs12_adcs_template) + FactoryBot.create(:metasploit_credential_core, + origin: FactoryBot.create(:metasploit_credential_origin_import), + private: priv, + public: nil, + realm: nil, + workspace: framework.db.workspace) + end - # # Somehow this is hitting a unique constraint on Cores with the same - # # Public, even though it has a different Private. Skip for now - # let!(:ntlm_core) do - # priv = FactoryBot.create(:metasploit_credential_ntlm_hash, data: ntlm_hash) - # FactoryBot.create(:metasploit_credential_core, - # origin: FactoryBot.create(:metasploit_credential_origin_import), - # private: priv, - # public: pub, - # realm: nil, - # workspace: framework.db.workspace) - # end - # let!(:nonreplayable_core) do - # priv = FactoryBot.create(:metasploit_credential_nonreplayable_hash, data: 'asdf') - # FactoryBot.create(:metasploit_credential_core, - # origin: FactoryBot.create(:metasploit_credential_origin_import), - # private: priv, - # public: pub, - # realm: nil, - # workspace: framework.db.workspace) - # end + let!(:ntlm_core) do + priv = FactoryBot.create(:metasploit_credential_ntlm_hash, data: ntlm_hash) + FactoryBot.create(:metasploit_credential_core, + origin: FactoryBot.create(:metasploit_credential_origin_import), + private: priv, + public: pub, + realm: nil, + workspace: framework.db.workspace) + end + let!(:nonreplayable_core) do + priv = FactoryBot.create(:metasploit_credential_nonreplayable_hash, data: 'asdf') + FactoryBot.create(:metasploit_credential_core, + origin: FactoryBot.create(:metasploit_credential_origin_import), + private: priv, + public: pub, + realm: nil, + workspace: framework.db.workspace) + end after(:example) do - # ntlm_core.destroy + ntlm_core.destroy password_core.destroy - # nonreplayable_core.destroy + nonreplayable_core.destroy + pkcs12_core.destroy end context 'password' do @@ -283,16 +299,48 @@ context 'ntlm' do it 'should show just the ntlm' do - skip 'Weird uniqueness constraint on Core (workspace_id, public_id)' creds.cmd_creds('-t', 'ntlm') expect(@output.join("\n")).to match_table <<~TABLE Credentials =========== - host origin service public private realm private_type JtR Format cracked_password - ---- ------ ------- ------ ------- ----- ------------ ---------- ---------------- - thisuser 1443d06412d8c0e6e72c57ef50f76a05:27c433245e4763d074d30a05aae0af2c NTLM hash + host origin service public private realm private_type JtR Format cracked_password + ---- ------ ------- ------ ------- ----- ------------ ---------- ---------------- + thisuser 1443d06412d8c0e6e72c57ef50f76a05:27c433245e4763d074d30a05aae0af2c NTLM hash + + TABLE + end + end + + context 'nonreplayable' do + it 'should show just the ntlm' do + + creds.cmd_creds('-t', 'hash') + expect(@output.join("\n")).to match_table <<~TABLE + Credentials + =========== + + host origin service public private realm private_type JtR Format cracked_password + ---- ------ ------- ------ ------- ----- ------------ ---------- ---------------- + thisuser asdf Nonreplayable hash + + TABLE + end + end + + context 'pkcs12' do + it 'should show just the pkcs12' do + private_str = "subject:#{pkcs12_subject},issuer:#{pkcs12_issuer},CA:#{pkcs12_ca},ADCS_template:#{pkcs12_adcs_template}" + private_str = "#{private_str[0,76]} (TRUNCATED)" + creds.cmd_creds('-t', 'pkcs12') + expect(@output.join("\n")).to match_table <<~TABLE + Credentials + =========== + + host origin service public private realm private_type JtR Format cracked_password + ---- ------ ------- ------ ------- ----- ------------ ---------- ---------------- + #{private_str} Pkcs12 (pfx) TABLE end @@ -479,6 +527,30 @@ }.to_not change { Metasploit::Credential::Core.count } end end + context 'pkcs12' do + let(:priv) { FactoryBot.create(:metasploit_credential_pkcs12) } + before(:each) do + @file = Tempfile.new('mypkcs12.pfx') + @file.write(Base64.strict_decode64(priv.pkcs12)) + @file.close + end + it 'creates a core if one does not exist' do + expect { + creds.cmd_creds('add', "pkcs12:#{@file.path}") + }.to change { Metasploit::Credential::Core.count }.by 1 + end + it 'does not create a core if it already exists' do + FactoryBot.create(:metasploit_credential_core, + origin: FactoryBot.create(:metasploit_credential_origin_import), + private: priv, + public: nil, + realm: nil, + workspace: framework.db.workspace) + expect { + creds.cmd_creds('add', "pkcs12:#{@file.path}") + }.to_not change { Metasploit::Credential::Core.count } + end + end end context 'realm-types' do Metasploit::Model::Realm::Key::SHORT_NAMES.each do |short_name, long_name| From 758a6a1b2ca171c8e8f9573ba15536ff7ebdd449 Mon Sep 17 00:00:00 2001 From: Christophe De La Fuente Date: Mon, 16 Dec 2024 15:06:35 +0100 Subject: [PATCH 2/4] Point Gemfile to the metasploit-credentials feature branch on cdelafuente-r7 repo --- Gemfile | 2 ++ Gemfile.lock | 27 +++++++++++++++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Gemfile b/Gemfile index 83b7b2811fbd..391cff021bc8 100644 --- a/Gemfile +++ b/Gemfile @@ -3,6 +3,8 @@ source 'https://rubygems.org' # spec.add_runtime_dependency '', [] gemspec name: 'metasploit-framework' +gem 'metasploit-credential', git: 'git@github.com:cdelafuente-r7/metasploit-credential.git', branch: 'enh/MS-9710/add_pkcs12_metadata' + # separate from test as simplecov is not run on travis-ci group :coverage do # code coverage for tests diff --git a/Gemfile.lock b/Gemfile.lock index a2b9def075a6..a3e8f2722ec2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,19 @@ +GIT + remote: git@github.com:cdelafuente-r7/metasploit-credential.git + revision: acc5a012f4bc7e7774af059e778b947cd994da1e + branch: enh/MS-9710/add_pkcs12_metadata + specs: + metasploit-credential (6.0.12) + metasploit-concern + metasploit-model + metasploit_data_models (>= 5.0.0) + net-ssh + pg + railties + rex-socket + rubyntlm + rubyzip + PATH remote: . specs: @@ -292,16 +308,6 @@ GEM activesupport (~> 7.0) railties (~> 7.0) zeitwerk - metasploit-credential (6.0.11) - metasploit-concern - metasploit-model - metasploit_data_models (>= 5.0.0) - net-ssh - pg - railties - rex-socket - rubyntlm - rubyzip metasploit-model (5.0.2) activemodel (~> 7.0) activesupport (~> 7.0) @@ -589,6 +595,7 @@ DEPENDENCIES factory_bot_rails fivemat memory_profiler + metasploit-credential! metasploit-framework! octokit pry-byebug From d0a459359e514b0b48fc7d5b6c90e02d6399c120 Mon Sep 17 00:00:00 2001 From: Christophe De La Fuente Date: Mon, 16 Dec 2024 15:49:18 +0100 Subject: [PATCH 3/4] Update Gemfile to use https --- Gemfile | 2 +- Gemfile.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 391cff021bc8..a6a9ebadd26e 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source 'https://rubygems.org' # spec.add_runtime_dependency '', [] gemspec name: 'metasploit-framework' -gem 'metasploit-credential', git: 'git@github.com:cdelafuente-r7/metasploit-credential.git', branch: 'enh/MS-9710/add_pkcs12_metadata' +gem 'metasploit-credential', git: 'https://github.com/cdelafuente-r7/metasploit-credential', branch: 'enh/MS-9710/add_pkcs12_metadata' # separate from test as simplecov is not run on travis-ci group :coverage do diff --git a/Gemfile.lock b/Gemfile.lock index a3e8f2722ec2..562cba57f3b8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,5 +1,5 @@ GIT - remote: git@github.com:cdelafuente-r7/metasploit-credential.git + remote: https://github.com/cdelafuente-r7/metasploit-credential revision: acc5a012f4bc7e7774af059e778b947cd994da1e branch: enh/MS-9710/add_pkcs12_metadata specs: From 407494c639c1fd9c61b02eef3f93e19e7bc53adc Mon Sep 17 00:00:00 2001 From: Christophe De La Fuente Date: Thu, 6 Feb 2025 13:22:36 +0100 Subject: [PATCH 4/4] Update `ms_icpr` and `creds` to reflect the changes in the Pkcs12 data model - a separate field is now used for metadata (`private_metadata`) when creating a new Pkcs12 - the `creds` command now support adding an encrypted Pkcs12 with a password --- .../workflows/command_shell_acceptance.yml | 1 + .../shared_meterpreter_acceptance.yml | 1 + Gemfile | 2 + Gemfile.lock | 44 ++++++++++++------- db/schema.rb | 3 +- lib/msf/core/exploit/remote/ms_icpr.rb | 8 +--- .../ui/console/command_dispatcher/creds.rb | 39 ++++++++-------- .../console/command_dispatcher/creds_spec.rb | 43 ++++++++++++++++-- 8 files changed, 96 insertions(+), 45 deletions(-) diff --git a/.github/workflows/command_shell_acceptance.yml b/.github/workflows/command_shell_acceptance.yml index 62da721a0bec..50e5de4c4a42 100644 --- a/.github/workflows/command_shell_acceptance.yml +++ b/.github/workflows/command_shell_acceptance.yml @@ -127,6 +127,7 @@ jobs: path: metasploit-framework - name: Setup Ruby + run: git config --system core.longpaths true env: BUNDLE_FORCE_RUBY_PLATFORM: true uses: ruby/setup-ruby@v1 diff --git a/.github/workflows/shared_meterpreter_acceptance.yml b/.github/workflows/shared_meterpreter_acceptance.yml index e595308e2652..f8e8844b4f80 100644 --- a/.github/workflows/shared_meterpreter_acceptance.yml +++ b/.github/workflows/shared_meterpreter_acceptance.yml @@ -190,6 +190,7 @@ jobs: ref: ${{ inputs.metasploit_framework_commit }} - name: Setup Ruby + run: git config --system core.longpaths true env: BUNDLE_FORCE_RUBY_PLATFORM: true # Required for macos13 pg gem compilation diff --git a/Gemfile b/Gemfile index a6a9ebadd26e..66e827a21893 100644 --- a/Gemfile +++ b/Gemfile @@ -4,6 +4,8 @@ source 'https://rubygems.org' gemspec name: 'metasploit-framework' gem 'metasploit-credential', git: 'https://github.com/cdelafuente-r7/metasploit-credential', branch: 'enh/MS-9710/add_pkcs12_metadata' +gem 'metasploit-model', git: 'https://github.com/cdelafuente-r7/metasploit-model', branch: 'feat/model/search/operation/jsonb' +gem 'metasploit_data_models', git: 'https://github.com/cdelafuente-r7/metasploit_data_models', branch: 'enh/visitor/jsonb' # separate from test as simplecov is not run on travis-ci group :coverage do diff --git a/Gemfile.lock b/Gemfile.lock index 562cba57f3b8..36a0a2a1972a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: https://github.com/cdelafuente-r7/metasploit-credential - revision: acc5a012f4bc7e7774af059e778b947cd994da1e + revision: 6c8554df2feab43489ca86eada790970e9749fb3 branch: enh/MS-9710/add_pkcs12_metadata specs: metasploit-credential (6.0.12) @@ -14,6 +14,32 @@ GIT rubyntlm rubyzip +GIT + remote: https://github.com/cdelafuente-r7/metasploit-model + revision: 925a11f61f02123f29e32bb196b374390d36beb6 + branch: feat/model/search/operation/jsonb + specs: + metasploit-model (5.0.3) + activemodel (~> 7.0) + activesupport (~> 7.0) + railties (~> 7.0) + +GIT + remote: https://github.com/cdelafuente-r7/metasploit_data_models + revision: 34fc27d3059c919eac98cf2a8061c31146189a26 + branch: enh/visitor/jsonb + specs: + metasploit_data_models (6.0.6) + activerecord (~> 7.0) + activesupport (~> 7.0) + arel-helpers + metasploit-concern + metasploit-model (>= 3.1) + pg + railties (~> 7.0) + recog + webrick + PATH remote: . specs: @@ -308,21 +334,7 @@ GEM activesupport (~> 7.0) railties (~> 7.0) zeitwerk - metasploit-model (5.0.2) - activemodel (~> 7.0) - activesupport (~> 7.0) - railties (~> 7.0) metasploit-payloads (2.0.189) - metasploit_data_models (6.0.5) - activerecord (~> 7.0) - activesupport (~> 7.0) - arel-helpers - metasploit-concern - metasploit-model (>= 3.1) - pg - railties (~> 7.0) - recog - webrick metasploit_payloads-mettle (1.0.35) method_source (1.1.0) mime-types (3.6.0) @@ -597,6 +609,8 @@ DEPENDENCIES memory_profiler metasploit-credential! metasploit-framework! + metasploit-model! + metasploit_data_models! octokit pry-byebug rake diff --git a/db/schema.rb b/db/schema.rb index 90d6436444c1..0c01a8d61cd7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2022_12_09_005658) do +ActiveRecord::Schema[7.0].define(version: 2025_02_04_172657) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -314,6 +314,7 @@ t.datetime "created_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false t.string "jtr_format" + t.jsonb "metadata", default: {}, null: false t.index "type, decode(md5(data), 'hex'::text)", name: "index_metasploit_credential_privates_on_type_and_data_pkcs12", unique: true, where: "((type)::text = 'Metasploit::Credential::Pkcs12'::text)" t.index "type, decode(md5(data), 'hex'::text)", name: "index_metasploit_credential_privates_on_type_and_data_sshkey", unique: true, where: "((type)::text = 'Metasploit::Credential::SSHKey'::text)" t.index ["type", "data"], name: "index_metasploit_credential_privates_on_type_and_data", unique: true, where: "(NOT (((type)::text = 'Metasploit::Credential::SSHKey'::text) OR ((type)::text = 'Metasploit::Credential::Pkcs12'::text)))" diff --git a/lib/msf/core/exploit/remote/ms_icpr.rb b/lib/msf/core/exploit/remote/ms_icpr.rb index f3fd1b21eebe..ef6eb368d6f7 100644 --- a/lib/msf/core/exploit/remote/ms_icpr.rb +++ b/lib/msf/core/exploit/remote/ms_icpr.rb @@ -239,12 +239,8 @@ def do_request_cert(icpr, opts) workspace_id: myworkspace_id, username: upn || datastore['SMBUser'], private_type: :pkcs12, - private_data: Metasploit::Credential::Pkcs12.build_data( - # pkcs12 is a binary format, but for persisting we Base64 encode it - pkcs12: Base64.strict_encode64(pkcs12.to_der), - ca: datastore['CA'], - adcs_template: cert_template - ), + private_data: Base64.strict_encode64(pkcs12.to_der), + private_metadata: { adcs_ca: datastore['CA'], adcs_template: cert_template }, origin_type: :service, module_fullname: fullname } diff --git a/lib/msf/ui/console/command_dispatcher/creds.rb b/lib/msf/ui/console/command_dispatcher/creds.rb index 2a165e621c5c..f4bddd358cbc 100644 --- a/lib/msf/ui/console/command_dispatcher/creds.rb +++ b/lib/msf/ui/console/command_dispatcher/creds.rb @@ -100,18 +100,19 @@ def cmd_creds_help print_line "Usage - Adding credentials:" print_line " creds add uses the following named parameters." { - user: 'Public, usually a username', - password: 'Private, private_type Password.', - ntlm: 'Private, private_type NTLM Hash.', - postgres: 'Private, private_type postgres MD5', - pkcs12: 'Private, private_type pkcs12 archive file, must be a file path.', - 'ssh-key' => 'Private, private_type SSH key, must be a file path.', - hash: 'Private, private_type Nonreplayable hash', - jtr: 'Private, private_type John the Ripper hash type.', - realm: 'Realm, ', - 'realm-type' => "Realm, realm_type (#{Metasploit::Model::Realm::Key::SHORT_NAMES.keys.join(' ')}), defaults to domain.", - ca: 'CA, Certificate Authority that issued the pkcs12 certificate', - 'adcs-template' => 'ADCS Template, template used to issue the pkcs12 certificate' + user: 'Public, usually a username', + password: 'Private, private_type Password.', + ntlm: 'Private, private_type NTLM Hash.', + postgres: 'Private, private_type postgres MD5', + pkcs12: 'Private, private_type pkcs12 archive file, must be a file path.', + 'ssh-key' => 'Private, private_type SSH key, must be a file path.', + hash: 'Private, private_type Nonreplayable hash', + jtr: 'Private, private_type John the Ripper hash type.', + realm: 'Realm, ', + 'realm-type' => "Realm, realm_type (#{Metasploit::Model::Realm::Key::SHORT_NAMES.keys.join(' ')}), defaults to domain.", + 'adcs-ca' => 'CA, Certificate Authority that issued the pkcs12 certificate', + 'adcs-template' => 'ADCS Template, template used to issue the pkcs12 certificate', + 'pkcs12-password' => 'The password to decrypt the Pkcs12, defaults to an empty password' }.each_pair do |keyword, description| print_line " #{keyword.to_s.ljust 10}: #{description}" end @@ -208,7 +209,7 @@ def creds_add(*args) end begin - params.assert_valid_keys('user','password','realm','realm-type','ntlm','ssh-key','hash','address','port','protocol', 'service-name', 'jtr', 'pkcs12', 'postgres', 'ca', 'adcs-template') + params.assert_valid_keys('user','password','realm','realm-type','ntlm','ssh-key','hash','address','port','protocol', 'service-name', 'jtr', 'pkcs12', 'postgres', 'adcs-ca', 'adcs-template', 'pkcs12-password') rescue ArgumentError => e print_error(e.message) end @@ -277,11 +278,11 @@ def creds_add(*args) print_error("Failed to add pkcs12 archive: #{e}") end data[:private_type] = :pkcs12 - data[:private_data] = Metasploit::Credential::Pkcs12.build_data( - pkcs12: pkcs12_data, - ca: params['ca'], - adcs_template: params['adcs-template'] - ) + data[:private_data] = pkcs12_data + data[:private_metadata] = {} + data[:private_metadata][:adcs_ca] = params['adcs-ca'] if params['adcs-ca'] + data[:private_metadata][:adcs_template] = params['adcs-template'] if params['adcs-template'] + data[:private_metadata][:pkcs12_password] = params['pkcs12-password'] if params['pkcs12-password'] end if params.key? 'hash' @@ -311,7 +312,7 @@ def creds_add(*args) framework.db.create_credential(data) end rescue ActiveRecord::RecordInvalid => e - print_error("Failed to add #{data['private_type']}: #{e}") + print_error("Failed to add #{data[:private_type]}: #{e}") end end diff --git a/spec/lib/msf/ui/console/command_dispatcher/creds_spec.rb b/spec/lib/msf/ui/console/command_dispatcher/creds_spec.rb index 67dcef8d3faf..9ffdbf37a69f 100644 --- a/spec/lib/msf/ui/console/command_dispatcher/creds_spec.rb +++ b/spec/lib/msf/ui/console/command_dispatcher/creds_spec.rb @@ -220,7 +220,7 @@ priv = FactoryBot.create(:metasploit_credential_pkcs12_with_ca_and_adcs_template, subject: pkcs12_subject, issuer: pkcs12_issuer, - ca: pkcs12_ca, + adcs_ca: pkcs12_ca, adcs_template: pkcs12_adcs_template) FactoryBot.create(:metasploit_credential_core, origin: FactoryBot.create(:metasploit_credential_origin_import), @@ -331,7 +331,7 @@ context 'pkcs12' do it 'should show just the pkcs12' do - private_str = "subject:#{pkcs12_subject},issuer:#{pkcs12_issuer},CA:#{pkcs12_ca},ADCS_template:#{pkcs12_adcs_template}" + private_str = "subject:#{pkcs12_subject},issuer:#{pkcs12_issuer},ADCS CA:#{pkcs12_ca},ADCS template:#{pkcs12_adcs_template}" private_str = "#{private_str[0,76]} (TRUNCATED)" creds.cmd_creds('-t', 'pkcs12') expect(@output.join("\n")).to match_table <<~TABLE @@ -528,10 +528,10 @@ end end context 'pkcs12' do - let(:priv) { FactoryBot.create(:metasploit_credential_pkcs12) } + let(:priv) { FactoryBot.build(:metasploit_credential_pkcs12) } before(:each) do @file = Tempfile.new('mypkcs12.pfx') - @file.write(Base64.strict_decode64(priv.pkcs12)) + @file.write(Base64.strict_decode64(priv.data)) @file.close end it 'creates a core if one does not exist' do @@ -550,6 +550,41 @@ creds.cmd_creds('add', "pkcs12:#{@file.path}") }.to_not change { Metasploit::Credential::Core.count } end + + context 'with a password' do + let(:pkcs12_password) { 'mypass' } + let(:priv) { + FactoryBot.build(:metasploit_credential_pkcs12, + pkcs12_password: pkcs12_password, + metadata: { pkcs12_password: pkcs12_password } + ) + } + + it 'creates a core if the password is correct' do + expect { + creds.cmd_creds('add', "pkcs12:#{@file.path}", "pkcs12-password:#{pkcs12_password}") + }.to change { Metasploit::Credential::Core.count }.by 1 + end + + it 'does not creates a core if the password is incorrect' do + expect { + creds.cmd_creds('add', "pkcs12:#{@file.path}", "pkcs12-password:wrongpass") + }.to_not change { Metasploit::Credential::Core.count } + end + end + + context 'with metadata other than password' do + let(:adcs_ca) { 'myca' } + let(:adcs_template) { 'mytemplate' } + + it 'creates a core if the password is correct' do + expect { + creds.cmd_creds('add', "pkcs12:#{@file.path}", "adcs-ca:#{adcs_ca}", "adcs-template:#{adcs_template}") + }.to change { Metasploit::Credential::Core.count }.by 1 + expect(Metasploit::Credential::Pkcs12.first.adcs_ca).to eq(adcs_ca) + expect(Metasploit::Credential::Pkcs12.first.adcs_template).to eq(adcs_template) + end + end end end context 'realm-types' do