1818 "GenericExecute" : 0x20000000 , # ADS_RIGHT_GENERIC_EXECUTE
1919 "GenericAll" : 0x10000000 , # ADS_RIGHT_GENERIC_ALL
2020
21- # Maximum Allowed access type
21+ # Maximum Allowed access type
2222 "MaximumAllowed" : 0x02000000 ,
2323
24- # Access System Acl access type
24+ # Access System Acl access type
2525 "AccessSystemSecurity" : 0x01000000 , # ADS_RIGHT_ACCESS_SYSTEM_SECURITY
2626
27- # Standard access types
27+ # Standard access types
2828 "Synchronize" : 0x00100000 , # ADS_RIGHT_SYNCHRONIZE
2929 "WriteOwner" : 0x00080000 , # ADS_RIGHT_WRITE_OWNER
3030 "WriteDACL" : 0x00040000 , # ADS_RIGHT_WRITE_DAC
3131 "ReadControl" : 0x00020000 , # ADS_RIGHT_READ_CONTROL
3232 "Delete" : 0x00010000 , # ADS_RIGHT_DELETE
3333
34- # Specific rights
34+ # Specific rights
3535 "AllExtendedRights" : 0x00000100 , # ADS_RIGHT_DS_CONTROL_ACCESS
3636 "ListObject" : 0x00000080 , # ADS_RIGHT_DS_LIST_OBJECT
3737 "DeleteTree" : 0x00000040 , # ADS_RIGHT_DS_DELETE_TREE
5454 "AllExtendedRights" : ACCESS_RIGHTS ["AllExtendedRights" ]
5555}
5656
57+
5758class NXCModule :
5859 """
5960 -------
@@ -84,8 +85,8 @@ def is_excluded_sid(self, sid, domain_sid):
8485 def get_domain_sid (self , ldap_session , base_dn ):
8586 """Retrieve the domain SID from the domain object in LDAP"""
8687 r = ldap_session .search (
87- searchBase = base_dn ,
88- searchFilter = "(objectClass=domain)" ,
88+ searchBase = base_dn ,
89+ searchFilter = "(objectClass=domain)" ,
8990 attributes = ["objectSid" ]
9091 )
9192 parsed = parse_result_attributes (r )
@@ -101,7 +102,7 @@ def find_bad_successor_ous(self, ldap_session, entries, base_dn):
101102 dn = entry ["distinguishedName" ]
102103 sd_data = entry ["nTSecurityDescriptor" ]
103104 sd = ldaptypes .SR_SECURITY_DESCRIPTOR (data = sd_data )
104-
105+
105106 for ace in sd ["Dacl" ]["Data" ]:
106107 if ace ["AceType" ] != ldaptypes .ACCESS_ALLOWED_ACE .ACE_TYPE :
107108 continue
@@ -112,7 +113,7 @@ def find_bad_successor_ous(self, ldap_session, entries, base_dn):
112113 if mask & right_value :
113114 has_relevant_right = True
114115 break
115-
116+
116117 if not has_relevant_right :
117118 continue # Skip this ACE if it doesn't have any relevant rights
118119
@@ -127,7 +128,7 @@ def find_bad_successor_ous(self, ldap_session, entries, base_dn):
127128 continue
128129
129130 results .setdefault (sid , []).append (dn )
130-
131+
131132 if hasattr (sd , "OwnerSid" ):
132133 owner_sid = str (sd ["OwnerSid" ])
133134 if not self .is_excluded_sid (owner_sid , domain_sid ):
@@ -138,13 +139,13 @@ def find_bad_successor_ous(self, ldap_session, entries, base_dn):
138139 def resolve_sid_to_name (self , ldap_session , sid , base_dn ):
139140 """
140141 Resolves a SID to a samAccountName using LDAP
141-
142+
142143 Args:
143144 ----
144145 ldap_session: The LDAP connection
145146 sid: The SID to resolve
146147 base_dn: The base DN for the LDAP search
147-
148+
148149 Returns:
149150 -------
150151 str: The samAccountName if found, otherwise the original SID
@@ -156,7 +157,7 @@ def resolve_sid_to_name(self, ldap_session, sid, base_dn):
156157 searchFilter = search_filter ,
157158 attributes = ["sAMAccountName" ]
158159 )
159-
160+
160161 parsed = parse_result_attributes (response )
161162 if parsed and "sAMAccountName" in parsed [0 ]:
162163 return parsed [0 ]["sAMAccountName" ]
@@ -165,14 +166,14 @@ def resolve_sid_to_name(self, ldap_session, sid, base_dn):
165166 return sid
166167
167168 def on_login (self , context , connection ):
168-
169+
169170 controls = security_descriptor_control (sdflags = 0x07 ) # OWNER_SECURITY_INFORMATION
170171 resp = connection .ldap_connection .search (
171- searchBase = connection .ldap_connection ._baseDN ,
172- searchFilter = "(objectClass=organizationalUnit)" ,
173- attributes = ["distinguishedName" , "nTSecurityDescriptor" ],
174- searchControls = controls ) # Fixed parameter name
175-
172+ searchBase = connection .ldap_connection ._baseDN ,
173+ searchFilter = "(objectClass=organizationalUnit)" ,
174+ attributes = ["distinguishedName" , "nTSecurityDescriptor" ],
175+ searchControls = controls ) # Fixed parameter name
176+
176177 context .log .debug (f"Found { len (resp )} entries" )
177178
178179 results = self .find_bad_successor_ous (connection .ldap_connection , resp , connection .ldap_connection ._baseDN )
@@ -184,11 +185,11 @@ def on_login(self, context, connection):
184185
185186 for sid , ous in results .items ():
186187 samaccountname = self .resolve_sid_to_name (
187- connection .ldap_connection ,
188- sid ,
188+ connection .ldap_connection ,
189+ sid ,
189190 connection .ldap_connection ._baseDN
190191 )
191-
192+
192193 for ou in ous :
193194 if sid == samaccountname :
194195 context .log .highlight (f"{ sid } , { ou } " )
0 commit comments