-
Notifications
You must be signed in to change notification settings - Fork 27
/
LogonSessionEnum.cs
211 lines (184 loc) · 9 KB
/
LogonSessionEnum.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
// Built from https://www.codeproject.com/Articles/18179/Using-the-Local-Security-Authority-to-Enumerate-Us
// and Pinvoke.net <3
namespace LogonSessionEnum
{
class Program
{
static void Main(string[] args)
{
int infoLength = 0;
IntPtr tokenInformation;
// since TokenInformation is a buffer, we need to call GetTokenInformation twice, first time to get the length for the buffer
GetTokenInformation(WindowsIdentity.GetCurrent().Token, TOKEN_INFORMATION_CLASS.TokenStatistics, IntPtr.Zero, 0, out infoLength);
tokenInformation = Marshal.AllocHGlobal(infoLength);
GetTokenInformation(System.Security.Principal.WindowsIdentity.GetCurrent().Token, TOKEN_INFORMATION_CLASS.TokenStatistics, tokenInformation, infoLength, out infoLength);
TOKEN_STATISTICS tokenStatistics = (TOKEN_STATISTICS)Marshal.PtrToStructure(tokenInformation, typeof(TOKEN_STATISTICS));
EnumerateLogonSessions(tokenStatistics.AuthenticationId.LowPart);
Marshal.FreeHGlobal(tokenInformation);
}
static void EnumerateLogonSessions(uint currentLUID)
{
UInt64 count;
IntPtr pLuid;
IntPtr pLuidList = IntPtr.Zero;
uint AccessDenied = 0xc0000022;
DateTime systime = new DateTime(1601, 1, 1, 0, 0, 0, 0);
if (LsaEnumerateLogonSessions(out count, out pLuidList) != 0)
{
Console.WriteLine("[!] Error running LsaEnumerateLogonSessions()");
Console.ReadLine();
return;
}
// Sets pLuid to the first LUID structure in the list
pLuid = pLuidList;
// count stores number of LUIDs in the list
for (ulong idx = 0; idx < count; idx++)
{
IntPtr pSessionData;
uint result = LsaGetLogonSessionData(pLuid, out pSessionData);
if (result != 0)
{
if (result == AccessDenied)
{
Console.WriteLine("[!] Access denied enumerating LogonId {0:X2}", pLuid);
}
else
{
Console.WriteLine("[!] Unknown error accessing session data for LogonId {0:X2}: {1}", pLuid, result);
}
continue;
}
SECURITY_LOGON_SESSION_DATA sessionData = (SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(pSessionData, typeof(SECURITY_LOGON_SESSION_DATA));
if (pSessionData == IntPtr.Zero)
{
// Not a valid logon session
continue;
}
// Marshal our data
String username = Marshal.PtrToStringUni(sessionData.Username.buffer).Trim();
String domain = Marshal.PtrToStringUni(sessionData.DnsDomainName.buffer).Trim();
String sid = new System.Security.Principal.SecurityIdentifier(sessionData.PSiD).Value;
String package = Marshal.PtrToStringUni(sessionData.AuthenticationPackage.buffer).Trim();
SECURITY_LOGON_TYPE logonType = (SECURITY_LOGON_TYPE)sessionData.LogonType;
DateTime logonTime = systime.AddTicks((long)sessionData.LoginTime);
if (domain == "")
{
domain = Marshal.PtrToStringUni(sessionData.LoginDomain.buffer).Trim();
}
// Write our data
Console.WriteLine();
if (currentLUID == sessionData.LoginID.LowPart)
{
Console.WriteLine("***********Current Session***********");
}
Console.WriteLine("LogonID (LUID): {0}", sessionData.LoginID.LowPart);
Console.WriteLine("User: {0}\\{1}", domain, username);
Console.WriteLine("SID: {0}", sid);
Console.WriteLine("Auth Package: {0}", package);
Console.WriteLine("Logon Type: {0}", logonType);
Console.WriteLine("Logon Time: {0}", logonTime);
if (currentLUID == sessionData.LoginID.LowPart)
{
Console.WriteLine("*************************************");
}
Console.WriteLine();
// Bunch of typecasts to essentially move our pointer to the next LUID in the list
pLuid = (IntPtr)((int)pLuid + Marshal.SizeOf(typeof(LUID)));
LsaFreeReturnBuffer(pSessionData);
}
LsaFreeReturnBuffer(pLuid);
}
[DllImport("Secur32.dll", SetLastError = false)]
private static extern uint LsaEnumerateLogonSessions(out UInt64 LogonSessionCount, out IntPtr LogonSessionList);
[DllImport("Secur32.dll", SetLastError = false)]
private static extern uint LsaGetLogonSessionData(IntPtr luid, out IntPtr ppLogonSessionData);
[DllImport("secur32.dll", SetLastError = false)]
private static extern uint LsaFreeReturnBuffer(IntPtr buffer);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
IntPtr TokenInformation, int TokenInformationLength, out int ReturnLength);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool OpenProcessToken(IntPtr hProcess, UInt32 dwDesiredAccess, out IntPtr hToken);
enum TOKEN_INFORMATION_CLASS
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct TOKEN_STATISTICS
{
public LUID TokenId;
public LUID AuthenticationId;
public long ExpirationTime;
public uint TokenType;
public uint ImpersonationLevel;
public uint DynamicCharged;
public uint DynamicAvailable;
public uint GroupCount;
public uint PrivilegeCount;
public LUID ModifiedId;
}
[StructLayout(LayoutKind.Sequential)]
private struct LSA_UNICODE_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
public IntPtr buffer;
}
[StructLayout(LayoutKind.Sequential)]
private struct LUID
{
public UInt32 LowPart;
public UInt32 HighPart;
}
[StructLayout(LayoutKind.Sequential)]
private struct SECURITY_LOGON_SESSION_DATA
{
public UInt32 Size;
public LUID LoginID;
public LSA_UNICODE_STRING Username;
public LSA_UNICODE_STRING LoginDomain;
public LSA_UNICODE_STRING AuthenticationPackage;
public UInt32 LogonType;
public UInt32 Session;
public IntPtr PSiD;
public UInt64 LoginTime;
public LSA_UNICODE_STRING LogonServer;
public LSA_UNICODE_STRING DnsDomainName;
public LSA_UNICODE_STRING Upn;
}
private enum SECURITY_LOGON_TYPE : uint
{
Interactive = 2, //The security principal is logging on interactively.
Network, //The security principal is logging using a network.
Batch, //The logon is for a batch process.
Service, //The logon is for a service account.
Proxy, //Not supported.
Unlock, //The logon is an attempt to unlock a workstation.
NetworkCleartext, //The logon is a network logon with cleartext credentials.
NewCredentials, // Allows the caller to clone its current token and specify new credentials for outbound connections.
RemoteInteractive, // A terminal server session that is both remote and interactive.
CachedInteractive, // Attempt to use the cached credentials without going out across the network.
CachedRemoteInteractive, // Same as RemoteInteractive, except used internally for auditing purposes.
CachedUnlock // The logon is an attempt to unlock a workstation.
}
}
}