使用提升的权限创建用户进程

6
我的服务正在以本地系统权限运行,并且需要在用户会话中以管理员权限启动应用程序。
我得到的方法如下:
1. 使用WTSGetActiveConsoleSessionID()获取当前活动的控制台会话ID。 2. 使用WTSQueryUserToken为会话ID获取用户令牌。 3. 使用CreateProcessAsUser启动进程。
然而,问题是我需要以管理员身份运行步骤3的进程,但不需要要求用户提供管理员密码。
在Linux系统上,我可以简单地使用“su”命令,但在Windows系统上该怎么做呢?

也许你不理解su的作用,但是在某一时刻,如果没有提供凭据,它是不能用来获取root权限的。接下来,如果登录用户不是管理员,你打算怎么做呢? - David Heffernan
你的想法是反过来的。像其他应用程序一样启动该应用程序,并让它与您的服务通信,如果应用程序需要请求用户没有足够权限执行的操作。不要浪费时间实现一个精心设计的安全漏洞。 - IInspectable
如果用户不是管理员,调用CreateProcessAsUser并传递一个非管理员用户的令牌会有什么帮助呢?我认为您并没有完全理解Windows安全模型。 - David Heffernan
该服务需要调用仅在用户会话中定义的方法。我不太理解这是什么意思。方法并不属于会话,至少根据我所知道的方法和会话的任何定义来看都不是如此。我认为您需要直面一个事实,即管理任务需要具有管理员权限的用户。 - David Heffernan
可能是在标准用户登录时启动管理员交互进程的重复问题。 - Harry Johnston
显示剩余5条评论
2个回答

3
我终于找到了解决方案来管理这个问题:
public void launchProcessInUserSession(String process) throws WindowsAPIException {

        final DWORD interactiveSessionId = kernel32.WTSGetActiveConsoleSessionId();
        final DWORD serviceSessionId = getCurrentSessionId();

        final HANDLEByReference pExecutionToken = new HANDLEByReference();

        final HANDLE currentProcessToken = getCurrentProcessToken();
        try {

            final HANDLE interactiveUserToken = getUserToken(interactiveSessionId);

            checkAPIError(advapi32.DuplicateTokenEx(currentProcessToken, WinNT.TOKEN_ALL_ACCESS, null, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
                    WinNT.TOKEN_TYPE.TokenPrimary, pExecutionToken));
        } finally {
            kernel32.CloseHandle(currentProcessToken);
        }

        final HANDLE executionToken = pExecutionToken.getValue();
        try {
            checkAPIError(advapi32.SetTokenInformation(executionToken, TOKEN_INFORMATION_CLASS.TokenSessionId, new IntByReference(interactiveSessionId.intValue()), DWORD.SIZE));

            final WinBase.STARTUPINFO si = new WinBase.STARTUPINFO();
            final PROCESS_INFORMATION processInfo = new WinBase.PROCESS_INFORMATION();
            final int dwFlags = WinBase.DETACHED_PROCESS;

            checkAPIError(advapi32.CreateProcessAsUser(executionToken, null, process, null, null, false, dwFlags, null, null, si, processInfo));
            LOGGER.debug("Execution done. Process ID is {}", processInfo.dwProcessId);
        } finally {
            kernel32.CloseHandle(executionToken);
        }
    }

你为什么创建了“interactiveUserToken”? - anangupadhyaya
无法从服务进程中调用工作。使用shellexecute runas可以运行,但需要询问UAC,并且无法将控制台重定向到原始进程。 - bronze man
无法从服务进程中调用工作。使用shellexecute runas可以工作,但需要询问UAC,并且无法将控制台重定向到原始进程。 - undefined

1
我需要以管理员身份运行进程(步骤3),而不要求用户输入管理员密码。如果低权限用户能够执行高权限用户的代码,那么系统的安全模型将被破坏。如果您想使用管理员权限执行代码,则需要在某个时候提供适当的凭据。您提出的行动计划涉及调用CreateProcessAsUser并传递低权限用户的用户令牌。根据问题中列出的计划,此计划无法成功。由于您提供的用户令牌是低权限用户的令牌,因此该进程将无法执行管理任务。您需要以某种方式提供具有管理权限的用户凭据。

既然我们正在谈论服务,我需要为管理帐户获取一个令牌。怎么做? - gorootde
为什么不将您的服务配置为在管理员用户帐户下运行? - David Heffernan
2
你们缺乏经验,认为主题作者提出了愚蠢的问题。他想要的一切都是合法和可能的。 假设我创建了一个通用的应用程序更新程序(系统服务),它监视已安装的公司应用程序并更新它们、更新服务和应用程序。更新后,我需要以当前登录的用户身份重新运行应用程序,这可能是系统中的任何一个用户。此外,许多应用程序可能需要提升的权限。因此,作为系统,我应该能够做任何事情,因此创建进程作为活动用户但具有提升的权限。 - Tommix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接