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??
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!!!
User contributions licensed under CC BY-SA 3.0