1

I'm able to create a new process via CreateProcessAsUser from code I found here: https://odetocode.com/blogs/scott/archive/2004/10/28/createprocessasuser.aspx

It works fine, but the new process does not contain the Kerberos ticket of the new user which was impersonated by IIS Asp.net Impersonation. I know IIS has the Kerberos ticket, I just don't know programmatic how to get it from from the parent worker process to the new process I spawn which invokes OpenSSH.

Edit: Updated Impersonation block with DupliateHandlers function as mentioned by @Steve

var CurrentIdentity = ((WindowsIdentity)User.Identity).Token;
            IntPtr parentHandle = IntPtr.Zero;

            QuerySecurityContextToken(ref CurrentIdentity, out parentHandle);


            using (WindowsImpersonationContext impersonationContext = ((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate())
            {
                IntPtr childHandle = CreateProcessAsUser();

                IntPtr lpTargetHandle = IntPtr.Zero;

                if (CloneParentProcessToken.DuplicateHandle(parentHandle, null, childHandle, out lpTargetHandle,
                    null, true, DuplicateOptions.DUPLICATE_SAME_ACCESS, ) > 0)
                {
                    if(ImpersonateLoggedOnUser(lpTargetHandle))
                    {

                    }
                }


                impersonationContext.Undo();
            }

private void CreateProcessAsUser()
    {
        IntPtr hToken = WindowsIdentity.GetCurrent().Token;
        IntPtr hDupedToken = IntPtr.Zero;

        ProcessUtility.PROCESS_INFORMATION pi = new ProcessUtility.PROCESS_INFORMATION();

        try
        {
            ProcessUtility.SECURITY_ATTRIBUTES sa = new ProcessUtility.SECURITY_ATTRIBUTES();
            sa.Length = Marshal.SizeOf(sa);

            bool result = ProcessUtility.DuplicateTokenEx(
                  hToken,
                  ProcessUtility.GENERIC_ALL_ACCESS,
                  ref sa,
                  (int)ProcessUtility.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
                  (int)ProcessUtility.TOKEN_TYPE.TokenPrimary,
                  ref hDupedToken
               );

            if (!result)
            {
                throw new ApplicationException("DuplicateTokenEx failed");
            }


            ProcessUtility.STARTUPINFO si = new ProcessUtility.STARTUPINFO();
            si.cb = Marshal.SizeOf(si);
            si.lpDesktop = String.Empty;

            result = ProcessUtility.CreateProcessAsUser(
                                 hDupedToken,
                                 null,
                                 "powershell.exe -Command SSHCommand.ps1",
                                 ref sa, ref sa,
                                 true, 0, IntPtr.Zero,
                                 @"C:\", ref si, ref pi
                           );

            if (!result)
            {
                int error = Marshal.GetLastWin32Error();
                string message = String.Format("CreateProcessAsUser Error: {0}", error);
                throw new ApplicationException(message);
            }
        }
        finally
        {
            if (pi.hProcess != IntPtr.Zero)
                ProcessUtility.CloseHandle(pi.hProcess);
            if (pi.hThread != IntPtr.Zero)
                ProcessUtility.CloseHandle(pi.hThread);
            if (hDupedToken != IntPtr.Zero)
                ProcessUtility.CloseHandle(hDupedToken);
        }
    }

}

public class ProcessUtility
{
    [StructLayout(LayoutKind.Sequential)]
    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 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;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct PROCESS_INFORMATION
    {
        public IntPtr hProcess;
        public IntPtr hThread;
        public Int32 dwProcessID;
        public Int32 dwThreadID;
    }

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

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

    public enum TOKEN_TYPE
    {
        TokenPrimary = 1,
        TokenImpersonation
    }

    public const int GENERIC_ALL_ACCESS = 0x10000000;
    public const int TOKEN_ASSIGN_PRIMARY = 0x0001;

    [
       DllImport("kernel32.dll",
          EntryPoint = "CloseHandle", SetLastError = true,
          CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)
    ]
    public static extern bool CloseHandle(IntPtr handle);

    [
       DllImport("advapi32.dll",
          EntryPoint = "CreateProcessAsUser", SetLastError = true,
          CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)
    ]
    public static extern bool
       CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine,
                           ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes,
                           bool bInheritHandle, Int32 dwCreationFlags, IntPtr lpEnvrionment,
                           string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo,
                           ref PROCESS_INFORMATION lpProcessInformation);

    [
       DllImport("advapi32.dll",
          EntryPoint = "DuplicateTokenEx")
    ]
    public static extern bool
       DuplicateTokenEx(IntPtr hExistingToken, Int32 dwDesiredAccess,
                        ref SECURITY_ATTRIBUTES lpThreadAttributes,
                        Int32 ImpersonationLevel, Int32 dwTokenType,
                        ref IntPtr phNewToken);
}
jangooni
  • 167
  • 3
  • 11
  • It looks like you're duplicating the token and only asking for identification. You need impersonation or possibly delegation depending on what you're doing in the child process. – Steve Aug 06 '19 at 16:39
  • @Steve thanks for the response. I did try both Impersonation and Delegation, but got this error: Error calling API LsaCallAuthenticationPackage (ShowTickets substatus): 1312 klist failed with 0xc000005f/-1073741729: A specified logon session does not exist. It may already have been terminated. – jangooni Aug 06 '19 at 17:41
  • 1
    Are you calling klist as the delegated application? Rereading this a bit I think you may run into an issue here because I think the new app needs to know to impersonate too. https://stackoverflow.com/questions/51735041/support-kerberos-constrained-delegation-using-sspi-for-multiprocess/51795116#51795116 – Steve Aug 06 '19 at 19:09
  • @Steve thanks. Is it possible to just find the krb5cache location and set it as an env var KRB5CCNAME in the new process? – jangooni Aug 06 '19 at 19:13
  • No, that's not how Windows works for security reasons. – Steve Aug 07 '19 at 01:37
  • @Steve thanks. I’m going Dow the route in the other SO you listed. I’m assuming the duplicate handle will put the new handle into the child process? It’s not clear from the MSDN documentation. – jangooni Aug 07 '19 at 20:32
  • Yes, the duplicate handle will be added to the handles list of the process, but you will have to signal to the app that's the handle to use. – Steve Aug 07 '19 at 22:02
  • Thanks @Steve, I've updated the code above with the DuplicateHandlers section. I'm just a little confused at 2 things: How to get the Child process created to use here before I actually call the child process to execute the exe, and How to use this new lpTargetHandle for the child process I need. I don't see any documentation on how to set a process' handler. – jangooni Aug 07 '19 at 23:52

1 Answers1

0

This should be a comment but I cannot add comments. I do not know if it makes any difference but I think your STARTUPINFO structure is missing an element dwYSize after dwXSize

user2849221
  • 113
  • 8