Skip to content

Commit

Permalink
Land #17353, Persist icpr cert as pkcs12 credential
Browse files Browse the repository at this point in the history
  • Loading branch information
dwelch-r7 committed Apr 12, 2023
2 parents 4ed5c59 + 875ad34 commit 275963e
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 33 deletions.
40 changes: 20 additions & 20 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -98,25 +98,25 @@ GEM
remote: https://rubygems.org/
specs:
Ascii85 (1.1.0)
actionpack (7.0.4.2)
actionview (= 7.0.4.2)
activesupport (= 7.0.4.2)
actionpack (7.0.4.3)
actionview (= 7.0.4.3)
activesupport (= 7.0.4.3)
rack (~> 2.0, >= 2.2.0)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actionview (7.0.4.2)
activesupport (= 7.0.4.2)
actionview (7.0.4.3)
activesupport (= 7.0.4.3)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
activemodel (7.0.4.2)
activesupport (= 7.0.4.2)
activerecord (7.0.4.2)
activemodel (= 7.0.4.2)
activesupport (= 7.0.4.2)
activesupport (7.0.4.2)
activemodel (7.0.4.3)
activesupport (= 7.0.4.3)
activerecord (7.0.4.3)
activemodel (= 7.0.4.3)
activesupport (= 7.0.4.3)
activesupport (7.0.4.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
Expand Down Expand Up @@ -227,7 +227,7 @@ GEM
logging (2.3.1)
little-plugger (~> 1.1)
multi_json (~> 1.14)
loofah (2.19.1)
loofah (2.20.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
memory_profiler (1.0.1)
Expand All @@ -237,7 +237,7 @@ GEM
activesupport (~> 7.0)
railties (~> 7.0)
zeitwerk
metasploit-credential (6.0.2)
metasploit-credential (6.0.4)
metasploit-concern
metasploit-model
metasploit_data_models (>= 5.0.0)
Expand Down Expand Up @@ -277,7 +277,7 @@ GEM
timeout
net-smtp (0.3.3)
net-protocol
net-ssh (7.0.1)
net-ssh (7.1.0)
network_interface (0.0.2)
nexpose (7.3.0)
nio4r (2.5.8)
Expand Down Expand Up @@ -315,19 +315,19 @@ GEM
puma (6.1.1)
nio4r (~> 2.0)
racc (1.6.2)
rack (2.2.6.3)
rack (2.2.6.4)
rack-protection (3.0.5)
rack
rack-test (2.0.2)
rack-test (2.1.0)
rack (>= 1.3)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.5.0)
loofah (~> 2.19, >= 2.19.1)
railties (7.0.4.2)
actionpack (= 7.0.4.2)
activesupport (= 7.0.4.2)
railties (7.0.4.3)
actionpack (= 7.0.4.3)
activesupport (= 7.0.4.3)
method_source
rake (>= 12.2)
thor (~> 1.0)
Expand All @@ -337,7 +337,7 @@ GEM
rasn1 (0.12.1)
strptime (~> 0.2.5)
rb-readline (0.5.5)
recog (3.0.3)
recog (3.1.1)
nokogiri
redcarpet (3.6.0)
regexp_parser (2.7.0)
Expand Down
5 changes: 3 additions & 2 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.0].define(version: 2019_05_07_120211) do
ActiveRecord::Schema[7.0].define(version: 2022_12_09_005658) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

Expand Down Expand Up @@ -314,8 +314,9 @@
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
t.string "jtr_format"
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))"
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)))"
end

create_table "metasploit_credential_publics", id: :serial, force: :cascade do |t|
Expand Down
37 changes: 29 additions & 8 deletions lib/msf/core/exploit/remote/ms_icpr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,7 @@ def connect_ipc
rescue Rex::Proto::SMB::Exceptions::Error, RubySMB::Error::RubySMBError => e
raise MsIcprAuthenticationError, "Unable to authenticate ([#{e.class}] #{e})."
end
report_service(
host: rhost,
port: rport,
host_name: simple.client.default_name,
proto: 'tcp',
name: 'smb',
info: "Module: #{fullname}, last negotiated version: SMBv#{simple.client.negotiated_smb_version} (dialect = #{simple.client.dialect})"
)
report_service(icpr_service_data)

begin
simple.client.tree_connect("\\\\#{sock.peerhost}\\IPC$")
Expand Down Expand Up @@ -222,6 +215,24 @@ def do_request_cert(icpr, opts)
pkcs12 = OpenSSL::PKCS12.create('', '', private_key, response[:certificate])
# see: https://pki-tutorial.readthedocs.io/en/latest/mime.html#mime-types
info = "#{simple.client.default_domain}\\#{datastore['SMBUser']} Certificate"

service_data = icpr_service_data
credential_data = {
**service_data,
address: service_data[:host],
port: rport,
protocol: service_data[:proto],
service_name: service_data[:name],
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),
origin_type: :service,
module_fullname: fullname
}
create_credential(credential_data)

stored_path = store_loot('windows.ad.cs', 'application/x-pkcs12', rhost, pkcs12.to_der, 'certificate.pfx', info)
print_status("Certificate stored at: #{stored_path}")

Expand Down Expand Up @@ -366,5 +377,15 @@ def get_cert_ext_property(cert, ext_oid, key)
nil
end

def icpr_service_data
{
host: rhost,
port: rport,
host_name: simple.client.default_name,
proto: 'tcp',
name: 'smb',
info: "Module: #{fullname}, last negotiated version: SMBv#{simple.client.negotiated_smb_version} (dialect = #{simple.client.dialect})"
}
end
end
end
20 changes: 17 additions & 3 deletions lib/msf/ui/console/command_dispatcher/creds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def cmd_creds_help
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.',
Expand All @@ -126,6 +127,8 @@ def cmd_creds_help
print_line " creds add ntlm:E2FC15074BF7751DD408E6B105741864:A1074A69B1BDE45403AB680504BBDD1A"
print_line " # Add a Postgres MD5"
print_line " creds add user:postgres postgres:md5be86a79bf2043622d58d5453c47d4860"
print_line " # Add a user with a PKCS12 file archive"
print_line " creds add user:alice pkcs12:/path/to/certificate.pfx"
print_line " # Add a user with an SSH key"
print_line " creds add user:sshadmin ssh-key:/path/to/id_rsa"
print_line " # Add a user and a NonReplayableHash"
Expand Down Expand Up @@ -203,14 +206,14 @@ 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', 'postgres')
params.assert_valid_keys('user','password','realm','realm-type','ntlm','ssh-key','hash','address','port','protocol', 'service-name', 'jtr', 'pkcs12', 'postgres')
rescue ArgumentError => e
print_error(e.message)
end

# Verify we only have one type of private
if params.slice('password','ntlm','ssh-key','hash', 'postgres').length > 1
private_keys = params.slice('password','ntlm','ssh-key','hash', 'postgres').keys
if params.slice('password','ntlm','ssh-key','hash', 'pkcs12', 'postgres').length > 1
private_keys = params.slice('password','ntlm','ssh-key','hash', 'pkcs12', 'postgres').keys
print_error("You can only specify a single Private type. Private types given: #{private_keys.join(', ')}")
return
end
Expand Down Expand Up @@ -264,6 +267,17 @@ def creds_add(*args)
data[:private_data] = key_data
end

if params.key? 'pkcs12'
begin
# pkcs12 is a binary format, but for persisting we Base64 encode it
pkcs12_data = Base64.strict_encode64(File.binread(params['pkcs12']))
rescue ::Errno::EACCES, ::Errno::ENOENT => e
print_error("Failed to add pkcs12 archive: #{e}")
end
data[:private_type] = :pkcs12
data[:private_data] = pkcs12_data
end

if params.key? 'hash'
data[:private_type] = :nonreplayable_hash
data[:private_data] = params['hash']
Expand Down

0 comments on commit 275963e

Please sign in to comment.