Skip to content

Commit a6fa872

Browse files
committed
Switch to user objects instead of multiple lists
1 parent 747df10 commit a6fa872

1 file changed

Lines changed: 34 additions & 65 deletions

File tree

nxc/modules/presence.py

Lines changed: 34 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)