0

I have an ASP.NET Core 6.0 Web API that runs on IIS 7. The application pool is running under an account local to the machine but not the local system, call it 'local-system-web-account'. I am trying to start an executable from the API, but do it with the credentials of a domain joined account, let's call it 'domain-account-with-different-access'.

Both user accounts have access to a folder on the C:\ drive, to a folder called Tools. Tools has a single application, HelloWorld.exe, that simply prints 'Hello World!' to the command line and exits (a standard, brand new console application).

When I run the API endpoint that does not switch to the domain account, the output from the following API call is

[HttpGet("api/v1/test/noContextSwitchingTest")]
public async Task<ActionResult<ReturnDetail<object>>> NoContextSwitchingTest() 
{
    var prInfo = new ProcessStartInfo 
                     {
                         FileName = @"C:\tools\helloworld.exe",
                         Arguments = "",
                         ErrorDialog = false,
                         UseShellExecute = false,
                         RedirectStandardOutput = true,
                         RedirectStandardError = true,
                         CreateNoWindow = true,
                     };

    var stdout = new StringBuilder();
    var stderr = new StringBuilder();

    using (System.Diagnostics.Process proc = new()) 
    {
        proc.StartInfo = prInfo;
        proc.EnableRaisingEvents = true;
        proc.ErrorDataReceived += (sender, errorLine) => { if (errorLine.Data != null) stderr.AppendLine(errorLine.Data); };
        proc.OutputDataReceived += (sender, outputLine) => { if (outputLine.Data != null) stdout.AppendLine(outputLine.Data); };

        proc.Start();

        proc.BeginErrorReadLine();
        proc.BeginOutputReadLine();

        proc.WaitForExit();
    }

    return Ok(new { Out = stdout.ToString(), Erro = stderr.ToString() });
}

{
  "out": "Hello, World!\r\n",
  "erro": ""
}

When I call the following API endpoint:

[HttpGet("api/v1/test/WithContextSwitchingTest")]
public async Task<ActionResult<ReturnDetail<object>>> WithContextSwitchingTest() 
{
    var prInfo = new ProcessStartInfo  
                     {
                         FileName = @"C:\tools\helloworld.exe",
                         Arguments = "",
                         ErrorDialog = false,
                         UseShellExecute = false,
                         RedirectStandardOutput = true,
                         RedirectStandardError = true,
                         CreateNoWindow = true,
                     };

    prInfo.UserName = "domain-account-with-different-access";
    prInfo.PasswordInClearText = "PASSWORD";

    var stdout = new StringBuilder();
    var stderr = new StringBuilder();

    using (System.Diagnostics.Process proc = new()) 
    {
        proc.StartInfo = prInfo;
        proc.EnableRaisingEvents = true;
        proc.ErrorDataReceived += (sender, errorLine) => { if (errorLine.Data != null) stderr.AppendLine(errorLine.Data); };
        proc.OutputDataReceived += (sender, outputLine) => { if (outputLine.Data != null) stdout.AppendLine(outputLine.Data); };

        proc.Start();

        proc.BeginErrorReadLine();
        proc.BeginOutputReadLine();

        proc.WaitForExit();
    }

    return Ok(new { Out = stdout.ToString(), Erro = stderr.ToString() });
}

with a switch to the domain account, I get an error in the Event Viewer

Application popup: HelloWorld.exe - Application Error : The application was unable to start correctly (0xc0000142). Click OK to close the application.

and I also get the following output from the API:

{
    "out": "",
    "erro": ""
}

But nothing else. No exception is thrown. It just silently doesn't work and nothing in the Standard Out or Standard Error.

If I switch the application pool to run as the domain account in IIS and rerun the no context switching endpoint, the HelloWorld executes just fine, so I know the domain account can run the executable and access it.

I'm looking for any advice on different code that could be used or areas of security interest that could be preventing the switch.

3
  • Based on your scenario, first of all,ensure that both the local-system-web-account and domain-account-with-different-access have appropriate permissions on the C:\tools directory and HelloWorld.exe. You ProcessStartInfo with UseShellExecute = true and FileName = "cmd.exe" to prompt for credentials securely, avoiding PasswordInClearText by using SecureString for the password. In addition, you should check Event Viewer logs for detailed error messages and test executing HelloWorld.exe manually under both accounts to verify permissions and resolve any access issues. Commented Jul 3 at 9:35
  • We have tried both PasswordInClearText and the SecureString method and it is the same result. All permissions are set correctly, because if we don't switch at the code level, but switch at the AppPool level, it works fine. And we tried just doing cmd.exe as well and it still won't work. The Event Viewer only shows the error that I mentioned above.
    – Josh
    Commented Jul 3 at 13:29
  • Thanks for your response, Instead of using Process.Start, have you tried using P/Invoke to call CreateProcessWithLogonW, which is designed to start a process as a different user. This might bypass some of the issues you're encountering. Commented Jul 12 at 8:14

0