繁体   English   中英

当从使用更安全令牌创建的进程调用时,RunAs Verb 不显示 UAC 弹出窗口且不提升

[英]RunAs Verb not showing a UAC popup and not elevating, when invoked from a process created with a Safer token

我想从一个提升的过程开始一个非提升的过程。 我已经使用 SaferComputeTokenFromLevel 完成了这项工作。 它似乎正在工作,因为:

C:\>whoami /groups | findstr BUILTIN\Administrators
BUILTIN\Administrators     Alias    S-1-5-32-544    Group used for deny only

拒绝只是在那里。 所以我不是管理员。

  • 1)为什么(supodsedly)非管理员进程控制台主机窗口在标题中显示为“管理员:”?

我什至使用SetTokenInformation将其设置为中等完整性。 它可以工作但仍然显示为“管理员”,即使它不是管理员。

然后,如果该非管理员进程想要通过ShellExecute使用Verb=RunAs (使用powershell -C Start-Process -Verb RunAs -FilePath CMD.EXE )再次启动提升的进程,则不会出现 UAC 弹出窗口,并且该进程是开始但没有提升,不是管理员。

  • 2)为什么会发生这种情况? (可能是链接令牌?)
  • 3)最后,我如何启动一个非提升的进程,它可以使用RunAs动词来触发 UAC 并成功提升?

完整的 Repro 代码(以管理员身份运行!)

using Microsoft.Win32.SafeHandles;
using System;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.InteropServices;

namespace SaferRepro
{
    class Program
    {
        static void Main(string[] args)
        {
            string appToRun = "CMD.EXE";
            string arguments = String.Empty;
            bool newWindow = true, hidden = false;
            var startupFolder = Environment.CurrentDirectory;
            int mediumIntegrity = 8192;

            using (var newToken = GetTokenFromSaferApi())
            {
                AdjustedTokenIntegrity(newToken, mediumIntegrity); // optional, launch as medium integrity process.
                var process = StartWithToken(newToken, appToRun, arguments, startupFolder, newWindow, hidden);
                GetProcessWaitHandle(process.DangerousGetHandle()).WaitOne();
            }
        }

        private static SafeTokenHandle GetTokenFromSaferApi()
        {
            IntPtr hSaferLevel;
            SafeTokenHandle hToken;

            SaferLevels level = SaferLevels.NormalUser;

            if (!NativeMethods.SaferCreateLevel(SaferScopes.User, level, 1, out hSaferLevel, IntPtr.Zero))
                throw new Win32Exception();

            if (!NativeMethods.SaferComputeTokenFromLevel(hSaferLevel, IntPtr.Zero, out hToken, SaferComputeTokenFlags.None, IntPtr.Zero))
                throw new Win32Exception();

            if (!NativeMethods.SaferCloseLevel(hSaferLevel))
                throw new Win32Exception();

            return hToken;
        }

        private static SafeProcessHandle StartWithToken(SafeTokenHandle newToken, string appToRun, string args, string startupFolder, bool newWindow, bool hidden)
        {
            var si = new STARTUPINFO();

            if (newWindow)
            {
                si.dwFlags = 0x00000001; // STARTF_USESHOWWINDOW
                si.wShowWindow = (short)(hidden ? 0 : 1);
            }

            si.cb = Marshal.SizeOf(si);

            var pi = new PROCESS_INFORMATION();
            uint dwCreationFlags = newWindow ? (uint)0x00000010 /*CREATE_NEW_CONSOLE*/: 0;

            if (!NativeMethods.CreateProcessAsUser(newToken, null, $"{appToRun} {args}",
                IntPtr.Zero, IntPtr.Zero, false, dwCreationFlags, IntPtr.Zero, startupFolder, ref si,
                out pi))
            {
                throw new Win32Exception();
            }

            NativeMethods.CloseHandle(pi.hThread);
            return new SafeProcessHandle(pi.hProcess, true);
        }

        private static bool AdjustedTokenIntegrity(SafeTokenHandle newToken, int integrityLevel)
        {
            string integritySid = "S-1-16-" + (integrityLevel.ToString(CultureInfo.InvariantCulture));
            IntPtr pIntegritySid;
            if (!NativeMethods.ConvertStringSidToSid(integritySid, out pIntegritySid))
                return false;

            TOKEN_MANDATORY_LABEL TIL = new TOKEN_MANDATORY_LABEL();
            TIL.Label.Attributes = 0x00000020 /* SE_GROUP_INTEGRITY */;
            TIL.Label.Sid = pIntegritySid;

            var pTIL = Marshal.AllocHGlobal(Marshal.SizeOf<TOKEN_MANDATORY_LABEL>());
            Marshal.StructureToPtr(TIL, pTIL, false);

            if (!NativeMethods.SetTokenInformation(newToken.DangerousGetHandle(),
               TOKEN_INFORMATION_CLASS.TokenIntegrityLevel,
               pTIL,
               (uint)(Marshal.SizeOf<TOKEN_MANDATORY_LABEL>() + NativeMethods.GetLengthSid(pIntegritySid))))
                return false;

            return true;
        }

        public static System.Threading.AutoResetEvent GetProcessWaitHandle(IntPtr processHandle) =>
            new System.Threading.AutoResetEvent(false)
            {
                SafeWaitHandle = new SafeWaitHandle(processHandle, ownsHandle: false)
            };
    }

    internal class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        internal SafeTokenHandle(IntPtr handle) : base(true)
        {
            base.SetHandle(handle);
        }

        private SafeTokenHandle() : base(true) { }

        protected override bool ReleaseHandle()
        {
            return NativeMethods.CloseHandle(base.handle);
        }
    }

    static class NativeMethods
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        internal static extern bool CloseHandle(IntPtr hObject);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CreateProcessAsUser(
             SafeTokenHandle hToken,
             string applicationName,
             string commandLine,
             IntPtr pProcessAttributes,
             IntPtr pThreadAttributes,
             bool bInheritHandles,
             uint dwCreationFlags,
             IntPtr pEnvironment,
             string currentDirectory,
             ref STARTUPINFO startupInfo,
             out PROCESS_INFORMATION processInformation);

        #region Safer

        [DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool SaferCreateLevel(
            SaferScopes dwScopeId,
            SaferLevels dwLevelId,
            int OpenFlags,
            out IntPtr pLevelHandle,
            IntPtr lpReserved);

        [DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool SaferCloseLevel(
            IntPtr pLevelHandle);

        [DllImport("advapi32", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool SaferComputeTokenFromLevel(
          IntPtr levelHandle,
          IntPtr inAccessToken,
          out SafeTokenHandle outAccessToken,
          SaferComputeTokenFlags dwFlags,
          IntPtr lpReserved
        );

        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool ConvertStringSidToSid(
            string StringSid,
            out IntPtr ptrSid
            );

        [DllImport("advapi32.dll")]
        public static extern int GetLengthSid(IntPtr pSid);

        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern Boolean SetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
            IntPtr TokenInformation, UInt32 TokenInformationLength);
        #endregion
    }

    [Flags]
    public enum SaferLevels : uint
    {
        Disallowed = 0,
        Untrusted = 0x1000,
        Constrained = 0x10000,
        NormalUser = 0x20000,
        FullyTrusted = 0x40000
    }
    [Flags]
    public enum SaferComputeTokenFlags : uint
    {
        None = 0x0,
        NullIfEqual = 0x1,
        CompareOnly = 0x2,
        MakeIntert = 0x4,
        WantFlags = 0x8
    }

    [Flags]
    public enum SaferScopes : uint
    {
        Machine = 1,
        User = 2
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    internal struct STARTUPINFO
    {
        public Int32 cb;
        public string lpReserved;
        public string lpDesktop;
        public string lpTitle;
        public Int32 dwX;
        public Int32 dwY;
        public Int32 dwXSize;
        public Int32 dwYSize;
        public Int32 dwXCountChars;
        public Int32 dwYCountChars;
        public Int32 dwFillAttribute;
        public Int32 dwFlags;
        public Int16 wShowWindow;
        public Int16 cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct PROCESS_INFORMATION
    {
        public IntPtr hProcess;
        public IntPtr hThread;
        public int dwProcessId;
        public int dwThreadId;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct TOKEN_MANDATORY_LABEL
    {

        public SID_AND_ATTRIBUTES Label;

    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SID_AND_ATTRIBUTES
    {
        public IntPtr Sid;
        public uint Attributes;
    }

    // Integrity Levels
    public enum TOKEN_INFORMATION_CLASS
    {
        TokenUser = 1, TokenGroups, TokenPrivileges, TokenOwner, TokenPrimaryGroup, TokenDefaultDacl, TokenSource, TokenType, TokenImpersonationLevel, TokenStatistics, TokenRestrictedSids, TokenSessionId, TokenGroupsAndPrivileges, TokenSessionReference, TokenSandBoxInert, TokenAuditPolicy, TokenOrigin, TokenElevationType, TokenLinkedToken, TokenElevation, TokenHasRestrictions, TokenAccessInformation, TokenVirtualizationAllowed, TokenVirtualizationEnabled, TokenIntegrityLevel, TokenUIAccess, TokenMandatoryPolicy, TokenLogonSid, MaxTokenInfoClass
    }
}

当您的令牌被提升时,似乎无法更改它以取消标记它的elevated标志状态。 您可以从本地管理员中删除成员资格(实际上将其设置为仅拒绝),或将完整性设置为中,但它仍将被标记为提升(即使没有管理员权限)。 设置此标志后,RunAs Verb 不会提升。

您的选择是:

  • 获取explorer.exe令牌并假设它没有提升。 (如果 UAC 被禁用或用户 .

  • 如果启用了 UAC,提升的令牌有一个指向未提升的令牌的链接,您可以使用GetTokenInformationTOKEN_INFORMATION_CLASS.TokenLinkedToken获取该链接。

  • 如果 UAC 被禁用,则没有链接令牌。 我的问题并不真正适用,因为 UAC 弹出窗口被禁用,永远不会显示。 仅供参考,您可以使用 SaferApi 创建一个设置了提升标志的非管理员令牌,但它的 RunAs 尝试将失败。

如果你想看看我是如何编码的,请检查我正在处理的gsudo (Windows 的 sudo):

https://github.com/gerardog/gsudo/blob/dev/src/gsudo/Tokens/TokenManager.cs https://github.com/gerardog/gsudo/blob/dev/src/gsudo/Helpers/ProcessFactory.cs #L182

或查看其他很棒的答案

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM