5
5
6
6
class MetasploitModule < Msf ::Auxiliary
7
7
8
- include Msf ::Exploit ::Remote ::LDAP
8
+ include Msf ::Exploit ::Remote ::LDAP :: ActiveDirectory
9
9
include Msf ::OptionalSession ::LDAP
10
10
include Msf ::Auxiliary ::Report
11
11
@@ -30,13 +30,6 @@ class MetasploitModule < Msf::Auxiliary
30
30
'msPKI-Template-Minor-Revision' ,
31
31
] . freeze
32
32
33
- # LDAP_SERVER_SD_FLAGS constant definition, taken from https://ldapwiki.com/wiki/LDAP_SERVER_SD_FLAGS_OID
34
- LDAP_SERVER_SD_FLAGS_OID = '1.2.840.113556.1.4.801' . freeze
35
- OWNER_SECURITY_INFORMATION = 0x1
36
- GROUP_SECURITY_INFORMATION = 0x2
37
- DACL_SECURITY_INFORMATION = 0x4
38
- SACL_SECURITY_INFORMATION = 0x8
39
-
40
33
def initialize ( info = { } )
41
34
super (
42
35
update_info (
@@ -88,20 +81,6 @@ def initialize(info = {})
88
81
] )
89
82
end
90
83
91
- def ldap_get ( filter , attributes : [ ] , base : nil , controls : [ ] )
92
- base ||= @base_dn
93
- raw_obj = @ldap . search ( base : base , filter : filter , attributes : attributes , controls : controls ) . first
94
- validate_query_result! ( @ldap . get_operation_result . table )
95
- return nil unless raw_obj
96
-
97
- obj = { }
98
- raw_obj . attribute_names . each do |attr |
99
- obj [ attr . to_s ] = raw_obj [ attr ] . map ( &:to_s )
100
- end
101
-
102
- obj
103
- end
104
-
105
84
def run
106
85
ldap_connect do |ldap |
107
86
validate_bind_success! ( ldap )
@@ -131,15 +110,20 @@ def run
131
110
fail_with ( Failure ::Unknown , "#{ e . class } : #{ e . message } " )
132
111
end
133
112
113
+ def ms_security_descriptor_control ( flags )
114
+ control_values = [ flags ] . map ( &:to_ber ) . to_ber_sequence . to_s . to_ber
115
+ [ LDAP_SERVER_SD_FLAGS_OID . to_ber , control_values ] . to_ber_sequence
116
+ end
117
+
134
118
def get_certificate_template
135
- obj = ldap_get (
136
- "(&(cn=#{ datastore [ 'CERT_TEMPLATE' ] } )(objectClass=pKICertificateTemplate))" ,
119
+ obj = @ldap . search (
120
+ filter : "(&(cn=#{ datastore [ 'CERT_TEMPLATE' ] } )(objectClass=pKICertificateTemplate))" ,
137
121
base : "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,#{ @base_dn } " ,
138
- controls : [ ms_security_descriptor_control ( DACL_SECURITY_INFORMATION ) ]
139
- )
122
+ controls : [ ms_security_descriptor_control ( 4 ) ]
123
+ ) &. first
140
124
fail_with ( Failure ::NotFound , 'The specified template was not found.' ) unless obj
141
125
142
- print_good ( "Read certificate template data for: #{ obj [ 'dn' ] . first } " )
126
+ print_good ( "Read certificate template data for: #{ obj . dn } " )
143
127
stored = store_loot (
144
128
'windows.ad.cs.template' ,
145
129
'application/json' ,
@@ -152,15 +136,6 @@ def get_certificate_template
152
136
[ obj , stored ]
153
137
end
154
138
155
- def get_domain_sid
156
- return @domain_sid if @domain_sid . present?
157
-
158
- obj = ldap_get ( '(objectClass=domain)' , attributes : %w[ name objectSID ] )
159
- fail_with ( Failure ::NotFound , 'The domain SID was not found!' ) unless obj &.fetch ( 'objectsid' , nil )
160
-
161
- Rex ::Proto ::MsDtyp ::MsDtypSid . read ( obj [ 'objectsid' ] . first )
162
- end
163
-
164
139
def get_pki_oids
165
140
return @pki_oids if @pki_oids . present?
166
141
@@ -231,9 +206,12 @@ def load_from_yaml(yaml)
231
206
232
207
# if the string only contains printable characters, treat it as SDDL
233
208
if value !~ /[^[:print:]]/
209
+ vprint_status ( "Parsing SDDL text: #{ value } " )
210
+ domain_info = adds_get_domain_info ( @ldap )
211
+ fail_with ( Failure ::Unknown , 'Failed to obtain the domain SID.' ) unless domain_info
212
+
234
213
begin
235
- vprint_status ( "Parsing SDDL text: #{ value } " )
236
- descriptor = Rex ::Proto ::MsDtyp ::MsDtypSecurityDescriptor . from_sddl_text ( value , domain_sid : get_domain_sid )
214
+ descriptor = Rex ::Proto ::MsDtyp ::MsDtypSecurityDescriptor . from_sddl_text ( value , domain_sid : domain_info [ :sid ] )
237
215
rescue RuntimeError => e
238
216
fail_with ( Failure ::BadConfig , e . message )
239
217
end
@@ -270,11 +248,6 @@ def load_local_template
270
248
end
271
249
end
272
250
273
- def ms_security_descriptor_control ( flags )
274
- control_values = [ flags ] . map ( &:to_ber ) . to_ber_sequence . to_s . to_ber
275
- [ LDAP_SERVER_SD_FLAGS_OID . to_ber , control_values ] . to_ber_sequence
276
- end
277
-
278
251
def action_create
279
252
dn = "CN=#{ datastore [ 'CERT_TEMPLATE' ] } ,"
280
253
dn << 'CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,'
@@ -346,14 +319,24 @@ def action_read
346
319
object_guid = Rex ::Proto ::MsDtyp ::MsDtypGuid . read ( obj [ 'objectguid' ] . first )
347
320
print_status ( " objectGUID: #{ object_guid } " )
348
321
end
349
- if obj [ 'ntsecuritydescriptor' ] . first . present?
322
+
323
+ if obj [ :nTSecurityDescriptor ] . first . present?
324
+ domain_info = adds_get_domain_info ( @ldap )
325
+ fail_with ( Failure ::Unknown , 'Failed to obtain the domain SID.' ) unless domain_info
326
+
350
327
begin
351
- sd = Rex ::Proto ::MsDtyp ::MsDtypSecurityDescriptor . read ( obj [ 'ntsecuritydescriptor' ] . first )
352
- sddl_text = sd . to_sddl_text ( domain_sid : get_domain_sid )
328
+ sd = Rex ::Proto ::MsDtyp ::MsDtypSecurityDescriptor . read ( obj [ :nTSecurityDescriptor ] . first )
329
+ sddl_text = sd . to_sddl_text ( domain_sid : domain_info [ :sid ] )
353
330
rescue StandardError => e
354
331
elog ( 'failed to parse a binary security descriptor to SDDL' , error : e )
355
332
else
356
333
print_status ( " nTSecurityDescriptor: #{ sddl_text } " )
334
+ permissions = [ 'READ' ] # if we have the object, we can assume we have read permissions
335
+ permissions << 'WRITE' if adds_obj_grants_permissions? ( @ldap , obj , SecurityDescriptorMatcher ::Allow . new ( :WP ) )
336
+ permissions << 'ENROLL' if adds_obj_grants_permissions? ( @ldap , obj , SecurityDescriptorMatcher ::Allow . certificate_enrollment )
337
+ permissions << 'AUTOENROLL' if adds_obj_grants_permissions? ( @ldap , obj , SecurityDescriptorMatcher ::Allow . certificate_autoenrollment )
338
+ whoami = adds_get_current_user ( @ldap )
339
+ print_status ( " * Permissions applied for #{ whoami [ :userPrincipalName ] . first } : #{ permissions . join ( ', ' ) } " )
357
340
end
358
341
end
359
342
@@ -375,7 +358,7 @@ def action_read
375
358
CT_FLAG_EXPORTABLE_KEY
376
359
] . each do |flag_name |
377
360
if pki_flag & Rex ::Proto ::MsCrtd . const_get ( flag_name ) != 0
378
- print_status ( " * #{ flag_name } " )
361
+ print_status ( " * #{ flag_name } " )
379
362
end
380
363
end
381
364
end
@@ -554,7 +537,7 @@ def action_update
554
537
return true
555
538
end
556
539
557
- @ldap . modify ( dn : obj [ 'dn' ] . first , operations : operations , controls : [ ms_security_descriptor_control ( DACL_SECURITY_INFORMATION ) ] )
540
+ @ldap . modify ( dn : obj . dn , operations : operations , controls : [ adds_build_ldap_sd_control ( owner : false , group : false ) ] )
558
541
validate_query_result! ( @ldap . get_operation_result . table )
559
542
true
560
543
end
0 commit comments