winapiiispermissionsopenprocess

Access Denied Calling OpenProcess From Process Running As IIS APPPOOL Account on Windows Server 2019


A tool for collecting diagnostic info, running under an account IIS APPPOOL\Content Server is attempting to make the following call:

hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, false, <process id>);

Process ID refers to a process running under NT AUTHORITY\IUSR account. hProcess is coming back NULL, in WinDbg !gle shows:

0:000> !gle
LastErrorValue: (Win32) 0x5 (5) - Access is denied.
LastStatusValue: (NTSTATUS) 0xc0000022 - {Access Denied}  A process has requested access to an object, but has not been granted those access rights.

Using SysInternals AccessChk shows the following user rights assignments:

  SeCreateTokenPrivilege (Create a token object):
  SeAssignPrimaryTokenPrivilege (Replace a process level token):
    IIS APPPOOL\DefaultAppPool
    IIS APPPOOL\Content Server
    NT AUTHORITY\NETWORK SERVICE
    NT AUTHORITY\LOCAL SERVICE
  SeLockMemoryPrivilege (Lock pages in memory):
  SeIncreaseQuotaPrivilege (Adjust memory quotas for a process):
    IIS APPPOOL\DefaultAppPool
    IIS APPPOOL\Content Server
    BUILTIN\Administrators
    NT AUTHORITY\NETWORK SERVICE
    NT AUTHORITY\LOCAL SERVICE
  SeMachineAccountPrivilege (Add workstations to domain):
  SeTcbPrivilege (Act as part of the operating system):
  SeSecurityPrivilege (Manage auditing and security log):
    BUILTIN\Administrators
  SeTakeOwnershipPrivilege (Take ownership of files or other objects):
    BUILTIN\Administrators
  SeLoadDriverPrivilege (Load and unload device drivers):
    BUILTIN\Administrators
  SeSystemProfilePrivilege (Profile system performance):
    NT SERVICE\WdiServiceHost
    BUILTIN\Administrators
  SeSystemtimePrivilege (Change the system time):
    BUILTIN\Administrators
    NT AUTHORITY\LOCAL SERVICE
  SeProfileSingleProcessPrivilege (Profile single process):
    BUILTIN\Administrators
  SeIncreaseBasePriorityPrivilege (Increase scheduling priority):
    Window Manager\Window Manager Group
    BUILTIN\Administrators
  SeCreatePagefilePrivilege (Create a pagefile):
    BUILTIN\Administrators
  SeCreatePermanentPrivilege (Create permanent shared objects):
  SeBackupPrivilege (Back up files and directories):
    BUILTIN\Backup Operators
    BUILTIN\Administrators
  SeRestorePrivilege (Restore files and directories):
    BUILTIN\Backup Operators
    BUILTIN\Administrators
  SeShutdownPrivilege (Shut down the system):
    BUILTIN\Backup Operators
    BUILTIN\Administrators
  SeDebugPrivilege (Debug programs):
    BUILTIN\Administrators
  SeAuditPrivilege (Generate security audits):
    IIS APPPOOL\DefaultAppPool
    IIS APPPOOL\Content Server
    NT AUTHORITY\NETWORK SERVICE
    NT AUTHORITY\LOCAL SERVICE
  SeSystemEnvironmentPrivilege (Modify firmware environment values):
    BUILTIN\Administrators
  SeChangeNotifyPrivilege (Bypass traverse checking):
    BUILTIN\Backup Operators
    BUILTIN\Users
    BUILTIN\Administrators
    NT AUTHORITY\NETWORK SERVICE
    NT AUTHORITY\LOCAL SERVICE
    Everyone
  SeRemoteShutdownPrivilege (Force shutdown from a remote system):
    BUILTIN\Administrators
  SeUndockPrivilege (Remove computer from docking station):
    BUILTIN\Administrators
  SeSyncAgentPrivilege (Synchronize directory service data):
  SeEnableDelegationPrivilege (Enable computer and user accounts to be trusted for delegation):
  SeManageVolumePrivilege (Perform volume maintenance tasks):
    BUILTIN\Administrators
  SeImpersonatePrivilege (Impersonate a client after authentication):
    NT AUTHORITY\SERVICE
    BUILTIN\IIS_IUSRS
    BUILTIN\Administrators
    NT AUTHORITY\NETWORK SERVICE
    NT AUTHORITY\LOCAL SERVICE
  SeCreateGlobalPrivilege (Create global objects):
    NT AUTHORITY\SERVICE
    BUILTIN\Administrators
    NT AUTHORITY\NETWORK SERVICE
    NT AUTHORITY\LOCAL SERVICE
  SeTrustedCredManAccessPrivilege (Access Credential Manager as a trusted caller):
  SeRelabelPrivilege (Modify an object label):
  SeIncreaseWorkingSetPrivilege (Increase a process working set):
    BUILTIN\Users
  SeTimeZonePrivilege (Change the time zone):
    BUILTIN\Administrators
    NT AUTHORITY\LOCAL SERVICE
  SeCreateSymbolicLinkPrivilege (Create symbolic links):
    BUILTIN\Administrators
  SeDelegateSessionUserImpersonatePrivilege (Obtain an impersonation token for another user in the same session):
    BUILTIN\Administrators
  SeBatchLogonRight:
    BUILTIN\IIS_IUSRS
    BUILTIN\Performance Log Users
    BUILTIN\Backup Operators
    BUILTIN\Administrators
  SeInteractiveLogonRight:
    BUILTIN\Backup Operators
    BUILTIN\Users
    BUILTIN\Administrators
  SeNetworkLogonRight:
    BUILTIN\Backup Operators
    BUILTIN\Users
    BUILTIN\Administrators
    Everyone
  SeServiceLogonRight:
    IIS APPPOOL\DefaultAppPool
    IIS APPPOOL\Content Server
    NT SERVICE\ALL SERVICES
  SeDenyBatchLogonRight:
  SeDenyInteractiveLogonRight:
  SeDenyNetworkLogonRight:
  SeDenyServiceLogonRight:
  SeRemoteInteractiveLogonRight:
    BUILTIN\Remote Desktop Users
    BUILTIN\Administrators
  SeDenyRemoteInteractiveLogonRight:

Checking with Process Explorer the process shows the following:

enter image description here

For an experiment I tried to grant the application SeDebugPrivilege via SecPol.msc (non domain joined computer) While this is a setting I didn't want to apply permanently for security reasons, it failed to resolve the problem. After this policy was applied and machine rebooted, in Process Explorer the process now showed SeDebugPrivilege but it was listed as "Disabled"

enter image description here

Finally I enabled "Process Access" logging with SysMon using the following XML profile:

<Sysmon schemaversion="4.22">
<EventFiltering>
    <RuleGroup name="ProcessAccess" groupRelation="or">
        <ProcessAccess onmatch="include">
            <SourceImage condition="contains">TargetProcess.exe</SourceImage>
        </ProcessAccess>
    </RuleGroup>
</EventFiltering>
</Sysmon>

From this I observed if trying to call OpenProcess from process running under SYSTEM it was successful, while running as IIS APPPOOL\Content Server failed.

Running as System

RuleName: ProcessAccess
UtcTime: 2020-06-16 11:39:35.620
SourceProcessGUID: {4cfe3c55-85e5-5ee8-0000-0010be161600}
SourceProcessId: 5728
SourceThreadId: 5680
SourceImage: c:\TEST\source.exe
TargetProcessGUID: {4cfe3c55-af77-5ee8-0000-0010af547d00}
TargetProcessId: 4004
TargetImage: c:\TEST\target.exe
GrantedAccess: 0x1400

Running As IIS APPPOOL\Content Server

RuleName: ProcessAccess
UtcTime: 2020-06-16 08:21:41.015
SourceProcessGUID: {4cfe3c55-8100-5ee8-0000-0010a5107500}
SourceProcessId: 3740
SourceThreadId: 1532
SourceImage: c:\TEST\source.exe
TargetProcessGUID: {4cfe3c55-8114-5ee8-0000-0010e1a87500}
TargetProcessId: 3992
TargetImage: c:\TEST\target.exe
GrantedAccess: 0x12367B

While 0x1400 is what is expected PROCESS_QUERY_INFORMATION + PROCESS_QUERY_LIMITED_INFORMATION the result returning granted access 0x12367B doesn't seem to match fully the documented access rights here

The lack of what privilege is blocking this access? The documentation for OpenProcess here doesn't seem to specify any specific privilege required except if request PROCESS_ALL_ACCESS. Target process is not a "protected" process.

Any options to configure this account to open process on target process?


Solution

  • The cause of this is missing permission on the target process. For testing the required permission can be viewed with Process Explorer and right clicking target process and selecting Properties then Security tab and selecting Permissions button, you can add the required permission Process Query Information Allow for the user account the process calling OpenProcess is running as. Permission can also be denied due to process mandatory integrity control i.e. Medium level integrity process cannot access High integrity process. Even if the user account is added the correct permission but you do not have access due to mandatory integrity control you will get access denied.

    enter image description here

    In code this can be achieved by modifying the ACLs of the object as documented here

    Here is a PowerShell script I wrote for testing different scenarios, such as adding the permission required.

    $code = @'
    using System;
    using System.Security;
    using System.Diagnostics;
    using System.Security.AccessControl;
    using System.Runtime.InteropServices;
    using System.Runtime.ConstrainedExecution;
    using System.Security.Principal;
    namespace CSharp
    {
        public class ProcessSecurity : NativeObjectSecurity
        {
            public ProcessSecurity(SafeHandle processHandle)
                : base(false, ResourceType.KernelObject, processHandle, AccessControlSections.Access)
            {
    
            }
    
            public void AddAccessRule(ProcessAccessRule rule)
            {
                base.AddAccessRule(rule);
            }
    
            // this is not a full impl- it only supports writing DACL changes
            public void SaveChanges(SafeHandle processHandle)
            {
                Persist(processHandle, AccessControlSections.Access);
            }
    
            public override Type AccessRightType
            {
                get { return typeof(ProcessAccessRights); }
            }
    
            public override AccessRule AccessRuleFactory(System.Security.Principal.IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type)
            {
                return new ProcessAccessRule(identityReference, (ProcessAccessRights)accessMask, isInherited, inheritanceFlags, propagationFlags, type);
            }
    
            public override Type AccessRuleType
            {
                get { return typeof(ProcessAccessRule); }
            }
    
            public override AuditRule AuditRuleFactory(System.Security.Principal.IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags)
            {
                throw new NotImplementedException();
            }
    
            public override Type AuditRuleType
            {
                get { throw new NotImplementedException(); }
            }
        }
    
        public class ProcessAccessRule : AccessRule
        {
            public ProcessAccessRule(IdentityReference identityReference, ProcessAccessRights accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type)
                : base(identityReference, (int)accessMask, isInherited, inheritanceFlags, propagationFlags, type)
            {
            }
    
            public ProcessAccessRights ProcessAccessRights { get { return (ProcessAccessRights)AccessMask; } }
        }
    
        [Flags]
        public enum ProcessAccessRights
        {
            STANDARD_RIGHTS_REQUIRED = (0x000F0000),
            DELETE = (0x00010000), // Required to delete the object. 
            READ_CONTROL = (0x00020000), // Required to read information in the security descriptor for the object, not including the information in the SACL. To read or write the SACL, you must request the ACCESS_SYSTEM_SECURITY access right. For more information, see SACL Access Right. 
            WRITE_DAC = (0x00040000), // Required to modify the DACL in the security descriptor for the object. 
            WRITE_OWNER = (0x00080000), // Required to change the owner in the security descriptor for the object. 
    
            PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF, //All possible access rights for a process object.
            PROCESS_CREATE_PROCESS = (0x0080), // Required to create a process. 
            PROCESS_CREATE_THREAD = (0x0002), // Required to create a thread. 
            PROCESS_DUP_HANDLE = (0x0040), // Required to duplicate a handle using DuplicateHandle. 
            PROCESS_QUERY_INFORMATION = (0x0400), // Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken, GetExitCodeProcess, GetPriorityClass, and IsProcessInJob). 
            PROCESS_QUERY_LIMITED_INFORMATION = (0x1000),
            PROCESS_SET_INFORMATION = (0x0200), // Required to set certain information about a process, such as its priority class (see SetPriorityClass). 
            PROCESS_SET_QUOTA = (0x0100), // Required to set memory limits using SetProcessWorkingSetSize. 
            PROCESS_SUSPEND_RESUME = (0x0800), // Required to suspend or resume a process. 
            PROCESS_TERMINATE = (0x0001), // Required to terminate a process using TerminateProcess. 
            PROCESS_VM_OPERATION = (0x0008), // Required to perform an operation on the address space of a process (see VirtualProtectEx and WriteProcessMemory). 
            PROCESS_VM_READ = (0x0010), // Required to read memory in a process using ReadProcessMemory. 
            PROCESS_VM_WRITE = (0x0020), // Required to write to memory in a process using WriteProcessMemory. 
            SYNCHRONIZE = (0x00100000), // Required to wait for the process to terminate using the wait functions. 
        }
    
        public static class NativeMethods
        {
            private const Int32 ANYSIZE_ARRAY        = 0x00000001;
            public const int SE_PRIVILEGE_ENABLED    = 0x00000002;
    
            //Use these for DesiredAccess
            public const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;
            public const UInt32 STANDARD_RIGHTS_READ = 0x00020000;
            public const UInt32 TOKEN_ASSIGN_PRIMARY = 0x0001;
            public const UInt32 TOKEN_DUPLICATE = 0x0002;
            public const UInt32 TOKEN_IMPERSONATE = 0x0004;
            public const UInt32 TOKEN_QUERY = 0x0008;
            public const UInt32 TOKEN_QUERY_SOURCE = 0x0010;
            public const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x0020;
            public const UInt32 TOKEN_ADJUST_GROUPS = 0x0040;
            public const UInt32 TOKEN_ADJUST_DEFAULT = 0x0080;
            public const UInt32 TOKEN_ADJUST_SESSIONID = 0x0100;
            public const UInt32 TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
            public const UInt32 TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |
                TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |
                TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |
                TOKEN_ADJUST_SESSIONID);
    
           public enum SecurityEntity
           {
              SE_CREATE_TOKEN_NAME,
              SE_ASSIGNPRIMARYTOKEN_NAME,
              SE_LOCK_MEMORY_NAME,
              SE_INCREASE_QUOTA_NAME,
              SE_UNSOLICITED_INPUT_NAME,
              SE_MACHINE_ACCOUNT_NAME,
              SE_TCB_NAME,
              SE_SECURITY_NAME,
              SE_TAKE_OWNERSHIP_NAME,
              SE_LOAD_DRIVER_NAME,
              SE_SYSTEM_PROFILE_NAME,
              SE_SYSTEMTIME_NAME,
              SE_PROF_SINGLE_PROCESS_NAME,
              SE_INC_BASE_PRIORITY_NAME,
              SE_CREATE_PAGEFILE_NAME,
              SE_CREATE_PERMANENT_NAME,
              SE_BACKUP_NAME,
              SE_RESTORE_NAME,
              SE_SHUTDOWN_NAME,
              SE_DEBUG_NAME,
              SE_AUDIT_NAME,
              SE_SYSTEM_ENVIRONMENT_NAME,
              SE_CHANGE_NOTIFY_NAME,
              SE_REMOTE_SHUTDOWN_NAME,
              SE_UNDOCK_NAME,
              SE_SYNC_AGENT_NAME,
              SE_ENABLE_DELEGATION_NAME,
              SE_MANAGE_VOLUME_NAME,
              SE_IMPERSONATE_NAME,
              SE_CREATE_GLOBAL_NAME,
              SE_CREATE_SYMBOLIC_LINK_NAME,
              SE_INC_WORKING_SET_NAME,
              SE_RELABEL_NAME,
              SE_TIME_ZONE_NAME,
              SE_TRUSTED_CREDMAN_ACCESS_NAME
           }
    
          public static string GetSecurityEntityValue(SecurityEntity securityEntity)
          {
             switch (securityEntity)
             {
                case SecurityEntity.SE_ASSIGNPRIMARYTOKEN_NAME:
                   return "SeAssignPrimaryTokenPrivilege";
                case SecurityEntity.SE_AUDIT_NAME:
                   return "SeAuditPrivilege";
                case SecurityEntity.SE_BACKUP_NAME:
                   return "SeBackupPrivilege";
                case SecurityEntity.SE_CHANGE_NOTIFY_NAME:
                   return "SeChangeNotifyPrivilege";
                case SecurityEntity.SE_CREATE_GLOBAL_NAME:
                   return "SeCreateGlobalPrivilege";
                case SecurityEntity.SE_CREATE_PAGEFILE_NAME:
                   return "SeCreatePagefilePrivilege";
                case SecurityEntity.SE_CREATE_PERMANENT_NAME:
                   return "SeCreatePermanentPrivilege";
                case SecurityEntity.SE_CREATE_SYMBOLIC_LINK_NAME:
                   return "SeCreateSymbolicLinkPrivilege";
                case SecurityEntity.SE_CREATE_TOKEN_NAME:
                   return "SeCreateTokenPrivilege";
                case SecurityEntity.SE_DEBUG_NAME:
                   return "SeDebugPrivilege";
                case SecurityEntity.SE_ENABLE_DELEGATION_NAME:
                   return "SeEnableDelegationPrivilege";
                case SecurityEntity.SE_IMPERSONATE_NAME:
                   return "SeImpersonatePrivilege";
                case SecurityEntity.SE_INC_BASE_PRIORITY_NAME:
                   return "SeIncreaseBasePriorityPrivilege";
                case SecurityEntity.SE_INCREASE_QUOTA_NAME:
                   return "SeIncreaseQuotaPrivilege";
                case SecurityEntity.SE_INC_WORKING_SET_NAME:
                   return "SeIncreaseWorkingSetPrivilege";
                case SecurityEntity.SE_LOAD_DRIVER_NAME:
                   return "SeLoadDriverPrivilege";
                case SecurityEntity.SE_LOCK_MEMORY_NAME:
                   return "SeLockMemoryPrivilege";
                case SecurityEntity.SE_MACHINE_ACCOUNT_NAME:
                   return "SeMachineAccountPrivilege";
                case SecurityEntity.SE_MANAGE_VOLUME_NAME:
                   return "SeManageVolumePrivilege";
                case SecurityEntity.SE_PROF_SINGLE_PROCESS_NAME:
                   return "SeProfileSingleProcessPrivilege";
                case SecurityEntity.SE_RELABEL_NAME:
                   return "SeRelabelPrivilege";
                case SecurityEntity.SE_REMOTE_SHUTDOWN_NAME:
                   return "SeRemoteShutdownPrivilege";
                case SecurityEntity.SE_RESTORE_NAME:
                   return "SeRestorePrivilege";
                case SecurityEntity.SE_SECURITY_NAME:
                   return "SeSecurityPrivilege";
                case SecurityEntity.SE_SHUTDOWN_NAME:
                   return "SeShutdownPrivilege";
                case SecurityEntity.SE_SYNC_AGENT_NAME:
                   return "SeSyncAgentPrivilege";
                case SecurityEntity.SE_SYSTEM_ENVIRONMENT_NAME:
                   return "SeSystemEnvironmentPrivilege";
                case SecurityEntity.SE_SYSTEM_PROFILE_NAME:
                   return "SeSystemProfilePrivilege";
                case SecurityEntity.SE_SYSTEMTIME_NAME:
                   return "SeSystemtimePrivilege";
                case SecurityEntity.SE_TAKE_OWNERSHIP_NAME:
                   return "SeTakeOwnershipPrivilege";
                case SecurityEntity.SE_TCB_NAME:
                   return "SeTcbPrivilege";
                case SecurityEntity.SE_TIME_ZONE_NAME:
                   return "SeTimeZonePrivilege";
                case SecurityEntity.SE_TRUSTED_CREDMAN_ACCESS_NAME:
                   return "SeTrustedCredManAccessPrivilege";
                case SecurityEntity.SE_UNDOCK_NAME:
                   return "SeUndockPrivilege";
                default:
                   throw new ArgumentOutOfRangeException(typeof(SecurityEntity).Name);
                }
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct LUID {
               public UInt32 LowPart;
               public Int32 HighPart;
            }
    
            public struct TOKEN_PRIVILEGES {
               public int PrivilegeCount;
               [MarshalAs(UnmanagedType.ByValArray, SizeConst=ANYSIZE_ARRAY)]
               public LUID_AND_ATTRIBUTES [] Privileges;
            }
    
            [StructLayout(LayoutKind.Sequential, Pack = 4)]
            public struct LUID_AND_ATTRIBUTES {
               public LUID Luid;
               public UInt32 Attributes;
            }
    
            [Flags]
            public enum ProcessAccessFlags : uint
            {
                All = 0x001F0FFF,
                Terminate = 0x00000001,
                CreateThread = 0x00000002,
                VirtualMemoryOperation = 0x00000008,
                VirtualMemoryRead = 0x00000010,
                VirtualMemoryWrite = 0x00000020,
                DuplicateHandle = 0x00000040,
                CreateProcess = 0x000000080,
                SetQuota = 0x00000100,
                SetInformation = 0x00000200,
                QueryInformation = 0x00000400,
                QueryLimitedInformation = 0x00001000,
                Synchronize = 0x00100000
            }
    
            [DllImport("kernel32.dll", SetLastError=true)]
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            [SuppressUnmanagedCodeSecurity]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool CloseHandle(IntPtr hObject);
    
            // Use this signature if you want the previous state information returned
            [DllImport("advapi32.dll", SetLastError=true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool AdjustTokenPrivileges(IntPtr TokenHandle,
               [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges,
               ref TOKEN_PRIVILEGES NewState,
               UInt32 BufferLengthInBytes,
               ref TOKEN_PRIVILEGES PreviousState,
               out UInt32 ReturnLengthInBytes);
    
            // Use this signature if you do not want the previous state
            [DllImport("advapi32.dll", SetLastError=true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool AdjustTokenPrivileges(IntPtr TokenHandle,
               [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges,
               ref TOKEN_PRIVILEGES NewState,
               UInt32 Zero,
               IntPtr Null1,
               IntPtr Null2);
    
            [DllImport("advapi32.dll")]
            public static extern bool LookupPrivilegeValue(string lpSystemName, string lpName,
               ref LUID lpLuid);
    
            [DllImport("advapi32.dll", SetLastError=true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool OpenProcessToken(IntPtr ProcessHandle,
                UInt32 DesiredAccess, out IntPtr TokenHandle);
    
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern IntPtr OpenProcess(
                ProcessAccessFlags processAccess,
                bool bInheritHandle,
                int processId
            );
    
            public static IntPtr OpenProcess(Process proc, ProcessAccessFlags flags)
            {
                return OpenProcess(flags, false, proc.Id);
            }
        }
    }
    '@
    
    Add-Type -TypeDefinition $code -IgnoreWarnings 
    
    Function Enable-DebugPrivilege
    {
        $hToken = New-Object System.IntPtr
        $luidSEDebugNameValue = New-Object CSharp.NativeMethods+LUID
        $tkpPrivileges = New-Object CSharp.NativeMethods+TOKEN_PRIVILEGES
    
        if (![CSharp.NativeMethods]::OpenProcessToken([System.Diagnostics.Process]::GetCurrentProcess().Handle, [CSharp.NativeMethods]::TOKEN_ADJUST_PRIVILEGES -bor [CSharp.NativeMethods]::TOKEN_QUERY, [ref]$hToken))
        {
            $win32exception = New-Object System.ComponentModel.Win32Exception([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())
            "OpenProcessToken Failed ERROR #$($win32exception.NativeErrorCode) HRESULT: 0x{0:X8} Message: $($win32exception.Message) " -f $($win32exception.HResult)
            return
        }
        else
        {
            "OpenProcessToken SUCCESS!"
        }
    
        if (![CSharp.NativeMethods]::LookupPrivilegeValue($null, [CSharp.NativeMethods]::GetSecurityEntityValue([CSharp.NativeMethods+SecurityEntity]::SE_DEBUG_NAME), [ref]$luidSEDebugNameValue))
        {
          $win32exception = New-Object System.ComponentModel.Win32Exception([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())
            "LookupPrivilegeValue Failed ERROR #$($win32exception.NativeErrorCode) HRESULT: 0x{0:X8} Message: $($win32exception.Message) " -f $($win32exception.HResult)
            return
            [CSharp.NativeMethods]::CloseHandle($hToken)
            return
        }
        else
        {
           "LookupPrivilegeValue() SUCCESS!"
        }
    
    
        $tkpPrivileges.PrivilegeCount = 1
    
        $luid = New-Object CSharp.NativeMethods+LUID_AND_ATTRIBUTES
        $luid.Luid = $luidSEDebugNameValue
        $luid.Attributes =  [CSharp.NativeMEthods]::SE_PRIVILEGE_ENABLED
        $tkpPrivileges.Privileges = @($luid)
    
        if (![CSharp.NativeMethods]::AdjustTokenPrivileges($hToken,$false,[ref]$tkpPrivileges, 0,[IntPtr]::Zero,[IntPtr]::Zero))
        {
          $win32exception = New-Object System.ComponentModel.Win32Exception([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())
            "AdjustTokenPriviles Failed ERROR #$($win32exception.NativeErrorCode) HRESULT: 0x{0:X8} Message: $($win32exception.Message) " -f $($win32exception.HResult)
            return
            [CSharp.NativeMethods]::CloseHandle($hToken)
            return
    
        }
        else
        {
            "SeDebugPrivilege is now available!";
        }
    
        [CSharp.NativeMethods]::CloseHandle($hToken);
    
    
    }
    
    Function Open-Process($Process)
    {
        $hProcess = [CSharp.NativeMethods]::OpenProcess($Process,[CSharp.NativeMethods+ProcessAccessFlags]::QueryInformation)
    
        if ($hProcess -eq 0 )
        {
            $win32exception = New-Object System.ComponentModel.Win32Exception([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())
            "ERROR #$($win32exception.NativeErrorCode) HRESULT: 0x{0:X8} Message: $($win32exception.Message) " -f $($win32exception.HResult)
        }
        else
        {
            "Handle to process $hProcess opened ok!"
        }
    }
    
    
    Function Add-ProcessQueryInfoPermission($Process,$IdentityReference)
    {
        $procSec = New-Object CSharp.ProcessSecurity($Process.SafeHandle)
        $accessRule = New-Object CSharp.ProcessAccessRule($IdentityReference, [CSharp.ProcessAccessRights]::PROCESS_QUERY_INFORMATION, $true, [System.Security.AccessControl.InheritanceFlags]::None, [System.Security.AccessControl.PropagationFlags]::None, [System.Security.AccessControl.AccessControlType]::Allow)
        $procSec.AddAccessRule($accessRule)
        $procSec.SaveChanges($Process.SafeHandle)
    }
    
    
    # change to hold your target process
    $targetProcess = (Get-process | Where-Object { $_.Id -eq 3700  })
    
    Add-Type -AssemblyName System.DirectoryServices.AccountManagement
    
    # change for appropriate account to add
    $ctx = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine)  
    $usr = [ System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($ctx,[System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName,"test")  
    
    # add process query information (This may need to be run elevated / run from different acct then open-process line depending on target process)
    Add-ProcessQueryInfoPermission -Process $targetProcess -IdentityReference $usr.Sid
    
    # test open process
    Open-Process -Process  $targetProcess