Unable to use CreateProcessWithTokenW from ASP.NET

A

Aadil Abbas

I need to create a child process from an impersonated ASP.NET application
(web service), the child process should also run in the security context of
the impersonated thread. I could not find any managed class that
encapsulates this functionality, therefore I am using
"CreateProcessWithTokenW" windows API function. Now this function is working
fine for me from a .NET console application, but when I run it from a web
service running on IIS 6.0 and windows 2003, it fails.

CreateProcessWithTokenW requires a primary token in order to create a child
process, for this reason I am using DuplicateTokenEx function. Now my
DuplicateTokenEx function returns true, and creates a duplicate primary
token, but unfortunately CreateProcessWithTokenW function fails with error
code "5", this win32 error depicts "Access is denied". My parent process has
the privilege "Replace a process level token".

The dwCreationFlags passed to "CreateProcessWithTokenW" has
"CREATE_NO_WINDOW", but still a window is created the reason being
"CREATE_NEW_CONSOLE" is enabled by default as stated in the documentation. I
have also tried by setting "DETACH_PROCESS" flag, in that case I get a
different error: error code 87 "The parameter is incorrect". I presume
either my calls to unmanaged code have some flaw or I am missing some
security setting. Please see if you could spot anything wrong.

[SecurityPermission(SecurityAction.Demand,ControlPrincipal = true)]
public class ProcessToken
{
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
internal static extern bool CreateProcessWithTokenW(IntPtr
dupeTokenHandle,
int dwLogonFlags, string applicationName, StringBuilder commandLine,
int creationFlags, IntPtr environment,
string currentDirectory,
ref STARTUPINFO sui,
out PROCESS_INFORMATION processInfo);

[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
internal static extern bool DuplicateTokenEx(IntPtr tokenHandle, int
dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpTokenAttributes, int
SECURITY_IMPERSONATION_LEVEL ,
int TOKEN_TYPE, ref IntPtr dupeTokenHandle);


[DllImport("kernel32")]
static extern bool CloseHandle(IntPtr handle);

[StructLayout(LayoutKind.Sequential)]
internal struct SECURITY_ATTRIBUTES
{
internal int nLength;
internal int lpSecurityDescriptor;
internal bool bInheritHandle;

}

[StructLayout(LayoutKind.Sequential)]
internal struct STARTUPINFO
{
internal int cb;
[MarshalAs(UnmanagedType.LPTStr)]
internal string lpReserved;
[MarshalAs(UnmanagedType.LPTStr)]
internal string lpDesktop;
[MarshalAs(UnmanagedType.LPTStr)]
internal string lpTitle;
internal int dwX;
internal int dwY;
internal int dwXSize;
internal int dwYSize;
internal int dwXCountChars;
internal int dwYCountChars;
internal int dwFillAttribute;
internal int dwFlags;
internal short wShowWindow;
internal short cbReserved2;
internal IntPtr lpReserved2;
internal IntPtr hStdInput;
internal IntPtr hStdOutput;
internal IntPtr hStdError;
}

[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
internal IntPtr hProcess;
internal IntPtr hThread;
internal int dwProcessId;
internal int dwThreadId;
}

// SECURITY_IMPERSONATION_LEVEL
const int SecurityAnonymous = 0;
const int SecurityIdentification = 1;
const int SecurityImpersonation = 2;
const int SecurityDelegation = 3;

// TOKEN_TYPE
const int TokenPrimary = 1;
const int TokenImpersonation = 2;

//dwLogonFlags Specifies the logon option
const int LOGON_WITH_PROFILE = 1;
const int LOGON_NETCREDENTIALS_ONLY = 2;

// Access Token constants
const int TOKEN_ALL_ACCESS = 0x10000000;

//dwCreationFlags - Specifies how the process is created
const int DETACHED_PROCESS = 0x00000008;
const int CREATE_NO_WINDOW = 0x08000000;
const int CREATE_SUSPENDED = 0x00000004;
const int CREATE_NEW_CONSOLE = 0x00000010;
const int CREATE_NEW_PROCESS_GROUP = 0x00000200;
const int CREATE_SEPARATE_WOW_VDM = 0x00000800;
const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
const int CREATE_DEFAULT_ERROR_MODE = 0x04000000;

//dwCreationFlags parameter controls the new process's priority class
const int NORMAL_PRIORITY_CLASS = 0x00000020;
const int IDLE_PRIORITY_CLASS = 0x00000040;
const int HIGH_PRIORITY_CLASS = 0x00000080;
const int REALTIME_PRIORITY_CLASS = 0x00000100;
const int BELOW_NORMAL_PRIORITY_CLASS = 0x00004000;
const int ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000;
//dwFlags
// This is a bit field that determines whether certain STARTUPINFO
// members are used when the process creates a window.
// Any combination of the following values can be specified:
const int STARTF_USESHOWWINDOW = 0x0000000;
const int STARTF_USESIZE = 0x00000002;
const int STARTF_USEPOSITION = 0x00000004;
const int STARTF_USECOUNTCHARS = 0x00000008;
const int STARTF_USEFILLATTRIBUTE = 0x00000010;
const int STARTF_FORCEONFEEDBACK = 0x00000040;
const int STARTF_FORCEOFFFEEDBACK = 0x00000080;
const int STARTF_USESTDHANDLES = 0x00000100;
const int STARTF_USEHOTKEY = 0x00000200;


public static string CreateTokenChild()
{
try
{
string temp = System.Web.HttpContext.Current.User.Identity.Name;

StringBuilder sb = new StringBuilder();
// process to execute
sb.Append(@"cmd.exe");

PROCESS_INFORMATION processInfo;
STARTUPINFO startInfo = new STARTUPINFO();
startInfo.cb = Marshal.SizeOf(startInfo);

// Create Process with token
IntPtr dupeTokenHandle = IntPtr.Zero;
IntPtr tokenHandle = WindowsIdentity.GetCurrent().Token;

// Setting security attributes
SECURITY_ATTRIBUTES lpTokenAttributes = new SECURITY_ATTRIBUTES();
lpTokenAttributes.nLength = Marshal.SizeOf(lpTokenAttributes);
lpTokenAttributes.lpSecurityDescriptor = 0;
lpTokenAttributes.bInheritHandle = true;

bool retVal = DuplicateTokenEx(tokenHandle, TOKEN_ALL_ACCESS, ref
lpTokenAttributes, SecurityImpersonation, TokenPrimary, ref
dupeTokenHandle);

bool ret = CreateProcessWithTokenW(dupeTokenHandle,
LOGON_WITH_PROFILE , null, sb,
CREATE_NO_WINDOW,
IntPtr.Zero, "c:\\",
ref startInfo, out processInfo);

if(!ret)
{
// If failure ...
int err = Marshal.GetLastWin32Error();
return err.ToString();
}
}

catch (Exception e)
{
return e.ToString();
}
return "child created";
}
}

Thanks
Aadil
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top