none
can't start vbs script (offscrub) in impersonate user/session context

    Question

  • Hi,

    I'm trying to launch an MS script (.vbs) from an console application with an non admin user.
    after searches, I found the impersonate function.

    So I create an code witch impersonate an user from the current user (the one who launch the .exe console app').
    But the problem is with the impersonate context I cannot launch my vbs script with Cscript without UAC prompt.

    My script is using registry reading functions, and If have no admin rights, it doesn't work.

    What I wanted to do, is to launch the app with no admin account, impersonate the context with an domain admin account & launch the script..but, it's not working.

    Someone can help me please ?

    Here is my code :

    class Program
        {
    
            [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
                int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
    
            [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
            public extern static bool CloseHandle(IntPtr handle);
    
            [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern int DuplicateToken(SafeTokenHandle hToken, int impersonationLevel,
                out SafeTokenHandle hNewToken);
    
            #region userprofile
            [StructLayout(LayoutKind.Sequential)]
            public struct ProfileInfo
            {
                ///
                /// Specifies the size of the structure, in bytes.
                ///
                public int dwSize;
    
                ///
                /// This member can be one of the following flags: 
                /// PI_NOUI or PI_APPLYPOLICY
                ///
                public int dwFlags;
    
                ///
                /// Pointer to the name of the user.
                /// This member is used as the base name of the directory 
                /// in which to store a new profile.
                ///
                public string lpUserName;
    
                ///
                /// Pointer to the roaming user profile path.
                /// If the user does not have a roaming profile, this member can be NULL.
                ///
                public string lpProfilePath;
    
                ///
                /// Pointer to the default user profile path. This member can be NULL.
                ///
                public string lpDefaultPath;
    
                ///
                /// Pointer to the name of the validating domain controller, in NetBIOS format.
                /// If this member is NULL, the Windows NT 4.0-style policy will not be applied.
                ///
                public string lpServerName;
    
                ///
                /// Pointer to the path of the Windows NT 4.0-style policy file. 
                /// This member can be NULL.
                ///
                public string lpPolicyPath;
    
                ///
                /// Handle to the HKEY_CURRENT_USER registry key.
                ///
                public IntPtr hProfile;
            }
    
            [DllImport("userenv.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern bool LoadUserProfile
                (IntPtr hToken, ref ProfileInfo lpProfileInfo);
    
            [DllImport("Userenv.dll", CallingConvention =
                CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Auto)]
            public static extern bool UnloadUserProfile
                (IntPtr hToken, IntPtr lpProfileInfo);
    
            #endregion
    
    
            // Test harness.
            // If you incorporate this code into a DLL, be sure to demand FullTrust.
            [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
    
            static void Main(string[] args)
            {
                IntPtr token = IntPtr.Zero;
                //IntPtr tokenDuplicate = IntPtr.Zero;
                const int SecurityImpersonation = 2;
                const int TokenType = 1;
                WindowsIdentity m_ImpersonatedUser;
                SafeTokenHandle tokenDuplicate;
    
                SafeTokenHandle safeTokenHandle;
                try
                {
                    string userName, domainName;
                    // Get the user token for the specified user, domain, and password using the
                    // unmanaged LogonUser method.
                    // The local machine name can be used for the domain name to impersonate a user on this machine.
    //FRED                Console.Write("Enter the name of the domain on which to log on: ");
                    //domainName = Console.ReadLine();
                    domainName = @"myDomain";
    
    //FRED                Console.Write("Enter the login of a user on {0} that you wish to impersonate: ", domainName);
                    //userName = Console.ReadLine();
                    userName = @"svc_MyUser";
    
    //FRED                Console.Write("Enter the password for {0}: ", userName);
    
                    const int LOGON32_PROVIDER_DEFAULT = 0;
                    //This parameter causes LogonUser to create a primary token.
                    const int LOGON32_LOGON_INTERACTIVE = 2;
    
                    // Call LogonUser to obtain a handle to an access token.  Console.ReadLine()
                    bool returnValue = LogonUser(userName, domainName, "myPassword",
                        LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                        out safeTokenHandle);
    
                    Console.WriteLine("Connexion en cours.");
    
                    if (false == returnValue)
                    {
                        int ret = Marshal.GetLastWin32Error();
                        Console.WriteLine("LogonUser failed with error code : {0}", ret);
                        throw new System.ComponentModel.Win32Exception(ret);
                    }
                    using (safeTokenHandle)
                    {
                        Console.WriteLine("Did LogonUser Succeed? " + (returnValue ? "Yes" : "No"));
                        Console.WriteLine("Value of Windows NT token: " + safeTokenHandle);
    
                        // Check the identity.
                        Console.WriteLine("Before impersonation: "
                            + WindowsIdentity.GetCurrent().Name);
    
                        // Use the token handle returned by LogonUser.
    
    
                        if (DuplicateToken(safeTokenHandle, SecurityImpersonation,
                                    out tokenDuplicate) != 0)
                                { 
                                    m_ImpersonatedUser = new WindowsIdentity(tokenDuplicate.DangerousGetHandle());
                                    using (WindowsImpersonationContext m_ImpersonationContext = m_ImpersonatedUser.Impersonate())
                                    {
                                        if (m_ImpersonationContext != null)
                                    {
                                        Console.WriteLine("After Impersonation succeeded:"  + Environment.NewLine +
                                                          "User Name: " +
                                                          WindowsIdentity.GetCurrent
                                                          (TokenAccessLevels.MaximumAllowed).Name +
                                                          Environment.NewLine +
                                                          "SID: " +
                                                          WindowsIdentity.GetCurrent(TokenAccessLevels.MaximumAllowed).User.Value);
    
    
                                        // Load user profile
                                        ProfileInfo profileInfo = new ProfileInfo();
                                        profileInfo.dwSize = Marshal.SizeOf(profileInfo);
                                        profileInfo.lpUserName = "svc_MyUser";
                                        profileInfo.dwFlags = 1;
                                        Boolean loadSuccess = LoadUserProfile(tokenDuplicate.DangerousGetHandle(), ref profileInfo);
    
                                        if (!loadSuccess)
                                        {
                                            Console.WriteLine("LoadUserProfile() failed with error code: " +
                                                Marshal.GetLastWin32Error());
                                            //throw new Win32Exception(Marshal.GetLastWin32Error());
                                        }
                                        else
                                        {
                                            Console.WriteLine("LoadUserProfile() ok !!!!!!!: ");
                                        }
    
                                        if (profileInfo.hProfile == IntPtr.Zero)
                                        {
                                            Console.WriteLine("LoadUserProfile() failed - HKCU handle was not loaded. Error code: " +
                                                Marshal.GetLastWin32Error());
                                            //throw new Win32Exception(Marshal.GetLastWin32Error());
                                        }
    
    
    
                                        CloseHandle(safeTokenHandle.DangerousGetHandle());
                                        CloseHandle(tokenDuplicate.DangerousGetHandle());
    
    
    
                                        System.Diagnostics.Process myProc = new System.Diagnostics.Process();
                                        myProc.StartInfo.CreateNoWindow = false;
                                        myProc.StartInfo.LoadUserProfile = true;
    
                                        myProc.StartInfo.WorkingDirectory = Directory.GetCurrentDirectory() + "\\";
    
                                        Console.WriteLine("TEST ");
                                        myProc.StartInfo.Verb = "runas";
                                        myProc.StartInfo.FileName = @"cmd.exe";
                                        myProc.StartInfo.Arguments = @"/c cscript.exe " + Directory.GetCurrentDirectory() +
                                            @"\temp\myScript.vbs";
                                        myProc.StartInfo.UseShellExecute = false;
                                        myProc.Start();
                                        myProc.WaitForExit();
    
                                        UnloadUserProfile(tokenDuplicate.DangerousGetHandle(), profileInfo.hProfile);
                                        m_ImpersonationContext.Undo();
    
                                        }
                                    }
                                
                                }
    
                        
                        // Releasing the context object stops the impersonation
                        // Check the identity.
                        Console.WriteLine("After closing the context: " + WindowsIdentity.GetCurrent().Name);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception occurred. " + ex.Message);
                }
                Console.ReadKey();
            }
    }

    The LoadUserProfile method is no working too with an error code 5.

    Thank you

    Wednesday, May 3, 2017 2:46 PM

Answers

  • The problem is not in the .vbs.

    I've found an solution using CSUACSelfelevation's .net solution from Microsoft, which use well the impersonate class.

    I've just have to create an other application (with my different credentials) which launch the CSUASelfelevation, and it worked.

    • Marked as answer by Frédéric.G Thursday, June 1, 2017 9:42 AM
    Thursday, June 1, 2017 9:42 AM

All replies

  • It's not clear to me what your complaint is. You keep saying that it is "not working". Does this mean that the only problem is that the UAC dialog box is being displayed? Does the code otherwise execute as expected? If not, specifically describe what is "not working".

    Wednesday, May 3, 2017 6:17 PM
  • Sorry I'm not clear 

    The program is starting well.
    cscript is launched by the program, but in the vbs, the script try to read registry but failed because of access restriction.

    What I may not understand well is : if impersonate is working well, My cscript will be launched by the user in parameter no? Not the user who launched the program?

    My domain user in parameter is admin member, so he has the permissions to read registry so why I have this access denied msg ? (the vbs is good I tested it manually)

    If I'm good :

     - User A launched the program
     - User B is impersonated (admin member)
     - User B launched the vbs script with cscript 

    Is this ok ?

    Wednesday, May 3, 2017 7:59 PM
  • Hi Frédéric.G,

    For the question about the VBS, you could post a new thread in The Official Scripting Guys Forum! forum for suitable support.

    Best Regards,

    Wendy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, June 1, 2017 7:09 AM
  • The problem is not in the .vbs.

    I've found an solution using CSUACSelfelevation's .net solution from Microsoft, which use well the impersonate class.

    I've just have to create an other application (with my different credentials) which launch the CSUASelfelevation, and it worked.

    • Marked as answer by Frédéric.G Thursday, June 1, 2017 9:42 AM
    Thursday, June 1, 2017 9:42 AM