Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report CA and ADCS Template along with Pkcs12 in the database #19736

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ source 'https://rubygems.org'
# spec.add_runtime_dependency '<name>', [<version requirements>]
gemspec name: 'metasploit-framework'

gem 'metasploit-credential', git: 'https://github.com/cdelafuente-r7/metasploit-credential', branch: 'enh/MS-9710/add_pkcs12_metadata'

Comment on lines +6 to +7
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will need to be reverted before landing.

# separate from test as simplecov is not run on travis-ci
group :coverage do
# code coverage for tests
Expand Down
27 changes: 17 additions & 10 deletions Gemfile.lock
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file will need to be updated to point to the new metasploit-credential gem is available instead of the this feature branch.

Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
GIT
remote: https://github.com/cdelafuente-r7/metasploit-credential
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:
Expand Down Expand Up @@ -286,16 +302,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)
Expand Down Expand Up @@ -581,6 +587,7 @@ DEPENDENCIES
factory_bot_rails
fivemat
memory_profiler
metasploit-credential!
metasploit-framework!
octokit
pry-byebug
Expand Down
8 changes: 6 additions & 2 deletions lib/msf/core/exploit/remote/ms_icpr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,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
}
Expand Down
34 changes: 21 additions & 13 deletions lib/msf/ui/console/command_dispatcher/creds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -414,11 +420,13 @@ def creds_search(*args)
when 'password'
Metasploit::Credential::Password
when 'hash'
Metasploit::Credential::PasswordHash
Metasploit::Credential::NonreplayableHash
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently hash corresponds to a Nonreplayable hash instead of a PasswordHash. This change were required otherwise the specs were failing.

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
Expand Down
124 changes: 98 additions & 26 deletions spec/lib/msf/ui/console/command_dispatcher/creds_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests are now working properly. I've added them back even if it is not related to the changes in this PR.

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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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|
Expand Down
Loading