@@ -40,6 +40,7 @@ class EnrollmentFlag(enum.IntFlag):
40
40
ALLOW_PREVIOUS_APPROVAL_KEYBASEDRENEWAL_VALIDATE_REENROLLMENT = 0x00010000
41
41
ISSUANCE_POLICIES_FROM_REQUEST = 0x00020000
42
42
SKIP_AUTO_RENEWAL = 0x00040000
43
+ NO_SECURITY_EXTENSION = 0x00080000
43
44
44
45
class PrivateKeyFlag (enum .IntFlag ):
45
46
REQUIRE_PRIVATE_KEY_ARCHIVAL = 0x00000001
@@ -196,6 +197,14 @@ def from_ldap(entry):
196
197
197
198
adi .calc_aces ()
198
199
return adi
200
+
201
+ def isLowPrivSid (self , sid ):
202
+ sid = str (sid )
203
+ if sid in ['S-1-1-0' , 'S-1-5-11' ]:
204
+ return True
205
+ if sid .startswith ('S-1-5-21-' ) is True and sid .rsplit ('-' ,1 )[1 ] in ['513' ,'515' ,'545' ]:
206
+ return True
207
+ return False
199
208
200
209
def allows_authentication (self ):
201
210
return self .can_be_used_for_any_purpose () or len (set ([EKU_CLIENT_AUTHENTICATION_OID , EKU_SMART_CARD_LOGON_OID , EKU_PKINIT_CLIENT_AUTHENTICATION_OID ]).intersection (set (self .pKIExtendedKeyUsage ))) > 0
@@ -216,24 +225,24 @@ def allows_to_request_agent_certificate(self):
216
225
return EKU_CERTIFICATE_REQUEST_AGENT_OID in self .pKIExtendedKeyUsage
217
226
218
227
def allows_to_use_agent_certificate (self ):
219
- return self .Template_Schema_Version == 1 \
220
- or (
221
- self .Template_Schema_Version > 1 \
222
- and self .RA_Signature == 1 \
223
- and EKU_CERTIFICATE_REQUEST_AGENT_OID in self .RA_Application_Policies
224
- )
225
-
226
- def is_vulnerable (self , tokengroups = None ):
227
- def isLowPrivSid (sid ):
228
- sid = str (sid )
229
- if sid in ['S-1-1-0' , 'S-1-5-11' ]:
230
- return True
231
- if sid .startswith ('S-1-5-21-' ) is True and sid .rsplit ('-' ,1 )[1 ] in ['513' ,'515' ,'545' ]:
232
- return True
233
- return False
228
+ if EKU_ANY_PURPOSE_OID in self .pKIExtendedKeyUsage :
229
+ return True
230
+ if EKU_CERTIFICATE_REQUEST_AGENT_OID in self .pKIExtendedKeyUsage :
231
+ return True
234
232
233
+ #return self.Template_Schema_Version == 1 \
234
+ # or (
235
+ # self.Template_Schema_Version > 1 \
236
+ # and self.RA_Signature == 1 \
237
+ # and EKU_CERTIFICATE_REQUEST_AGENT_OID in self.RA_Application_Policies
238
+ # )
239
+
240
+ def no_securty_extension (self ):
241
+ return EnrollmentFlag .NO_SECURITY_EXTENSION in EnrollmentFlag (self .Enrollment_Flag )
242
+
243
+ def is_vulnerable (self , tokengroups = None ):
235
244
if tokengroups is None :
236
- if isLowPrivSid (str (self .nTSecurityDescriptor .Owner )) is True :
245
+ if self . isLowPrivSid (str (self .nTSecurityDescriptor .Owner )) is True :
237
246
return True , 'Owner is low priv user'
238
247
239
248
else :
@@ -242,22 +251,22 @@ def isLowPrivSid(sid):
242
251
243
252
lowprivcanenroll = False
244
253
if tokengroups is None :
245
- if any (isLowPrivSid (str (sid )) for sid in self .fullcontrol_sids ) is True :
254
+ if any (self . isLowPrivSid (str (sid )) for sid in self .fullcontrol_sids ) is True :
246
255
return True , 'Lowpriv SID has full control'
247
256
248
- if any (isLowPrivSid (str (sid )) for sid in self .write_dacl_sids ) is True :
257
+ if any (self . isLowPrivSid (str (sid )) for sid in self .write_dacl_sids ) is True :
249
258
return True , 'Lowpriv SID can write DACLs'
250
259
251
- if any (isLowPrivSid (str (sid )) for sid in self .write_owner_sids ) is True :
260
+ if any (self . isLowPrivSid (str (sid )) for sid in self .write_owner_sids ) is True :
252
261
return True , 'Lowpriv SID can change Owner'
253
262
254
- if any (isLowPrivSid (str (sid )) for sid in self .write_property_sids ) is True :
263
+ if any (self . isLowPrivSid (str (sid )) for sid in self .write_property_sids ) is True :
255
264
return True , 'Lowpriv SID can write property'
256
265
257
- if any (isLowPrivSid (str (sid )) for sid in self .enroll_sids ) is True :
266
+ if any (self . isLowPrivSid (str (sid )) for sid in self .enroll_sids ) is True :
258
267
lowprivcanenroll = True
259
268
260
- if any (isLowPrivSid (str (sid )) for sid in self .allextendedrights_sids ) is True :
269
+ if any (self . isLowPrivSid (str (sid )) for sid in self .allextendedrights_sids ) is True :
261
270
lowprivcanenroll = True
262
271
263
272
else :
@@ -290,6 +299,83 @@ def isLowPrivSid(sid):
290
299
291
300
return False , 'No match found'
292
301
302
+ def check_dangerous_permissions (self , tokengroups = None ):
303
+ issues = []
304
+ if tokengroups is None or len (tokengroups ) == 0 :
305
+ if self .isLowPrivSid (str (self .nTSecurityDescriptor .Owner )) is True :
306
+ issues .append ('Owner is low priv user' )
307
+
308
+ if any (self .isLowPrivSid (str (sid )) for sid in self .fullcontrol_sids ) is True :
309
+ issues .append ('Lowpriv SID has full control' )
310
+
311
+ if any (self .isLowPrivSid (str (sid )) for sid in self .write_dacl_sids ) is True :
312
+ issues .append ('Lowpriv SID can write DACLs' )
313
+
314
+ if any (self .isLowPrivSid (str (sid )) for sid in self .write_owner_sids ) is True :
315
+ issues .append ('Lowpriv SID can change Owner' )
316
+
317
+ if any (self .isLowPrivSid (str (sid )) for sid in self .write_property_sids ) is True :
318
+ issues .append ('Lowpriv SID can write property' )
319
+
320
+ else :
321
+ if len (self .write_dacl_sids .intersection (set (tokengroups ))) > 0 :
322
+ issues .append ('Current user can write DACLs' )
323
+
324
+ if len (self .write_owner_sids .intersection (set (tokengroups ))) > 0 :
325
+ issues .append ('Current user can change Owner' )
326
+
327
+ if len (self .write_property_sids .intersection (set (tokengroups ))) > 0 :
328
+ issues .append ('Current user can write property' )
329
+
330
+ if len (self .fullcontrol_sids .intersection (set (tokengroups ))) > 0 :
331
+ issues .append ('Current user has full control' )
332
+
333
+ if str (self .nTSecurityDescriptor .Owner ) in tokengroups :
334
+ issues .append ('The current user can control the owner -or is the owner-' )
335
+
336
+ return issues
337
+
338
+ def is_vulnerable2 (self , tokengroups = None ):
339
+ vulns = {}
340
+ if tokengroups is None :
341
+ tokengroups = []
342
+
343
+ user_can_enroll = False
344
+ if len (set (self .enroll_sids ).intersection (set (tokengroups ))) > 0 :
345
+ user_can_enroll = True
346
+
347
+ if user_can_enroll and self .allows_authentication () and self .allows_to_specify_san ():
348
+ vulns ['ESC1' ] = {
349
+ 'SIDs' : self .enroll_sids ,
350
+ 'Reason' : 'Users can enroll, enrollee supplies subject and template allows client authentication'
351
+ }
352
+
353
+ if user_can_enroll and self .can_be_used_for_any_purpose () is True :
354
+ vulns ['ESC2' ] = {
355
+ 'SIDs' : self .enroll_sids ,
356
+ 'Reason' : 'Users can enroll and template allows any purpose'
357
+ }
358
+
359
+ if user_can_enroll and self .allows_to_use_agent_certificate ():
360
+ vulns ['ESC3' ] = {
361
+ 'SIDs' : self .enroll_sids ,
362
+ 'Reason' : 'Users can enroll and template allows certificate request agent'
363
+ }
364
+
365
+ if user_can_enroll and self .no_securty_extension ():
366
+ vulns ['ESC9' ] = {
367
+ 'SIDs' : self .enroll_sids ,
368
+ 'Reason' : 'Users can enroll and template does not require security extension'
369
+ }
370
+
371
+ perm_issues = self .check_dangerous_permissions (tokengroups )
372
+ if len (perm_issues ) > 0 :
373
+ vulns ['ESC4' ] = {
374
+ 'SIDs' : tokengroups ,
375
+ 'Reason' : ', ' .join (perm_issues )
376
+ }
377
+ return vulns
378
+
293
379
def calc_aces (self ):
294
380
if self .nTSecurityDescriptor is None :
295
381
return
@@ -324,6 +410,18 @@ def calc_aces(self):
324
410
@property
325
411
def is_enabled (self ):
326
412
return len (self .enroll_services ) > 0
413
+
414
+ @property
415
+ def enrollment_services (self ):
416
+ res = []
417
+ for es in self .enroll_services :
418
+ if es .find ('\\ ' ) != - 1 :
419
+ hostname , service = es .split ('\\ ' , 1 )
420
+ res .append ((hostname , service ))
421
+ else :
422
+ res .append ((None , service ))
423
+ return res
424
+
327
425
328
426
def __str__ (self ):
329
427
t = '== MSADCertificateTemplate ==\r \n '
0 commit comments