// ReSharper disable once TooManyArguments internal static extern bool AdjustTokenPrivileges( [In] SafeNativeHandle tokenHandle, [In] bool disableAllPrivileges, [In] ref TokenPrivileges newState, [In] uint bufferLength, IntPtr previousState, IntPtr returnLength );
// ReSharper disable once TooManyArguments public static extern bool DuplicateTokenEx( [In] SafeNativeHandle hExistingToken, [In] TokenAccessLevels dwDesiredAccess, [In] IntPtr lpTokenAttributes, [In] TokenImpersonationLevel impersonationLevel, [In] TokenType tokenType, [Out] out SafeNativeHandle newToken );
public static extern bool CreateProcessWithTokenW( SafeNativeHandle hToken, LogonFlags dwLogonFlags, [MarshalAs(UnmanagedType.LPWStr)] string lpApplicationName, StringBuilder lpCommandLine, Process.NativeHelpers.ProcessCreationFlags dwCreationFlags, Process.SafeMemoryBuffer lpEnvironment, [MarshalAs(UnmanagedType.LPWStr)] string lpCurrentDirectory, Process.NativeHelpers.STARTUPINFOEX lpStartupInfo, out Process.NativeHelpers.PROCESS_INFORMATION lpProcessInformation);
public static extern bool CreateProcessWithTokenW( SafeNativeHandle token, LogonFlags logonFlags, [MarshalAs(UnmanagedType.LPWStr)] string applicationName, [MarshalAs(UnmanagedType.LPWStr)] string commandLine, ProcessCreationFlags creationFlags, IntPtr environment, [MarshalAs(UnmanagedType.LPWStr)] string currentDirectory, [In] ref StartupInfo startupInfo, out ProcessInformation processInformation);
public static extern bool CreateProcessAsUserW( SafeNativeHandle token, [MarshalAs(UnmanagedType.LPWStr)] string applicationName, [MarshalAs(UnmanagedType.LPWStr)] string commandLine, IntPtr processAttributes, IntPtr threadAttributes, bool inheritHandles, ProcessCreationFlags creationFlags, IntPtr environment, [MarshalAs(UnmanagedType.LPWStr)] string currentDirectory, [In] ref StartupInfo startupInfo, out ProcessInformation processInformation);
public static extern UInt32 LsaLogonUser( SafeLsaHandle LsaHandle, NativeHelpers.LSA_STRING OriginName, LogonType LogonType, UInt32 AuthenticationPackage, IntPtr AuthenticationInformation, UInt32 AuthenticationInformationLength, IntPtr LocalGroups, NativeHelpers.TOKEN_SOURCE SourceContext, out SafeLsaMemoryBuffer ProfileBuffer, out UInt32 ProfileBufferLength, out Luid LogonId, out SafeNativeHandle Token, out IntPtr Quotas, out UInt32 SubStatus);
private static NativeHelpers.SECURITY_LOGON_TYPE GetTokenLogonType(SafeNativeHandle hToken) { TokenStatistics stats = TokenUtil.GetTokenStatistics(hToken); SafeLsaMemoryBuffer sessionDataPtr; UInt32 res = NativeMethods.LsaGetLogonSessionData(ref stats.AuthenticationId, out sessionDataPtr); if (res != 0) { // Default to Network, if we weren't able to get the actual type treat it as an error and assume // we don't want to run a process with the token return(NativeHelpers.SECURITY_LOGON_TYPE.Network); } using (sessionDataPtr) { NativeHelpers.SECURITY_LOGON_SESSION_DATA sessionData = (NativeHelpers.SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure( sessionDataPtr.DangerousGetHandle(), typeof(NativeHelpers.SECURITY_LOGON_SESSION_DATA)); return(sessionData.LogonType); } }
private static SafeNativeHandle GetElevatedToken(SafeNativeHandle hToken) { TokenElevationType tet = TokenUtil.GetTokenElevationType(hToken); // We already have the best token we can get, no linked token is really available. if (tet != TokenElevationType.Limited) { return(null); } SafeNativeHandle linkedToken = TokenUtil.GetTokenLinkedToken(hToken); TokenStatistics tokenStats = TokenUtil.GetTokenStatistics(linkedToken); // We can only use a token if it's a primary one (we had the SeTcbPrivilege set) if (tokenStats.TokenType == TokenType.Primary) { return(linkedToken); } else { return(null); } }
/// <summary> /// Starts a new <see cref="Process" /> with the start info provided and with the same rights as the mentioned /// <see cref="Process" /> /// </summary> /// <param name="process">The <see cref="Process" /> to copy rights from</param> /// <param name="startInfo">Contains the information about the <see cref="Process" /> to be started</param> /// <returns>Returns the newly started <see cref="Process" /></returns> /// <exception cref="InvalidOperationException">This method needs administrative access rights.-or-UAC is not enable</exception> /// <exception cref="NotSupportedException">Current version of Windows does not meets the needs of this method</exception> public static Process StartAndCopyProcessPermission(Process process, ProcessStartInfo startInfo) { if (!string.IsNullOrWhiteSpace(startInfo.UserName)) { throw new InvalidOperationException(Resources.Error_StartWithUsername); } if (!IsElevated) { throw new InvalidOperationException(Resources.Error_AccessDenied); } Tokens.EnablePrivilegeOnProcess(Process.GetCurrentProcess(), SecurityEntities.SeImpersonatePrivilege); using (var primaryToken = Tokens.DuplicatePrimaryToken(process)) { var lockTaken = false; try { Monitor.Enter(startInfo, ref lockTaken); var unicode = Environment.OSVersion.Platform == PlatformID.Win32NT; var creationFlags = startInfo.CreateNoWindow ? ProcessCreationFlags.CreateNoWindow : ProcessCreationFlags.None; if (unicode) { creationFlags |= ProcessCreationFlags.UnicodeEnvironment; } var commandLine = IOPath.BuildCommandLine(startInfo.FileName, startInfo.Arguments); var workingDirectory = string.IsNullOrEmpty(startInfo.WorkingDirectory) ? Environment.CurrentDirectory : startInfo.WorkingDirectory; var startupInfo = StartupInfo.GetOne(); var gcHandle = new GCHandle(); try { gcHandle = GCHandle.Alloc( IOPath.EnvironmentBlockToByteArray(startInfo.EnvironmentVariables, unicode), GCHandleType.Pinned); var environmentPtr = gcHandle.AddrOfPinnedObject(); var logonFlags = startInfo.LoadUserProfile ? LogonFlags.LogonWithProfile : LogonFlags.None; ProcessInformation processInfo; bool processCreationResult; if (IsUACSupported) // Vista + { processCreationResult = AdvancedAPI.CreateProcessWithTokenW(primaryToken, logonFlags, null, commandLine, creationFlags, environmentPtr, workingDirectory, ref startupInfo, out processInfo); } else { Tokens.EnablePrivilegeOnProcess(Process.GetCurrentProcess(), SecurityEntities.SeIncreaseQuotaPrivilege); processCreationResult = AdvancedAPI.CreateProcessAsUserW(primaryToken, null, commandLine, IntPtr.Zero, IntPtr.Zero, false, creationFlags, environmentPtr, workingDirectory, ref startupInfo, out processInfo); } if (!processCreationResult) { throw new Win32Exception(); } SafeNativeHandle.CloseHandle(processInfo.Thread); SafeNativeHandle.CloseHandle(processInfo.Process); if (processInfo.ProcessId <= 0) { throw new InvalidOperationException(Resources.Error_Unknown); } return(Process.GetProcessById(processInfo.ProcessId)); } catch (EntryPointNotFoundException) { throw new NotSupportedException(); } finally { if (gcHandle.IsAllocated) { gcHandle.Free(); } } } finally { if (lockTaken) { Monitor.Exit(startInfo); } } } }
private static SafeNativeHandle GetPrimaryTokenForUser(SecurityIdentifier sid, List <string> requiredPrivileges = null, bool mostPrivileges = false) { // According to CreateProcessWithTokenW we require a token with // TOKEN_QUERY, TOKEN_DUPLICATE and TOKEN_ASSIGN_PRIMARY // Also add in TOKEN_IMPERSONATE so we can get an impersonated token TokenAccessLevels dwAccess = TokenAccessLevels.Query | TokenAccessLevels.Duplicate | TokenAccessLevels.AssignPrimary | TokenAccessLevels.Impersonate; SafeNativeHandle userToken = null; int privilegeCount = 0; foreach (SafeNativeHandle hToken in TokenUtil.EnumerateUserTokens(sid, dwAccess)) { // Filter out any Network logon tokens, using become with that is useless when S4U // can give us a Batch logon NativeHelpers.SECURITY_LOGON_TYPE tokenLogonType = GetTokenLogonType(hToken); if (tokenLogonType == NativeHelpers.SECURITY_LOGON_TYPE.Network) { continue; } List <string> actualPrivileges = TokenUtil.GetTokenPrivileges(hToken).Select(x => x.Name).ToList(); // If the token has less or the same number of privileges than the current token, skip it. if (mostPrivileges && privilegeCount >= actualPrivileges.Count) { continue; } // Check that the required privileges are on the token if (requiredPrivileges != null) { int missing = requiredPrivileges.Where(x => !actualPrivileges.Contains(x)).Count(); if (missing > 0) { continue; } } // Duplicate the token to convert it to a primary token with the access level required. try { userToken = TokenUtil.DuplicateToken(hToken, TokenAccessLevels.MaximumAllowed, SecurityImpersonationLevel.Anonymous, TokenType.Primary); privilegeCount = actualPrivileges.Count; } catch (Process.Win32Exception) { continue; } // If we don't care about getting the token with the most privileges, escape the loop as we already // have a token. if (!mostPrivileges) { break; } } return(userToken); }
private static List <SafeNativeHandle> GetUserTokens(string username, string password, LogonType logonType) { List <SafeNativeHandle> userTokens = new List <SafeNativeHandle>(); SafeNativeHandle systemToken = null; bool impersonated = false; string becomeSid = username; if (logonType != LogonType.NewCredentials) { // If prefixed with .\, we are becoming a local account, strip the prefix if (username.StartsWith(".\\")) { username = username.Substring(2); } NTAccount account = new NTAccount(username); becomeSid = ((SecurityIdentifier)account.Translate(typeof(SecurityIdentifier))).Value; // Grant access to the current Windows Station and Desktop to the become user GrantAccessToWindowStationAndDesktop(account); // Try and impersonate a SYSTEM token, we need a SYSTEM token to either become a well known service // account or have administrative rights on the become access token. // If we ultimately are becoming the SYSTEM account we want the token with the most privileges available. // https://github.com/assible/assible/issues/71453 bool mostPrivileges = becomeSid == "S-1-5-18"; systemToken = GetPrimaryTokenForUser(new SecurityIdentifier("S-1-5-18"), new List <string>() { "SeTcbPrivilege" }, mostPrivileges); if (systemToken != null) { try { TokenUtil.ImpersonateToken(systemToken); impersonated = true; } catch (Process.Win32Exception) { } // We tried, just rely on current user's permissions. } } // We require impersonation if becoming a service sid or becoming a user without a password if (!impersonated && (SERVICE_SIDS.Contains(becomeSid) || String.IsNullOrEmpty(password))) { throw new Exception("Failed to get token for NT AUTHORITY\\SYSTEM required for become as a service account or an account without a password"); } try { if (becomeSid == "S-1-5-18") { userTokens.Add(systemToken); } // Cannot use String.IsEmptyOrNull() as an empty string is an account that doesn't have a pass. // We only use S4U if no password was defined or it was null else if (!SERVICE_SIDS.Contains(becomeSid) && password == null && logonType != LogonType.NewCredentials) { // If no password was specified, try and duplicate an existing token for that user or use S4U to // generate one without network credentials SecurityIdentifier sid = new SecurityIdentifier(becomeSid); SafeNativeHandle becomeToken = GetPrimaryTokenForUser(sid); if (becomeToken != null) { userTokens.Add(GetElevatedToken(becomeToken)); userTokens.Add(becomeToken); } else { becomeToken = GetS4UTokenForUser(sid, logonType); userTokens.Add(null); userTokens.Add(becomeToken); } } else { string domain = null; switch (becomeSid) { case "S-1-5-19": logonType = LogonType.Service; domain = "NT AUTHORITY"; username = "******"; break; case "S-1-5-20": logonType = LogonType.Service; domain = "NT AUTHORITY"; username = "******"; break; default: // Trying to become a local or domain account if (username.Contains(@"\")) { string[] userSplit = username.Split(new char[1] { '\\' }, 2); domain = userSplit[0]; username = userSplit[1]; } else if (!username.Contains("@")) { domain = "."; } break; } SafeNativeHandle hToken = TokenUtil.LogonUser(username, domain, password, logonType, LogonProvider.Default); // Get the elevated token for a local/domain accounts only if (!SERVICE_SIDS.Contains(becomeSid)) { userTokens.Add(GetElevatedToken(hToken)); } userTokens.Add(hToken); } } finally { if (impersonated) { TokenUtil.RevertToSelf(); } } return(userTokens); }
public static extern bool OpenProcessToken( IntPtr processHandle, TokenAccessLevels desiredAccess, out SafeNativeHandle tokenHandle );