@@ -688,7 +688,7 @@ def is_host_dc(self):
688688 from impacket .dcerpc .v5 import nrpc , epm
689689
690690 self .logger .debug ("Performing authentication attempts..." )
691-
691+
692692 # First check if port 135 is open
693693 if self ._is_port_open (135 ):
694694 self .logger .debug ("Port 135 is open, attempting MSRPC connection..." )
@@ -964,7 +964,7 @@ def enumerate_sessions_info(self, sessions):
964964 sessions [SessionId ]["DisconnectTime" ] = sessdata ["LSMSessionInfoExPtr" ]["LSM_SessionInfo_Level1" ]["DisconnectTime" ]
965965 sessions [SessionId ]["LogonTime" ] = sessdata ["LSMSessionInfoExPtr" ]["LSM_SessionInfo_Level1" ]["LogonTime" ]
966966 sessions [SessionId ]["LastInputTime" ] = sessdata ["LSMSessionInfoExPtr" ]["LSM_SessionInfo_Level1" ]["LastInputTime" ]
967-
967+
968968 try :
969969 with TSTS .RCMPublic (self .conn , self .host , self .kerberos ) as rcm :
970970 for SessionId in sessions :
@@ -1011,33 +1011,32 @@ def qwinsta(self):
10111011 "WTS_SESSIONSTATE_LOCK" : "Locked" ,
10121012 "WTS_SESSIONSTATE_UNLOCK" : "Unlocked" ,
10131013 }
1014+
10141015 sessions = self .get_session_list ()
1015- if not len ( sessions ) :
1016+ if not sessions :
10161017 return
1018+
10171019 self .enumerate_sessions_info (sessions )
10181020
1021+ # Calculate max lengths for formatting
10191022 maxSessionNameLen = max (len (sessions [i ]["SessionName" ]) + 1 for i in sessions )
1020- maxSessionNameLen = maxSessionNameLen if len ( "SESSIONNAME" ) < maxSessionNameLen else len ("SESSIONNAME" ) + 1
1023+ maxSessionNameLen = max ( maxSessionNameLen , len ("SESSIONNAME" ) + 1 )
10211024 maxUsernameLen = max (len (sessions [i ]["Username" ] + sessions [i ]["Domain" ]) + 1 for i in sessions ) + 1
1022- maxUsernameLen = maxUsernameLen if len ( "Username" ) < maxUsernameLen else len ("Username " ) + 1
1025+ maxUsernameLen = max ( maxUsernameLen , len ("USERNAME " ) + 1 )
10231026 maxIdLen = max (len (str (i )) for i in sessions )
1024- maxIdLen = maxIdLen if len ( "ID" ) < maxIdLen else len ("ID" ) + 1
1027+ maxIdLen = max ( maxIdLen , len ("ID" ) + 1 )
10251028 maxStateLen = max (len (sessions [i ]["state" ]) + 1 for i in sessions )
1026- maxStateLen = maxStateLen if len ("STATE" ) < maxStateLen else len ("STATE" ) + 1
1027- maxRemoteIp = max (len (sessions [i ]["RemoteIp" ]) + 1 for i in sessions )
1028- maxRemoteIp = maxRemoteIp if len ("RemoteAddress" ) < maxRemoteIp else len ("RemoteAddress" ) + 1
1029- maxClientName = max (len (sessions [i ]["ClientName" ]) + 1 for i in sessions )
1030- maxClientName = maxClientName if len ("ClientName" ) < maxClientName else len ("ClientName" ) + 1
1031- template = ("{SESSIONNAME: <%d} " # noqa: UP031
1032- "{USERNAME: <%d} "
1033- "{ID: <%d} "
1029+ maxStateLen = max (maxStateLen , len ("STATE" ) + 1 )
1030+
1031+ # Create the template for formatting
1032+ template = (f"{{SESSIONNAME: <{ maxSessionNameLen } }} "
1033+ f"{{USERNAME: <{ maxUsernameLen } }} "
1034+ f"{{ID: <{ maxIdLen } }} "
10341035 "{IPv4: <16} "
1035- "{ STATE: <%d } "
1036+ f"{{ STATE: <{ maxStateLen } } } "
10361037 "{DSTATE: <9} "
10371038 "{CONNTIME: <20} "
1038- "{DISCTIME: <20} " ) % (maxSessionNameLen , maxUsernameLen , maxIdLen , maxStateLen )
1039-
1040- result = []
1039+ "{DISCTIME: <20} " )
10411040 header = template .format (
10421041 SESSIONNAME = "SESSIONNAME" ,
10431042 USERNAME = "USERNAME" ,
@@ -1048,7 +1047,6 @@ def qwinsta(self):
10481047 CONNTIME = "ConnectTime" ,
10491048 DISCTIME = "DisconnectTime" ,
10501049 )
1051-
10521050 header2 = template .replace (" <" , "=<" ).format (
10531051 SESSIONNAME = "" ,
10541052 USERNAME = "" ,
@@ -1059,30 +1057,49 @@ def qwinsta(self):
10591057 CONNTIME = "" ,
10601058 DISCTIME = "" ,
10611059 )
1062- result .extend ((header , header2 ))
1060+ result = [header , header2 ]
1061+
1062+ # Check if we need to filter for usernames
1063+ usernames = None
1064+ if self .args .qwinsta :
1065+ arg = self .args .qwinsta
1066+ if os .path .isfile (arg ):
1067+ with open (arg ) as f :
1068+ usernames = [line .strip ().lower () for line in f if line .strip ()]
1069+ else :
1070+ usernames = [arg .lower ()]
10631071
10641072 for i in sessions :
1073+ username = sessions [i ]["Username" ]
1074+ domain = sessions [i ]["Domain" ]
1075+ user_full = f"{ domain } \\ { username } " if username else ""
1076+
1077+ # If usernames are provided, filter them
1078+ if usernames and username .lower () not in usernames :
1079+ continue
1080+
10651081 connectTime = sessions [i ]["ConnectTime" ]
10661082 connectTime = connectTime .strftime (r"%Y/%m/%d %H:%M:%S" ) if connectTime .year > 1601 else "None"
10671083
10681084 disconnectTime = sessions [i ]["DisconnectTime" ]
10691085 disconnectTime = disconnectTime .strftime (r"%Y/%m/%d %H:%M:%S" ) if disconnectTime .year > 1601 else "None"
1070- userName = sessions [i ]["Domain" ] + "\\ " + sessions [i ]["Username" ] if len (sessions [i ]["Username" ]) else ""
10711086
1072- result . append ( template .format (
1087+ row = template .format (
10731088 SESSIONNAME = sessions [i ]["SessionName" ],
1074- USERNAME = userName ,
1089+ USERNAME = user_full ,
10751090 ID = i ,
10761091 IPv4 = sessions [i ]["RemoteIp" ],
10771092 STATE = sessions [i ]["state" ],
10781093 DSTATE = desktop_states [sessions [i ]["flags" ]],
10791094 CONNTIME = connectTime ,
10801095 DISCTIME = disconnectTime ,
1081- ))
1096+ )
1097+ result .append (row )
10821098
1083- self .logger .success ("Enumerated qwinsta sessions" )
1084- for row in result :
1085- self .logger .highlight (row )
1099+ if len (result ) > 2 :
1100+ self .logger .success ("Enumerated qwinsta sessions" )
1101+ for row in result :
1102+ self .logger .highlight (row )
10861103
10871104 @requires_admin
10881105 def tasklist (self ):
@@ -1242,16 +1259,20 @@ def shares(self):
12421259 error = get_error_string (e )
12431260 self .logger .debug (f"Error adding share: { error } " )
12441261
1262+ if self .args .filter_shares :
1263+ self .logger .display ("[REMOVED] Use the --shares read,write options instead." )
1264+
12451265 self .logger .display ("Enumerated shares" )
12461266 self .logger .highlight (f"{ 'Share' :<15} { 'Permissions' :<15} { 'Remark' } " )
12471267 self .logger .highlight (f"{ '-----' :<15} { '-----------' :<15} { '------' } " )
1268+
12481269 for share in permissions :
12491270 name = share ["name" ]
12501271 remark = share ["remark" ]
1251- perms = share ["access" ]
1252- if self .args .filter_shares and not any ( x in perms for x in self . args . filter_shares ):
1272+ perms = "," . join ( share ["access" ])
1273+ if self .args .shares and self . args . shares . lower () not in perms . lower ( ):
12531274 continue
1254- self .logger .highlight (f"{ name :<15} { ',' . join ( perms ) :<15} { remark } " )
1275+ self .logger .highlight (f"{ name :<15} { perms :<15} { remark } " )
12551276 return permissions
12561277
12571278 def dir (self ):
@@ -1531,16 +1552,16 @@ def rid_brute(self, max_rid=None):
15311552 max_rid = int (self .args .rid_brute )
15321553
15331554 KNOWN_PROTOCOLS = {
1534- 135 : {"bindstr" : rf"ncacn_ip_tcp:{ self .host } " },
1535- 139 : {"bindstr" : rf"ncacn_np:{ self .host } [\pipe\lsarpc]" },
1536- 445 : {"bindstr" : rf"ncacn_np:{ self .host } [\pipe\lsarpc]" },
1555+ 135 : {"bindstr" : rf"ncacn_ip_tcp:{ self .remoteName } " },
1556+ 139 : {"bindstr" : rf"ncacn_np:{ self .remoteName } [\pipe\lsarpc]" },
1557+ 445 : {"bindstr" : rf"ncacn_np:{ self .remoteName } [\pipe\lsarpc]" },
15371558 }
15381559
15391560 try :
15401561 string_binding = KNOWN_PROTOCOLS [self .port ]["bindstr" ]
15411562 self .logger .debug (f"StringBinding { string_binding } " )
15421563 rpc_transport = transport .DCERPCTransportFactory (string_binding )
1543- rpc_transport .setRemoteHost (self .host )
1564+ rpc_transport .setRemoteHost (self .remoteName )
15441565
15451566 if hasattr (rpc_transport , "set_credentials" ):
15461567 # This method exists only for selected protocol sequences.
0 commit comments