Beispiel #1
0
 private static bool ProcessOwnedBySuitableUser(int pid, ProcessExecuteArgs execArgs)
 {
     if ((execArgs.flags & ProcessExecuteFlags.ImpersonateAnyUser) > 0)
     {
         return(true);
     }
     if ((execArgs.flags & ProcessExecuteFlags.ImpersonateLocalSystem) > 0 && UserIsMatch(pid, WellKnownSidType.LocalSystemSid))
     {
         return(true);
     }
     if ((execArgs.flags & ProcessExecuteFlags.ImpersonateSpecificUser) > 0 && ProcessOwnedByUser(pid, execArgs.userName, execArgs.userNameIgnoreCase))
     {
         return(true);
     }
     return(false);
 }
Beispiel #2
0
 /// <summary>
 /// Returns true if the specified process is suitable for impersonation based on all the rules specified in the ProcessExecuteArgs instance.
 /// </summary>
 /// <param name="p"></param>
 /// <param name="execArgs"></param>
 /// <returns></returns>
 private static bool IsSuitableProcess(Process p, ProcessExecuteArgs execArgs)
 {
     // p.ProcessName does not include the file extension. GetProcessesByName uses case-sensitive matching, so we'll use case-insensitive matching on process names here too.
     if (execArgs.requiredSessionID != null && p.SessionId != execArgs.requiredSessionID)
     {
         return(false);
     }
     else if ((execArgs.flags & ProcessExecuteFlags.ImpersonateExplorer) == 0 && string.Compare(p.ProcessName, "explorer", true) == 0)
     {
         return(false);
     }
     else if ((execArgs.flags & ProcessExecuteFlags.ImpersonateWinlogon) == 0 && string.Compare(p.ProcessName, "winlogon", true) == 0)
     {
         return(false);
     }
     else if (!ProcessOwnedBySuitableUser(p.Id, execArgs))
     {
         return(false);
     }
     return(true);
 }
Beispiel #3
0
        /// <summary>
        /// Attempts to start the specified interactive process in the current console session (a.k.a. local desktop visible on the computer's monitor) by impersonating the security context of another process that is running in that session.  This method can be called from a background service to start an interactive process.  Returns the process ID of the executed program, or -1 if there was a problem. May also throw an exception.
        /// </summary>
        /// <param name="executablePath">This can be null if the first token in the [commandLine] argument is the executable path.</param>
        /// <param name="commandLine">Sometimes, for unknown reasons, the first argument in this command line can be dropped.  This may be avoided by passing null for [executablePath] and including the executable path as the first token of [commandLine].</param>
        /// <param name="workingDirectory"></param>
        /// <param name="execArgs">Optional arguments to control process selection.</param>
        /// <returns>The process ID of the executed program, or -1 if there was a problem. May also throw an exception.</returns>
        /// <returns></returns>
        public static int ExecuteInteractive(string executablePath, string commandLine, string workingDirectory, ProcessExecuteArgs execArgs = null)
        {
            if (execArgs == null)
            {
                execArgs = ProcessExecuteArgs.Default();
            }
            if (execArgs.requiredSessionID == -1)
            {
                execArgs.requiredSessionID = GetConsoleSessionId();
            }
            if (execArgs.requiredSessionID == -1)
            {
                return(-1);                // No session currently attached to the console.
            }
            // In order to be able to open a process when no user is logged in, we will use an
            // existing process from the active console session as a sort of template.

            int templateProcessId = -1;

            if (templateProcessId == -1 && (execArgs.flags & ProcessExecuteFlags.ImpersonateExplorer) > 0)
            {
                // First, we will try explorer.exe
                // GetProcessesByName uses case-sensitive matching.
                templateProcessId = Process.GetProcessesByName("explorer").FirstOrDefault(p => IsSuitableProcess(p, execArgs))?.Id ?? -1;
                if (templateProcessId != -1)
                {
                    Logger.Info("Will impersonate explorer.exe for session " + execArgs.requiredSessionID);
                }
            }

            if (templateProcessId == -1 && (execArgs.flags & ProcessExecuteFlags.ImpersonateWinlogon) > 0)
            {
                // Next, we will try winlogon.exe, though it is said a process impersonating winlogon is killed by the system after about 10 minutes.
                templateProcessId = Process.GetProcessesByName("winlogon").FirstOrDefault(p => IsSuitableProcess(p, execArgs))?.Id ?? -1;
                if (templateProcessId != -1)
                {
                    Logger.Info("Will impersonate winlogon.exe for session " + execArgs.requiredSessionID);
                }
            }

            if (templateProcessId == -1 && (execArgs.flags & ProcessExecuteFlags.ImpersonateAnyProcess) > 0)
            {
                // If the above scans failed, try any process that meets the other criteria.
                templateProcessId = Process.GetProcesses().FirstOrDefault(p => IsSuitableProcess(p, execArgs))?.Id ?? -1;
                if (templateProcessId != -1)
                {
                    Logger.Info("Will impersonate an arbitrary local system process for session " + execArgs.requiredSessionID);                     // Don't log the process name, as that could potentially reveal private information if a log is shared.
                }
            }

            if (templateProcessId == -1)
            {
                return(-1);                // No process could be found to use as a template.
            }
            // Open Process
            using (AutoDisposeHandle cloneableProcHandle = OpenProcess(templateProcessId))
            {
                // Get token from process
                using (AutoDisposeHandle originalToken = OpenProcessToken(cloneableProcHandle))
                {
                    if (originalToken == null)
                    {
                        return(-1);
                    }

                    // Clone the token
                    using (AutoDisposeHandle duplicatedToken = DuplicateTokenEx(originalToken))
                    {
                        if (duplicatedToken == null)
                        {
                            return(-1);
                        }

                        // Try to start process
                        return(CreateProcessAsUser(executablePath, commandLine, workingDirectory, duplicatedToken));
                    }
                }
            }
        }