none
LogonUser with SetTokenInformation RRS feed

  • Question

  • I have a C# and I need to run a process as a Admin user inside current user session.

    I can run the process with admin user, but the process is in session 0, and i want to change to the current user session

    So I'm using SetTokenInformation, but I gives me a error 24.

    my code :

       private void StartProc(object state)
            {
                try
                {
                    IntPtr hToken;
                    Boolean visible = true;
    
                    if (Win32.LogonUser("Infra", "INDRACPS040", "Indra1234", Win32.LOGON32_LOGON_INTERACTIVE, Win32.LOGON32_PROVIDER_DEFAULT, out hToken))
                    {
                        int len = Marshal.SizeOf<Win32.TOKEN_LINKED_TOKEN>();
    #pragma warning disable IDE0018 // Declaração de variável embutida
                        int retlen;
    #pragma warning restore IDE0018 // Declaração de variável embutida
                        IntPtr tlt = Marshal.AllocHGlobal(len);
    
                        if (Win32.GetTokenInformation(hToken, Win32.TOKEN_INFORMATION_CLASS.TokenLinkedToken, tlt, len, out retlen))
                        {
                            Win32.TOKEN_LINKED_TOKEN linked = Marshal.PtrToStructure<Win32.TOKEN_LINKED_TOKEN>(tlt);
                            Win32.PROFILEINFO profinfo = new Win32.PROFILEINFO();
    
                            profinfo.dwSize = Marshal.SizeOf<Win32.PROFILEINFO>();
                            profinfo.lpUserName = "Infra";
                            if (Win32.LoadUserProfile(linked.LinkedToken, ref profinfo))
                            {
    
                                uint dwCreationFlags = Win32.CREATE_UNICODE_ENVIRONMENT | (uint)(visible ? Win32.CREATE_NEW_CONSOLE : Win32.CREATE_NO_WINDOW);
                                bool bImpersonating = Win32.ImpersonateLoggedOnUser(linked.LinkedToken);
                                UInt32 dwSessionId = Win32.WTSGetActiveConsoleSessionId();
                                Boolean setInfo = Win32.SetTokenInformation(linked.LinkedToken, Win32.TOKEN_INFORMATION_CLASS.TokenSessionId, ref dwSessionId, (UInt32)len);
                                if (!setInfo)
                                {
                                    int err = Marshal.GetLastWin32Error();
                                    string strError = "SetTokenInformation failed with error code " + err.ToString() + " dwSessionID:" + dwSessionId.ToString();
                                    this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                                }
                                else
                                {
                                    this.eventLog1.WriteEntry("Set token info is " + setInfo.ToString(), EventLogEntryType.Information);
                                }
    
                                IntPtr pEnvironment;
                                if (Win32.CreateEnvironmentBlock(out pEnvironment, linked.LinkedToken, false))
                                {
                                    Win32.PROCESS_INFORMATION pi;
                                    Win32.STARTUPINFO si = new Win32.STARTUPINFO();
                                    Win32.SECURITY_ATTRIBUTES sa = new Win32.SECURITY_ATTRIBUTES();
    
                                    sa.nLength = Marshal.SizeOf<Win32.SECURITY_ATTRIBUTES>();
                                    si.cb = Marshal.SizeOf<Win32.STARTUPINFO>();
                                    si.lpDesktop = "winsta0\\default";
                                    si.wShowWindow = (ushort)(visible ? Win32.SW.SW_SHOW : Win32.SW.SW_HIDE);                               
    
                                    if (Win32.CreateProcessAsUser(linked.LinkedToken,
                                            @"C:\Cap\Capturap.exe",
                                            string.Empty, 
                                            ref sa, 
                                            ref sa, 
                                            false,
                                            dwCreationFlags,
                                            pEnvironment, @"C:\Temp", 
                                            ref si,
                                            out pi))
                                    {
                                        uint exitCode;
    
                                        Win32.CloseHandle(pi.hThread);
                                        Win32.WaitForSingleObject(pi.hProcess, Win32.INFINITE);
                                        Win32.GetExitCodeProcess(pi.hProcess, out exitCode);
                                        Win32.CloseHandle(pi.hProcess);
    
                                        string strMsg = "Process TokenLister.exe terminated with return code " + exitCode.ToString();
                                        this.eventLog1.WriteEntry(strMsg, EventLogEntryType.Information);
                                    }
                                    else
                                    {
                                        int err = Marshal.GetLastWin32Error();
                                        string strError = "CreateProcessAsUser failed with error code " + err.ToString();
                                        this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                                    }
    
                                    if (bImpersonating)
                                        Win32.RevertToSelf();
    
                                    Win32.DestroyEnvironmentBlock(pEnvironment);
                                }
                                else
                                {
                                    int err = Marshal.GetLastWin32Error();
                                    string strError = "CreateEnvironmentBlock failed with error code " + err.ToString();
                                    this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                                }
    
                                Win32.UnloadUserProfile(linked.LinkedToken, profinfo.hProfile);
                            }
                            else
                            {
                                int err = Marshal.GetLastWin32Error();
                                string strError = "LoadUserProfile failed with error code " + err.ToString();
                                this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                            }
    
                            Win32.CloseHandle(linked.LinkedToken);
                        }
                        else
                        {
                            int err = Marshal.GetLastWin32Error();
                            string strError = "GetTokenInformation failed with error code " + err.ToString();
                            this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                        }
    
                        Marshal.FreeHGlobal(tlt);
    
                        Win32.CloseHandle(hToken);
                    }
                    else
                    {
                        int err = Marshal.GetLastWin32Error();
                        string strError = "LogonUser failed with error code " + err.ToString();
                        this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                    }
                }
                catch (Exception ex)
                {
                    string strExeption = "Caught exception : " + ex.Message;
                    this.eventLog1.WriteEntry(strExeption, EventLogEntryType.Error);
                }
            }


    Friday, October 11, 2019 2:08 PM

All replies

  • You must NOT be impersonating when you call SetTokenInformation.

    Also, what value are you passing in the len parameter?


    • Edited by RLWA32 Friday, October 11, 2019 6:42 PM
    Friday, October 11, 2019 6:40 PM
  • You will have another significant problem to overcome since you want to do screen capture in the user's interactive session.

    The process started by CreateProcessAsUser for the Infra account will NOT have access to the window station and the desktop of the interactive session.

    The docs say -

    "By default, CreateProcessAsUser creates the new process on a noninteractive window station with a desktop that is not visible and cannot receive user input. To enable user interaction with the new process, you must specify the name of the default interactive window station and desktop, "winsta0\default", in the lpDesktop member of the STARTUPINFO structure. In addition, before calling CreateProcessAsUser, you must change the discretionary access control list (DACL) of both the default interactive window station and the default desktop. The DACLs for the window station and desktop must grant access to the user or the logon session represented by the hToken parameter."

    Friday, October 11, 2019 6:48 PM
  •   private void StartProc(object state)
            {
                try
                {
                    IntPtr hToken;
                    Boolean visible = true;
                    UInt32 dwSessionId = Win32.WTSGetActiveConsoleSessionId();
    
                    if (Win32.LogonUser("Infra", "INDRACPS040", "Indra1234", Win32.LOGON32_LOGON_INTERACTIVE, Win32.LOGON32_PROVIDER_DEFAULT, out hToken))
                    {
                        int len = Marshal.SizeOf<Win32.TOKEN_LINKED_TOKEN>();
    #pragma warning disable IDE0018 // Declaração de variável embutida
                        int retlen;
    #pragma warning restore IDE0018 // Declaração de variável embutida
                        IntPtr tlt = Marshal.AllocHGlobal(len);
    
                        if (Win32.GetTokenInformation(hToken, Win32.TOKEN_INFORMATION_CLASS.TokenLinkedToken, tlt, len, out retlen))
                        {
                            Win32.TOKEN_LINKED_TOKEN linked = Marshal.PtrToStructure<Win32.TOKEN_LINKED_TOKEN>(tlt);
                            Win32.PROFILEINFO profinfo = new Win32.PROFILEINFO();
    
                            profinfo.dwSize = Marshal.SizeOf<Win32.PROFILEINFO>();
                            profinfo.lpUserName = "Infra";
                            if (Win32.LoadUserProfile(linked.LinkedToken, ref profinfo))
                            {                          
                                IntPtr pEnvironment;
                                if (Win32.CreateEnvironmentBlock(out pEnvironment, linked.LinkedToken, false))
                                {
                                    Win32.PROCESS_INFORMATION pi;
                                    Win32.STARTUPINFO si = new Win32.STARTUPINFO();
                                    Win32.SECURITY_ATTRIBUTES sa = new Win32.SECURITY_ATTRIBUTES();
                                    uint dwCreationFlags = Win32.CREATE_UNICODE_ENVIRONMENT | (uint)(visible ? Win32.CREATE_NEW_CONSOLE : Win32.CREATE_NO_WINDOW);
                                    
                                    sa.nLength = Marshal.SizeOf<Win32.SECURITY_ATTRIBUTES>();
                                    si.cb = Marshal.SizeOf<Win32.STARTUPINFO>();
                                    //si.lpDesktop = "winsta0\\default";
                                    si.wShowWindow = (ushort)(visible ? Win32.SW.SW_SHOW : Win32.SW.SW_HIDE);                     
                                    
                                    Boolean setInfo = Win32.SetTokenInformation(linked.LinkedToken, Win32.TOKEN_INFORMATION_CLASS.TokenSessionId, ref dwSessionId, (UInt32)Marshal.SizeOf(dwSessionId));
                                    if (!setInfo)
                                    {
                                        int err = Marshal.GetLastWin32Error();
                                        string strError = "SetTokenInformation failed with error code " + err.ToString() + " dwSessionID:" + dwSessionId.ToString();
                                        this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                                    }
                                    else
                                    {
                                        this.eventLog1.WriteEntry("Set token info is " + setInfo.ToString(), EventLogEntryType.Information);
                                    }
    
                                    //bool bImpersonating = Win32.ImpersonateLoggedOnUser(linked.LinkedToken);
    
                                    if (Win32.CreateProcessAsUser(linked.LinkedToken,
                                            @"C:\Cap\Capturap.exe",
                                            string.Empty, 
                                            ref sa, 
                                            ref sa, 
                                            false,
                                            dwCreationFlags,
                                            pEnvironment,
                                            @"C:\Temp", 
                                            ref si,
                                            out pi))
                                    {
                                        uint exitCode;
    
                                        Win32.CloseHandle(pi.hThread);
                                        Win32.WaitForSingleObject(pi.hProcess, Win32.INFINITE);
                                        Win32.GetExitCodeProcess(pi.hProcess, out exitCode);
                                        Win32.CloseHandle(pi.hProcess);
    
                                        string strMsg = "Process TokenLister.exe terminated with return code " + exitCode.ToString();
                                        this.eventLog1.WriteEntry(strMsg, EventLogEntryType.Information);
                                    }
                                    else
                                    {
                                        int err = Marshal.GetLastWin32Error();
                                        string strError = "CreateProcessAsUser failed with error code " + err.ToString();
                                        this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                                    }
    
                                   /* if (bImpersonating)
                                        Win32.RevertToSelf();*/
    
                                    Win32.DestroyEnvironmentBlock(pEnvironment);
                                }
                                else
                                {
                                    int err = Marshal.GetLastWin32Error();
                                    string strError = "CreateEnvironmentBlock failed with error code " + err.ToString();
                                    this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                                }
    
                                Win32.UnloadUserProfile(linked.LinkedToken, profinfo.hProfile);
                            }
                            else
                            {
                                int err = Marshal.GetLastWin32Error();
                                string strError = "LoadUserProfile failed with error code " + err.ToString();
                                this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                            }
    
                            Win32.CloseHandle(linked.LinkedToken);
                        }
                        else
                        {
                            int err = Marshal.GetLastWin32Error();
                            string strError = "GetTokenInformation failed with error code " + err.ToString();
                            this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                        }
    
                        Marshal.FreeHGlobal(tlt);
    
                        Win32.CloseHandle(hToken);
                    }
                    else
                    {
                        int err = Marshal.GetLastWin32Error();
                        string strError = "LogonUser failed with error code " + err.ToString();
                        this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                    }
                }
                catch (Exception ex)
                {
                    string strExeption = "Caught exception : " + ex.Message;
                    this.eventLog1.WriteEntry(strExeption, EventLogEntryType.Error);
                }
            }       

    Yes, thats rigth.

    This is what I see if I start like this:

    Friday, October 11, 2019 7:21 PM
  • There is another way to do this ?
    Friday, October 11, 2019 7:22 PM
  • The way I see it there are a couple of possible workarounds.

    1) Obtain the logon session sid from the Infra token created by the service.  Start a helper process in the user's interactive session (running as the logged-on user) and use it to adjust the security descriptors of the window station and the desktop to allow access to the Infra token's logon session.  After this is done, start the elevated process as Infra in the interactive session.

    or

    2) Get the interactive user's logon session sid from the token returned by WTSQueryUserToken.  Use LsaLogonUser to logon Infra and pass the function the logon session sid in the LocalGroups parameter.  The token returned by LsaLogonUser should contain the same logon session sid as that of the logged-on user so window station and desktop access should be allowed.

    I don't have any C# code already written to accomplish either workaround.

    Friday, October 11, 2019 8:11 PM
  • Ok, I will search about it.
    Friday, October 11, 2019 9:42 PM
  • Any progress?

    There is sample C++ code at Starting an Interactive Client Process in C++ that demonstrates how to add a logon sid to the security descriptors for a window station and desktop.

    Thursday, October 17, 2019 4:06 PM