CreateProcessWithTokenW winapi return false but no reason why

0

I am New to winapi and I am trying to run a process with system privileges.

Lot of people suggested to use the Function CreateProcessWithTokenW.

I wrote the falling code:

$run = @"

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
    public Int32 cb;
    public string lpReserved;
    public string lpDesktop;
    public string lpTitle;
    public Int32 dwX;
    public Int32 dwY;
    public Int32 dwXSize;
    public Int32 dwYSize;
    public Int32 dwXCountChars;
    public Int32 dwYCountChars;
    public Int32 dwFillAttribute;
    public Int32 dwFlags;
    public Int16 wShowWindow;
    public Int16 cbReserved2;
    public IntPtr lpReserved2;
    public IntPtr hStdInput;
    public IntPtr hStdOutput;
    public IntPtr hStdError;
}

public struct ProcessInformation
{
    public IntPtr process;
    public IntPtr thread;
    public int    processId;
    public int    threadId;
}

[DllImport("advapi32", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CreateProcessWithTokenW(IntPtr hToken, int dwLogonFlags, string 
lpApplicationName, string lpCommandLine, uint dwCreationFlags, IntPtr lpEnvironment, string 
lpCurrentDirectory, [In] ref STARTUPINFO lpStartupInfo, out ProcessInformation lpProcessInformation);


[StructLayout(LayoutKind.Sequential)] 
public struct SECURITY_ATTRIBUTES
{
    public int    Length;
    public IntPtr lpSecurityDescriptor;
    public bool   bInheritHandle;
}


public enum SECURITY_IMPERSONATION_LEVEL 
{
    SecurityAnonymous,
    SecurityIdentification,
    SecurityImpersonation,
    SecurityDelegation
}

[DllImport("advapi32.dll", EntryPoint="DuplicateTokenEx",SetLastError=true)]
public static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref 
SECURITY_ATTRIBUTES lpThreadAttributes, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, int 
TokenType, ref IntPtr DuplicateTokenHandle);

[DllImport("advapi32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool OpenProcessToken(IntPtr ProcessHandle,UInt32 DesiredAccess, out IntPtr 
TokenHandle);

[DllImport("advapi32.dll", SetLastError=true)]
public static extern bool ImpersonateLoggedOnUser(IntPtr hToken);

"@

Add-Type -MemberDefinition $run -Namespace "token" -Name "run"
$si = New-Object token.run+STARTUPINFO
$si.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($si)
$si.lpReserved = $null

$pi = New-Object token.run+ProcessInformation

$processPath = $env:ComSpec
[uint32]$GENERIC_ALL = 0x10000000
[uint32]$CREATE_NO_WINDOW =  0x08000000
[uint32]$NORMAL_PRIORITY_CLASS = 0x00000020
[uint32]$CREATE_UNICODE_ENVIRONMENT = 0x00000400
$TOKEN_DUPLICATE = 2

$hprocess = (Get-Process -Name lsass).Handle
$htoken = New-Object System.IntPtr
[token.run]::OpenProcessToken($hprocess,$TOKEN_DUPLICATE, [ref]$htoken)
$DupToken = New-Object System.IntPtr

$sa = New-Object token.run+SECURITY_ATTRIBUTES
$sa.bInheritHandle = $true
$sa.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($sa)
$sa.lpSecurityDescriptor = [System.IntPtr]::Zero

$CREATE_NEW_CONSOLE = 0x00000010

[token.run]::DuplicateTokenEx($htoken,$GENERIC_ALL,[ref]$sa, 
[token.run+SECURITY_IMPERSONATION_LEVEL]::SecurityImpersonation,1,[ref]$DupToken)
[token.run]::ImpersonateLoggedOnUser($DupToken)
[token.run]::CreateProcessWithTokenW($DupToken,0,$null,$processPath,$CREATE_NEW_CONSOLE, 
[System.IntPtr]::Zero,$null,[ref]$si,[ref]$pi)

this code returns: True,True,True,False

It means that it managed to OpenProcessToken and Duplicate it and Impersonate to be System.

But for some reason it didn't manage to Create a process with the given token. (moreover if I run

[System.Runtime.InteropServices.Marshal]::GetLastWin32Error()

, it shows 0, that means that the operation finished successfully).

Can someone please explain why it is failing??

c#
powershell
winapi
process
token
asked on Stack Overflow Jul 26, 2020 by DaniDin

1 Answer

0
Function token-run($processPath)
{
    $run = @"
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct STARTUPINFO
    {
        public Int32 cb;
        public string lpReserved;
        public string lpDesktop;
        public string lpTitle;
        public Int32 dwX;
        public Int32 dwY;
        public Int32 dwXSize;
        public Int32 dwYSize;
        public Int32 dwXCountChars;
        public Int32 dwYCountChars;
        public Int32 dwFillAttribute;
        public Int32 dwFlags;
        public Int16 wShowWindow;
        public Int16 cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;
    }

public struct ProcessInformation
{
    public IntPtr process;
    public IntPtr thread;
    public int    processId;
    public int    threadId;
}

[DllImport("advapi32", SetLastError=true, CharSet=CharSet.Unicode)]
public static extern bool CreateProcessWithTokenW(IntPtr hToken, int dwLogonFlags, string lpApplicationName, string lpCommandLine, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFO lpStartupInfo, out ProcessInformation lpProcessInformation);

[StructLayout(LayoutKind.Sequential)] 
public struct SECURITY_ATTRIBUTES
{
    public int    Length;
    public IntPtr lpSecurityDescriptor;
    public bool   bInheritHandle;
}


public enum SECURITY_IMPERSONATION_LEVEL 
{
    SecurityAnonymous,
    SecurityIdentification,
    SecurityImpersonation,
    SecurityDelegation
}

[DllImport("advapi32.dll", EntryPoint="DuplicateTokenEx",SetLastError=true)]
public static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, int TokenType, ref IntPtr DuplicateTokenHandle);
"@

Add-Type -MemberDefinition $run -Namespace "token" -Name "run"
$si = New-Object token.run+STARTUPINFO
$si.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($si)
$pi = New-Object token.run+ProcessInformation
[uint32]$GENERIC_ALL = 0x10000000
$htoken = [System.Security.Principal.WindowsIdentity]::GetCurrent().Token
$DupToken = New-Object System.IntPtr
$sa = New-Object token.run+SECURITY_ATTRIBUTES
$sa.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($sa)
$CREATE_NEW_CONSOLE = 0x00000010
[token.run]::DuplicateTokenEx($htoken,$GENERIC_ALL,[ref]$sa,[token.run+SECURITY_IMPERSONATION_LEVEL]::SecurityImpersonation,1,[ref]$DupToken)|Out-Null
[token.run]::CreateProcessWithTokenW($DupToken,0,$processPath,$null,$CREATE_NEW_CONSOLE,[System.IntPtr]::Zero,"c:\windows\system32",[ref]$si,[ref]$pi)|Out-Null
}

This is the fixed code. I read in some other questions that when creating a process using CreateProcess function you have to give him an lpCurrentDirectory because powershell don't know how to handle it if it is null. Thank you very much all for your answers, hope it will help others!!!

answered on Stack Overflow Jul 27, 2020 by DaniDin

User contributions licensed under CC BY-SA 3.0