Skip to content

Commit 1c262fe

Browse files
author
Aurélien CHALOT
committed
Update so that it supports passing a file with usernames
1 parent 2febbf6 commit 1c262fe

2 files changed

Lines changed: 25 additions & 15 deletions

File tree

nxc/protocols/smb.py

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -978,16 +978,21 @@ def enumerate_sessions_info(self, sessions):
978978
except SessionError:
979979
self.logger.fail("RDP is probably not enabled, cannot list remote IPv4 addresses.")
980980

981+
981982
@requires_admin
982983
def qwinsta(self):
984+
import os
985+
983986
desktop_states = {
984987
"WTS_SESSIONSTATE_UNKNOWN": "",
985988
"WTS_SESSIONSTATE_LOCK": "Locked",
986989
"WTS_SESSIONSTATE_UNLOCK": "Unlocked",
987990
}
991+
988992
sessions = self.get_session_list()
989-
if not len(sessions):
993+
if not sessions:
990994
return
995+
991996
self.enumerate_sessions_info(sessions)
992997

993998
maxSessionNameLen = max(len(sessions[i]["SessionName"]) + 1 for i in sessions)
@@ -998,10 +1003,6 @@ def qwinsta(self):
9981003
maxIdLen = max(maxIdLen, len("ID") + 1)
9991004
maxStateLen = max(len(sessions[i]["state"]) + 1 for i in sessions)
10001005
maxStateLen = max(maxStateLen, len("STATE") + 1)
1001-
maxRemoteIp = max(len(sessions[i]["RemoteIp"]) + 1 for i in sessions)
1002-
maxRemoteIp = max(maxRemoteIp, len("RemoteAddress") + 1)
1003-
maxClientName = max(len(sessions[i]["ClientName"]) + 1 for i in sessions)
1004-
maxClientName = max(maxClientName, len("ClientName") + 1)
10051006

10061007
template = ("{SESSIONNAME: <%d} "
10071008
"{USERNAME: <%d} "
@@ -1036,27 +1037,34 @@ def qwinsta(self):
10361037

10371038
result = [header, header2]
10381039

1040+
usernames = None
1041+
if self.args.qwinsta and self.args.qwinsta is not True:
1042+
arg = self.args.qwinsta
1043+
if os.path.isfile(arg):
1044+
with open(arg, "r") as f:
1045+
usernames = [line.strip().lower() for line in f if line.strip()]
1046+
else:
1047+
usernames = [arg.lower()]
1048+
10391049
found_user = False
10401050

10411051
for i in sessions:
10421052
username = sessions[i]["Username"]
10431053
domain = sessions[i]["Domain"]
10441054
user_full = f"{domain}\\{username}" if username else ""
10451055

1046-
# If args.qwinsta is not True then a username was supplised to look for
1047-
if self.args.qwinsta and self.args.qwinsta is not True:
1048-
if username.lower() != self.args.qwinsta.lower():
1049-
# If the provided username doesn't match, we pass to the next session
1056+
if usernames:
1057+
if username.lower() not in usernames:
10501058
continue
10511059

1052-
# If the username matches or no username was supplied, we activate that falag
10531060
found_user = True
10541061

1055-
# Then we get the connectTime, disconnectTime and format the row to be printed
10561062
connectTime = sessions[i]["ConnectTime"]
10571063
connectTime = connectTime.strftime(r"%Y/%m/%d %H:%M:%S") if connectTime.year > 1601 else "None"
1064+
10581065
disconnectTime = sessions[i]["DisconnectTime"]
10591066
disconnectTime = disconnectTime.strftime(r"%Y/%m/%d %H:%M:%S") if disconnectTime.year > 1601 else "None"
1067+
10601068
row = template.format(
10611069
SESSIONNAME=sessions[i]["SessionName"],
10621070
USERNAME=user_full,
@@ -1068,14 +1076,16 @@ def qwinsta(self):
10681076
DISCTIME=disconnectTime,
10691077
)
10701078
result.append(row)
1071-
1072-
# This flag should be on if a username was supplied and found or if no username was supplied
1079+
10731080
if found_user:
10741081
self.logger.success("Enumerated qwinsta sessions")
10751082
for row in result:
10761083
self.logger.highlight(row)
10771084
else:
1078-
self.logger.fail(f"No user session found matching '{self.args.qwinsta}'")
1085+
if usernames:
1086+
self.logger.fail(f"No user session found matching: {', '.join(usernames)}")
1087+
else:
1088+
self.logger.fail("No sessions found")
10791089

10801090
@requires_admin
10811091
def tasklist(self):

nxc/protocols/smb/proto_args.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def proto_args(parser, parents):
5353
mapping_enum_group.add_argument("--local-groups", nargs="?", const="", metavar="GROUP", help="Enumerate local groups, if a group is specified then its members are Enumerated")
5454
mapping_enum_group.add_argument("--pass-pol", action="store_true", help="dump password policy")
5555
mapping_enum_group.add_argument("--rid-brute", nargs="?", type=int, const=4000, metavar="MAX_RID", help="Enumerate users by bruteforcing RIDs")
56-
mapping_enum_group.add_argument("--qwinsta", type=str, nargs="?", const=True, help="Enumerate user sessions. If a username is given, filter for it; if no value is given, list all.")
56+
mapping_enum_group.add_argument("--qwinsta", type=str, nargs="?", const=True, help="Enumerate user sessions. If a username is given, filter for it; if a file is given, filter for listed usernames. If no value is given, list all.")
5757
mapping_enum_group.add_argument("--tasklist", action="store_true", help="Enumerate running processes")
5858

5959
wmi_group = smb_parser.add_argument_group("WMI", "Options for WMI Queries")

0 commit comments

Comments
 (0)