@@ -56,6 +56,7 @@ def on_admin_login(self, context, connection):
5656 "Administrators" : 544 ,
5757 }
5858
59+ # Enumerate admin groups and their members
5960 for group_name , group_rid in admin_rids .items ():
6061 context .log .debug (f"Looking up group: { group_name } with RID { group_rid } " )
6162
@@ -68,15 +69,10 @@ def on_admin_login(self, context, connection):
6869 user_handle = samr .hSamrOpenUser (dce , domain_handle , samr .MAXIMUM_ALLOWED , rid )["UserHandle" ]
6970 username = samr .hSamrQueryInformationUser2 (dce , user_handle , samr .USER_INFORMATION_CLASS .UserAllInformation )["Buffer" ]["All" ]["UserName" ]
7071
71- admin_users .add (f"{ domain } \\ { username } (Member of { group_name } )" )
72- usernames .add (username )
73-
74- # map sid string of user to username
75- user_sid = f"{ domain_sid } -{ rid } "
76- self .sid_to_user [user_sid ] = f"{ domain } \\ { username } "
72+ admin_users .append ({"username" : username , "sid" : f"{ domain_sid } -{ rid } " , "domain" : domain , "group" : group_name , "in_tasks" : False , "in_directory" : False })
73+ context .log .debug (f"Found user: { username } with RID { rid } in group { group_name } " )
7774 except Exception as e :
7875 context .log .debug (f"Failed to get user info for RID { rid } : { e !s} " )
79- admin_users .add (f"{ domain } \\ { domain_sid } -{ rid } (Member of { group_name } )" )
8076 finally :
8177 with suppress (Exception ):
8278 samr .hSamrCloseHandle (dce , user_handle )
@@ -86,27 +82,17 @@ def on_admin_login(self, context, connection):
8682 with suppress (Exception ):
8783 samr .hSamrCloseHandle (dce , group_handle )
8884
89- usernames = sorted (usernames )
90-
91- matched_dirs = self .check_users_directory (context , connection , usernames )
92- matched_tasks = self .check_tasklist (context , connection , usernames , connection .hostname )
93-
94- # collect results for printing
95- results = {
96- "netbios_name" : connection .hostname ,
97- "admin_users" : usernames ,
98- "matched_dirs" : matched_dirs ,
99- "matched_tasks" : matched_tasks ,
100- }
85+ # Update user objects to check if they are in tasklist or users directory
86+ self .check_users_directory (context , connection , admin_users )
87+ self .check_tasklist (context , connection , admin_users )
10188
10289 # print grouped/logged results nicely
103- self .print_grouped_results (context , connection , results )
90+ self .print_grouped_results (context , admin_users )
10491 except Exception as e :
10592 context .log .fail (str (e ))
106- return False
93+ context . log . debug ( traceback . format_exc ())
10794
10895 def check_users_directory (self , context , connection , admin_users ):
109- matched_dirs = []
11096 dirs_found = set ()
11197
11298 # try C$\Users first
@@ -118,7 +104,7 @@ def check_users_directory(self, context, connection, admin_users):
118104 files = connection .conn .listPath ("C$" , "\\ Documents and Settings\\ *" )
119105 except Exception as e :
120106 context .log .fail (f"Error listing fallback directory: { e } " )
121- return matched_dirs # return empty
107+ return
122108 else :
123109 context .log .debug ("Successfully listed C$\\ Users" )
124110
@@ -127,63 +113,46 @@ def check_users_directory(self, context, connection, admin_users):
127113
128114 # for admin users, check for folder presence
129115 for user in admin_users :
130- # only match folders like "administrator.something", not "administrator"
131- if user .lower () == "administrator" :
132- matched = [d for d in dirs_found if d .startswith ("administrator." ) and d != "administrator" ]
133- matched_dirs .extend (matched )
134- else :
135- if user .lower () in dirs_found :
136- matched_dirs .append (user )
137- return matched_dirs
138-
139- def check_tasklist (self , context , connection , admin_users , netbios_name ):
116+ if user ["username" ].lower () in dirs_found :
117+ user ["in_directory" ] = True
118+ context .log .debug (f"Found user { user ['username' ]} in directories" )
119+
120+ def check_tasklist (self , context , connection , admin_users ):
140121 """Checks tasklist over rpc."""
141122 try :
142- with TSTS .LegacyAPI (connection .conn , netbios_name , kerberos = False ) as legacy :
123+ with TSTS .LegacyAPI (connection .conn , connection . host , kerberos = False ) as legacy :
143124 handle = legacy .hRpcWinStationOpenServer ()
144125 processes = legacy .hRpcWinStationGetAllProcesses (handle )
145126 except Exception as e :
146127 context .log .fail (f"Error in check_tasklist RPC method: { e } " )
147128 return []
148129
149- context .log .debug (f"Enumerated { len (processes )} processes on { netbios_name } " )
150-
151- matched_admin_users = {}
152-
153- # prepare admin users in lowercase for case-insensitive matching
154- admin_users_lower = {u .lower () for u in admin_users }
130+ context .log .debug (f"Enumerated { len (processes )} processes on { connection .host } " )
155131
156132 for process in processes :
157133 context .log .debug (f"ImageName: { process ['ImageName' ]} , UniqueProcessId: { process ['SessionId' ]} , pSid: { process ['pSid' ]} " )
158- username = self .sid_to_user .get (process ["pSid" ])
159- if username :
160- # extract username part after '\'
161- user_only = username .split ("\\ " )[- 1 ]
162- if user_only .lower () in admin_users_lower :
163- # save original casing
164- matched_admin_users [user_only ] = True
165-
166- if matched_admin_users :
167- context .log .info ("Found users in tasklist:\n " + "\n " .join (matched_admin_users .keys ()))
168- else :
169- context .log .info ("No admin user processes found in tasklist" )
170-
171- return list (matched_admin_users .keys ())
134+ # Check if process SID matches any admin user SID
135+ for user in admin_users :
136+ if process ["pSid" ] == user ["sid" ]:
137+ user ["in_tasks" ] = True
138+ context .log .debug (f"Matched process { process ['ImageName' ]} with user { user ['username' ]} " )
172139
173- def print_grouped_results (self , context , connection , results ):
140+ def print_grouped_results (self , context , admin_users ):
174141 """Logs all results grouped per host in order"""
175- if results ["admin_users" ]:
176- context .log .success (f"Identified Admin Users: { ', ' .join (results ['admin_users' ])} " )
142+ context .log .success (f"Identified Admin Users: { ', ' .join ([user ['username' ] for user in admin_users ])} )" )
177143
178- if results ["matched_dirs" ]:
144+ dir_users = [user for user in admin_users if user ["in_directory" ]]
145+ if dir_users :
179146 context .log .success ("Found users in directories:" )
180- for d in results [ "matched_dirs" ] :
181- context .log .highlight (d )
147+ for user in dir_users :
148+ context .log .highlight (f" { user [ 'username' ] } ( { user [ 'group' ] } )" )
182149
183- if results ["matched_tasks" ]:
150+ tasklist_users = [user for user in admin_users if user ["in_tasks" ]]
151+ if tasklist_users :
184152 context .log .success ("Found users in tasklist:" )
185- for t in results [ "matched_tasks" ] :
186- context .log .highlight (t )
153+ for user in tasklist_users :
154+ context .log .highlight (f" { user [ 'username' ] } ( { user [ 'group' ] } )" )
187155
188- if not results ["matched_dirs" ] and not results ["matched_tasks" ]:
189- context .log .success ("No matches found in users directory or tasklist." )
156+ # Making this less verbose to better scan large ranges
157+ if not dir_users and not tasklist_users :
158+ context .log .info ("No matches found in users directory or tasklist." )
0 commit comments