@@ -39,13 +39,10 @@ def on_admin_login(self, context, connection):
3939 context .log .fail (str (e ))
4040 context .log .debug (traceback .format_exc ())
4141
42- def enumerate_admin_users (self , context , connection ):
43- admin_users = []
44- string_binding = fr"ncacn_np:{ connection .kdcHost } [\pipe\samr]"
45- context .log .debug (f"Using string binding: { string_binding } " )
46-
42+ def get_dce_rpc (self , target , string_binding , dce_binding , connection ):
43+ # Create a DCE/RPC transport object with the specified string binding
4744 rpctransport = transport .DCERPCTransportFactory (string_binding )
48- rpctransport .setRemoteHost (connection . kdcHost )
45+ rpctransport .setRemoteHost (target )
4946 rpctransport .set_credentials (
5047 connection .username ,
5148 connection .password ,
@@ -54,11 +51,28 @@ def enumerate_admin_users(self, context, connection):
5451 connection .nthash ,
5552 aesKey = connection .aesKey ,
5653 )
54+ rpctransport .set_kerberos (connection .kerberos , connection .kdcHost )
5755
56+ # Connect to the DCE/RPC endpoint
5857 dce = rpctransport .get_dce_rpc ()
59- dce .set_auth_level (RPC_C_AUTHN_LEVEL_PKT_PRIVACY )
58+ if connection .kerberos :
59+ dce .set_auth_type (RPC_C_AUTHN_GSS_NEGOTIATE )
60+ dce .set_credentials (* rpctransport .get_credentials ())
6061 dce .connect ()
61- dce .bind (samr .MSRPC_UUID_SAMR )
62+ dce .set_auth_level (RPC_C_AUTHN_LEVEL_PKT_PRIVACY )
63+ dce .bind (dce_binding )
64+ return dce
65+
66+ def enumerate_admin_users (self , context , connection ):
67+ admin_users = []
68+
69+ try :
70+ string_binding = fr"ncacn_np:{ connection .kdcHost } [\pipe\samr]"
71+ dce = self .get_dce_rpc (connection .kdcHost , string_binding , samr .MSRPC_UUID_SAMR , connection )
72+ except Exception as e :
73+ context .log .fail (f"Failed to connect to SAMR: { e } " )
74+ context .log .debug (traceback .format_exc ())
75+ return admin_users
6276
6377 try :
6478 server_handle = samr .hSamrConnect2 (dce )["ServerHandle" ]
@@ -70,7 +84,7 @@ def enumerate_admin_users(self, context, connection):
7084 except Exception as e :
7185 context .log .fail (f"Failed to open domain { domain } : { e !s} " )
7286 context .log .debug (traceback .format_exc ())
73- return []
87+ return admin_users
7488
7589 admin_rids = {
7690 "Domain Admins" : 512 ,
@@ -140,7 +154,7 @@ def check_users_directory(self, context, connection, admin_users):
140154 def check_tasklist (self , context , connection , admin_users ):
141155 """Checks tasklist over rpc."""
142156 try :
143- with TSTS .LegacyAPI (connection .conn , connection .host , kerberos = connection .kerberos ) as legacy :
157+ with TSTS .LegacyAPI (connection .conn , connection .remoteName , kerberos = connection .kerberos ) as legacy :
144158 handle = legacy .hRpcWinStationOpenServer ()
145159 processes = legacy .hRpcWinStationGetAllProcesses (handle )
146160 except Exception as e :
@@ -159,31 +173,14 @@ def check_tasklist(self, context, connection, admin_users):
159173
160174 def check_scheduled_tasks (self , context , connection , admin_users ):
161175 """Checks scheduled tasks over rpc."""
162- target = connection .hostname if connection .kerberos else connection .host
163- stringbinding = f"ncacn_np:{ target } [\\ pipe\\ atsvc]"
164- rpctransport = transport .DCERPCTransportFactory (stringbinding )
165- rpctransport .setRemoteHost (connection .hostname )
166- rpctransport .set_credentials (
167- connection .username ,
168- connection .password ,
169- connection .domain ,
170- connection .lmhash ,
171- connection .nthash ,
172- aesKey = connection .aesKey ,
173- )
174- rpctransport .set_kerberos (connection .kerberos , connection .kdcHost )
175-
176176 try :
177- dce = rpctransport .get_dce_rpc ()
178- if connection .kerberos :
179- dce .set_auth_type (RPC_C_AUTHN_GSS_NEGOTIATE )
180- dce .set_credentials (* rpctransport .get_credentials ())
181- dce .connect ()
182- dce .set_auth_level (RPC_C_AUTHN_LEVEL_PKT_PRIVACY )
183- dce .bind (tsch .MSRPC_UUID_TSCHS )
177+ target = connection .remoteName if connection .kerberos else connection .host
178+ stringbinding = f"ncacn_np:{ target } [\\ pipe\\ atsvc]"
179+ dce = self .get_dce_rpc (target , stringbinding , tsch .MSRPC_UUID_TSCHS , connection )
184180
185181 # Also extract non admins where we can get the password
186- self .non_admin_sids = []
182+ self .non_admins = []
183+ non_admin_sids = set ()
187184
188185 tasks = tsch .hSchRpcEnumTasks (dce , "\\ " )["pNames" ]
189186 for task in tasks :
@@ -200,7 +197,22 @@ def check_scheduled_tasks(self, context, connection, admin_users):
200197 user ["in_scheduled_tasks" ] = True
201198 else :
202199 # If not an admin user, add to non_admin_sids for further processing
203- self .non_admin_sids .append (sid .group (1 ))
200+ non_admin_sids .add (sid .group (1 ))
201+
202+ if non_admin_sids :
203+ string_binding = fr"ncacn_np:{ connection .kdcHost } [\pipe\samr]"
204+ dce = self .get_dce_rpc (connection .kdcHost , string_binding , samr .MSRPC_UUID_SAMR , connection )
205+
206+ # Get Domain Handle
207+ server_handle = samr .hSamrConnect2 (dce )["ServerHandle" ]
208+ domain = samr .hSamrEnumerateDomainsInSamServer (dce , server_handle )["Buffer" ]["Buffer" ][0 ]["Name" ]
209+ domain_sid = samr .hSamrLookupDomainInSamServer (dce , server_handle , domain )["DomainId" ]
210+ domain_handle = samr .hSamrOpenDomain (dce , server_handle , samr .DOMAIN_LOOKUP | samr .DOMAIN_LIST_ACCOUNTS , domain_sid )["DomainHandle" ]
211+
212+ for sid in non_admin_sids :
213+ user_handle = samr .hSamrOpenUser (dce , domain_handle , samr .MAXIMUM_ALLOWED , int (sid .split ("-" )[- 1 ]))["UserHandle" ]
214+ username = samr .hSamrQueryInformationUser2 (dce , user_handle , samr .USER_INFORMATION_CLASS .UserAllInformation )["Buffer" ]["All" ]["UserName" ]
215+ self .non_admins .append (username )
204216
205217 except Exception as e :
206218 context .log .fail (f"Failed to enumerate scheduled tasks: { e } " )
@@ -231,9 +243,9 @@ def print_grouped_results(self, context, admin_users):
231243 context .log .success ("Found admins in scheduled tasks:" )
232244 for user in scheduled_tasks_users :
233245 context .log .highlight (f"{ user ['username' ]} ({ ', ' .join (user ['group' ])} )" )
234- if self .non_admin_sids :
235- context .log .success (f"Found { len (self .non_admin_sids )} non-admin scheduled tasks with passwords stored in dpapi:" )
236- for sid in self .non_admin_sids :
246+ if self .non_admins :
247+ context .log .success (f"Found { len (self .non_admins )} non-admin scheduled tasks with passwords stored in dpapi:" )
248+ for sid in self .non_admins :
237249 context .log .highlight (sid )
238250
239251 # Making this less verbose to better scan large ranges
0 commit comments