├── .gitattributes ├── README.md ├── wmiServSessEnum.sln └── wmiServSessEnum ├── App.config ├── Program.cs ├── Properties └── AssemblyInfo.cs └── wmiServSessEnum.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wmiServSessEnum 2 | multithreaded .net tool that uses WMI queries to enumerate active user sessions and accounts configured to run services (even those that are stopped and disabled) on remote systems 3 | 4 | # Usage 5 | WmiServSessEnum can be ran in several different modes: 6 | - **sessions** – output similar to other user enumeration tools, this will query the Win32_LoggedOnUser and Win32_SessionProcess WMI classes to return a list of active sessions on the remote system 7 | - **services** – this option will query the Win32_Service WMI class and return a list (if any) of non-default accounts configured to run services on the remote system 8 | - **all**(default) – runs both collection methods on each host 9 | 10 | **Required Flags (one of the following two required)** 11 | - **-L** - Comma seperated list of IP's / hostnames to scan. Please don't include spaces between addresses 12 | - **-F** - File containing a list of IP's / hostnames to scan, one per line 13 | 14 | 15 | **Optional Flags** 16 | - **-M** - Mode selection (options = services, sessions, all) (Default: all) 17 | - **-U** - Username to use, if you want to use alternate credentials to run. Must use with -P and -D flags 18 | - **-P** - Plaintext password to use, if you want to use alternate credentials to run. Must use with -U and -D flags 19 | - **-D** - Domain to use, if you want to use alternate credentials to run (. for local domain). Must use with -U and -P flags 20 | - **-T** - Threads to use to concurently enumerate multiple remote hosts (Default: 10) 21 | - **-W** - Wait time, in seconds, for CimSession connect before connection timeout (Default: 10) - I wouldn't drop this number too low or you will get false negatives 22 | 23 | 24 | Note: Designed for informational purposes only, please only use this tool on networks you own or have permission to test against. 25 | -------------------------------------------------------------------------------- /wmiServSessEnum.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29025.244 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wmiServSessEnum", "wmiServSessEnum\wmiServSessEnum.csproj", "{FE750AD8-C3F7-4221-B9FB-BA4E40AEC9CD}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {FE750AD8-C3F7-4221-B9FB-BA4E40AEC9CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {FE750AD8-C3F7-4221-B9FB-BA4E40AEC9CD}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {FE750AD8-C3F7-4221-B9FB-BA4E40AEC9CD}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {FE750AD8-C3F7-4221-B9FB-BA4E40AEC9CD}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {A125E307-7974-4DB3-98B9-7375FD20AFB9} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /wmiServSessEnum/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /wmiServSessEnum/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using Microsoft.Management.Infrastructure; 4 | using Microsoft.Management.Infrastructure.Options; 5 | using System.Security; 6 | using System.Collections.Generic; 7 | using System.IO; 8 | using System.Linq; 9 | 10 | namespace wmiServSessEnum 11 | { 12 | class Program 13 | { 14 | static void Main(string[] args) 15 | { 16 | Thread th = Thread.CurrentThread; 17 | th.Name = "MainThread"; 18 | var comparer = StringComparer.OrdinalIgnoreCase; 19 | var arguments = new Dictionary(comparer); 20 | CimCredential Credentials = null; 21 | int maxThreads = 10; 22 | int timeout = 10; 23 | int workers, async; 24 | String mode = "all"; 25 | //we create a DComSessionOptions object to force our remote connections to use DCom instead of WinRM 26 | DComSessionOptions SessionOptions = new DComSessionOptions(); 27 | foreach (string argument in args) 28 | { 29 | int idx = argument.IndexOf('='); 30 | if (idx > 0) 31 | arguments[argument.Substring(0, idx)] = argument.Substring(idx + 1); 32 | if (argument.ToLower() == "help" || argument.ToLower() == "-h") 33 | { 34 | help(); 35 | System.Environment.Exit(0); 36 | } 37 | } 38 | 39 | List targetHosts = new List(); 40 | Console.WriteLine(""); 41 | //gather targets, either from file or directly from commandline 42 | if (arguments.ContainsKey("-l")) 43 | { 44 | targetHosts = arguments["-l"].Split(',').ToList(); 45 | if (arguments.ContainsKey("-f")) 46 | { 47 | Console.WriteLine("Error -- please only use one targeting flag at a time (-l or -f)"); 48 | System.Environment.Exit(1); 49 | } 50 | } 51 | else if (arguments.ContainsKey("-f")) 52 | { 53 | try 54 | { 55 | targetHosts = File.ReadAllLines(arguments["-f"]).ToList(); 56 | } 57 | catch 58 | { 59 | Console.WriteLine($"Error - the input file at {arguments["-f"]} could not be read"); 60 | System.Environment.Exit(2); 61 | } 62 | } 63 | else 64 | { 65 | Console.WriteLine("Error -- please to enter systems to target\n"); 66 | help(); 67 | Environment.Exit(1); 68 | } 69 | if (arguments.ContainsKey("-m")) 70 | { 71 | try 72 | { 73 | mode = System.Enum.Parse(typeof(Modules), arguments["-m"], true).ToString(); 74 | } 75 | catch 76 | { 77 | Console.WriteLine("Error -- invalid collection mode selected"); 78 | System.Environment.Exit(1); 79 | } 80 | } 81 | if ((arguments.ContainsKey("-d")) || (arguments.ContainsKey("-u")) || (arguments.ContainsKey("-p"))) 82 | { 83 | try 84 | { 85 | SecureString securepassword = new SecureString(); 86 | foreach (char c in arguments["-p"]) 87 | { 88 | securepassword.AppendChar(c); 89 | } 90 | Credentials = new CimCredential(PasswordAuthenticationMechanism.Default, arguments["-d"], arguments["-u"], securepassword); 91 | } 92 | catch 93 | { 94 | Console.WriteLine("Error -- if using alternative credentials, please ensure to include domain, username, and password (use a domain of . for a local account)"); 95 | System.Environment.Exit(1); 96 | } 97 | } 98 | 99 | //get available worker threads, we dont care about async. 100 | ThreadPool.GetAvailableThreads(out workers, out async); 101 | if (arguments.ContainsKey("-t")) 102 | { 103 | if (System.Convert.ToInt32(arguments["-t"]) <= workers) 104 | { 105 | maxThreads = System.Convert.ToInt32(arguments["-t"]); 106 | } 107 | else 108 | { 109 | Console.WriteLine("Error - not enough available worker threads in the .net thread pool (max available = " + workers + ")"); 110 | System.Environment.Exit(1); 111 | } 112 | } 113 | Console.WriteLine(workers + " worker threads available, will use up to " + maxThreads + " threads"); 114 | ThreadPool.SetMaxThreads(maxThreads, 1); 115 | 116 | //wait / timeout value for wmi connects 117 | if (arguments.ContainsKey("-w")) 118 | { 119 | timeout = System.Convert.ToInt32(arguments["-w"]); 120 | } 121 | TimeSpan interval = new TimeSpan(0, 0, timeout); 122 | SessionOptions.Timeout = interval; 123 | 124 | // if using CimCredential with creds not inherited from current session, we'll add to our session options 125 | if (Credentials != null) 126 | { 127 | SessionOptions.AddDestinationCredentials(Credentials); 128 | } 129 | 130 | Console.WriteLine("Starting collection on " + targetHosts.Count + " host(s)"); 131 | var count = new CountdownEvent(targetHosts.Count); 132 | foreach (string s in targetHosts) 133 | { 134 | ThreadPool.QueueUserWorkItem(status => { wmiConnect(s, SessionOptions, mode); count.Signal(); }); 135 | } 136 | count.Wait(); 137 | 138 | Console.WriteLine("----------Collection completed, results should be displayed above----------"); 139 | } 140 | 141 | static void wmiConnect(string target, DComSessionOptions SessionOptions, string mode) 142 | { 143 | CimSession Session = CimSession.Create(target, SessionOptions); 144 | try 145 | { 146 | if (mode.ToLower() == "all" || mode.ToLower() == "services") 147 | { 148 | var allServices = Session.QueryInstances(@"root\cimv2", "WQL", "SELECT * FROM Win32_Service where NOT startname like '%LocalSystem%' AND NOT startname like '%NT AUTHORITY%'"); 149 | foreach (CimInstance service in allServices) 150 | { 151 | if (service.CimInstanceProperties["StartName"].ToString() != "StartName") 152 | { 153 | Console.WriteLine($"[+]Non-default service account found on {target}: {service.CimInstanceProperties["StartName"].Value.ToString()}"); 154 | } 155 | } 156 | } 157 | 158 | if (mode.ToLower() == "all" || mode.ToLower() == "sessions") 159 | { 160 | var allSessions = Session.QueryInstances(@"root\cimv2", "WQL", "SELECT * FROM Win32_LoggedOnUser"); 161 | var allProcesses = Session.QueryInstances(@"root\cimv2", "WQL", "SELECT * FROM Win32_SessionProcess"); 162 | 163 | //gets us the sessionID associated with each running process on the system, done in order to avoid showing false positives tied to stale sessions 164 | List processSessions = new List(); 165 | foreach (CimInstance proc in allProcesses) 166 | { 167 | processSessions.Add(Int32.Parse(proc.CimInstanceProperties["antecedent"].Value.ToString().Split('"')[1])); 168 | } 169 | IEnumerable uniqueProcessSessions = processSessions.Distinct(); 170 | 171 | //gets us a list of all sessions on the remote system. This will include a variety of false positives / unwanted system sessions that we have to filter out. Results are added to a keyed dictionary for lookups against running processes. 172 | List sessions = new List(); 173 | var ses2 = new Dictionary(); 174 | foreach (CimInstance session in allSessions) 175 | { 176 | String antecedent = session.CimInstanceProperties["antecedent"].Value.ToString(); 177 | String dependent = session.CimInstanceProperties["dependent"].Value.ToString(); 178 | String[] userDomain = antecedent.Split('"'); 179 | int dependentKey = Int32.Parse(dependent.Split('"')[1]); 180 | if ((!userDomain[1].ToLower().Contains("dwm-")) && (!userDomain[1].ToLower().Contains("umfd-")) && (!userDomain[1].ToLower().Contains("anonymous logon")) && (!userDomain[1].ToLower().Contains("local service")) && (!userDomain[1].ToLower().Contains("network service")) && (!userDomain[1].ToLower().Equals("system"))) 181 | { 182 | sessions.Add($"{userDomain[3]}\\{userDomain[1]}"); 183 | ses2.Add(dependentKey, $"{userDomain[3]}\\{userDomain[1]}"); 184 | } 185 | } 186 | 187 | //Now that we have a list of sessions and a list of all logonSessionIDs with currently active processes we can compare the two in order to get an accurate list of active sessions 188 | foreach (int procSession in uniqueProcessSessions) 189 | { 190 | if (ses2.ContainsKey(procSession)) 191 | { 192 | Console.WriteLine($"[+]Session found on {target}: {ses2[procSession]}"); 193 | } 194 | } 195 | } 196 | } 197 | catch (CimException e) 198 | { 199 | if (e.MessageId.Contains("40004")) 200 | { 201 | Console.WriteLine($"[-]The following host was unreachable: {target}"); 202 | return; 203 | } 204 | else if (e.MessageId.Contains("70005")) 205 | { 206 | Console.WriteLine($"[-]Insufficient privileges / invalid credentials on the following host: {target}"); 207 | return; 208 | } 209 | else if (e.MessageId.Contains("800706")) 210 | { 211 | Console.WriteLine($"[-]No route to the following host: {target}"); 212 | return; 213 | } 214 | else 215 | { 216 | Console.WriteLine($"[-]Error - undefined error on the following host: {target} errorID: {e.MessageId}"); 217 | return; 218 | } 219 | } 220 | catch (Exception e) 221 | { 222 | Console.WriteLine($"[-]Error - undefined error on the following host: {target} errorID: {e.Message}"); 223 | return; 224 | } 225 | Session.Close(); 226 | } 227 | 228 | static void help() 229 | { 230 | Console.WriteLine("\n-----------WmiSessionEnum Options-----------\n"); 231 | Console.WriteLine("Flag usage: -Flag=setValue\n"); 232 | Console.WriteLine("--Required Flags--"); 233 | Console.WriteLine("(Use one of the following)"); 234 | Console.WriteLine("-L :: comma seperated list of IP's / hostnames to scan. Please don't include spaces between addresses"); 235 | Console.WriteLine("-F :: file containing a list of IP's / hostnames to scan, one per line\n"); 236 | Console.WriteLine("--Optional Flags--"); 237 | Console.WriteLine("-M :: Mode selection (options = services, sessions, all) (Default: all)"); 238 | Console.WriteLine("-U :: Username to use, if not running in current user's context. Must use with -P and -D flags"); 239 | Console.WriteLine("-P :: Plaintext password to use, if not running in current user's context. Must use with -U and -D flags"); 240 | Console.WriteLine("-D :: Domain to use, if not running in current user's context (. for local). Must use with -U and -P flags"); 241 | Console.WriteLine("-T :: Threads to use to concurently enumerate multiple remote hosts (Default: 10)"); 242 | Console.WriteLine("-W :: Wait time, in seconds, for CimSession connect before connection timeout (Default: 10)"); 243 | } 244 | } 245 | } 246 | 247 | enum Modules 248 | { 249 | all, sessions, services 250 | } 251 | -------------------------------------------------------------------------------- /wmiServSessEnum/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("wmiServSessEnum")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("wmiServSessEnum")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("fe750ad8-c3f7-4221-b9fb-ba4e40aec9cd")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /wmiServSessEnum/wmiServSessEnum.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {FE750AD8-C3F7-4221-B9FB-BA4E40AEC9CD} 8 | Exe 9 | wmiServSessEnum 10 | wmiServSessEnum 11 | v4.7.2 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | False 38 | ..\..\..\..\..\..\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.Management.Infrastructure\v4.0_1.0.0.0__31bf3856ad364e35\Microsoft.Management.Infrastructure.dll 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | --------------------------------------------------------------------------------