处理从域用户启动过程启动为域管理员,并在域网络中激活UAC

时间:2013-11-12 11:39:27

标签: .net windows uac process.start elevated-privileges

我正在尝试做一些事情,现在在我的头撞到屏幕之后,我不确定是否可以做到。

方案如下:

  • 具有域控制器的Windows网络,其中PC的普通用户没有管理权限。
  • 一个程序,当它在网络共享(UNC路径)中找到更新(MSI)时,将运行更新。
  • 因为用户无法进行安装。必须与具有管理员权限的其他用户一起运行更新。

理论合理但是:

  • 仅当admin用户是给定PC中的本地管理员时才有效。我无法使其在PC中没有本地帐户的域管理员工作。

我尝试过:

  • 使用来自advapi32.dll LogonUser的令牌进行用户模拟。
  • 进程 - > Start()安装,提供域管理员用户凭据。
  • 进程 - > Start()使用域管理员进行广告,然后使用普通用户进行Process-> start()安装。

如上所述,如果管理员用户在PC中有本地帐户,它将起作用。但是,如果我使用域管理员,PC将提示UAC屏幕询问有效的管理员凭据。

如果我检查任务管理器,则使用给定的凭据启动该过程。它只是没有安装权。

我可以在这里尝试吗?如果没有,任何方式?

问题是网络是从域管理的,而PC并不一定在本地创建管理员用户帐户。

1 个答案:

答案 0 :(得分:1)

  

如上所述,如果管理员用户在PC中有本地帐户,它将起作用。但是,如果我使用域管理员,PC将提示UAC屏幕询问有效的管理员凭据。

你想要发生什么?为了冒充用户,您必须知道他们的密码。

用户需要以任何方式知道域管理员的密码,因此他们将其输入“同意”对话框,然后安装即可继续。

您是否正在设想一个系统,其中应用程序可以作为管理员运行,而无需任何人输入域管理凭据?这根本不允许。


  

我可以在这里尝试吗?

我不确定你想要在这里发生什么。这就是为什么我在问你究竟想要发生什么。

我感觉您想要将进程作为具有管理权限的帐户启动;所以这个单独的过程可以执行更新。我收集的问题是登录用户不是管理员。

  

我无法使用在PC中没有本地帐户的域管理员。

在使用域管理员时,您特别想要做什么工作?什么,正是你想看到发生的事吗?您是否认为通过代码,您可以在没有出现UAC提示的情况下以域用户身份启动提升的流程?那不会发生。

但有可能

所有这一切,你所描述的是可能的。作为Chris Jackson noted in a blog entry,诀窍是:

  1. 使用CreateProcessWithLogonW
  2. 以域管理员身份启动程序
  3. 从该应用程序中,将ShellExecuterunas动词一起使用以提升为管理员
  4. 执行更新
  5. 我用一个快速的Delphi应用程序模拟它。

    最初,测试应用程序作为标准用户运行(名为 Forest Gump )。我发现他不是管理员,并在更新软件按钮上显示UAC屏蔽:

    enter image description here

    单击该按钮会导致软件启动自身副本,但使用域管理员帐户的凭据(我, Ian )。这是使用CreateProcessWithLogonW

    完成的
    if IsUserAdmin then
    begin
        //No need for hoops, we're already an admin. Do the update.
        PerformUpdate();
        Exit;
    end;
    
    //Relaunch ourselves as a particular domain admin user.
    username := 'ian@redacted.com';
    password := 'correct battery horse staple';
    applicationName := ParamStr(0);
    commandLine := applicationName+' /performUpdates';
    
    ZeroMemory(@si, SizeOf(si));
    si.cb := SizeOf(si);
    
    CreateProcessWithLogonW(PWideChar(username), nil, PWideChar(password), 0, PWideChar(applicationName), PWideChar(commandLine), 0, nil, nil, si, {var} pi)
    

    诀窍是我们传递了/performUpdates选项。当我们的应用启动时,它会检测是否指示他们执行更新。如果是这样,我们会使用ShellExecuterunas动词来启动我们自己的提升副本:

    procedure TForm1.FormActivate(Sender: TObject);
    begin
        if FindCmdLineSwitch('performUpdates', True) then
        begin
            //If we're not an admin, then use ShellExecute to launch ourselves as one
            if not IsUserAdmin then
            begin
                //Relaunch ourselves as an admin
                Toolkit.RunAsAdmin(0, ParamStr(0), '/performUpdates'); //don't forget to pass the command option
                Application.Terminate;
                Exit;
            end;
    
            //We are an admin; do the updates.
            PerformUpdates;
            MessageDlg('Update complete.', mtINformation, [mbOk], 0);
    
            Application.Terminate;
            Exit;
        end;
    end;
    

    带有ShellExecute谓词的runas触发UAC提升提示,然后以我身份运行的提升应用( Ian ),出现具有管理员权限的其他管理员用户:

    enter image description here

    RunAsAdmin函数是ShellExecute的简单包装:

    function RunAsAdmin(hWnd: HWND; filename: string; Parameters: string): Boolean;
    {
        See Step 3: Redesign for UAC Compatibility (UAC)
        http://msdn.microsoft.com/en-us/library/bb756922.aspx
    }
    var
        sei: TShellExecuteInfo;
    begin
        ZeroMemory(@sei, SizeOf(sei));
        sei.cbSize := SizeOf(TShellExecuteInfo);
        sei.Wnd := hwnd;
        sei.fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI;
        sei.lpVerb := PChar('runas');
        sei.lpFile := PChar(Filename); // PAnsiChar;
        if parameters <> '' then
            sei.lpParameters := PChar(parameters); // PAnsiChar;
        sei.nShow := SW_SHOWNORMAL; //Integer;
    
        Result := ShellExecuteEx(@sei);
    end;
    

    语法稍微容易一些,但 UseShellExecute Verb =&#34; runas&#34; 是关键点。

    .NET中的函数 IsUserAdmin 更容易:

    //helper function that tells us if we're already running with administrative rights
    private Boolean IsUserAnAdmin()
    {
        //A user can be a member of the Administrator group, but not an administrator.
        //Conversely, the user can be an administrator and not a member of the administrators group.
    
        //Check if the current user has administrative privelages
        var identity = WindowsIdentity.GetCurrent();
        return (null != identity && new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator));
    }
    

    比本机代码:

    function IsUserAdmin: Boolean;
    var
        b: BOOL;
        AdministratorsGroup: PSID;
    begin
        {
            This function returns true if you are currently running with admin privelages.
            In Vista and later, if you are non-elevated, this function will return false (you are not running with administrative privelages).
            If you *are* running elevated, then IsUserAdmin will return true, as you are running with admin privelages.
    
            Windows provides this similar function in Shell32.IsUserAnAdmin. But the function is depricated, and this code is lifted
            from the docs for CheckTokenMembership: http://msdn.microsoft.com/en-us/library/aa376389.aspx
        }
    
        {
            Routine Description: This routine returns TRUE if the callers
            process is a member of the Administrators local group. Caller is NOT
            expected to be impersonating anyone and is expected to be able to
            open its own process and process token.
            Arguments: None.
            Return Value:
                TRUE - Caller has Administrators local group.
                FALSE - Caller does not have Administrators local group.
        }
        b := AllocateAndInitializeSid(
                SECURITY_NT_AUTHORITY,
                2, //2 sub-authorities
                SECURITY_BUILTIN_DOMAIN_RID,    //sub-authority 0
                DOMAIN_ALIAS_RID_ADMINS,        //sub-authority 1
                0, 0, 0, 0, 0, 0,               //sub-authorities 2-7 not passed
                AdministratorsGroup);
        if (b) then
        begin
            if not CheckTokenMembership(0, AdministratorsGroup, b) then
                b := False;
            FreeSid(AdministratorsGroup);
        end;
    
        Result := b;
    end;
    

    所以,一切正常,并做你需要的。但是仍然会向用户显示UAC 同意对话框;虽然他们只需要继续。我认为这对你来说并不合适。即使它是:

    不要这样做

    上述代码中的关键问题,Chris Jackon在他的博客中提及:

      

    最常见的请求是编写本土软件部署软件的人,他们希望将凭据编码到应用程序中并提升自己的流程。这里真正的问题不在于缺少API,而是 您在应用中编码了管理员凭据,供全世界阅读 。如果你有这个,你想要的是一种方法,以尽可能快地到达你没有那个的地方,而不是更容易建立在该设计上。

    可怕的,可怕的,有问题的代码是:

    //Relaunch ourselves as a particular domain admin user.
    username := 'ian@redacted.com';
    password := 'correct battery horse staple';
    

    您已对用户的密码进行了硬编码。那不好。你不想要那个。

    想要 管理员实际上需要走到机器并输入他的凭据。

    更简单的选项

    您处于允许 任何用户 更新应用程序的世界中。如果是这样,如果允许所有用户修改文件和注册表项,那么让他们

    在应用程序安装期间,更改应用程序文件夹的NTFS权限,以便所有用户具有完全控制

    enter image description here

    这是解决您问题的正确的解决方案。

    即使以上都没有回答你的问题。

    你想看到什么?

    现在我们来了。你想看到什么?

      

    注意:任何代码都会发布到公共域中。无需归属。