├── .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 |
--------------------------------------------------------------------------------