démarrage d'un processus élevé UAC d'un service non interactif (Win32 / NET / powershell)
-
19-09-2019 - |
Question
J'utilise une partie thrid service Windows qui gère des tâches d'automatisation par scripts en cours d'exécution et les exécutables utilisant CreateProcessAsUser (). Je suis en cours d'exécution dans des problèmes sur Windows Server 2008 en raison de l'UAC et ainsi l'élévation LUA est manipulé par les API.
Le service fonctionne en tant que LocalSystem et ne pas « interagir avec le bureau » est activée. Les processus sont en cours d'exécution en tant que les utilisateurs du groupe Administrateurs, mais pas le compte Administrateur (qui est exempté de nombreuses restrictions CCU). Tous les paramètres par défaut. UAC en place
Je peux passer des commandes arbitraires ou code powershell au service, mais je ne peux pas sembler « sortir » de la non-élevée, processus non interactif qui obtient lancé par le service.
Le nœud du problème semble être que la seule option API (public) pour le démarrage d'un processus élevé est ShellExecute () avec le verbe les «runas de, mais pour autant que je peux dire que ne peut pas être appelé à partir d'un service non interactif ou vous obtenez des erreurs comme « Cette opération nécessite une station de fenêtre interactive ».
La seule solution que j'ai trouvé est mentionné ici: http://www.eggheadcafe.com/ logiciel / aspnet / 29620442 / comment-approprié à utiliser-sendinp.aspx
Dans Vista, la voie officielle documentée d'élever un processus est seulement en utilisant la shell API ShellExecute (Ex) (non CreateProcess ou CreateProcessAsUser). Ainsi, votre application doit appeler ShellExecute (Ex) pour lancer un assistant élevée pour appeler SendInput. En outre, en raison de la Session 0 l'isolement, un service ne peut utiliser CreateProcessAsUser ou CreateProcessWithLogonW (ne peut pas utiliser ShellExecute (Ex)) pour spécifier le bureau interactif.
.. Je pense qu'il n'y a aucun moyen direct de engendrer un processus élevée à partir d'un service de fenêtres. Nous ne pouvons utiliser d'abord CreateProcessAsUser ou CreateProcessWithLogonW pour frayer un Procédé non-élevée à l'utilisateur session (bureau interactif). Puis dans le processus non élevée, il peut utiliser ShellExecute (Ex) pour frayer une élévation processus pour la tâche réelle.
Pour ce faire, de .net / code Powershell, il semble que je dois faire quelques trucs P / Invoke élaborée pour appeler CreateProcessAsUser ou CreateProcessWithLogonW depuis le .Net System.Diagnostics.ProcessStartInfo ne dispose pas d'un équivalent de lpDesktop que je pouvais mettre à « winsta0 \ default ». Et je ne suis pas certain si LocalSystem a même le droit d'appeler CreateProcessAsUser ou CreateProcessWithLogonW.
J'ai aussi regardé http: //blogs.msdn.com/alejacma/archive/2007/12/20/how-to-call-createprocesswithlogonw-createprocessasuser-in-net.aspx et Process.Start avec différentes informations d'identification avec contrôle de compte sur
Sur la base de tout cela, je suis parvenu à la conclusion qu'il n'y a aucun moyen simple de le faire. Est-ce que je manque quelque chose? Cela ne semble pas vraiment comme il devrait être si difficile. Il se sent comme tout simplement jamais été UAC conçu pour traiter les cas d'utilisation non interactifs.
Et si les Microsoft gens finissent par lire ceci, j'ai remarqué que la façon dont ShellExecute gère en interne l'élévation est en appelant à la demande Service d'information (AIS). Pourquoi est-ce même pas appel à AIS disponible via une API Win32 ou .NET? http://msdn.microsoft.com/en-us/library/bb756945. aspx
Désolé qui a couru un peu long. Merci pour toutes les idées.
La solution
La façon de briser l'isolement zéro séance « officielle » est d'utiliser une combinaison de l'API de services terminaux et CreateProcessAsUser()
de lancer un processus dans la session d'un utilisateur. A mon ancien emploi, nous avons fait exactement cela, car nous avions besoin pour afficher une boîte de dialogue à l'utilisateur d'un service avant d'installer une mise à jour téléchargée Donc, je sais que cela fonctionne, sur Windows XP, Win2K3, Vista et Win7 au moins, mais je ne vous attendez pas que Win 2K8 serait trop différent. Fondamentalement, le processus se déroule comme suit:
- Appel
WTSGetActiveConsoleSessionId()
pour obtenir l'identifiant de session de la console active (très important, car la session interactive est pas toujours la session 1, même sur les systèmes clients). Cette API sera également de retour -1 s'il n'y a pas d'utilisateur actif connecté à la session interactive (qui est connecté localement à la machine physique, par opposition à l'utilisation de RDP). - Faites passer l'identifiant de session de l'appel API avant
WTSQueryUserToken()
pour obtenir un jeton ouvert qui reprents l'utilisateur connecté à la console. - Appel
DuplicateTokenEx()
pour convertir le jeton d'emprunt d'identité (deWTSQueryUserToken
) dans un jeton primaire. - Appel
CreateEnvironmentBlock()
pour créer un nouvel environnement pour le processus (en option, mais si vous ne le faites pas, le processus a pas). - Faire passer le jeton principal de l'étape 3 dans un appel à
CreateProccessAsUser()
, ainsi que la ligne de commande de l'exécutable. Si vous avez créé un bloc d'environnement de l'étape 4, vous devez passer le drapeauCREATE_UNICODE_ENVIRONMENT
et (toujours). Cela peut sembler stupide, mais l'API échoue horriblement si vous ne le faites pas (avecERROR_INVALID_PARAMTER
). - Si vous avez créé un bloc d'environnement, alors vous devez appeler
DestroyEnvironmentBlock
, sinon vous allez générer une fuite de mémoire. Le processus reçoit une copie séparée du bloc de l'environnement lors de son lancement, de sorte que vous ne sont en train de détruire les données locales.
Et le tour est joué! Windows ne magie interne, et vous voyez le lancement de l'application. Cependant, bien que cela va lancer et processus interactif d'un service, je ne suis pas sûr si elle contournera UAC (mais ne me citez pas cela). En d'autres termes, il ne peut pas lancer comme un processus élevé à moins que le registre ou manifeste interne dit de le faire, et même alors, vous pourrait toujours obtenir une invite UAC. Si le jeton que vous obtenez de l'étape 3 est un jeton restreint, vous pourriez être en mesure d'utiliser AdjustTokenPrivileges()
pour restaurer le jeton élevé (complet), mais ne me citez pas non plus. Toutefois, comme indiqué dans la documentation MSDN, s'il vous plaît noter qu'il est impossible de « ajouter » des privilèges sur un jeton qui ne le sont pas encore (par exemple, vous ne pouvez pas transformer un jeton d'utilisateur restreint en un administrateur en utilisant AdjustTokenPrivileges
, le sous-jacent utilisateur doit être administrateur pour commencer).
Il est techniquement possible de faire tout cela à partir Win2K avant. Cependant, il est vraiment possible que commencer avec Windows XP, Win2K manque de l'API et WTSGetActiveConsoleSessionId()
WTSQueryUserToken()
(avec WTSEnumerateProcesses()
pour Win2K Pro). Vous pouvez coder en dur 0 comme l'identifiant de session (puisque c'est toujours le cas dans Win2K), et je suppose que vous pourriez être en mesure d'obtenir le jeton d'utilisateur en dénombrant les processus en cours et dupliquer un de leurs jetons (il devrait être celui qui a le SID interactive présent). Peu importe, le CreateProcessAsUser()
se comportera de la même manière lorsqu'il est passé un jeton d'utilisateur interactif, même si vous ne sélectionnez pas « interagir avec le bureau » des paramètres de service. Il est également plus sûr que le lancement directement du service de toute façon, que le processus ne sera pas hériter le jeton divin d'accès LocalSystem
.
Maintenant, je ne sais pas si votre application tierce que tout cela quand il exécute le script / processus, mais si vous voulez le faire d'un service, qui est de savoir comment (et avec Vista ou Win7, c'est la seule façon de surmonter la session 0 isolement).
Autres conseils
En fonction, vous pouvez faire votre cas d'utilisation ce que je fais. Je chasse le processus winlogon pour la session active et son jeton vole. S'il n'y a pas de session active (API retourne -1), utilisez 1 si WINVER> = 6 sinon 0. Il en résulte SYSTEM sur la session active.