public Task <int> Start() { try { var t1 = new StreamReader(_connection.ControlStream).ConsumeOutput(HandleControlStream); WaitHandle.WaitAny(new WaitHandle[] { tokenSwitchSuccessEvent.WaitHandle, _process.GetProcessWaitHandle(), _connection.DisconnectedWaitHandle }); if (!tokenSwitchSuccessEvent.IsSet) { Logger.Instance.Log( _connection?.IsAlive ?? true ? $"Failed to substitute token." : $"Failed to substitute token. Connection from server lost." , LogLevel.Error); TerminateProcess(); return(Task.FromResult(Constants.GSUDO_ERROR_EXITCODE)); } Logger.Instance.Log("Process token successfully substituted.", LogLevel.Debug); _ = _connection.FlushAndCloseAll(); return(GetResult()); } finally { ConsoleApi.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, false); } }
private static SafeProcessHandle CreateProcessWithToken(IntPtr newToken, string appToRun, string args, string startupFolder, bool hidden) { var STARTF_USESHOWWINDOW = 0x00000001; var STARTF_USESTDHANDLES = 0x00000100; var startupInfo = new STARTUPINFO() { cb = (int)Marshal.SizeOf(typeof(STARTUPINFO)), dwFlags = STARTF_USESHOWWINDOW, wShowWindow = (short)(hidden ? 0 : 1), }; if (Console.IsErrorRedirected | Console.IsInputRedirected | Console.IsOutputRedirected) { startupInfo.dwFlags |= STARTF_USESTDHANDLES; startupInfo.hStdOutput = ConsoleApi.GetStdHandle(ConsoleApi.STD_OUTPUT_HANDLE); startupInfo.hStdInput = ConsoleApi.GetStdHandle(ConsoleApi.STD_INPUT_HANDLE); startupInfo.hStdError = ConsoleApi.GetStdHandle(ConsoleApi.STD_ERROR_HANDLE); } PROCESS_INFORMATION processInformation; if (!CreateProcessWithTokenW(newToken, 0, null, $"{appToRun} {args}", (UInt32)0, IntPtr.Zero, startupFolder, ref startupInfo, out processInformation)) { throw new Win32Exception(); } return(new SafeProcessHandle(processInformation.hProcess, true)); }
public TokenSwitchRenderer(Connection connection, ElevationRequest elevationRequest) { if (Settings.SecurityEnforceUacIsolation && !elevationRequest.NewWindow) { throw new Exception("TokenSwitch mode not supported when SecurityEnforceUacIsolation is set."); } _connection = connection; _elevationRequest = elevationRequest; Environment.SetEnvironmentVariable("prompt", Environment.ExpandEnvironmentVariables(elevationRequest.Prompt)); ProcessApi.CreateProcessFlags dwCreationFlags = ProcessApi.CreateProcessFlags.CREATE_SUSPENDED; if (elevationRequest.NewWindow) { dwCreationFlags |= ProcessApi.CreateProcessFlags.CREATE_NEW_CONSOLE; } string exeName, args; if (elevationRequest.IntegrityLevel == IntegrityLevel.MediumPlus && ArgumentsHelper.UnQuote(elevationRequest.FileName.ToUpperInvariant()) != Environment.GetEnvironmentVariable("COMSPEC").ToUpperInvariant()) { // Now, we have an issue with this method: The process launched with the new token throws Access Denied if it tries to read its own token. // Kind of dirty workaround is to wrap the call with a "CMD.exe /c ".. this intermediate process will then // launching the command with a fresh new (desired) token and we know cmd wont try to read it's substitute token (throwing Access Denied). exeName = Environment.GetEnvironmentVariable("COMSPEC"); args = $"/s /c \"{elevationRequest.FileName} {elevationRequest.Arguments}\""; } else { // Hack not needed if we are already calling CMD exeName = elevationRequest.FileName; args = elevationRequest.Arguments; } _process = ProcessFactory.CreateProcessAsUserWithFlags(exeName, args, dwCreationFlags, out _processInformation); elevationRequest.TargetProcessId = _processInformation.dwProcessId; if (!elevationRequest.NewWindow) { ConsoleApi.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, true); } }
private static uint[] GetConsoleAttachedPids(uint[] processIds) { var num = ConsoleApi.GetConsoleProcessList(processIds, 1); if (num == 0) { throw new System.ComponentModel.Win32Exception(); } processIds = new UInt32[num]; num = ConsoleApi.GetConsoleProcessList(processIds, (uint)processIds.Length); if (num == 0) { throw new System.ComponentModel.Win32Exception(); } return(processIds); }
/// <summary> /// Shows or hides the Console window. /// </summary> /// <param name="show">true to show; false to hide</param> public static void ShowWindow(bool show = true) { const int SW_HIDE = 0; const int SW_SHOW = 5; var handle = ConsoleApi.GetConsoleWindow(); if (handle == IntPtr.Zero && show) { ConsoleApi.AllocConsole(); handle = ConsoleApi.GetConsoleWindow(); } if (handle == IntPtr.Zero) { throw new InvalidOperationException("No console window available!"); } ConsoleApi.ShowWindow(handle, show ? SW_SHOW : SW_HIDE); }
public bool TryBreak() { bool tmpResult = false; try { tmpResult = ConsoleApi.GenerateConsoleCtrlEvent(0, (uint)this.process.Handle.ToInt32()); if (!tmpResult) { int tmpError = Marshal.GetLastWin32Error(); } } catch (Exception ex) { SimpleFileLogger.Instance.LogError("Unable to break the process", ex); } return(tmpResult); }
public Task <int> GetResult() { try { _ = ProcessApi.ResumeThread(_processInformation.hThread); if (_elevationRequest.Wait) { _process.GetProcessWaitHandle().WaitOne(); if (ProcessApi.GetExitCodeProcess(_process, out int exitCode)) { return(Task.FromResult(exitCode)); } } return(Task.FromResult(0)); } finally { ConsoleApi.SetConsoleCtrlHandler(ConsoleHelper.IgnoreConsoleCancelKeyPress, false); } }
internal static SafeProcessHandle CreateProcessAsUserWithFlags(string lpApplicationName, string args, ProcessApi.CreateProcessFlags dwCreationFlags, out PROCESS_INFORMATION pInfo) { var sInfoEx = new ProcessApi.STARTUPINFOEX(); sInfoEx.StartupInfo.cb = Marshal.SizeOf(sInfoEx); IntPtr lpValue = IntPtr.Zero; var pSec = new ProcessApi.SECURITY_ATTRIBUTES(); var tSec = new ProcessApi.SECURITY_ATTRIBUTES(); pSec.nLength = Marshal.SizeOf(pSec); tSec.nLength = Marshal.SizeOf(tSec); var command = $"{lpApplicationName} {args}"; Logger.Instance.Log($"{nameof(CreateProcessAsUser)}: {lpApplicationName} {args}", LogLevel.Debug); if (!ProcessApi.CreateProcess(null, command, ref pSec, ref tSec, false, dwCreationFlags, IntPtr.Zero, null, ref sInfoEx, out pInfo)) { throw new Win32Exception((int)ConsoleApi.GetLastError()); } return(new SafeProcessHandle(pInfo.hProcess, true)); }
internal static TokenProvider CreateUnelevated(IntegrityLevel level) { if (ProcessHelper.IsAdministrator()) { // Have you impersonated system first? if (!WindowsIdentity.GetCurrent().IsSystem) { try { return(TokenProvider .CreateFromSystemAccount() .EnablePrivilege(Privilege.SeAssignPrimaryTokenPrivilege, true) .Impersonate(() => { return CreateFromCurrentProcessToken().GetLinkedToken().Duplicate() .SetIntegrity(level); })); } catch (Exception e) { Logger.Instance.Log("Unable to get unelevated token, will try SaferApi Token. " + e.ToString(), LogLevel.Warning); return(TokenProvider.CreateFromSaferApi(SaferLevels.NormalUser)); } } else { IntPtr hwnd = ConsoleApi.GetShellWindow(); _ = ConsoleApi.GetWindowThreadProcessId(hwnd, out uint pid); return(TokenProvider.CreateFromProcessToken((int)pid)); } } else { return(TokenProvider.CreateFromCurrentProcessToken()); } }
void OnMessageReceived(byte[] RawMessage) { try { string Message = Encoding.Unicode.GetString(RawMessage); XElement xMsg = XElement.Parse(Message, LoadOptions.PreserveWhitespace); if (xMsg.Name.LocalName == "Connect-Terminal") { try { string Domain = xMsg.Attribute("Domain").Value; string UserName = xMsg.Attribute("UserName").Value; string Password = xMsg.Attribute("Password").Value; lock (ProcessLock) { // Remove any processes which have exited so that instead of reattaching we launch a new one... List <string> ToRemove = new List <string>(); foreach (var kvp in Processes) { var TheProcess = kvp.Value; if (TheProcess.CommandPrompt == null || !TheProcess.CommandPrompt.IsStillRunning) { ToRemove.Add(kvp.Key); } } foreach (string Key in ToRemove) { Processes.Remove(Key); } // Next check if we have this process already open, referenced by full username... string FullUserName; if (Domain.Length > 0) { FullUserName = Domain + "\\" + UserName; } else { FullUserName = UserName; } if (Processes.ContainsKey(FullUserName)) { CredentialValidation.ValidateUser(Domain, UserName, Password); ConnectedProcess = Processes[FullUserName]; if (!ConsoleApi.AttachConsole((uint)ConnectedProcess.CommandPrompt.ProcessId)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } if (Conin != null) { Conin.Dispose(); Conin = null; } Conin = new ConsoleInput(); if (CT != null) { CT.Dispose(); CT = null; } CT = new ConsoleTracker(); string XmlMsg = "<Terminal-Connected Reconnected=\"true\" full-user-name=\"" + FullUserName + "\" />"; byte[] RawMsg = Encoding.Unicode.GetBytes(XmlMsg); SendMessage(NetworkStream, RawMsg); } else { ConnectedProcess = new SlaveProcess(); try { #if DEBUG && ShowCmdWindow ConnectedProcess.Start(Domain, UserName, Password, IsLocalProvider); #else ConnectedProcess.Start(Domain, UserName, Password, false); #endif Processes.Add(FullUserName, ConnectedProcess); Thread.Sleep(2500); // TODO: WaitForInputIdle() would be preferred and more robust. //ConnectedProcess.CommandPrompt.WaitForInputIdle(15000); if (!ConnectedProcess.CommandPrompt.IsStillRunning) { throw new Exception("Newly launched terminal appears to have exited immediately or never actually launched."); } if (!ConsoleApi.AttachConsole((uint)ConnectedProcess.CommandPrompt.ProcessId)) { this.Log.WriteLine("AttachConsole() failed.", Severity.Debug); throw new Win32Exception(Marshal.GetLastWin32Error()); } this.Log.WriteLine("Console attached.", Severity.Debug); if (Conin != null) { Conin.Dispose(); Conin = null; } Conin = new ConsoleInput(); if (CT != null) { CT.Dispose(); CT = null; } CT = new ConsoleTracker(); this.Log.WriteLine("Console established without errors.", Severity.Debug); } finally { if (ConnectedProcess.CommandPrompt.DebugLog.Length > 0) { this.Log.WriteLine(ConnectedProcess.CommandPrompt.DebugLog.ToString(), Severity.Debug); string XmlMsg = "<Debug>" + ConnectedProcess.CommandPrompt.DebugLog.ToString() + "</Debug>"; byte[] RawMsg = Encoding.Unicode.GetBytes(XmlMsg); SendMessage(NetworkStream, RawMsg); ConnectedProcess.CommandPrompt.DebugLog.Clear(); } } { string XmlMsg = "<Terminal-Connected Reconnected=\"false\" full-user-name=\"" + FullUserName + "\" />"; byte[] RawMsg = Encoding.Unicode.GetBytes(XmlMsg); SendMessage(NetworkStream, RawMsg); } } } } catch (Exception ex) { string EncodedText = System.Convert.ToBase64String(Encoding.Unicode.GetBytes(ex.ToString() + "\n")); string XmlMsg = "<Error>" + EncodedText + "</Error>"; byte[] RawMsg = Encoding.Unicode.GetBytes(XmlMsg); SendMessage(NetworkStream, RawMsg); } } if (xMsg.Name.LocalName == "Console-Input") { // TODO: This xml format isn't very efficient. Could at least string it all into one array of INPUT_RECORDs. List <ConsoleApi.KEY_EVENT_RECORD> Keys = new List <ConsoleApi.KEY_EVENT_RECORD>(); foreach (var Key in xMsg.Elements()) { if (Key.Name != "Key") { throw new FormatException("Expected <Key> objects in <Console-Input>"); } ConsoleApi.KEY_EVENT_RECORD KER = new ConsoleApi.KEY_EVENT_RECORD(); KER.bKeyDown = Boolean.Parse(Key.Attribute("down").Value); KER.dwControlKeyState = (ConsoleApi.ControlKeyState)UInt32.Parse(Key.Attribute("ctrl").Value); KER.UnicodeChar = (char)UInt32.Parse(Key.Attribute("char").Value); KER.wRepeatCount = UInt16.Parse(Key.Attribute("repeat").Value); KER.wVirtualKeyCode = UInt16.Parse(Key.Attribute("key").Value); KER.wVirtualScanCode = UInt16.Parse(Key.Attribute("scan").Value); Keys.Add(KER); } //byte[] Raw = System.Convert.FromBase64String(xMsg.Value); //string Msg = Encoding.Unicode.GetString(Raw); lock (ProcessLock) { if (ConnectedProcess != null) { StringBuilder Text = new StringBuilder(); foreach (var Key in Keys) { Text.Append(Key.UnicodeChar); } //Debug.WriteLine("Writing to console as input: '" + Text + "'"); ConsoleApi.INPUT_RECORD[] irs = new ConsoleApi.INPUT_RECORD[1]; ConsoleApi.INPUT_RECORD ir = new ConsoleApi.INPUT_RECORD(); ir.EventType = (ushort)ConsoleApi.EventTypes.KEY_EVENT; foreach (var Key in Keys) { ir.KeyEvent = Key; irs[0] = ir; Conin.Write(irs); } //Thread.Sleep(50); //CT.DebugWholeConsole(); } } } if (xMsg.Name.LocalName == "Reload-Console") { lock (ProcessLock) CT.PendingReload = true; } } catch (Exception ex) { Debug.Write("Exception detected in SlaveCore.OnMessageReceived(): " + ex.ToString()); throw ex; } }
protected void ClientThreadEntry() { try { TcpListener listenerV4 = new TcpListener(IPAddress.Any, PortNumber); TcpListener listenerV6 = new TcpListener(IPAddress.IPv6Any, PortNumber); listenerV4.Start(10); listenerV6.Start(10); // Start listening for connections. Log.WriteLine("Listening for TCP connections on port " + PortNumber + "...\n", Severity.Debug); while (!Stopping) { TcpClient ClientRequest; try { if (listenerV4.Pending()) { ClientRequest = listenerV4.AcceptTcpClient(); } else if (listenerV6.Pending()) { ClientRequest = listenerV6.AcceptTcpClient(); } else { Thread.Sleep(250); continue; } Log.WriteLine("TCP Client accepted.\n", Severity.Debug); NetworkStream = new SslStream(ClientRequest.GetStream(), false); NetworkStream.AuthenticateAsServer(GetRemoteDesktopCertificate(), false, SslProtocols.Tls12, true); if (!NetworkStream.IsAuthenticated) { NetworkStream = null; Log.WriteLine("Unable to authenticate incoming connection from " + ((IPEndPoint)ClientRequest.Client.RemoteEndPoint).Address.ToString() + ".", Severity.Warning); ClientRequest.Close(); continue; } if (!NetworkStream.IsEncrypted) { NetworkStream = null; Log.WriteLine("Unable to encrypt incoming connection from " + ((IPEndPoint)ClientRequest.Client.RemoteEndPoint).Address.ToString() + ".", Severity.Warning); ClientRequest.Close(); continue; } // Display the properties and settings for the authenticated stream. Log.WriteLine("Authentication successful [host].\n", Severity.Debug); #if DEBUG DisplaySecurityLevel(Log, NetworkStream, Severity.Debug); DisplaySecurityServices(Log, NetworkStream, Severity.Debug); DisplayCertificateInformation(Log, NetworkStream, Severity.Debug); DisplayStreamProperties(Log, NetworkStream, Severity.Debug); #endif // Transmit our version info as a hello. System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location); string version = fvi.FileVersion; string XmlMsg = "<Portal-Version Core-Library=\"" + fvi.FileVersion + "\" />"; byte[] RawMsg = Encoding.Unicode.GetBytes(XmlMsg); if (NetworkStream != null) { SendMessage(NetworkStream, RawMsg); } } catch (Win32Exception ex) { Log.WriteLine("Exception accepting new connection: " + ex.ToString(), Severity.Debug); if ((uint)ex.ErrorCode == 0x80004005) { // The credentials supplied to the pacakage were not recognized. // This error comes up rom NetworkStream.AuthenticateAsServer() or GetRemoteDesktopCertificate() for localhost slave when there is no administrative access. Log.WriteLine("This exception usually indicates that administrative access was required but not present.", Severity.Debug); } continue; } catch (Exception ex) { // Note: "The credentials supplied to the package were not recognized" is probably a sign that the code doesn't have Administrator access and can't access the subsystem or certificate it needs. Log.WriteLine("Exception accepting new connection: " + ex.ToString(), Severity.Debug); continue; } try { ServiceConnection(NetworkStream, ClientRequest, ClientRequest.GetStream()); } catch (Exception ex) { Log.WriteLine("Exception servicing connection: " + ex.ToString(), Severity.Debug); } lock (ProcessLock) { // Setting ConnectedProcess to null before accepting a new connection is essential to security. It prevents access to the console without a new authentication and Connect-Terminal. ConnectedProcess = null; // If we aren't attached to a console, FreeConsole() would return ERROR_INVALID_PARAMETER. ConsoleApi.FreeConsole(); Log.WriteLine("Closing connection in SlaveCore (if it isn't already).", Severity.Debug); if (ClientRequest != null) { ClientRequest.Dispose(); ClientRequest = null; } if (Conin != null) { Conin.Dispose(); Conin = null; } if (CT != null) { CT.Dispose(); CT = null; } } } lock (ProcessLock) { ConnectedProcess = null; foreach (var kvp in Processes) { kvp.Value.Dispose(); } Processes.Clear(); } } catch (Exception e) { Log.WriteLine("Error: " + e.ToString(), Severity.Error); } }
public void Init() { instance = new ConsoleApi(); }
static Console() { Handler = ConsoleCtrlHandler; ConsoleApi.SetConsoleCtrlHandler(Handler, true); SystemEvents.SessionEnding += SystemEvents_SessionEnding; }
public GetIntersightConsoleConsoleConfig() { ApiInstance = new ConsoleApi(Config); MethodName = "GetConsoleConsoleConfigListWithHttpInfo"; }