diff --git a/nxc/protocols/smb.py b/nxc/protocols/smb.py index fe77919f..0fe39902 100755 --- a/nxc/protocols/smb.py +++ b/nxc/protocols/smb.py @@ -991,18 +991,19 @@ class smb(connection): self.enumerate_sessions_info(sessions) maxSessionNameLen = max(len(sessions[i]["SessionName"]) + 1 for i in sessions) - maxSessionNameLen = maxSessionNameLen if len("SESSIONNAME") < maxSessionNameLen else len("SESSIONNAME") + 1 + maxSessionNameLen = max(maxSessionNameLen, len("SESSIONNAME") + 1) maxUsernameLen = max(len(sessions[i]["Username"] + sessions[i]["Domain"]) + 1 for i in sessions) + 1 - maxUsernameLen = maxUsernameLen if len("Username") < maxUsernameLen else len("Username") + 1 + maxUsernameLen = max(maxUsernameLen, len("USERNAME") + 1) maxIdLen = max(len(str(i)) for i in sessions) - maxIdLen = maxIdLen if len("ID") < maxIdLen else len("ID") + 1 + maxIdLen = max(maxIdLen, len("ID") + 1) maxStateLen = max(len(sessions[i]["state"]) + 1 for i in sessions) - maxStateLen = maxStateLen if len("STATE") < maxStateLen else len("STATE") + 1 + maxStateLen = max(maxStateLen, len("STATE") + 1) maxRemoteIp = max(len(sessions[i]["RemoteIp"]) + 1 for i in sessions) - maxRemoteIp = maxRemoteIp if len("RemoteAddress") < maxRemoteIp else len("RemoteAddress") + 1 + maxRemoteIp = max(maxRemoteIp, len("RemoteAddress") + 1) maxClientName = max(len(sessions[i]["ClientName"]) + 1 for i in sessions) - maxClientName = maxClientName if len("ClientName") < maxClientName else len("ClientName") + 1 - template = ("{SESSIONNAME: <%d} " # noqa: UP031 + maxClientName = max(maxClientName, len("ClientName") + 1) + + template = ("{SESSIONNAME: <%d} " "{USERNAME: <%d} " "{ID: <%d} " "{IPv4: <16} " @@ -1011,7 +1012,6 @@ class smb(connection): "{CONNTIME: <20} " "{DISCTIME: <20} ") % (maxSessionNameLen, maxUsernameLen, maxIdLen, maxStateLen) - result = [] header = template.format( SESSIONNAME="SESSIONNAME", USERNAME="USERNAME", @@ -1033,30 +1033,49 @@ class smb(connection): CONNTIME="", DISCTIME="", ) - result.extend((header, header2)) + + result = [header, header2] + + found_user = False for i in sessions: + username = sessions[i]["Username"] + domain = sessions[i]["Domain"] + user_full = f"{domain}\\{username}" if username else "" + + # If args.qwinsta is not True then a username was supplised to look for + if self.args.qwinsta and self.args.qwinsta is not True: + if username.lower() != self.args.qwinsta.lower(): + # If the provided username doesn't match, we pass to the next session + continue + + # If the username matches or no username was supplied, we activate that falag + found_user = True + + # Then we get the connectTime, disconnectTime and format the row to be printed connectTime = sessions[i]["ConnectTime"] connectTime = connectTime.strftime(r"%Y/%m/%d %H:%M:%S") if connectTime.year > 1601 else "None" - disconnectTime = sessions[i]["DisconnectTime"] disconnectTime = disconnectTime.strftime(r"%Y/%m/%d %H:%M:%S") if disconnectTime.year > 1601 else "None" - userName = sessions[i]["Domain"] + "\\" + sessions[i]["Username"] if len(sessions[i]["Username"]) else "" - - result.append(template.format( + row = template.format( SESSIONNAME=sessions[i]["SessionName"], - USERNAME=userName, + USERNAME=user_full, ID=i, IPv4=sessions[i]["RemoteIp"], STATE=sessions[i]["state"], DSTATE=desktop_states[sessions[i]["flags"]], CONNTIME=connectTime, DISCTIME=disconnectTime, - )) + ) + result.append(row) - self.logger.success("Enumerated qwinsta sessions") - for row in result: - self.logger.highlight(row) + # This flag should be on if a username was supplied and found or if no username was supplied + if found_user: + self.logger.success("Enumerated qwinsta sessions") + for row in result: + self.logger.highlight(row) + else: + self.logger.fail(f"No user session found matching '{self.args.qwinsta}'") @requires_admin def tasklist(self): diff --git a/nxc/protocols/smb/proto_args.py b/nxc/protocols/smb/proto_args.py index cc914988..372ef2ab 100644 --- a/nxc/protocols/smb/proto_args.py +++ b/nxc/protocols/smb/proto_args.py @@ -53,7 +53,7 @@ def proto_args(parser, parents): 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") mapping_enum_group.add_argument("--pass-pol", action="store_true", help="dump password policy") mapping_enum_group.add_argument("--rid-brute", nargs="?", type=int, const=4000, metavar="MAX_RID", help="Enumerate users by bruteforcing RIDs") - mapping_enum_group.add_argument("--qwinsta", action="store_true", help="Enumerate RDP connections") + 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.") mapping_enum_group.add_argument("--tasklist", action="store_true", help="Enumerate running processes") wmi_group = smb_parser.add_argument_group("WMI", "Options for WMI Queries")