From 358172447df95152612aee5676986633efc70116 Mon Sep 17 00:00:00 2001 From: Christophe De La Fuente Date: Thu, 6 Feb 2025 13:22:36 +0100 Subject: [PATCH] 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 --- 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 | 24 +++++++++++- 4 files changed, 47 insertions(+), 27 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index 90d6436444c14..0c01a8d61cd72 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 f3fd1b21eebe1..1d07a9f36b85e 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: { 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 2a165e621c5c0..79ca7d1d7a649 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.", + 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', '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][:ca] = params['ca'] if params['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 67dcef8d3fafd..8fcc98962ab28 100644 --- a/spec/lib/msf/ui/console/command_dispatcher/creds_spec.rb +++ b/spec/lib/msf/ui/console/command_dispatcher/creds_spec.rb @@ -531,7 +531,7 @@ let(:priv) { FactoryBot.create(: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,28 @@ 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.create(: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 end end context 'realm-types' do