2010-03-11 8 views
14

Ich verwende einen Windows-Dienst von Drittanbietern, der einige Automatisierungsaufgaben durch Ausführen von Skripts und ausführbaren Dateien mithilfe von CreateProcessAsUser() verarbeitet. Ich habe Probleme mit Windows Server 2008 aufgrund der UAC und der Art und Weise, wie die LUA-Erhöhung über die APIs gehandhabt wird.Starten eines erhöhten UAC-Prozesses von einem nicht interaktiven Dienst (win32/.net/powershell)

Der Dienst wird als LocalSystem ausgeführt und hat keine Interaktion mit dem Desktop aktiviert. Die Prozesse werden als Benutzer in der Gruppe Administratoren ausgeführt, nicht jedoch als Administratorkonto (das von vielen UAC-Einschränkungen ausgenommen ist). Alle UAC-Standardeinstellungen sind vorhanden.

Ich kann beliebige Befehle oder Powershell-Code an den Dienst übergeben, aber ich kann nicht von dem nicht erhöhten, nicht interaktiven Prozess, der vom Dienst gestartet wird, "ausbrechen". Der Kern des Problems scheint zu sein, dass die einzige (öffentliche) API-Option zum Starten eines erhöhten Prozesses ShellExecute() mit dem Verb "runas" ist, aber soweit ich sagen kann, kann nicht von dort aufgerufen werden ein nicht interaktiver Dienst oder Sie erhalten Fehler wie "Dieser Vorgang erfordert eine interaktive Fensterstation".

Die einzige Abhilfe, die ich gefunden habe, ist hier erwähnt: http://www.eggheadcafe.com/software/aspnet/29620442/how-to-proper-use-sendinp.aspx

In Vista, die offizielle Art und Weise dokumentiert ein Verfahren zu erheben nur mit der Shell API ShellExecute (Ex) (nicht Createprocess oder CreateProcessAsUser). Ihre Anwendung muss daher ShellExecute (Ex) aufrufen, um einen Helper ausgelöst zu starten, um SendInput aufzurufen. Außerdem ist es aufgrund Sitzung 0 Isolation kann ein Service verwendet nur CreateProcessAsUser oder CreateProcessWithLogonW (nicht ShellExecute (Ex) verwenden kann), um die interaktive Desktop zu spezifizieren.

..Ich denke, es gibt keinen direkten Weg zu spawnen einen erhöhten Prozess von einem Windows-Dienst. Wir können zuerst CreateProcessAsUser oder CreateProcessWithLogonW verwenden, um einen nicht erhöhten Prozess in den Benutzer Sitzung (interaktiver Desktop) zu spawnen. Dann in der nicht erhöhten Prozess, kann es ShellExecute (Ex) verwenden, um einen erhöhten Prozess für die echte Aufgabe zu generieren.

Um dies zu tun, von .net/Powershell-Code, es sieht aus wie ich einige aufwendige P zu tun haben würde/Invoke Sachen CreateProcessAsUser oder CreateProcessWithLogonW seit dem .Net System.Diagnostics.ProcessStartInfo zu nennen ein nicht haben Äquivalent von lpDesktop, das ich auf "winsta0 \ default" einstellen könnte. Und ich bin nicht klar, ob LocalSystem sogar die Rechte hat, CreateProcessAsUser oder CreateProcessWithLogonW aufzurufen.

Ich sah auch bei http://blogs.msdn.com/alejacma/archive/2007/12/20/how-to-call-createprocesswithlogonw-createprocessasuser-in-net.aspx und Process.Start with different credentials with UAC on

Basierend auf dass alle, ich bin zu dem Schluss erreicht, dass es keine einfache Möglichkeit, dies zu tun. Fehle ich etwas? Das scheint wirklich nicht so schwer zu sein. Es fühlt sich an, als wäre UAC nie nur für nicht interaktive Anwendungsfälle konzipiert worden.

Und wenn irgendwelche Microsoft-Leute am Ende das lesen, bemerkte ich, dass die Art, wie ShellExecute intern die Höhe behandelt, durch den Aufruf an Application Information Service (AIS). Warum ist AIS nicht über eine Win32- oder .NET-API verfügbar? http://msdn.microsoft.com/en-us/library/bb756945.aspx

Sorry, das lief ein bisschen lang. Danke für jede Idee.

+0

Sagen Sie lieber, dass Server Core UAC nicht unterstützt. Scheint meine Einschätzung zu bestätigen. http://blogs.technet.com/server_core/archive/2009/01/19/user-account-control-uac-and-server-core.aspx –

+0

Siehe meinen Beitrag hier, der erklärt, wie insbesondere die LinkedToken aussehen Abschnitt: http://brianbondy.com/blog/id/100/understanding-windows-at-a-deeper-level-sessions-window-stations-and-desktops –

Antwort

16

Der "offizielle" Weg zum Zerbrechen der Isolation bei Session Zero besteht darin, eine Kombination aus Terminal-Services-API und CreateProcessAsUser() zu verwenden, um einen Prozess innerhalb einer Benutzersitzung zu starten. Bei meinem alten Job haben wir genau das getan, da wir vor der Installation eines heruntergeladenen Updates einen Dialog für den Benutzer von einem Dienst anzeigen mussten. Also weiß ich, dass es funktioniert, zumindest unter WinXP, Win2K3, Vista und Win7, aber ich Erwarte nicht, dass Win 2K8 zu anders wäre. Grundsätzlich geht der Prozess wie folgt:

  1. Anruf WTSGetActiveConsoleSessionId() die aktive Konsole Session-ID zu bekommen (sehr wichtig, da die interaktive Sitzung ist NICHT immer Sitzung 1, auch auf Client-Systemen). Diese API gibt auch eine -1 zurück, wenn kein aktiver Benutzer in der interaktiven Sitzung angemeldet ist (dh lokal bei der physischen Maschine angemeldet ist, anstatt RDP zu verwenden).
  2. Übergeben Sie die Sitzungs-ID aus dem vorherigen API-Aufruf an WTSQueryUserToken(), um ein geöffnetes Token zu erhalten, das den in der Konsole angemeldeten Benutzer darstellt.
  3. Rufen Sie DuplicateTokenEx() auf, um das Identitätswechsel-Token (von WTSQueryUserToken) in ein primäres Token zu konvertieren.
  4. Rufen Sie CreateEnvironmentBlock() an, um eine neue Umgebung für den Prozess zu erstellen (optional, aber falls nicht, wird der Prozess keine haben).
  5. Übergeben Sie das primäre Token aus Schritt 3 in einen Aufruf an CreateProccessAsUser() zusammen mit der Befehlszeile für die ausführbare Datei. Wenn Sie einen Umgebungsblock aus Schritt 4 erstellt haben, müssen Sie auch das Flag CREATE_UNICODE_ENVIRONMENT (immer) übergeben. Dies mag albern erscheinen, aber die API schlägt schrecklich fehl, wenn Sie das nicht tun (mit ERROR_INVALID_PARAMTER).
  6. Wenn Sie einen Umgebungsblock erstellt haben, müssen Sie DestroyEnvironmentBlock aufrufen, andernfalls generieren Sie ein Speicherleck. Der Prozess erhält beim Start eine separate Kopie des Umgebungsblocks, sodass Sie nur lokale Daten zerstören.

Und voila! Windows macht einige interne Magie, und Sie sehen den Start der Anwendung. Obwohl dies von einem Dienst gestartet und interaktiv ausgeführt wird, bin ich mir nicht sicher, ob es UAC umgehen wird (aber zitieren Sie mich nicht dazu). Mit anderen Worten, es wird möglicherweise nicht als ein erhöhter Prozess gestartet, es sei denn, die Registrierung oder das interne Manifest sagt dies, und selbst dann erhalten Sie möglicherweise immer noch eine UAC-Eingabeaufforderung. Wenn das Token aus Schritt 3 ein eingeschränktes Token ist, können Sie möglicherweise AdjustTokenPrivileges() verwenden, um das erhöhte (vollständige) Token wiederherzustellen, aber zitieren Sie mich auch nicht darauf. Beachten Sie jedoch, dass es in den MSDN-Dokumenten nicht möglich ist, Privilegien für ein Token hinzuzufügen, das sie noch nicht hatte (z. B. können Sie ein Token mit eingeschränktem Benutzerrecht nicht als Administrator verwenden, indem Sie AdjustTokenPrivileges; das zugrunde liegende Element verwenden Benutzer müsste ein Administrator sein, um mit zu beginnen).

Es ist technisch möglich, all dies von Win2K vorwärts zu tun. Allerdings ist es wirklich nur möglich, beginnend mit WinXP, als Win2K fehlt die WTSGetActiveConsoleSessionId() und WTSQueryUserToken() APIs (zusammen mit WTSEnumerateProcesses() für Win2K Pro). Sie können 0 als Sitzungs-ID fest codieren (da dies in Win2K immer der Fall ist), und ich nehme an, Sie könnten das Benutzer-Token abrufen, indem Sie die laufenden Prozesse aufzählen und eines ihrer Tokens duplizieren (es sollte eines sein der interaktive SID vorhanden).Unabhängig davon verhält sich die CreateProcessAsUser() auf dieselbe Weise, wenn Sie ein interaktives Benutzer-Token übergeben, auch wenn Sie in den Diensteinstellungen nicht "Interagieren mit dem Desktop" auswählen. Es ist auch sicherer als direkt vom Dienst starten, da der Prozess das göttliche LocalSystem Zugriffstoken nicht erbt.

Jetzt weiß ich nicht, ob Ihre Drittanbieter-App dies tut, wenn es das Skript/den Prozess ausführt, aber wenn Sie es von einem Dienst ausführen möchten, ist dies (und mit Vista oder Win7, ist es der einzige Weg zur Überwindung der Isolation von Sitzung 0).

+3

Es ist nicht notwendig, 'DuplicateTokenEx' aufzurufen. 'CreateProcessAsUser' würde den Prozess mit dem Token ausführen, das von' WTSQueryUserToken' erhalten wurde. Ihre Antwort ist ziemlich detailliert, aber beantwortet nicht "Wie gestarteten erhöhten Prozess vom Dienst? (UAC aktiviert)" – Ajay

+1

Tatsächlich tut es nicht. Dies wird Sie mit einem eingeschränkten Token verlassen. – Joshua

+0

Es gibt ein paar Dinge zu beachten: 1) Da @Ajay erwähnt 'WTSQueryUserToken' gibt bereits ein primäres Token zurück, so dass Sie Schritt 3 überspringen können. 2) Bei aktivierter UAC müssen Sie nach Schritt 2 das sogenannte Linked Token erhalten , was Sie tun, indem Sie 'GetTokenInformation' mit der' TokenLinkedToken' -Informationsklasse aufrufen, aber nur, wenn die Abfrage des 'TokenElevationType' besagt, dass die Höhe begrenzt ist. 3) Wenn Sie keinen Umgebungsblock erstellen, hat der neue Prozess die Umgebung des Erstellungsprozesses, die Ihr Service ist –

1

Abhängig von Ihrem Anwendungsfall könnten Sie tun, was ich tue. Ich jage den Winlogon-Prozess für die aktive Sitzung und klaue seinen Token. Wenn es keine aktive Sitzung gibt (API gab -1 zurück), verwenden Sie 1, wenn WINVER> = 6, andernfalls 0. Dies führt zu SYSTEM in der aktiven Sitzung.

Verwandte Themen